Skip to content

Commit 7592b2a

Browse files
authored
Merge pull request #2425 from jmyvalour/iox-2408-multi-domain-id-req-rep
Iox 2408 multi domain id req rep
2 parents 4449fcf + 436040b commit 7592b2a

35 files changed

+1235
-8
lines changed

iceoryx_examples/experimental/node/CMakeLists.txt

+12
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,15 @@ iox_add_executable(
4040
FILES ./iox_cpp_node_subscriber.cpp
4141
LIBS iceoryx_posh::iceoryx_posh
4242
)
43+
44+
iox_add_executable(
45+
TARGET iox-cpp-node-server
46+
FILES ./iox_cpp_node_server.cpp
47+
LIBS iceoryx_posh::iceoryx_posh
48+
)
49+
50+
iox_add_executable(
51+
TARGET iox-cpp-node-client
52+
FILES ./iox_cpp_node_client.cpp
53+
LIBS iceoryx_posh::iceoryx_posh
54+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Copyright (c) 2025 by Valour Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
//! [iceoryx includes]
18+
#include "request_and_response_types.hpp"
19+
20+
#include "topic_data.hpp"
21+
22+
#include "iox/optional.hpp"
23+
#include "iox/posh/experimental/node.hpp"
24+
#include "iox/signal_watcher.hpp"
25+
26+
#include <iostream>
27+
28+
constexpr char APP_NAME[] = "iox-cpp-node-client";
29+
volatile bool keepRunning = {true};
30+
31+
using WaitSet = iox::popo::WaitSet<>;
32+
volatile WaitSet* waitsetSigHandlerAccess{nullptr};
33+
34+
//! [context data to store Fibonacci numbers and sequence ids]
35+
struct ContextData
36+
{
37+
uint64_t fibonacciLast = 0;
38+
uint64_t fibonacciCurrent = 1;
39+
int64_t requestSequenceId = 0;
40+
int64_t expectedResponseSequenceId = requestSequenceId;
41+
};
42+
//! [context data to store Fibonacci numbers and sequence ids]
43+
44+
static void signalHandler(int sig [[maybe_unused]])
45+
{
46+
keepRunning = false;
47+
if (waitsetSigHandlerAccess)
48+
{
49+
waitsetSigHandlerAccess->markForDestruction();
50+
}
51+
}
52+
53+
int main()
54+
{
55+
auto sigTermGuard =
56+
iox::registerSignalHandler(iox::PosixSignal::TERM, signalHandler).expect("failed to register SIGTERM");
57+
auto sigIntGuard =
58+
iox::registerSignalHandler(iox::PosixSignal::INT, signalHandler).expect("failed to register SIGINT");
59+
60+
//! [create the node]
61+
auto node_result = iox::posh::experimental::NodeBuilder(APP_NAME).domain_id_from_env_or_default().create();
62+
63+
while (keepRunning && node_result.has_error())
64+
{
65+
std::cout << "Could not create the node!" << std::endl;
66+
67+
node_result = iox::posh::experimental::NodeBuilder(APP_NAME)
68+
.domain_id_from_env_or_default()
69+
.roudi_registration_timeout(iox::units::Duration::fromSeconds(1))
70+
.create();
71+
}
72+
73+
auto node = std::move(node_result.value());
74+
//! [create the node]
75+
76+
77+
//! [create waitset]
78+
auto waitset = node.wait_set().create().expect("Getting a wait set");
79+
waitsetSigHandlerAccess = waitset.get();
80+
81+
//! [create client]
82+
auto client = node.client({"Example", "Request-Response", "Add"})
83+
.response_queue_capacity(2)
84+
.create<AddRequest, AddResponse>()
85+
.expect("Getting a client");
86+
//! [create client]
87+
88+
// attach client to waitset
89+
waitset->attachState(*client.get(), iox::popo::ClientState::HAS_RESPONSE).or_else([](auto) {
90+
std::cerr << "failed to attach client" << std::endl;
91+
std::exit(EXIT_FAILURE);
92+
});
93+
//! [create waitset]
94+
95+
ContextData ctx;
96+
97+
//! [mainloop]
98+
while (keepRunning)
99+
{
100+
//! [send request]
101+
client->loan()
102+
.and_then([&](auto& request) {
103+
request.getRequestHeader().setSequenceId(ctx.requestSequenceId);
104+
ctx.expectedResponseSequenceId = ctx.requestSequenceId;
105+
ctx.requestSequenceId += 1;
106+
request->augend = ctx.fibonacciLast;
107+
request->addend = ctx.fibonacciCurrent;
108+
std::cout << APP_NAME << " Send Request: " << ctx.fibonacciLast << " + " << ctx.fibonacciCurrent
109+
<< std::endl;
110+
request.send().or_else(
111+
[&](auto& error) { std::cout << "Could not send Request! Error: " << error << std::endl; });
112+
})
113+
.or_else([](auto& error) { std::cout << "Could not allocate Request! Error: " << error << std::endl; });
114+
//! [send request]
115+
116+
117+
// We block and wait for samples to arrive, when the time is up we send the request again
118+
//! [wait and check if the client triggered]
119+
auto notificationVector = waitset->timedWait(iox::units::Duration::fromSeconds(5));
120+
121+
for (auto& notification : notificationVector)
122+
{
123+
if (notification->doesOriginateFrom(client.get()))
124+
{
125+
//! [take response]
126+
while (client->take().and_then([&](const auto& response) {
127+
auto receivedSequenceId = response.getResponseHeader().getSequenceId();
128+
if (receivedSequenceId == ctx.expectedResponseSequenceId)
129+
{
130+
ctx.fibonacciLast = ctx.fibonacciCurrent;
131+
ctx.fibonacciCurrent = response->sum;
132+
std::cout << APP_NAME << " Got Response : " << ctx.fibonacciCurrent << std::endl;
133+
}
134+
else
135+
{
136+
std::cout << "Got Response with outdated sequence ID! Expected = "
137+
<< ctx.expectedResponseSequenceId << "; Actual = " << receivedSequenceId
138+
<< "! -> skip" << std::endl;
139+
}
140+
}))
141+
{
142+
}
143+
//! [take response]
144+
}
145+
}
146+
//! [wait and check if the client triggered]
147+
constexpr std::chrono::milliseconds SLEEP_TIME{950U};
148+
std::this_thread::sleep_for(SLEEP_TIME);
149+
}
150+
//! [mainloop]
151+
152+
std::cout << "shutting down" << std::endl;
153+
154+
waitsetSigHandlerAccess = nullptr; // invalidate for signal handler
155+
156+
return (EXIT_SUCCESS);
157+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) 2025 by Valour Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
//! [iceoryx includes]
18+
#include "request_and_response_types.hpp"
19+
20+
#include "iox/optional.hpp"
21+
#include "iox/posh/experimental/node.hpp"
22+
#include "iox/signal_watcher.hpp"
23+
//! [iceoryx includes]
24+
25+
#include <iostream>
26+
27+
constexpr char APP_NAME[] = "iox-cpp-node-server";
28+
volatile bool keepRunning = {true};
29+
30+
static void signalHandler(int sig [[maybe_unused]])
31+
{
32+
keepRunning = false;
33+
}
34+
35+
//! [request callback]
36+
void onRequestReceived(iox::popo::Server<AddRequest, AddResponse>* server)
37+
{
38+
//! [take request]
39+
while (server->take().and_then([&](const auto& request) {
40+
std::cout << APP_NAME << " Got Request: " << request->augend << " + " << request->addend << std::endl;
41+
42+
//! [send response]
43+
server->loan(request)
44+
.and_then([&](auto& response) {
45+
response->sum = request->augend + request->addend;
46+
std::cout << APP_NAME << " Send Response: " << response->sum << std::endl;
47+
response.send().or_else(
48+
[&](auto& error) { std::cout << "Could not send Response! Error: " << error << std::endl; });
49+
})
50+
.or_else([](auto& error) { std::cout << "Could not allocate Response! Error: " << error << std::endl; });
51+
//! [send response]
52+
}))
53+
{
54+
}
55+
//! [take request]
56+
}
57+
//! [request callback]
58+
59+
int main()
60+
{
61+
auto sigTermGuard =
62+
iox::registerSignalHandler(iox::PosixSignal::TERM, signalHandler).expect("failed to register SIGTERM");
63+
auto sigIntGuard =
64+
iox::registerSignalHandler(iox::PosixSignal::INT, signalHandler).expect("failed to register SIGINT");
65+
//! [create the node]
66+
auto node_result = iox::posh::experimental::NodeBuilder(APP_NAME).domain_id_from_env_or_default().create();
67+
68+
while (keepRunning && node_result.has_error())
69+
{
70+
std::cout << "Could not create the node!" << std::endl;
71+
72+
node_result = iox::posh::experimental::NodeBuilder(APP_NAME)
73+
.domain_id_from_env_or_default()
74+
.roudi_registration_timeout(iox::units::Duration::fromSeconds(1))
75+
.create();
76+
}
77+
78+
auto node = std::move(node_result.value());
79+
//! [create the node]
80+
81+
//! [create server]
82+
auto server = node.server({"Example", "Request-Response", "Add"})
83+
.request_queue_capacity(10u)
84+
.create<AddRequest, AddResponse>()
85+
.expect("Getting a listener");
86+
//! [create server]
87+
88+
//! [create listener]
89+
auto listener = node.listener().create().expect("Getting a listener");
90+
//! [create listener]
91+
92+
//! [attach listener]
93+
listener
94+
->attachEvent(*server.get(),
95+
iox::popo::ServerEvent::REQUEST_RECEIVED,
96+
iox::popo::createNotificationCallback(onRequestReceived))
97+
.or_else([](auto) {
98+
std::cerr << "unable to attach server" << std::endl;
99+
std::exit(EXIT_FAILURE);
100+
});
101+
//! [attach listener]
102+
103+
//! [wait for termination]
104+
iox::waitForTerminationRequest();
105+
//! [wait for termination]
106+
107+
//! [cleanup]
108+
listener->detachEvent(*server.get(), iox::popo::ServerEvent::REQUEST_RECEIVED);
109+
//! [cleanup]
110+
111+
return EXIT_SUCCESS;
112+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2022 by Apex.AI Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
#ifndef IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP
18+
#define IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP
19+
20+
#include <cstdint>
21+
22+
//! [request]
23+
struct AddRequest
24+
{
25+
uint64_t augend{0};
26+
uint64_t addend{0};
27+
};
28+
//! [request]
29+
30+
//! [response]
31+
struct AddResponse
32+
{
33+
uint64_t sum{0};
34+
};
35+
//! [response]
36+
37+
#endif // IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP

iceoryx_integrationtest/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ if(BUILD_TESTING)
3232
)
3333

3434
if(IOX_EXPERIMENTAL_POSH)
35-
list(APPEND IOX_INT_TESTS test_experimental_node)
35+
list(APPEND IOX_INT_TESTS test_experimental_node_publish_subscribe test_experimental_node_request_response)
3636
else()
3737
message(FATAL_ERROR "Please run colcon with '--meta=path/to/iceoryx_integrationtest/colcon.meta' to enable the experimental feature flag for the integration tests")
3838
endif()

0 commit comments

Comments
 (0)