Skip to content

Commit 8c5ec0b

Browse files
committed
Add create_service() to standard bridge loader
Signed-off-by: bdm-k <kokusyunn@gmail.com>
1 parent 1055020 commit 8c5ec0b

3 files changed

Lines changed: 90 additions & 38 deletions

File tree

src/agnocastlib/include/agnocast/bridge/agnocast_bridge_node.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,10 @@ std::shared_ptr<void> start_agno_to_ros_node(
273273

274274
template <typename ServiceT>
275275
std::shared_ptr<void> start_ros_to_agno_service_node(
276-
rclcpp::Node::SharedPtr node, const ServiceBridgeTargetInfo & info, const rmw_qos_profile_t & qos)
276+
rclcpp::Node::SharedPtr node, const ServiceBridgeTargetInfo & info)
277277
{
278278
std::string service_name(static_cast<const char *>(info.name));
279+
const rmw_qos_profile_t & qos = info.qos;
279280
return std::make_shared<RosToAgnocastServiceBridge<ServiceT>>(node, service_name, qos);
280281
}
281282

src/agnocastlib/include/agnocast/bridge/standard/agnocast_standard_bridge_loader.hpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ namespace agnocast
1313

1414
using BridgeFn = std::shared_ptr<void> (*)(
1515
rclcpp::Node::SharedPtr, const PubsubBridgeTargetInfo &, const rclcpp::QoS &);
16+
using ServiceBridgeFn =
17+
std::shared_ptr<void> (*)(rclcpp::Node::SharedPtr, const ServiceBridgeTargetInfo &);
1618

1719
class StandardBridgeLoader
1820
{
@@ -24,21 +26,27 @@ class StandardBridgeLoader
2426
StandardBridgeLoader & operator=(const StandardBridgeLoader &) = delete;
2527

2628
std::shared_ptr<void> create(
27-
const MqMsgBridge & req, const std::string & topic_name_with_direction,
29+
const MqMsgBridge & req, const std::string & bridge_target_key,
2830
const rclcpp::Node::SharedPtr & node, const rclcpp::QoS & qos);
31+
std::shared_ptr<void> create_service(
32+
const MqMsgBridge & req, const std::string & bridge_target_key,
33+
const rclcpp::Node::SharedPtr & node);
2934

3035
private:
3136
rclcpp::Logger logger_;
3237

33-
std::map<std::string, std::pair<BridgeFn, std::shared_ptr<void>>> cached_factories_;
38+
std::map<std::string, std::pair<uintptr_t, std::shared_ptr<void>>> cached_factories_;
3439

3540
std::shared_ptr<void> create_bridge_instance(
3641
BridgeFn entry_func, const std::shared_ptr<void> & lib_handle,
3742
const rclcpp::Node::SharedPtr & node, const PubsubBridgeTargetInfo & target,
3843
const rclcpp::QoS & qos);
44+
std::shared_ptr<void> create_service_bridge_instance(
45+
ServiceBridgeFn entry_func, const std::shared_ptr<void> & lib_handle,
46+
const rclcpp::Node::SharedPtr & node, const ServiceBridgeTargetInfo & target);
3947
static std::pair<void *, uintptr_t> load_library(const char * lib_path, const char * symbol_name);
40-
std::pair<BridgeFn, std::shared_ptr<void>> resolve_factory_function(
41-
const MqMsgBridge & req, const std::string & topic_name_with_direction);
48+
std::pair<uintptr_t, std::shared_ptr<void>> resolve_factory_function(
49+
const MqMsgBridge & req, const std::string & bridge_target_key);
4250
static bool is_address_in_library_code_segment(void * handle, uintptr_t addr);
4351
};
4452

src/agnocastlib/src/bridge/standard/agnocast_standard_bridge_loader.cpp

Lines changed: 76 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,39 @@ StandardBridgeLoader::~StandardBridgeLoader()
2525
}
2626

2727
std::shared_ptr<void> StandardBridgeLoader::create(
28-
const MqMsgBridge & req, const std::string & topic_name_with_direction,
28+
const MqMsgBridge & req, const std::string & bridge_target_key,
2929
const rclcpp::Node::SharedPtr & node, const rclcpp::QoS & qos)
3030
{
31-
auto [entry_func, lib_handle] = resolve_factory_function(req, topic_name_with_direction);
31+
auto [entry_func, lib_handle] = resolve_factory_function(req, bridge_target_key);
3232

33-
if (entry_func == nullptr) {
33+
if (entry_func == 0) {
3434
const char * err = dlerror();
3535
RCLCPP_ERROR(
36-
logger_, "Failed to resolve factory for '%s': %s", topic_name_with_direction.c_str(),
36+
logger_, "Failed to resolve factory for '%s': %s", bridge_target_key.c_str(),
3737
err ? err : "Unknown error");
3838
return nullptr;
3939
}
4040

41-
return create_bridge_instance(entry_func, lib_handle, node, req.pubsub_target, qos);
41+
return create_bridge_instance(
42+
reinterpret_cast<BridgeFn>(entry_func), lib_handle, node, req.pubsub_target, qos);
43+
}
44+
45+
std::shared_ptr<void> StandardBridgeLoader::create_service(
46+
const MqMsgBridge & req, const std::string & bridge_target_key,
47+
const rclcpp::Node::SharedPtr & node)
48+
{
49+
auto [entry_func, lib_handle] = resolve_factory_function(req, bridge_target_key);
50+
51+
if (entry_func == 0) {
52+
const char * err = dlerror();
53+
RCLCPP_ERROR(
54+
logger_, "Failed to resolve factory for '%s': %s", bridge_target_key.c_str(),
55+
err ? err : "Unknown error");
56+
return nullptr;
57+
}
58+
59+
return create_service_bridge_instance(
60+
reinterpret_cast<ServiceBridgeFn>(entry_func), lib_handle, node, req.srv_target);
4261
}
4362

4463
std::shared_ptr<void> StandardBridgeLoader::create_bridge_instance(
@@ -68,6 +87,32 @@ std::shared_ptr<void> StandardBridgeLoader::create_bridge_instance(
6887
}
6988
}
7089

90+
std::shared_ptr<void> StandardBridgeLoader::create_service_bridge_instance(
91+
ServiceBridgeFn entry_func, const std::shared_ptr<void> & lib_handle,
92+
const rclcpp::Node::SharedPtr & node, const ServiceBridgeTargetInfo & target)
93+
{
94+
try {
95+
auto bridge_resource = entry_func(node, target);
96+
if (!bridge_resource) {
97+
return nullptr;
98+
}
99+
100+
if (lib_handle) {
101+
// Prevent library unload while bridge_resource is alive (aliasing constructor)
102+
using BundleType = std::pair<std::shared_ptr<void>, std::shared_ptr<void>>;
103+
auto bundle = std::make_shared<BundleType>(lib_handle, bridge_resource);
104+
return {bundle, bridge_resource.get()};
105+
}
106+
107+
RCLCPP_ERROR(logger_, "Library handle is missing. Cannot ensure bridge lifetime safety.");
108+
return nullptr;
109+
110+
} catch (const std::exception & e) {
111+
RCLCPP_ERROR(logger_, "Exception in service factory: %s", e.what());
112+
return nullptr;
113+
}
114+
}
115+
71116
std::pair<void *, uintptr_t> StandardBridgeLoader::load_library(
72117
const char * lib_path, const char * symbol_name)
73118
{
@@ -91,10 +136,10 @@ std::pair<void *, uintptr_t> StandardBridgeLoader::load_library(
91136
return {handle, map->l_addr};
92137
}
93138

94-
std::pair<BridgeFn, std::shared_ptr<void>> StandardBridgeLoader::resolve_factory_function(
95-
const MqMsgBridge & req, const std::string & topic_name_with_direction)
139+
std::pair<uintptr_t, std::shared_ptr<void>> StandardBridgeLoader::resolve_factory_function(
140+
const MqMsgBridge & req, const std::string & bridge_target_key)
96141
{
97-
if (auto it = cached_factories_.find(topic_name_with_direction); it != cached_factories_.end()) {
142+
if (auto it = cached_factories_.find(bridge_target_key); it != cached_factories_.end()) {
98143
// Return the cached pair of the factory function and the shared library handle.
99144
return it->second;
100145
}
@@ -111,49 +156,47 @@ std::pair<BridgeFn, std::shared_ptr<void>> StandardBridgeLoader::resolve_factory
111156
if (raw_handle != nullptr) {
112157
dlclose(raw_handle);
113158
}
114-
return {nullptr, nullptr};
159+
return {0, nullptr};
115160
}
116161

117-
// Manage Handle Lifecycle
162+
// Manage handle lifecycle
118163
std::shared_ptr<void> lib_handle_ptr(raw_handle, [](void * h) {
119164
if (h != nullptr) {
120165
dlclose(h);
121166
}
122167
});
123168

124-
// Resolve Main Function
125-
uintptr_t entry_addr = base_addr + req.factory.fn_offset;
126-
BridgeFn entry_func = nullptr;
127-
128-
if (is_address_in_library_code_segment(raw_handle, entry_addr)) {
129-
entry_func = reinterpret_cast<BridgeFn>(entry_addr);
130-
} else {
169+
// Resolve main function
170+
uintptr_t entry_func = base_addr + req.factory.fn_offset;
171+
if (!is_address_in_library_code_segment(raw_handle, entry_func)) {
131172
RCLCPP_ERROR(
132173
logger_, "Main factory function pointer for '%s' is out of bounds: 0x%lx",
133-
topic_name_with_direction.c_str(), static_cast<unsigned long>(entry_addr));
134-
return {nullptr, nullptr};
174+
bridge_target_key.c_str(), static_cast<unsigned long>(entry_func));
175+
return {0, nullptr};
135176
}
136177

137-
// Register Reverse Function
178+
// Service bridges do not have reverse factories yet, so early return here.
179+
if (req.is_service) {
180+
cached_factories_[bridge_target_key] = {entry_func, lib_handle_ptr};
181+
return {entry_func, lib_handle_ptr};
182+
}
183+
184+
// Construct reverse key
138185
std::string_view suffix =
139186
(req.direction == BridgeDirection::ROS2_TO_AGNOCAST) ? SUFFIX_A2R : SUFFIX_R2A;
140-
std::string topic_name_with_reverse(static_cast<const char *>(req.pubsub_target.topic_name));
141-
topic_name_with_reverse += suffix;
187+
std::string reverse_key(static_cast<const char *>(req.pubsub_target.topic_name));
188+
reverse_key += suffix;
142189

143-
uintptr_t reverse_addr = base_addr + req.factory.fn_offset_reverse;
144-
BridgeFn reverse_func = nullptr;
145-
146-
if (is_address_in_library_code_segment(raw_handle, reverse_addr)) {
147-
reverse_func = reinterpret_cast<BridgeFn>(reverse_addr);
148-
} else {
190+
uintptr_t reverse_func = base_addr + req.factory.fn_offset_reverse;
191+
if (!is_address_in_library_code_segment(raw_handle, reverse_func)) {
149192
RCLCPP_ERROR(
150-
logger_, "Reverse function pointer for '%s' is out of bounds: 0x%lx",
151-
topic_name_with_reverse.c_str(), static_cast<unsigned long>(reverse_addr));
152-
return {nullptr, nullptr};
193+
logger_, "Reverse function pointer for '%s' is out of bounds: 0x%lx", reverse_key.c_str(),
194+
static_cast<unsigned long>(reverse_func));
195+
return {0, nullptr};
153196
}
154197

155-
cached_factories_[topic_name_with_direction] = {entry_func, lib_handle_ptr};
156-
cached_factories_[topic_name_with_reverse] = {reverse_func, lib_handle_ptr};
198+
cached_factories_[bridge_target_key] = {entry_func, lib_handle_ptr};
199+
cached_factories_[reverse_key] = {reverse_func, lib_handle_ptr};
157200

158201
return {entry_func, lib_handle_ptr};
159202
}

0 commit comments

Comments
 (0)