@@ -25,20 +25,39 @@ StandardBridgeLoader::~StandardBridgeLoader()
2525}
2626
2727std::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
4463std::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+
71116std::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