diff --git a/iceoryx_examples/request_response_basic/CMakeLists.txt b/iceoryx_examples/request_response_basic/CMakeLists.txt new file mode 100644 index 00000000000..73a29b4b4c2 --- /dev/null +++ b/iceoryx_examples/request_response_basic/CMakeLists.txt @@ -0,0 +1,120 @@ +# Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# Build request_response_basic example +cmake_minimum_required(VERSION 3.5) +project(example_request_response_basic) + +include(GNUInstallDirs) + +find_package(iceoryx_posh REQUIRED) +find_package(iceoryx_hoofs REQUIRED) + +get_target_property(ICEORYX_CXX_STANDARD iceoryx_posh::iceoryx_posh CXX_STANDARD) +include(IceoryxPlatform) + +## C++ typed API client +add_executable( + iox-cpp-request-response-basic-client + client_cxx_api.cpp +) +target_link_libraries( + iox-cpp-request-response-basic-client + PRIVATE + iceoryx_hoofs::iceoryx_hoofs + iceoryx_posh::iceoryx_posh +) +target_compile_options( + iox-cpp-request-response-basic-client + PRIVATE + ${ICEORYX_WARNINGS} + ${ICEORYX_SANITIZER_FLAGS} +) + +## C++ typed API client with events +add_executable( + iox-cpp-request-response-event-client + client_cxx_api_event.cpp +) +target_link_libraries( + iox-cpp-request-response-event-client + PRIVATE + iceoryx_hoofs::iceoryx_hoofs + iceoryx_posh::iceoryx_posh +) +target_compile_options( + iox-cpp-request-response-event-client + PRIVATE + ${ICEORYX_WARNINGS} + ${ICEORYX_SANITIZER_FLAGS} +) + +## C++ typed API server +add_executable( + iox-cpp-request-response-basic-server + server_cxx_api.cpp +) +target_link_libraries( + iox-cpp-request-response-basic-server + PRIVATE + iceoryx_hoofs::iceoryx_hoofs + iceoryx_posh::iceoryx_posh +) +target_compile_options( + iox-cpp-request-response-basic-server + PRIVATE + ${ICEORYX_WARNINGS} + ${ICEORYX_SANITIZER_FLAGS} +) + +## C++ typed API server with events +add_executable( + iox-cpp-request-response-event-server + server_cxx_api_event.cpp +) +target_link_libraries( + iox-cpp-request-response-event-server + PRIVATE + iceoryx_hoofs::iceoryx_hoofs + iceoryx_posh::iceoryx_posh +) +target_compile_options( + iox-cpp-request-response-event-server + PRIVATE + ${ICEORYX_WARNINGS} + ${ICEORYX_SANITIZER_FLAGS} +) + +## additional properties +set_target_properties( + iox-cpp-request-response-basic-client + iox-cpp-request-response-basic-server + iox-cpp-request-response-event-client + iox-cpp-request-response-event-server + PROPERTIES + CXX_STANDARD_REQUIRED ON + CXX_STANDARD ${ICEORYX_CXX_STANDARD} + POSITION_INDEPENDENT_CODE ON +) + +install( + TARGETS + iox-cpp-request-response-basic-client + iox-cpp-request-response-basic-server + iox-cpp-request-response-event-client + iox-cpp-request-response-event-server + RUNTIME DESTINATION bin +) diff --git a/iceoryx_examples/request_response_basic/client_cxx_api.cpp b/iceoryx_examples/request_response_basic/client_cxx_api.cpp new file mode 100644 index 00000000000..049e1fda368 --- /dev/null +++ b/iceoryx_examples/request_response_basic/client_cxx_api.cpp @@ -0,0 +1,92 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +//! [iceoryx includes] +#include "request_and_response_types.hpp" + +#include "iceoryx_hoofs/posix_wrapper/signal_watcher.hpp" +#include "iceoryx_posh/popo/client.hpp" +#include "iceoryx_posh/runtime/posh_runtime.hpp" +//! [iceoryx includes] + +#include + +int main() +{ + //! [initialize runtime] + constexpr char APP_NAME[] = "iox-cpp-request-response-client"; + iox::runtime::PoshRuntime::initRuntime(APP_NAME); + //! [initialize runtime] + + //! [create client] + iox::popo::Client client({"Example", "Request-Response", "Add"}); + //! [create client] + + //! [send requests in a loop] + uint64_t fibonacciLast = 0; + uint64_t fibonacciCurrent = 1; + int64_t requestSequenceId = 0; + int64_t expectedResponseSequenceId = requestSequenceId; + while (!iox::posix::hasTerminationRequested()) + { + //! [send request] + client.allocateRequest() + .and_then([&](auto& requestHeader) { + requestHeader->setSequenceId(requestSequenceId); + expectedResponseSequenceId = requestSequenceId; + requestSequenceId += 1; + auto request = static_cast(requestHeader->getUserPayload()); + request->augend = fibonacciLast; + request->addend = fibonacciCurrent; + std::cout << "Send Request: " << fibonacciLast << " + " << fibonacciCurrent << std::endl; + client.sendRequest(requestHeader); + }) + .or_else([](auto& error) { + std::cout << "Could not allocate Request! Return value = " << static_cast(error) << std::endl; + }); + //! [send request] + + // the server polls with an interval of 100ms + constexpr std::chrono::milliseconds DELAY_TIME{150U}; + std::this_thread::sleep_for(DELAY_TIME); + + //! [take response] + while (client.getResponse().and_then([&](auto& responseHeader) { + if (responseHeader->getSequenceId() == expectedResponseSequenceId) + { + auto response = static_cast(responseHeader->getUserPayload()); + fibonacciLast = fibonacciCurrent; + fibonacciCurrent = response->sum; + client.releaseResponse(responseHeader); + std::cout << "Got Response : " << fibonacciCurrent << std::endl; + } + else + { + std::cout << "Got Response with outdated sequence ID! Expected = " << expectedResponseSequenceId + << "; Actual = " << responseHeader->getSequenceId() << "! -> skip" << std::endl; + } + })) + { + }; + //! [take response] + + constexpr std::chrono::milliseconds SLEEP_TIME{950U}; + std::this_thread::sleep_for(SLEEP_TIME); + } + //! [send requests in a loop] + + return EXIT_SUCCESS; +} diff --git a/iceoryx_examples/request_response_basic/client_cxx_api_event.cpp b/iceoryx_examples/request_response_basic/client_cxx_api_event.cpp new file mode 100644 index 00000000000..21b0beab349 --- /dev/null +++ b/iceoryx_examples/request_response_basic/client_cxx_api_event.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +//! [iceoryx includes] +#include "request_and_response_types.hpp" + +#include "iceoryx_hoofs/internal/concurrent/smart_lock.hpp" +#include "iceoryx_hoofs/posix_wrapper/signal_watcher.hpp" +#include "iceoryx_posh/popo/client.hpp" +#include "iceoryx_posh/popo/listener.hpp" +#include "iceoryx_posh/popo/notification_callback.hpp" +#include "iceoryx_posh/runtime/posh_runtime.hpp" +//! [iceoryx includes] + +#include + +struct ContextData +{ + uint64_t fibonacciLast = 0; + uint64_t fibonacciCurrent = 1; + int64_t requestSequenceId = 0; + int64_t expectedResponseSequenceId = requestSequenceId; +}; + +void onResponseReceived(iox::popo::Client* client, + iox::concurrent::smart_lock* ctx) +{ + auto guardedCtx = ctx->getScopeGuard(); + //! [take response] + while (client->getResponse().and_then([&](auto& responseHeader) { + if (responseHeader->getSequenceId() == guardedCtx->expectedResponseSequenceId) + { + auto response = static_cast(responseHeader->getUserPayload()); + guardedCtx->fibonacciLast = guardedCtx->fibonacciCurrent; + guardedCtx->fibonacciCurrent = response->sum; + client->releaseResponse(responseHeader); + std::cout << "Got Response : " << guardedCtx->fibonacciCurrent << std::endl; + } + else + { + std::cout << "Got Response with outdated sequence ID! Expected = " << guardedCtx->expectedResponseSequenceId + << "; Actual = " << responseHeader->getSequenceId() << "! -> skip" << std::endl; + } + })) + { + } + //! [take response] +} + +int main() +{ + //! [initialize runtime] + constexpr char APP_NAME[] = "iox-cpp-request-response-client-event"; + iox::runtime::PoshRuntime::initRuntime(APP_NAME); + //! [initialize runtime] + + iox::popo::Listener listener; + + //! [create client] + iox::popo::Client client({"Example", "Request-Response", "Add"}); + //! [create client] + + iox::concurrent::smart_lock ctx; + + listener + .attachEvent(client, + iox::popo::ClientEvent::RESPONSE_RECEIVED, + iox::popo::createNotificationCallback(onResponseReceived, ctx)) + .or_else([](auto) { + std::cerr << "unable to attach server" << std::endl; + std::exit(EXIT_FAILURE); + }); + + //! [send requests in a loop] + while (!iox::posix::hasTerminationRequested()) + { + //! [send request] + client.allocateRequest() + .and_then([&](auto& requestHeader) { + auto guardedCtx = ctx.getScopeGuard(); + requestHeader->setSequenceId(guardedCtx->requestSequenceId); + guardedCtx->expectedResponseSequenceId = guardedCtx->requestSequenceId; + guardedCtx->requestSequenceId += 1; + auto request = static_cast(requestHeader->getUserPayload()); + request->augend = guardedCtx->fibonacciLast; + request->addend = guardedCtx->fibonacciCurrent; + std::cout << "Send Request: " << guardedCtx->fibonacciLast << " + " << guardedCtx->fibonacciCurrent + << std::endl; + client.sendRequest(requestHeader); + }) + .or_else([](auto& error) { + std::cout << "Could not allocate Request! Return value = " << static_cast(error) << std::endl; + }); + //! [send request] + + constexpr std::chrono::milliseconds SLEEP_TIME{1000U}; + std::this_thread::sleep_for(SLEEP_TIME); + } + //! [send requests in a loop] + + listener.detachEvent(client, iox::popo::ClientEvent::RESPONSE_RECEIVED); + + return EXIT_SUCCESS; +} diff --git a/iceoryx_examples/request_response_basic/request_and_response_types.hpp b/iceoryx_examples/request_response_basic/request_and_response_types.hpp new file mode 100644 index 00000000000..74ae1fb5e51 --- /dev/null +++ b/iceoryx_examples/request_response_basic/request_and_response_types.hpp @@ -0,0 +1,37 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP +#define IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP + +#include + +//! [request] +struct AddRequest +{ + uint64_t augend{0}; + uint64_t addend{0}; +}; +//! [request] + +//! [response] +struct AddResponse +{ + uint64_t sum{0}; +}; +//! [response] + +#endif // IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP diff --git a/iceoryx_examples/request_response_basic/server_cxx_api.cpp b/iceoryx_examples/request_response_basic/server_cxx_api.cpp new file mode 100644 index 00000000000..bb21254bb41 --- /dev/null +++ b/iceoryx_examples/request_response_basic/server_cxx_api.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2021 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +//! [iceoryx includes] +#include "request_and_response_types.hpp" + +#include "iceoryx_hoofs/posix_wrapper/signal_watcher.hpp" +#include "iceoryx_posh/popo/server.hpp" +#include "iceoryx_posh/runtime/posh_runtime.hpp" +//! [iceoryx includes] + +#include + +int main() +{ + //! [initialize runtime] + constexpr char APP_NAME[] = "iox-cpp-request-response-server"; + iox::runtime::PoshRuntime::initRuntime(APP_NAME); + //! [initialize runtime] + + //! [create server] + iox::popo::Server server({"Example", "Request-Response", "Add"}); + //! [create server] + + //! [process requests in a loop] + while (!iox::posix::hasTerminationRequested()) + { + //! [take request] + server.getRequest().and_then([&](auto& requestHeader) { + auto request = static_cast(requestHeader->getUserPayload()); + std::cout << "Got Request: " << request->augend << " + " << request->addend << std::endl; + + //! [send response] + server.allocateResponse(requestHeader) + .and_then([&](auto& responseHeader) { + auto response = static_cast(responseHeader->getUserPayload()); + response->sum = request->augend + request->addend; + std::cout << "Send Response: " << response->sum << std::endl; + server.sendResponse(responseHeader); + }) + .or_else([](auto& error) { + std::cout << "Could not allocate Response! Return value = " << static_cast(error) + << std::endl; + }); + //! [send response] + + server.releaseRequest(requestHeader); + }); + //! [take request] + + constexpr std::chrono::milliseconds SLEEP_TIME{100U}; + std::this_thread::sleep_for(SLEEP_TIME); + } + //! [process requests in a loop] + + return EXIT_SUCCESS; +} diff --git a/iceoryx_examples/request_response_basic/server_cxx_api_event.cpp b/iceoryx_examples/request_response_basic/server_cxx_api_event.cpp new file mode 100644 index 00000000000..7557e07689b --- /dev/null +++ b/iceoryx_examples/request_response_basic/server_cxx_api_event.cpp @@ -0,0 +1,83 @@ +// Copyright (c) 2021 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +//! [iceoryx includes] +#include "request_and_response_types.hpp" + +#include "iceoryx_hoofs/posix_wrapper/signal_watcher.hpp" +#include "iceoryx_posh/popo/listener.hpp" +#include "iceoryx_posh/popo/notification_callback.hpp" +#include "iceoryx_posh/popo/server.hpp" +#include "iceoryx_posh/runtime/posh_runtime.hpp" +//! [iceoryx includes] + +#include + +void onRequestReceived(iox::popo::Server* server) +{ + //! [take request] + while (server->getRequest().and_then([&](auto& requestHeader) { + auto request = static_cast(requestHeader->getUserPayload()); + std::cout << "Got Request: " << request->augend << " + " << request->addend << std::endl; + + //! [send response] + server->allocateResponse(requestHeader) + .and_then([&](auto& responseHeader) { + auto response = static_cast(responseHeader->getUserPayload()); + response->sum = request->augend + request->addend; + std::cout << "Send Response: " << response->sum << std::endl; + server->sendResponse(responseHeader); + }) + .or_else([](auto& error) { + std::cout << "Could not allocate Response! Return value = " << static_cast(error) + << std::endl; + }); + //! [send response] + + server->releaseRequest(requestHeader); + })) + { + } + //! [take request] +} + +int main() +{ + //! [initialize runtime] + constexpr char APP_NAME[] = "iox-cpp-request-response-server-event"; + iox::runtime::PoshRuntime::initRuntime(APP_NAME); + //! [initialize runtime] + + iox::popo::Listener listener; + + //! [create server] + iox::popo::Server server({"Example", "Request-Response", "Add"}); + //! [create server] + + listener + .attachEvent( + server, iox::popo::ServerEvent::REQUEST_RECEIVED, iox::popo::createNotificationCallback(onRequestReceived)) + .or_else([](auto) { + std::cerr << "unable to attach server" << std::endl; + std::exit(EXIT_FAILURE); + }); + + iox::posix::waitForTerminationRequest(); + + listener.detachEvent(server, iox::popo::ServerEvent::REQUEST_RECEIVED); + + return EXIT_SUCCESS; +} diff --git a/iceoryx_meta/CMakeLists.txt b/iceoryx_meta/CMakeLists.txt index a0e4bd76e62..4b5722d7caf 100644 --- a/iceoryx_meta/CMakeLists.txt +++ b/iceoryx_meta/CMakeLists.txt @@ -77,6 +77,7 @@ if(EXAMPLES) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../iceoryx_examples/singleprocess ${CMAKE_BINARY_DIR}/iceoryx_examples/singleprocess) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../iceoryx_examples/ice_access_control ${CMAKE_BINARY_DIR}/iceoryx_examples/ice_access_control) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../iceoryx_examples/complexdata ${CMAKE_BINARY_DIR}/iceoryx_examples/complexdata) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../iceoryx_examples/request_response_basic ${CMAKE_BINARY_DIR}/iceoryx_examples/request_response_basic) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../iceoryx_examples/user_header ${CMAKE_BINARY_DIR}/iceoryx_examples/user_header) endif()