LCOV - code coverage report
Current view: top level - modules/dds - dds_factory.cc (source / functions) Hit Total Coverage
Test: vlink Lines: 469 580 80.9 %
Date: 2026-09-30 18:30:16 Functions: 34 58 58.6 %
Branches: 519 1146 45.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2026 by Thun Lu. All rights reserved.
       3                 :            :  * Author: Thun Lu <thun.lu@zohomail.cn>
       4                 :            :  * Repo:   https://github.com/thun-res/vlink
       5                 :            :  *  _    __   __      _           __
       6                 :            :  * | |  / /  / /     (_) ____    / /__
       7                 :            :  * | | / /  / /     / / / __ \  / //_/
       8                 :            :  * | |/ /  / /___  / / / / / / / ,<
       9                 :            :  * |___/  /_____/ /_/ /_/ /_/ /_/|_|
      10                 :            :  *
      11                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
      12                 :            :  * you may not use this file except in compliance with the License.
      13                 :            :  * You may obtain a copy of the License at
      14                 :            :  *
      15                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
      16                 :            :  *
      17                 :            :  * Unless required by applicable law or agreed to in writing, software
      18                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      19                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      20                 :            :  * See the License for the specific language governing permissions and
      21                 :            :  * limitations under the License.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include "./dds_factory.h"
      25                 :            : 
      26                 :            : #include <charconv>
      27                 :            : #include <limits>
      28                 :            : #include <memory>
      29                 :            : #include <string>
      30                 :            : #include <utility>
      31                 :            : #include <vector>
      32                 :            : 
      33                 :            : #include "./base/helpers.h"
      34                 :            : #include "./base/utils.h"
      35                 :            : #include "./dds_qos.h"
      36                 :            : #include "./dds_topic.h"
      37                 :            : #include "./extension/qos_profile.h"
      38                 :            : #include "./impl/ssl_options.h"
      39                 :            : 
      40                 :            : namespace vlink {
      41                 :            : 
      42                 :            : // DdsFactory
      43         [ +  - ]:         13 : DdsFactory::DdsFactory() {
      44                 :         13 :   Bytes::init_memory_pool();
      45                 :            : 
      46         [ -  + ]:         13 :   if VUNLIKELY (DdsConf::get_thread_count() != 1) {
      47   [ #  #  #  #  :          0 :     VLOG_W("DdsFactory: Dds does not support setting thread count.");
                   #  # ]
      48                 :            :   }
      49                 :            : 
      50         [ +  + ]:        221 :   for (const auto& [name, qos] : QosProfile::get_available_qos_map()) {
      51         [ +  - ]:        208 :     DdsConf::register_qos_internal(name, qos);
      52                 :            :   }
      53                 :            : 
      54   [ +  -  +  - ]:         26 :   std::string dds_debug_str = Utils::get_env("VLINK_DDS_DEBUG");
      55                 :            : 
      56         [ -  + ]:         13 :   if (dds_debug_str == "1") {
      57         [ #  # ]:          0 :     dds::Log::SetVerbosity(dds::Log::Kind::Info);
      58                 :            :   } else {
      59         [ +  - ]:         13 :     dds::Log::SetVerbosity(dds::Log::Kind::Error);
      60                 :            :   }
      61                 :            : 
      62         [ +  - ]:         13 :   dds_factory_ = dds::DomainParticipantFactory::get_instance();
      63                 :            : 
      64   [ +  -  +  - ]:         26 :   std::string qos_file = Utils::get_env("VLINK_FASTDDS_QOS_FILE");
      65                 :            : 
      66         [ -  + ]:         13 :   if (!qos_file.empty()) {
      67         [ #  # ]:          0 :     dds_factory_->load_XML_profiles_file(qos_file);
      68                 :            :   }
      69                 :            : 
      70   [ +  -  +  - ]:         26 :   std::string default_event_qos_str = Utils::get_env("VLINK_DDS_EVENT_QOS");
      71   [ +  -  +  - ]:         26 :   std::string default_method_qos_str = Utils::get_env("VLINK_DDS_METHOD_QOS");
      72   [ +  -  +  - ]:         26 :   std::string default_field_qos_str = Utils::get_env("VLINK_DDS_FIELD_QOS");
      73                 :            : 
      74         [ +  - ]:         13 :   if (default_event_qos_str.empty()) {
      75                 :         13 :     default_event_qos_ = QosProfile::kEvent;
      76                 :            :   } else {
      77         [ #  # ]:          0 :     default_event_qos_ = DdsConf::find_qos(default_event_qos_str);
      78                 :            :   }
      79                 :            : 
      80         [ +  - ]:         13 :   if (default_method_qos_str.empty()) {
      81                 :         13 :     default_method_qos_ = QosProfile::kMethod;
      82                 :            :   } else {
      83         [ #  # ]:          0 :     default_method_qos_ = DdsConf::find_qos(default_method_qos_str);
      84                 :            :   }
      85                 :            : 
      86         [ +  - ]:         13 :   if (default_field_qos_str.empty()) {
      87                 :         13 :     default_field_qos_ = QosProfile::kField;
      88                 :            :   } else {
      89         [ #  # ]:          0 :     default_field_qos_ = DdsConf::find_qos(default_field_qos_str);
      90                 :            :   }
      91                 :         13 : }
      92                 :            : 
      93                 :         13 : DdsFactory::~DdsFactory() = default;
      94                 :            : 
      95                 :          5 : std::vector<std::tuple<std::string, std::string>> DdsFactory::get_discovered_topics(int32_t _domain) {
      96                 :          5 :   std::vector<std::tuple<std::string, std::string>> topics;
      97                 :            : 
      98   [ +  +  +  -  :          5 :   static auto& factory = DdsFactory::get();
             +  -  -  - ]
      99         [ +  - ]:          5 :   std::lock_guard lifecycle_lock(factory.participant_mtx_);
     100                 :            : 
     101         [ +  - ]:          5 :   auto* part = factory.dds_factory_->lookup_participant(_domain);
     102                 :            : 
     103         [ +  + ]:          5 :   if VUNLIKELY (!part) {
     104                 :          4 :     return topics;
     105                 :            :   }
     106                 :            : 
     107                 :          1 :   std::vector<dds::InstanceHandle_t> topic_handles;
     108         [ +  - ]:          1 :   part->get_discovered_topics(topic_handles);
     109                 :            : 
     110         [ +  - ]:          1 :   topics.reserve(topic_handles.size());
     111                 :            : 
     112         [ -  + ]:          1 :   for (const auto& instance : topic_handles) {
     113         [ #  # ]:          0 :     dds::builtin::TopicBuiltinTopicData topic_data;
     114         [ #  # ]:          0 :     part->get_discovered_topic_data(topic_data, instance);
     115         [ #  # ]:          0 :     topics.emplace_back(std::forward_as_tuple(std::move(topic_data.name), std::move(topic_data.type_name)));
     116                 :          0 :   }
     117                 :            : 
     118                 :          1 :   return topics;
     119                 :          5 : }
     120                 :            : 
     121                 :          2 : bool DdsFactory::load_global_qos_file(const std::string& filepath) {
     122   [ +  -  +  -  :          2 :   static auto& factory = DdsFactory::get();
             +  -  -  - ]
     123                 :            : 
     124                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     125                 :            :   return factory.dds_factory_->load_XML_profiles_file(filepath) == dds::RETCODE_OK;
     126                 :            : #else
     127         [ +  - ]:          2 :   return factory.dds_factory_->load_XML_profiles_file(filepath) == ReturnCode_t::RETCODE_OK;
     128                 :            : #endif
     129                 :            : }
     130                 :            : 
     131                 :        272 : std::shared_ptr<dds::DomainParticipant> DdsFactory::create_participant(uint8_t type, const DdsConf& conf,
     132                 :            :                                                                        const Conf::PropertiesMap& properties) {
     133   [ +  +  +  -  :        272 :   static auto& factory = DdsFactory::get();
             +  -  -  - ]
     134                 :            : 
     135   [ +  -  +  - ]:        272 :   const auto& dds_qos_ext = get_qos_ext(conf.qos_ext, "part");
     136         [ +  - ]:        272 :   const auto& id = std::make_tuple(type, conf.domain, dds_qos_ext, properties);
     137                 :            : 
     138         [ +  - ]:        272 :   std::lock_guard lifecycle_lock(factory.participant_mtx_);
     139         [ +  - ]:        272 :   std::unique_lock lock(factory.mtx_);
     140                 :            : 
     141         [ +  - ]:        272 :   std::shared_ptr<dds::DomainParticipant> part = get_weak_ptr(factory.part_map_, id).lock();
     142                 :            : 
     143         [ +  + ]:        272 :   if (!part) {
     144         [ +  - ]:        140 :     lock.unlock();
     145                 :            : 
     146                 :        140 :     dds::DomainParticipant* ptr = nullptr;
     147                 :            : 
     148         [ +  + ]:        140 :     if (dds_qos_ext.empty()) {
     149         [ +  - ]:        139 :       auto dds_qos = dds::PARTICIPANT_QOS_DEFAULT;
     150                 :            : 
     151         [ +  - ]:        139 :       set_participant_qos(dds_qos, properties);
     152                 :            : 
     153         [ +  - ]:        139 :       ptr = factory.dds_factory_->create_participant(conf.domain, dds_qos, nullptr, dds::StatusMask::all());
     154                 :        139 :     } else {
     155         [ +  - ]:          1 :       ptr = factory.dds_factory_->create_participant_with_profile(conf.domain, dds_qos_ext, nullptr,
     156                 :          2 :                                                                   dds::StatusMask::all());
     157                 :            :     }
     158                 :            : 
     159         [ +  + ]:        140 :     if VUNLIKELY (!ptr) {
     160   [ +  -  +  -  :          4 :       VLOG_E("DdsFactory: Failed to create participant.");
                   +  - ]
     161                 :          2 :       return nullptr;
     162                 :            :     }
     163                 :            : 
     164   [ +  -  +  - ]:        276 :     part = std::shared_ptr<dds::DomainParticipant>(ptr, [id](dds::DomainParticipant* part) {
     165         [ +  - ]:        138 :       std::lock_guard lifecycle_lock(factory.participant_mtx_);
     166                 :            : 
     167                 :            :       {
     168         [ +  - ]:        138 :         std::lock_guard lock(factory.mtx_);
     169         [ +  - ]:        138 :         auto iter = factory.part_map_.find(id);
     170                 :            : 
     171   [ +  -  +  -  :        138 :         if (iter != factory.part_map_.end() && iter->second.expired()) {
                   +  - ]
     172         [ +  - ]:        138 :           factory.part_map_.erase(iter);
     173                 :            :         }
     174                 :        138 :       }
     175                 :            : 
     176         [ +  - ]:        138 :       factory.dds_factory_->delete_participant(part);
     177                 :        276 :     });
     178                 :            : 
     179         [ +  - ]:        138 :     lock.lock();
     180                 :            : 
     181         [ +  - ]:        138 :     auto [iter, inserted] = factory.part_map_.emplace(id, part);
     182                 :            : 
     183         [ -  + ]:        138 :     if (!inserted) {
     184                 :          0 :       auto inserted_part = iter->second.lock();
     185                 :            : 
     186         [ #  # ]:          0 :       if VLIKELY (inserted_part) {
     187         [ #  # ]:          0 :         lock.unlock();
     188                 :          0 :         part = std::move(inserted_part);
     189                 :            :       } else {
     190                 :          0 :         iter->second = part;
     191                 :            :       }
     192                 :          0 :     }
     193                 :            :   }
     194                 :            : 
     195                 :        270 :   return part;
     196                 :        272 : }
     197                 :            : 
     198                 :        322 : std::shared_ptr<dds::Topic> DdsFactory::create_topic(uint8_t type, const DdsConf& conf, dds::DomainParticipant* part,
     199                 :            :                                                      bool is_cdr_type, std::string topic, std::string cdr_type_name) {
     200   [ +  +  +  -  :        322 :   static auto& factory = DdsFactory::get();
             +  -  -  - ]
     201                 :            : 
     202                 :        322 :   dds::TypeSupport type_support;
     203                 :        322 :   dds::TypeSupport native_type;
     204                 :            : 
     205         [ +  + ]:        322 :   if (topic.empty()) {
     206         [ +  - ]:        222 :     topic = conf.topic;
     207                 :            :   }
     208                 :            : 
     209         [ +  - ]:        322 :   Function<void*()> type_support_callback = DdsConf::find_type_support(topic);
     210                 :            : 
     211         [ +  + ]:        322 :   if (is_cdr_type) {
     212         [ -  + ]:          2 :     if (type_support_callback) {
     213   [ #  #  #  # ]:          0 :       native_type.reset(static_cast<dds::TopicDataType*>(type_support_callback()));
     214                 :            : 
     215         [ #  # ]:          0 :       if VUNLIKELY (!native_type) {
     216   [ #  #  #  #  :          0 :         VLOG_F("DdsFactory: Topic ", topic, " CDR typesupport creation failed.");
                   #  # ]
     217                 :            :       }
     218                 :            : 
     219                 :          0 :       const auto& native_type_name = native_type.get_type_name();
     220                 :            : 
     221   [ #  #  #  #  :          0 :       if VUNLIKELY (!cdr_type_name.empty() && cdr_type_name != native_type_name) {
                   #  # ]
     222   [ #  #  #  #  :          0 :         CLOG_W("DdsFactory: Topic [%s] CDR type [%s] => [%s].", topic.c_str(), cdr_type_name.c_str(),
                   #  # ]
     223                 :            :                native_type_name.c_str());
     224                 :            :       }
     225                 :            : 
     226         [ #  # ]:          0 :       cdr_type_name = native_type_name;
     227                 :            :     }
     228                 :            : 
     229         [ -  + ]:          2 :     if VUNLIKELY (cdr_type_name.empty()) {
     230   [ #  #  #  #  :          0 :       VLOG_F("DdsFactory: Topic ", topic, " has no CDR type name.");
                   #  # ]
     231                 :            :     }
     232                 :            :   } else {
     233         [ -  + ]:        320 :     if VUNLIKELY (type_support_callback) {
     234   [ #  #  #  #  :          0 :       VLOG_F("DdsFactory: Topic ", topic, " does not support BuiltIn::Raw.");
                   #  # ]
     235                 :            :     }
     236                 :            : 
     237         [ +  - ]:        320 :     std::lock_guard raw_lock(factory.raw_typesupport_mtx_);
     238                 :            : 
     239         [ +  + ]:        320 :     if VUNLIKELY (!factory.raw_typesupport_) {
     240   [ +  -  +  -  :         12 :       factory.raw_typesupport_.reset(new BuiltInRawPubSubType);  // NOLINT(modernize-make-shared)
                   +  - ]
     241                 :            :     }
     242                 :        320 :   }
     243                 :            : 
     244   [ +  -  +  - ]:        322 :   const auto& dds_qos_ext = get_qos_ext(conf.qos_ext, "topic");
     245                 :            : 
     246         [ +  + ]:        322 :   if VUNLIKELY (!part) {
     247   [ +  -  +  -  :          4 :     VLOG_E("DdsFactory: Cannot create topic without participant.");
                   +  - ]
     248                 :          2 :     return nullptr;
     249                 :            :   }
     250                 :            : 
     251         [ +  - ]:        320 :   const auto& id = std::make_tuple(type, conf.domain, topic, part);
     252                 :            : 
     253         [ +  - ]:        320 :   std::unique_lock lock(factory.mtx_);
     254         [ +  - ]:        320 :   std::shared_ptr<dds::Topic> dds_topic = get_weak_ptr(factory.topic_map_, id).lock();
     255                 :            : 
     256         [ +  + ]:        320 :   if (!dds_topic) {
     257         [ +  - ]:        182 :     lock.unlock();
     258                 :            : 
     259         [ +  + ]:        182 :     if (is_cdr_type) {
     260   [ +  -  +  -  :          2 :       type_support.reset(new DdsCdrPubSubType(cdr_type_name, std::move(native_type)));
                   +  - ]
     261                 :            :     } else {
     262         [ +  - ]:        180 :       std::lock_guard raw_lock(factory.raw_typesupport_mtx_);
     263                 :        180 :       type_support = factory.raw_typesupport_;
     264                 :        180 :     }
     265                 :            : 
     266         [ +  - ]:        182 :     if VLIKELY (type_support) {
     267         [ +  - ]:        182 :       part->register_type(type_support);
     268                 :            :     } else {
     269   [ #  #  #  #  :          0 :       VLOG_F("DdsFactory: Topic ", topic, " registration failed.");
                   #  # ]
     270                 :            :     }
     271                 :            : 
     272                 :        182 :     dds::Topic* ptr = nullptr;
     273                 :            : 
     274         [ +  + ]:        182 :     if (dds_qos_ext.empty()) {
     275         [ +  - ]:        181 :       auto dds_qos = dds::TOPIC_QOS_DEFAULT;
     276                 :            : 
     277         [ +  - ]:        181 :       ptr = part->create_topic(topic, type_support.get_type_name(), dds_qos);
     278                 :          0 :     } else {
     279         [ +  - ]:          1 :       ptr = part->create_topic_with_profile(topic, type_support.get_type_name(), dds_qos_ext);
     280                 :            :     }
     281                 :            : 
     282         [ +  + ]:        182 :     if VUNLIKELY (!ptr) {
     283   [ +  -  +  -  :          2 :       VLOG_E("DdsFactory: Failed to create topic: ", topic, ".");
                   +  - ]
     284                 :          1 :       return nullptr;
     285                 :            :     }
     286                 :            : 
     287   [ +  -  +  - ]:        362 :     dds_topic = std::shared_ptr<dds::Topic>(ptr, [id](dds::Topic* topic) {
     288                 :            :       {
     289         [ +  - ]:        181 :         std::lock_guard lock(factory.mtx_);
     290         [ +  - ]:        181 :         auto iter = factory.topic_map_.find(id);
     291                 :            : 
     292   [ +  -  +  -  :        181 :         if (iter != factory.topic_map_.end() && iter->second.expired()) {
                   +  - ]
     293         [ +  - ]:        181 :           factory.topic_map_.erase(iter);
     294                 :            :         }
     295                 :        181 :       }
     296                 :            : 
     297                 :        181 :       auto* participant = const_cast<dds::DomainParticipant*>(topic->get_participant());
     298                 :        181 :       participant->delete_topic(topic);
     299                 :        362 :     });
     300                 :            : 
     301         [ +  - ]:        181 :     lock.lock();
     302                 :            : 
     303         [ +  - ]:        181 :     auto [iter, inserted] = factory.topic_map_.emplace(id, dds_topic);
     304                 :            : 
     305         [ -  + ]:        181 :     if (!inserted) {
     306                 :          0 :       auto inserted_topic = iter->second.lock();
     307                 :            : 
     308         [ #  # ]:          0 :       if VLIKELY (inserted_topic) {
     309         [ #  # ]:          0 :         lock.unlock();
     310                 :          0 :         dds_topic = std::move(inserted_topic);
     311                 :            :       } else {
     312                 :          0 :         iter->second = dds_topic;
     313                 :            :       }
     314                 :          0 :     }
     315                 :            :   } else {
     316         [ -  + ]:        138 :     const auto& expected_type_name = is_cdr_type ? cdr_type_name : factory.raw_typesupport_.get_type_name();
     317                 :            : 
     318         [ -  + ]:        138 :     if VUNLIKELY (dds_topic->get_type_name() != expected_type_name) {
     319   [ #  #  #  #  :          0 :       VLOG_F("DdsFactory: Topic ", topic, " type mismatch.");
                   #  # ]
     320                 :            :     }
     321                 :            : 
     322         [ +  - ]:        138 :     type_support = part->find_type(dds_topic->get_type_name());
     323                 :            : 
     324         [ -  + ]:        138 :     if (!type_support) {
     325         [ #  # ]:          0 :       if (is_cdr_type) {
     326   [ #  #  #  #  :          0 :         type_support.reset(new DdsCdrPubSubType(cdr_type_name, std::move(native_type)));
                   #  # ]
     327                 :            :       } else {
     328         [ #  # ]:          0 :         std::lock_guard raw_lock(factory.raw_typesupport_mtx_);
     329                 :          0 :         type_support = factory.raw_typesupport_;
     330                 :          0 :       }
     331                 :            :     }
     332                 :            : 
     333         [ +  - ]:        138 :     if VLIKELY (type_support) {
     334         [ +  - ]:        138 :       part->register_type(type_support);
     335                 :            :     } else {
     336   [ #  #  #  #  :          0 :       VLOG_F("DdsFactory: Topic ", topic, " registration failed.");
                   #  # ]
     337                 :            :     }
     338                 :            :   }
     339                 :            : 
     340         [ +  + ]:        319 :   const auto& expected_type_name = is_cdr_type ? cdr_type_name : factory.raw_typesupport_.get_type_name();
     341                 :            : 
     342         [ -  + ]:        319 :   if VUNLIKELY (dds_topic->get_type_name() != expected_type_name) {
     343   [ #  #  #  #  :          0 :     VLOG_F("DdsFactory: Topic ", topic, " type mismatch.");
                   #  # ]
     344                 :            :   }
     345                 :            : 
     346                 :        319 :   return dds_topic;
     347                 :        322 : }
     348                 :            : 
     349                 :         50 : std::pair<std::shared_ptr<dds::Topic>, std::shared_ptr<dds::Topic>> DdsFactory::create_method_topic(
     350                 :            :     uint8_t type, const DdsConf& conf, dds::DomainParticipant* part, bool is_cdr_type,
     351                 :            :     const std::string& cdr_type_names) {
     352         [ +  - ]:         50 :   const std::string& resp_topic = conf.topic + DdsConf::kRespSuffix;
     353                 :            : 
     354   [ +  -  -  +  :         50 :   if VUNLIKELY (conf.topic.empty() || resp_topic.empty()) {
                   -  + ]
     355   [ #  #  #  #  :          0 :     VLOG_F("DdsFactory: Method conf topic error.");
                   #  # ]
     356                 :            :   }
     357                 :            : 
     358         [ -  + ]:         50 :   if VUNLIKELY (conf.topic == resp_topic) {
     359   [ #  #  #  #  :          0 :     VLOG_F("DdsFactory: Method conf topic req and resp cannot be equal.");
                   #  # ]
     360                 :            :   }
     361                 :            : 
     362                 :         50 :   std::string req_cdr_type_name;
     363                 :         50 :   std::string resp_cdr_type_name;
     364                 :            : 
     365         [ -  + ]:         50 :   if (is_cdr_type) {
     366                 :          0 :     const auto separator = cdr_type_names.find('|');
     367                 :            : 
     368         [ #  # ]:          0 :     if (separator == std::string::npos) {
     369         [ #  # ]:          0 :       req_cdr_type_name = cdr_type_names;
     370         [ #  # ]:          0 :       resp_cdr_type_name = cdr_type_names;
     371                 :            :     } else {
     372         [ #  # ]:          0 :       if VUNLIKELY (separator == 0U) {
     373   [ #  #  #  #  :          0 :         VLOG_F("DdsFactory: CDR method request type name is empty.");
                   #  # ]
     374                 :            :       }
     375                 :            : 
     376         [ #  # ]:          0 :       if VUNLIKELY (separator + 1U == cdr_type_names.size()) {
     377   [ #  #  #  #  :          0 :         VLOG_F("DdsFactory: CDR method response type name is empty.");
                   #  # ]
     378                 :            :       }
     379                 :            : 
     380         [ #  # ]:          0 :       req_cdr_type_name = cdr_type_names.substr(0U, separator);
     381         [ #  # ]:          0 :       resp_cdr_type_name = cdr_type_names.substr(separator + 1U);
     382                 :            :     }
     383                 :            :   }
     384                 :            : 
     385   [ +  -  +  - ]:        100 :   return {create_topic(type, conf, part, is_cdr_type, conf.topic, std::move(req_cdr_type_name)),
     386   [ +  -  +  - ]:        100 :           create_topic(type, conf, part, is_cdr_type, resp_topic, std::move(resp_cdr_type_name))};
     387                 :         50 : }
     388                 :            : 
     389                 :        165 : std::shared_ptr<dds::Publisher> DdsFactory::create_publisher(uint8_t type, const DdsConf& conf,
     390                 :            :                                                              dds::DomainParticipant* part) {
     391   [ +  +  +  -  :        165 :   static auto& factory = DdsFactory::get();
             +  -  -  - ]
     392                 :            : 
     393   [ +  -  +  - ]:        165 :   const auto& dds_qos_ext = get_qos_ext(conf.qos_ext, "pub");
     394   [ +  -  +  - ]:        165 :   const auto& writer_qos = get_qos_ext(conf.qos_ext, "writer");
     395                 :            : 
     396         [ +  + ]:        165 :   if VUNLIKELY (!part) {
     397   [ +  -  +  -  :          4 :     VLOG_E("DdsFactory: Cannot create publisher without participant.");
                   +  - ]
     398                 :          2 :     return nullptr;
     399                 :            :   }
     400                 :            : 
     401         [ +  - ]:        163 :   const auto& id = std::make_tuple(type, conf.domain, conf.qos, dds_qos_ext, writer_qos, part);
     402                 :            : 
     403         [ +  - ]:        163 :   std::unique_lock lock(factory.mtx_);
     404         [ +  - ]:        163 :   std::shared_ptr<dds::Publisher> publisher = get_weak_ptr(factory.publisher_map_, id).lock();
     405                 :            : 
     406         [ +  + ]:        163 :   if (!publisher) {
     407         [ +  - ]:        149 :     lock.unlock();
     408                 :            : 
     409                 :        149 :     dds::Publisher* ptr = nullptr;
     410                 :            : 
     411         [ +  + ]:        149 :     if (dds_qos_ext.empty()) {
     412         [ +  - ]:        148 :       auto dds_qos = dds::PUBLISHER_QOS_DEFAULT;
     413                 :            : 
     414         [ +  - ]:        148 :       ptr = part->create_publisher(dds_qos, nullptr);
     415                 :        148 :     } else {
     416         [ +  - ]:          1 :       ptr = part->create_publisher_with_profile(dds_qos_ext, nullptr);
     417                 :            :     }
     418                 :            : 
     419         [ +  + ]:        149 :     if VUNLIKELY (!ptr) {
     420   [ +  -  +  -  :          2 :       VLOG_E("DdsFactory: Failed to create publisher.");
                   +  - ]
     421                 :          1 :       return nullptr;
     422                 :            :     }
     423                 :            : 
     424   [ +  -  +  - ]:        296 :     publisher = std::shared_ptr<dds::Publisher>(ptr, [id](dds::Publisher* publisher) {
     425                 :            :       {
     426         [ +  - ]:        148 :         std::lock_guard lock(factory.mtx_);
     427         [ +  - ]:        148 :         auto iter = factory.publisher_map_.find(id);
     428                 :            : 
     429   [ +  -  +  +  :        148 :         if (iter != factory.publisher_map_.end() && iter->second.expired()) {
                   +  + ]
     430         [ +  - ]:        147 :           factory.publisher_map_.erase(iter);
     431                 :            :         }
     432                 :        148 :       }
     433                 :            : 
     434                 :        148 :       auto* participant = const_cast<dds::DomainParticipant*>(publisher->get_participant());
     435                 :        148 :       participant->delete_publisher(publisher);
     436                 :        296 :     });
     437                 :            : 
     438         [ +  - ]:        148 :     lock.lock();
     439                 :            : 
     440         [ +  - ]:        148 :     auto [iter, inserted] = factory.publisher_map_.emplace(id, publisher);
     441                 :            : 
     442         [ +  + ]:        148 :     if (!inserted) {
     443                 :          1 :       auto inserted_publisher = iter->second.lock();
     444                 :            : 
     445         [ +  - ]:          1 :       if VLIKELY (inserted_publisher) {
     446         [ +  - ]:          1 :         lock.unlock();
     447                 :          1 :         publisher = std::move(inserted_publisher);
     448                 :            :       } else {
     449                 :          0 :         iter->second = publisher;
     450                 :            :       }
     451                 :          1 :     }
     452                 :            :   }
     453                 :            : 
     454                 :        162 :   return publisher;
     455                 :        165 : }
     456                 :            : 
     457                 :        157 : std::shared_ptr<dds::Subscriber> DdsFactory::create_subscriber(uint8_t type, const DdsConf& conf,
     458                 :            :                                                                dds::DomainParticipant* part) {
     459   [ +  +  +  -  :        157 :   static auto& factory = DdsFactory::get();
             +  -  -  - ]
     460                 :            : 
     461   [ +  -  +  - ]:        157 :   const auto& dds_qos_ext = get_qos_ext(conf.qos_ext, "sub");
     462   [ +  -  +  - ]:        157 :   const auto& reader_qos = get_qos_ext(conf.qos_ext, "reader");
     463                 :            : 
     464         [ -  + ]:        157 :   if VUNLIKELY (!part) {
     465   [ #  #  #  #  :          0 :     VLOG_E("DdsFactory: Cannot create subscriber without participant.");
                   #  # ]
     466                 :          0 :     return nullptr;
     467                 :            :   }
     468                 :            : 
     469         [ +  - ]:        157 :   const auto& id = std::make_tuple(type, conf.domain, conf.qos, dds_qos_ext, reader_qos, part);
     470                 :            : 
     471         [ +  - ]:        157 :   std::unique_lock lock(factory.mtx_);
     472                 :            : 
     473         [ +  - ]:        157 :   std::shared_ptr<dds::Subscriber> subscriber = get_weak_ptr(factory.subscriber_map_, id).lock();
     474                 :            : 
     475         [ +  + ]:        157 :   if (!subscriber) {
     476         [ +  - ]:        144 :     lock.unlock();
     477                 :        144 :     dds::Subscriber* ptr = nullptr;
     478                 :            : 
     479         [ +  + ]:        144 :     if (dds_qos_ext.empty()) {
     480         [ +  - ]:        143 :       auto dds_qos = dds::SUBSCRIBER_QOS_DEFAULT;
     481         [ +  - ]:        143 :       ptr = part->create_subscriber(dds_qos, nullptr);
     482                 :        143 :     } else {
     483         [ +  - ]:          1 :       ptr = part->create_subscriber_with_profile(dds_qos_ext, nullptr);
     484                 :            :     }
     485                 :            : 
     486         [ +  + ]:        144 :     if VUNLIKELY (!ptr) {
     487   [ +  -  +  -  :          2 :       VLOG_E("DdsFactory: Failed to create subscriber.");
                   +  - ]
     488                 :          1 :       return nullptr;
     489                 :            :     }
     490                 :            : 
     491   [ +  -  +  - ]:        286 :     subscriber = std::shared_ptr<dds::Subscriber>(ptr, [id](dds::Subscriber* subscriber) {
     492                 :            :       {
     493         [ +  - ]:        143 :         std::lock_guard lock(factory.mtx_);
     494         [ +  - ]:        143 :         auto iter = factory.subscriber_map_.find(id);
     495                 :            : 
     496   [ +  -  +  -  :        143 :         if (iter != factory.subscriber_map_.end() && iter->second.expired()) {
                   +  - ]
     497         [ +  - ]:        143 :           factory.subscriber_map_.erase(iter);
     498                 :            :         }
     499                 :        143 :       }
     500                 :        143 :       auto* participant = const_cast<dds::DomainParticipant*>(subscriber->get_participant());
     501                 :        143 :       participant->delete_subscriber(subscriber);
     502                 :        286 :     });
     503                 :            : 
     504         [ +  - ]:        143 :     lock.lock();
     505                 :            : 
     506         [ +  - ]:        143 :     auto [iter, inserted] = factory.subscriber_map_.emplace(id, subscriber);
     507                 :            : 
     508         [ -  + ]:        143 :     if (!inserted) {
     509                 :          0 :       auto inserted_subscriber = iter->second.lock();
     510                 :            : 
     511         [ #  # ]:          0 :       if VLIKELY (inserted_subscriber) {
     512         [ #  # ]:          0 :         lock.unlock();
     513                 :          0 :         subscriber = std::move(inserted_subscriber);
     514                 :            :       } else {
     515                 :          0 :         iter->second = subscriber;
     516                 :            :       }
     517                 :          0 :     }
     518                 :            :   }
     519                 :            : 
     520                 :        156 :   return subscriber;
     521                 :        157 : }
     522                 :            : 
     523                 :        162 : std::shared_ptr<dds::DataWriter> DdsFactory::create_datawriter(uint8_t type, const DdsConf& conf,
     524                 :            :                                                                dds::Publisher* publisher, dds::Topic* topic,
     525                 :            :                                                                dds::DataWriterListener* listener, bool is_cdr_type) {
     526                 :            :   (void)is_cdr_type;
     527                 :            : 
     528   [ +  +  +  -  :        162 :   static auto& factory = DdsFactory::get();
             +  -  -  - ]
     529                 :            : 
     530   [ +  -  +  - ]:        162 :   const auto& dds_qos_ext = get_qos_ext(conf.qos_ext, "writer");
     531                 :            : 
     532   [ +  +  -  +  :        162 :   if VUNLIKELY (!publisher || !topic) {
                   +  + ]
     533   [ +  -  +  -  :          2 :     VLOG_E("DdsFactory: Cannot create datawriter without publisher/topic.");
                   +  - ]
     534                 :          1 :     return nullptr;
     535                 :            :   }
     536                 :            : 
     537                 :        161 :   dds::DataWriter* ptr = nullptr;
     538                 :            : 
     539         [ +  + ]:        161 :   if (dds_qos_ext.empty()) {
     540         [ +  - ]:        158 :     auto dds_qos = dds::DATAWRITER_QOS_DEFAULT;
     541                 :            : 
     542         [ +  + ]:        158 :     if (conf.qos.empty()) {
     543   [ +  +  -  + ]:        135 :       if ((type & kPublisher) || (type & kSubscriber)) {
     544         [ +  - ]:         55 :         convert_qos(dds_qos, factory.default_event_qos_, conf.depth);
     545   [ +  +  +  + ]:         80 :       } else if ((type & kClient) || (type & kServer)) {
     546         [ +  - ]:         55 :         convert_qos(dds_qos, factory.default_method_qos_, conf.depth);
     547   [ -  +  -  - ]:         25 :       } else if ((type & kSetter) || (type & kGetter)) {
     548         [ +  - ]:         25 :         convert_qos(dds_qos, factory.default_field_qos_, conf.depth);
     549                 :            :       }
     550                 :            :     } else {
     551   [ +  -  +  - ]:         23 :       convert_qos(dds_qos, DdsConf::find_qos(conf.qos), conf.depth);
     552                 :            :     }
     553                 :            : 
     554                 :        158 :     dds_qos.endpoint().history_memory_policy = rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
     555                 :            : 
     556         [ +  - ]:        158 :     ptr = publisher->create_datawriter(topic, dds_qos, listener);
     557                 :        158 :   } else {
     558         [ +  - ]:          3 :     auto dds_qos = dds::DATAWRITER_QOS_DEFAULT;
     559         [ +  - ]:          3 :     const auto ret = publisher->get_datawriter_qos_from_profile(dds_qos_ext, dds_qos);
     560                 :            : 
     561                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     562                 :            :     if VLIKELY (ret == dds::RETCODE_OK) {
     563                 :            : #else
     564         [ -  + ]:          3 :     if VLIKELY (ret == ReturnCode_t::RETCODE_OK) {
     565                 :            : #endif
     566                 :          0 :       dds_qos.endpoint().history_memory_policy = rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
     567         [ #  # ]:          0 :       ptr = publisher->create_datawriter(topic, dds_qos, listener);
     568                 :            :     }
     569                 :          3 :   }
     570                 :            : 
     571         [ +  + ]:        161 :   if VUNLIKELY (!ptr) {
     572   [ +  -  +  -  :         12 :     VLOG_E("DdsFactory: Failed to create datawriter.");
                   +  - ]
     573                 :          6 :     return nullptr;
     574                 :            :   }
     575                 :            : 
     576                 :        155 :   return std::shared_ptr<dds::DataWriter>(ptr, [](dds::DataWriter* writer) {
     577         [ +  - ]:        155 :     writer->set_listener(nullptr, dds::StatusMask::none());
     578                 :        155 :     auto* publisher = const_cast<dds::Publisher*>(writer->get_publisher());
     579                 :        155 :     publisher->delete_datawriter(writer);
     580         [ +  - ]:        310 :   });
     581                 :        162 : }
     582                 :            : 
     583                 :        145 : std::shared_ptr<dds::DataReader> DdsFactory::create_datareader(uint8_t type, const DdsConf& conf,
     584                 :            :                                                                dds::Subscriber* subscriber, dds::Topic* topic,
     585                 :            :                                                                dds::DataReaderListener* listener, bool is_cdr_type) {
     586                 :            :   (void)is_cdr_type;
     587                 :            : 
     588   [ +  +  +  -  :        145 :   static auto& factory = DdsFactory::get();
             +  -  -  - ]
     589                 :            : 
     590   [ +  -  +  - ]:        145 :   const auto& dds_qos_ext = get_qos_ext(conf.qos_ext, "reader");
     591                 :            : 
     592   [ +  -  -  +  :        145 :   if VUNLIKELY (!subscriber || !topic) {
                   -  + ]
     593   [ #  #  #  #  :          0 :     VLOG_E("DdsFactory: Cannot create datareader without subscriber/topic.");
                   #  # ]
     594                 :          0 :     return nullptr;
     595                 :            :   }
     596                 :            : 
     597                 :        145 :   dds::DataReader* ptr = nullptr;
     598                 :            : 
     599         [ +  + ]:        145 :   if (dds_qos_ext.empty()) {
     600         [ +  - ]:        142 :     auto dds_qos = dds::DATAREADER_QOS_DEFAULT;
     601                 :            : 
     602         [ +  + ]:        142 :     if (conf.qos.empty()) {
     603   [ +  -  +  + ]:        121 :       if ((type & kPublisher) || (type & kSubscriber)) {
     604         [ +  - ]:         42 :         convert_qos(dds_qos, factory.default_event_qos_, conf.depth);
     605   [ +  +  +  + ]:         79 :       } else if ((type & kClient) || (type & kServer)) {
     606         [ +  - ]:         54 :         convert_qos(dds_qos, factory.default_method_qos_, conf.depth);
     607   [ +  -  +  - ]:         25 :       } else if ((type & kSetter) || (type & kGetter)) {
     608         [ +  - ]:         25 :         convert_qos(dds_qos, factory.default_field_qos_, conf.depth);
     609                 :            :       }
     610                 :            :     } else {
     611   [ +  -  +  - ]:         21 :       convert_qos(dds_qos, DdsConf::find_qos(conf.qos), conf.depth);
     612                 :            :     }
     613                 :            : 
     614                 :        142 :     dds_qos.endpoint().history_memory_policy = rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
     615                 :            : 
     616   [ +  -  +  - ]:        142 :     ptr = subscriber->create_datareader(topic, dds_qos, listener);
     617                 :        142 :   } else {
     618         [ +  - ]:          3 :     auto dds_qos = dds::DATAREADER_QOS_DEFAULT;
     619         [ +  - ]:          3 :     const auto ret = subscriber->get_datareader_qos_from_profile(dds_qos_ext, dds_qos);
     620                 :            : 
     621                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     622                 :            :     if VLIKELY (ret == dds::RETCODE_OK) {
     623                 :            : #else
     624         [ -  + ]:          3 :     if VLIKELY (ret == ReturnCode_t::RETCODE_OK) {
     625                 :            : #endif
     626                 :          0 :       dds_qos.endpoint().history_memory_policy = rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
     627   [ #  #  #  # ]:          0 :       ptr = subscriber->create_datareader(topic, dds_qos, listener);
     628                 :            :     }
     629                 :          3 :   }
     630                 :            : 
     631         [ +  + ]:        145 :   if VUNLIKELY (!ptr) {
     632   [ +  -  +  -  :         12 :     VLOG_E("DdsFactory: Failed to create datareader.");
                   +  - ]
     633                 :          6 :     return nullptr;
     634                 :            :   }
     635                 :            : 
     636                 :        139 :   return std::shared_ptr<dds::DataReader>(ptr, [](dds::DataReader* reader) {
     637         [ +  - ]:        139 :     reader->set_listener(nullptr, dds::StatusMask::none());
     638                 :        139 :     auto* subscriber = const_cast<dds::Subscriber*>(reader->get_subscriber());
     639                 :        139 :     subscriber->delete_datareader(reader);
     640         [ +  - ]:        278 :   });
     641                 :        145 : }
     642                 :            : 
     643                 :        201 : bool DdsFactory::write_data(dds::DataWriter* writer, const Bytes& bytes, uint64_t id) {
     644         [ -  + ]:        201 :   if VUNLIKELY (bytes.is_ptr()) {
     645   [ #  #  #  #  :          0 :     VLOG_E("DdsFactory: write_data() type mismatch, expected raw bytes but received ptr type.");
                   #  # ]
     646                 :          0 :     return false;
     647                 :            :   }
     648                 :            : 
     649         [ +  - ]:        201 :   BuiltInRaw raw;
     650         [ +  - ]:        201 :   raw.id() = id;
     651                 :            : 
     652         [ +  - ]:        201 :   raw.data().shallow_copy(bytes);
     653                 :            : 
     654                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     655                 :            :   return writer->write(&raw) == dds::RETCODE_OK;
     656                 :            : #else
     657         [ +  - ]:        201 :   return writer->write(&raw);
     658                 :            : #endif
     659                 :        201 : }
     660                 :            : 
     661                 :          0 : bool DdsFactory::write_cdr_data(dds::DataWriter* writer, const Bytes& bytes, rtps::WriteParams* params) {
     662   [ #  #  #  #  :          0 :   if VUNLIKELY (bytes.is_ptr() || bytes.size() < 4U || bytes.size() > std::numeric_limits<uint32_t>::max()) {
          #  #  #  #  #  
                      # ]
     663   [ #  #  #  #  :          0 :     VLOG_E("DdsFactory: write_cdr_data() expected an encapsulated CDR payload.");
                   #  # ]
     664                 :          0 :     return false;
     665                 :            :   }
     666                 :            : 
     667                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     668                 :            : 
     669                 :            :   if (params) {
     670                 :            :     return writer->write(const_cast<Bytes*>(&bytes), *params) == dds::RETCODE_OK;
     671                 :            :   }
     672                 :            : 
     673                 :            :   return writer->write(const_cast<Bytes*>(&bytes)) == dds::RETCODE_OK;
     674                 :            : #else
     675                 :            : 
     676         [ #  # ]:          0 :   if (params) {
     677                 :          0 :     return writer->write(const_cast<Bytes*>(&bytes), *params);
     678                 :            :   }
     679                 :            : 
     680                 :          0 :   return writer->write(const_cast<Bytes*>(&bytes));
     681                 :            : #endif
     682                 :            : }
     683                 :            : 
     684                 :        398 : bool DdsFactory::take_data(dds::DataReader* reader, ReadMessage& msg) {
     685         [ +  - ]:        398 :   auto ret = reader->take(msg.samples, msg.infos, 1);
     686                 :            : 
     687                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     688                 :            : 
     689                 :            :   if (ret == dds::RETCODE_NO_DATA) {
     690                 :            :     return false;
     691                 :            :   }
     692                 :            : 
     693                 :            :   if VUNLIKELY (ret != dds::RETCODE_OK) {
     694                 :            :     VLOG_E("DdsFactory: Failed to take data.");
     695                 :            :     return false;
     696                 :            :   }
     697                 :            : #else
     698                 :            : 
     699         [ +  + ]:        398 :   if (ret == ReturnCode_t::RETCODE_NO_DATA) {
     700                 :        199 :     return false;
     701                 :            :   }
     702                 :            : 
     703         [ -  + ]:        199 :   if VUNLIKELY (ret != ReturnCode_t::RETCODE_OK) {
     704   [ #  #  #  #  :          0 :     VLOG_E("DdsFactory: Failed to take data.");
                   #  # ]
     705                 :          0 :     return false;
     706                 :            :   }
     707                 :            : #endif
     708                 :            : 
     709         [ +  - ]:        199 :   const auto& info = msg.infos[0];
     710                 :            : 
     711         [ +  - ]:        199 :   if VLIKELY (info.valid_data) {
     712   [ +  -  +  - ]:        199 :     msg.id = msg.samples[0].id();
     713                 :            :   } else {
     714                 :          0 :     msg.id = 0;
     715                 :            :   }
     716                 :            : 
     717         [ +  - ]:        199 :   msg.timestamp = info.source_timestamp.to_ns();
     718                 :            : 
     719                 :        199 :   return true;
     720                 :            : }
     721                 :            : 
     722                 :        199 : void DdsFactory::return_data_loan(dds::DataReader* reader, ReadMessage& msg) {
     723         [ +  - ]:        199 :   auto ret = reader->return_loan(msg.samples, msg.infos);
     724                 :            : 
     725                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     726                 :            : 
     727                 :            :   if VUNLIKELY (ret != dds::RETCODE_OK) {
     728                 :            :     VLOG_E("DdsFactory: Failed to return data loan.");
     729                 :            :   }
     730                 :            : #else
     731                 :            : 
     732         [ -  + ]:        199 :   if VUNLIKELY (ret != ReturnCode_t::RETCODE_OK) {
     733   [ #  #  #  #  :          0 :     VLOG_E("DdsFactory: Failed to return data loan.");
                   #  # ]
     734                 :            :   }
     735                 :            : #endif
     736                 :        199 : }
     737                 :            : 
     738                 :          0 : bool DdsFactory::take_cdr_data(dds::DataReader* reader, ReadCdrMessage& msg) {
     739         [ #  # ]:          0 :   auto ret = reader->take(msg.samples, msg.infos, 1);
     740                 :            : 
     741                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     742                 :            : 
     743                 :            :   if (ret == dds::RETCODE_NO_DATA) {
     744                 :            :     return false;
     745                 :            :   }
     746                 :            : 
     747                 :            :   if VUNLIKELY (ret != dds::RETCODE_OK) {
     748                 :            :     VLOG_E("DdsFactory: Failed to take data.");
     749                 :            :     return false;
     750                 :            :   }
     751                 :            : #else
     752                 :            : 
     753         [ #  # ]:          0 :   if (ret == ReturnCode_t::RETCODE_NO_DATA) {
     754                 :          0 :     return false;
     755                 :            :   }
     756                 :            : 
     757         [ #  # ]:          0 :   if VUNLIKELY (ret != ReturnCode_t::RETCODE_OK) {
     758   [ #  #  #  #  :          0 :     VLOG_E("DdsFactory: Failed to take data.");
                   #  # ]
     759                 :          0 :     return false;
     760                 :            :   }
     761                 :            : #endif
     762                 :            : 
     763         [ #  # ]:          0 :   const auto& info = msg.infos[0];
     764                 :          0 :   msg.id = info.sample_identity.sequence_number().to64long();
     765                 :            : 
     766         [ #  # ]:          0 :   msg.timestamp = info.source_timestamp.to_ns();
     767                 :            : 
     768                 :          0 :   return true;
     769                 :            : }
     770                 :            : 
     771                 :          0 : void DdsFactory::return_cdr_loan(dds::DataReader* reader, ReadCdrMessage& msg) {
     772         [ #  # ]:          0 :   auto ret = reader->return_loan(msg.samples, msg.infos);
     773                 :            : 
     774                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     775                 :            : 
     776                 :            :   if VUNLIKELY (ret != dds::RETCODE_OK) {
     777                 :            :     VLOG_E("DdsFactory: Failed to return CDR loan.");
     778                 :            :   }
     779                 :            : #else
     780                 :            : 
     781         [ #  # ]:          0 :   if VUNLIKELY (ret != ReturnCode_t::RETCODE_OK) {
     782   [ #  #  #  #  :          0 :     VLOG_E("DdsFactory: Failed to return CDR loan.");
                   #  # ]
     783                 :            :   }
     784                 :            : #endif
     785                 :          0 : }
     786                 :            : 
     787                 :         29 : uint64_t DdsFactory::get_guid(const rtps::GUID_t& guid, uint32_t seq) {
     788                 :         29 :   const auto& handle = static_cast<const rtps::InstanceHandle_t&>(guid);
     789                 :         29 :   uint64_t result = 14695981039346656037ULL;
     790                 :            : 
     791         [ +  + ]:        493 :   for (size_t i = 0; i < 16U; ++i) {
     792                 :        464 :     result ^= static_cast<uint64_t>(handle.value[i]);
     793                 :        464 :     result *= 1099511628211ULL;
     794                 :            :   }
     795                 :            : 
     796         [ +  + ]:        145 :   for (size_t i = 0; i < sizeof(seq); ++i) {
     797                 :        116 :     result ^= static_cast<uint64_t>((seq >> (i * 8)) & 0xFFU);
     798                 :        116 :     result *= 1099511628211ULL;
     799                 :            :   }
     800                 :            : 
     801                 :         29 :   return result;
     802                 :            : }
     803                 :            : 
     804                 :         13 : int DdsFactory::get_default_domain_id() {
     805   [ +  -  +  - ]:         13 :   const std::string& domain_str = Utils::get_env("VLINK_DDS_DOMAIN");
     806                 :         26 :   return Helpers::to_int(domain_str, 0);
     807                 :         13 : }
     808                 :            : 
     809                 :        139 : void DdsFactory::set_participant_qos(dds::DomainParticipantQos& dds_qos, const Conf::PropertiesMap& properties) {
     810   [ +  +  +  -  :        139 :   static const std::string& discovery_ip_str = Utils::get_env("VLINK_DISCOVER_IP");
          +  -  +  -  -  
                      - ]
     811   [ +  +  +  -  :        139 :   static const std::string& ip_str = Utils::get_env("VLINK_DDS_IP", discovery_ip_str);
             +  -  -  - ]
     812   [ +  +  +  -  :        139 :   static const std::string& ip_multicast_str = Utils::get_env("VLINK_DDS_MULTICAST_IP");
          +  -  +  -  -  
                      - ]
     813   [ +  +  +  -  :        139 :   static const std::string& peer_str = Utils::get_env("VLINK_DDS_PEER");
          +  -  +  -  -  
                      - ]
     814   [ +  +  +  -  :        139 :   static const std::string& buf_str = Utils::get_env("VLINK_DDS_BUF");
          +  -  +  -  -  
                      - ]
     815   [ +  +  +  -  :        139 :   static const std::string& mtu_str = Utils::get_env("VLINK_DDS_MTU");
          +  -  +  -  -  
                      - ]
     816                 :            : 
     817   [ +  +  +  -  :        139 :   static bool enable_udp = Helpers::to_int(Utils::get_env("VLINK_DDS_UDP"), 1) != 0;
          +  -  +  -  -  
                      - ]
     818   [ +  +  +  -  :        139 :   static bool enable_tcp = Helpers::to_int(Utils::get_env("VLINK_DDS_TCP"), 0) != 0;
          +  -  +  -  -  
                      - ]
     819   [ +  +  +  -  :        139 :   static bool enable_shm = Helpers::to_int(Utils::get_env("VLINK_DDS_SHM"), 0) != 0;
          +  -  +  -  -  
                      - ]
     820   [ +  +  +  -  :        139 :   static bool enable_noblock = Helpers::to_int(Utils::get_env("VLINK_DDS_NOBLOCK"), 0) != 0;
          +  -  +  -  -  
                      - ]
     821                 :            : 
     822   [ +  +  +  -  :        139 :   static bool enable_less_memory = Helpers::to_int(Utils::get_env("VLINK_DDS_LESS_MEMORY"), 0) != 0;
          +  -  +  -  -  
                      - ]
     823                 :            : 
     824   [ +  +  +  -  :        139 :   static bool enable_ip_filter = Helpers::to_int(Utils::get_env("VLINK_DDS_IP_FILTER"), 0) != 0;
          +  -  +  -  -  
                      - ]
     825                 :            : 
     826   [ +  +  +  - ]:        139 :   static std::vector<std::string> default_ip_list = Utils::get_dds_default_address(enable_ip_filter);
     827                 :            : 
     828         [ +  - ]:        139 :   std::string prop_ip_str = ip_str;
     829         [ +  - ]:        139 :   std::string prop_ip_multicast_str = ip_multicast_str;
     830         [ +  - ]:        139 :   std::string prop_peer_str = peer_str;
     831                 :        139 :   size_t prop_buf = 0;
     832                 :        139 :   size_t prop_mtu = 0;
     833                 :        139 :   bool prop_enable_udp = enable_udp;
     834                 :        139 :   bool prop_enable_tcp = enable_tcp;
     835                 :        139 :   [[maybe_unused]] bool prop_enable_shm = enable_shm;
     836                 :        139 :   bool prop_enable_noblock = enable_noblock;
     837                 :        139 :   [[maybe_unused]] bool prop_enable_less_memory = enable_less_memory;
     838                 :            : 
     839         [ -  + ]:        139 :   if (!buf_str.empty()) {
     840         [ #  # ]:          0 :     std::from_chars(buf_str.data(), buf_str.data() + buf_str.size(), prop_buf);
     841                 :            :   }
     842                 :            : 
     843         [ -  + ]:        139 :   if (!mtu_str.empty()) {
     844         [ #  # ]:          0 :     std::from_chars(mtu_str.data(), mtu_str.data() + mtu_str.size(), prop_mtu);
     845                 :            :   }
     846                 :            : 
     847         [ +  + ]:        196 :   for (const auto& [prop, value] : properties) {
     848         [ +  + ]:         57 :     if (!Helpers::has_startwith(prop, "dds.")) {
     849                 :         10 :       continue;
     850                 :            :     }
     851                 :            : 
     852         [ +  + ]:         47 :     if (prop == "dds.ip") {
     853         [ +  - ]:          8 :       prop_ip_str = value;
     854         [ +  + ]:         39 :     } else if (prop == "dds.multicast.ip") {
     855         [ +  - ]:          3 :       prop_ip_multicast_str = value;
     856         [ +  + ]:         36 :     } else if (prop == "dds.peer") {
     857         [ +  - ]:          3 :       prop_peer_str = value;
     858         [ +  + ]:         33 :     } else if (prop == "dds.buf") {
     859         [ +  - ]:          7 :       std::from_chars(value.data(), value.data() + value.size(), prop_buf);
     860         [ +  + ]:         26 :     } else if (prop == "dds.mtu") {
     861         [ +  - ]:          7 :       std::from_chars(value.data(), value.data() + value.size(), prop_mtu);
     862         [ +  + ]:         19 :     } else if (prop == "dds.udp") {
     863                 :          5 :       prop_enable_udp = (value == "1");
     864         [ +  + ]:         14 :     } else if (prop == "dds.tcp") {
     865                 :          6 :       prop_enable_tcp = (value == "1");
     866         [ +  + ]:          8 :     } else if (prop == "dds.shm") {
     867                 :          3 :       prop_enable_shm = (value == "1");
     868         [ +  + ]:          5 :     } else if (prop == "dds.noblock") {
     869                 :          1 :       prop_enable_noblock = (value == "1");
     870         [ +  + ]:          4 :     } else if (prop == "dds.less_memory") {
     871                 :          3 :       prop_enable_less_memory = (value == "1");
     872                 :            :     } else {
     873         [ +  - ]:          1 :       dds_qos.properties().properties().emplace_back(prop, value);
     874                 :            :     }
     875                 :            :   }
     876                 :            : 
     877                 :        139 :   dds_qos.transport().use_builtin_transports = false;
     878                 :            : #if defined(VLINK_SUPPORT_DDS_V3) || FASTRTPS_VERSION_MINOR >= 10
     879                 :        139 :   dds_qos.wire_protocol().ignore_non_matching_locators = true;
     880                 :            : #endif
     881                 :        139 :   dds_qos.wire_protocol().builtin.avoid_builtin_multicast = true;
     882                 :            : 
     883                 :            :   //   dds_qos.wire_protocol().port.domainIDGain = 250;
     884                 :            :   //   dds_qos.wire_protocol().port.participantIDGain = 2;
     885                 :            :   //   dds_qos.wire_protocol().port.portBase = 7400;
     886                 :            :   //   dds_qos.wire_protocol().port.offsetd0 = 0;
     887                 :            :   //   dds_qos.wire_protocol().port.offsetd1 = 10;
     888                 :            :   //   dds_qos.wire_protocol().port.offsetd2 = 1;
     889                 :            :   //   dds_qos.wire_protocol().port.offsetd3 = 11;
     890                 :            :   // #ifdef VLINK_SUPPORT_DDS_V3
     891                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.discoveryProtocol = rtps::DiscoveryProtocol::SIMPLE;
     892                 :            :   // #else
     893                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.discoveryProtocol = rtps::DiscoveryProtocol_t::SIMPLE;
     894                 :            :   // #endif
     895                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.use_SIMPLE_EndpointDiscoveryProtocol = true;
     896                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.m_simpleEDP.use_PublicationReaderANDSubscriptionWriter = true;
     897                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.m_simpleEDP.use_PublicationWriterANDSubscriptionReader = true;
     898                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.leaseDuration = get_dds_duration(20000);
     899                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.leaseDuration_announcementperiod = get_dds_duration(3000);
     900                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.initial_announcements.count = 5;
     901                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.initial_announcements.period = get_dds_duration(100);
     902                 :            :   //   dds_qos.wire_protocol().builtin.discovery_config.ignoreParticipantFlags =
     903                 :            :   //       static_cast<rtps::ParticipantFilteringFlags>(rtps::ParticipantFilteringFlags::FILTER_SAME_PROCESS);
     904                 :            : 
     905         [ +  + ]:        139 :   if (prop_enable_less_memory) {
     906                 :          3 :     dds_qos.wire_protocol().builtin.readerHistoryMemoryPolicy = rtps::DYNAMIC_RESERVE_MEMORY_MODE;
     907                 :          3 :     dds_qos.wire_protocol().builtin.writerHistoryMemoryPolicy = rtps::DYNAMIC_RESERVE_MEMORY_MODE;
     908                 :            :     // dds_qos.allocation().participants = {2, 10, 1};
     909                 :            :     // dds_qos.allocation().readers = {2, 20, 1};
     910                 :            :     // dds_qos.allocation().writers = {2, 20, 1};
     911                 :            :     // dds_qos.wire_protocol().builtin.readerPayloadSize = 512;
     912                 :            :     // dds_qos.wire_protocol().builtin.writerPayloadSize = 512;
     913                 :            :     // dds_qos.allocation().locators.max_unicast_locators = 4;
     914                 :            :     // dds_qos.allocation().locators.max_multicast_locators = 1;
     915                 :            :     // dds_qos.allocation().data_limits.max_user_data = 256;
     916                 :            :     // dds_qos.allocation().data_limits.max_properties = 512;
     917                 :            :     // dds_qos.allocation().data_limits.max_partitions = 256;
     918                 :            :   }
     919                 :            : 
     920                 :            : #if !defined(__ANDROID__) && !defined(_WIN32)
     921                 :            : 
     922         [ -  + ]:        139 :   if (prop_enable_shm) {
     923         [ #  # ]:          0 :     auto shm_descriptor = std::make_shared<rtps2::SharedMemTransportDescriptor>();
     924         [ #  # ]:          0 :     dds_qos.transport().user_transports.emplace_back(std::move(shm_descriptor));
     925                 :          0 :   }
     926                 :            : #endif
     927                 :            : 
     928                 :            :   {
     929                 :        139 :     rtps::Locator_t pdp_locator;
     930                 :        139 :     pdp_locator.kind = LOCATOR_KIND_UDPv4;
     931   [ +  -  +  - ]:        139 :     rtps::IPLocator::setIPv4(pdp_locator, "239.255.0.1");
     932         [ +  - ]:        139 :     dds_qos.wire_protocol().builtin.metatrafficMulticastLocatorList.push_back(std::move(pdp_locator));
     933                 :            :   }
     934                 :            : 
     935                 :        139 :   std::vector<std::string> ip_str_list;
     936                 :            : 
     937         [ -  + ]:        139 :   if (prop_ip_str.empty()) {
     938         [ #  # ]:          0 :     ip_str_list = default_ip_list;
     939                 :            :   } else {
     940                 :        139 :     ip_str_list = Helpers::split_any(prop_ip_str);
     941                 :            :   }
     942                 :            : 
     943         [ +  - ]:        139 :   rtps::LocatorList_t ip_locators = get_locators(ip_str_list);
     944                 :            : 
     945         [ +  - ]:        139 :   if (!ip_locators.empty()) {
     946         [ +  - ]:        139 :     if (!prop_enable_shm) {
     947         [ +  - ]:        139 :       dds_qos.wire_protocol().default_unicast_locator_list.push_back(ip_locators);
     948                 :            :     }
     949                 :            : 
     950         [ +  - ]:        139 :     dds_qos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(ip_locators);
     951                 :            :   }
     952                 :            : 
     953         [ +  + ]:        139 :   if (!prop_ip_multicast_str.empty()) {
     954                 :          3 :     const auto multicast_ip_list = Helpers::split_any(prop_ip_multicast_str);
     955         [ +  - ]:          3 :     rtps::LocatorList_t multicast_ip_locators = get_locators(multicast_ip_list);
     956                 :            : 
     957         [ +  - ]:          3 :     if (!multicast_ip_locators.empty()) {
     958         [ +  - ]:          3 :       dds_qos.wire_protocol().default_multicast_locator_list.push_back(std::move(multicast_ip_locators));
     959                 :            :     }
     960                 :          3 :   }
     961                 :            : 
     962         [ +  + ]:        139 :   if (!prop_peer_str.empty()) {
     963                 :          3 :     auto peer_str_list = Helpers::split_any(prop_peer_str);
     964         [ +  - ]:          3 :     rtps::LocatorList_t peer_locators = get_locators(peer_str_list);
     965                 :            : 
     966         [ +  - ]:          3 :     if (!peer_locators.empty()) {
     967         [ -  + ]:          3 :       if (dds_qos.wire_protocol().builtin.metatrafficUnicastLocatorList.empty()) {
     968         [ #  # ]:          0 :         dds_qos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(rtps::LocatorList_t());
     969                 :            :       }
     970                 :            : 
     971         [ +  - ]:          3 :       dds_qos.wire_protocol().builtin.initialPeersList.push_back(std::move(peer_locators));
     972                 :            :     }
     973                 :          3 :   }
     974                 :            : 
     975         [ +  + ]:        139 :   if (prop_enable_udp) {
     976         [ +  - ]:        137 :     auto udp_descriptor = std::make_shared<rtps2::UDPv4TransportDescriptor>();
     977                 :            : 
     978   [ -  +  -  -  :        137 :     if (ip_str_list.size() == 1 || !prop_ip_str.empty()) {
                   +  - ]
     979                 :            : #ifdef VLINK_SUPPORT_DDS_V3
     980                 :            :       udp_descriptor->interface_allowlist.reserve(ip_str_list.size());
     981                 :            : 
     982                 :            :       for (const auto& ip : ip_str_list) {
     983                 :            :         // rtps::NetmaskFilterKind::OFF
     984                 :            :         udp_descriptor->interface_allowlist.emplace_back(ip);
     985                 :            :       }
     986                 :            : #else
     987         [ +  - ]:        137 :       udp_descriptor->interfaceWhiteList = ip_str_list;
     988                 :            : #endif
     989                 :            :     }
     990                 :            : 
     991         [ +  + ]:        137 :     if (prop_buf > 0) {
     992                 :          6 :       udp_descriptor->sendBufferSize = static_cast<uint32_t>(prop_buf);
     993                 :          6 :       udp_descriptor->receiveBufferSize = static_cast<uint32_t>(prop_buf);
     994                 :            :     }
     995                 :            : 
     996         [ +  + ]:        137 :     if (prop_mtu > 0) {
     997                 :          6 :       udp_descriptor->maxMessageSize = static_cast<uint32_t>(prop_mtu);
     998                 :            :     }
     999                 :            : 
    1000                 :        137 :     udp_descriptor->non_blocking_send = prop_enable_noblock;
    1001                 :            : 
    1002         [ +  - ]:        137 :     dds_qos.transport().user_transports.emplace_back(std::move(udp_descriptor));
    1003                 :        137 :   }
    1004                 :            : 
    1005                 :        139 :   auto ssl_cfg = SslOptions::parse_from(properties);
    1006                 :            : 
    1007                 :        139 :   bool ssl_cfg_valid = ssl_cfg.is_valid();
    1008                 :            : 
    1009   [ +  +  +  - ]:        139 :   if (ssl_cfg_valid && !prop_enable_tcp) {
    1010                 :          2 :     prop_enable_tcp = true;
    1011                 :            :   }
    1012                 :            : 
    1013         [ +  + ]:        139 :   if (prop_enable_tcp) {
    1014         [ +  - ]:          2 :     auto tcp_descriptor = std::make_shared<rtps2::TCPv4TransportDescriptor>();
    1015                 :            : 
    1016         [ +  + ]:          2 :     if (prop_buf > 0) {
    1017                 :          1 :       tcp_descriptor->sendBufferSize = static_cast<uint32_t>(prop_buf);
    1018                 :          1 :       tcp_descriptor->receiveBufferSize = static_cast<uint32_t>(prop_buf);
    1019                 :            :     }
    1020                 :            : 
    1021                 :          2 :     tcp_descriptor->keep_alive_frequency_ms = 1000;
    1022                 :          2 :     tcp_descriptor->keep_alive_timeout_ms = 3000;
    1023                 :            : #if defined(VLINK_SUPPORT_DDS_V3) || FASTRTPS_VERSION_MINOR >= 14
    1024                 :            :     tcp_descriptor->non_blocking_send = prop_enable_noblock;
    1025                 :            : #endif
    1026                 :            : 
    1027         [ +  - ]:          2 :     if (ssl_cfg_valid) {
    1028                 :          2 :       tcp_descriptor->apply_security = true;
    1029                 :            : 
    1030         [ +  - ]:          2 :       if (!ssl_cfg.ca_file.empty()) {
    1031         [ +  - ]:          2 :         tcp_descriptor->tls_config.verify_file = ssl_cfg.ca_file;
    1032                 :            :       }
    1033                 :            : 
    1034         [ +  + ]:          2 :       if (!ssl_cfg.cert_file.empty()) {
    1035         [ +  - ]:          1 :         tcp_descriptor->tls_config.cert_chain_file = ssl_cfg.cert_file;
    1036                 :            :       }
    1037                 :            : 
    1038         [ +  + ]:          2 :       if (!ssl_cfg.key_file.empty()) {
    1039         [ +  - ]:          1 :         tcp_descriptor->tls_config.private_key_file = ssl_cfg.key_file;
    1040                 :            :       }
    1041                 :            : 
    1042         [ +  + ]:          2 :       if (!ssl_cfg.key_password.empty()) {
    1043         [ +  - ]:          1 :         tcp_descriptor->tls_config.password = ssl_cfg.key_password;
    1044                 :            :       }
    1045                 :            : 
    1046                 :            : #if defined(VLINK_SUPPORT_DDS_V3) || FASTRTPS_VERSION_MINOR >= 10
    1047         [ +  + ]:          2 :       if (!ssl_cfg.server_name.empty()) {
    1048         [ +  - ]:          1 :         tcp_descriptor->tls_config.server_name = ssl_cfg.server_name;
    1049                 :            :       }
    1050                 :            : #endif
    1051                 :            : 
    1052         [ +  + ]:          2 :       if (ssl_cfg.verify_peer) {
    1053                 :          1 :         tcp_descriptor->tls_config.add_verify_mode(
    1054                 :            :             rtps2::TCPTransportDescriptor::TLSConfig::TLSVerifyMode::VERIFY_PEER);
    1055                 :            :       } else {
    1056                 :          1 :         tcp_descriptor->tls_config.add_verify_mode(
    1057                 :            :             rtps2::TCPTransportDescriptor::TLSConfig::TLSVerifyMode::VERIFY_NONE);
    1058                 :            :       }
    1059                 :            : 
    1060                 :          2 :       tcp_descriptor->tls_config.add_option(rtps2::TCPTransportDescriptor::TLSConfig::TLSOptions::DEFAULT_WORKAROUNDS);
    1061                 :          2 :       tcp_descriptor->tls_config.add_option(rtps2::TCPTransportDescriptor::TLSConfig::TLSOptions::NO_SSLV2);
    1062                 :          2 :       tcp_descriptor->tls_config.add_option(rtps2::TCPTransportDescriptor::TLSConfig::TLSOptions::NO_SSLV3);
    1063                 :            :     }
    1064                 :            : 
    1065         [ +  - ]:          2 :     tcp_descriptor->add_listener_port(0);
    1066                 :          2 :     rtps::Locator_t tcp_locator;
    1067                 :          2 :     tcp_locator.kind = LOCATOR_KIND_TCPv4;
    1068   [ +  -  +  - ]:          2 :     rtps::IPLocator::setIPv4(tcp_locator, "0.0.0.0");
    1069         [ +  - ]:          2 :     rtps::IPLocator::setPhysicalPort(tcp_locator, 0);
    1070         [ +  - ]:          2 :     rtps::IPLocator::setLogicalPort(tcp_locator, 0);
    1071         [ +  - ]:          2 :     dds_qos.wire_protocol().builtin.metatrafficUnicastLocatorList.push_back(tcp_locator);
    1072         [ +  - ]:          2 :     dds_qos.wire_protocol().default_unicast_locator_list.push_back(tcp_locator);
    1073                 :          2 :     rtps::Locator_t pdp_locator;
    1074                 :          2 :     pdp_locator.kind = LOCATOR_KIND_UDPv4;
    1075   [ +  -  +  - ]:          2 :     rtps::IPLocator::setIPv4(pdp_locator, "239.255.0.1");
    1076         [ +  - ]:          2 :     dds_qos.wire_protocol().builtin.metatrafficMulticastLocatorList.push_back(std::move(pdp_locator));
    1077         [ +  - ]:          2 :     dds_qos.transport().user_transports.emplace_back(std::move(tcp_descriptor));
    1078                 :          2 :   }
    1079                 :        139 : }
    1080                 :            : 
    1081                 :        145 : rtps::LocatorList_t DdsFactory::get_locators(const std::vector<std::string>& list) {
    1082                 :        145 :   rtps::LocatorList_t locator_list;
    1083                 :            : 
    1084         [ -  + ]:        145 :   if (list.empty()) {
    1085                 :          0 :     return locator_list;
    1086                 :            :   }
    1087                 :            : 
    1088         [ +  + ]:        290 :   for (const auto& ip : list) {
    1089         [ -  + ]:        145 :     if (ip.find(':') != std::string::npos) {
    1090                 :          0 :       rtps2::Locator locator;
    1091                 :          0 :       locator.kind = LOCATOR_KIND_UDPv6;
    1092                 :          0 :       locator.port = 0;
    1093                 :            : 
    1094   [ #  #  #  # ]:          0 :       if VLIKELY (rtps::IPLocator::setIPv6(locator, ip)) {
    1095         [ #  # ]:          0 :         locator_list.push_back(std::move(locator));
    1096                 :            :       }
    1097                 :            :     } else {
    1098                 :        145 :       rtps2::Locator locator;
    1099                 :        145 :       locator.kind = LOCATOR_KIND_UDPv4;
    1100                 :        145 :       locator.port = 0;
    1101                 :            : 
    1102   [ +  -  +  - ]:        145 :       if VLIKELY (rtps::IPLocator::setIPv4(locator, ip)) {
    1103         [ +  - ]:        145 :         locator_list.push_back(std::move(locator));
    1104                 :            :       }
    1105                 :            :     }
    1106                 :            :   }
    1107                 :            : 
    1108                 :        145 :   return locator_list;
    1109                 :          0 : }
    1110                 :            : 
    1111                 :       1545 : std::string DdsFactory::get_qos_ext(const Conf::PropertiesMap& ext, const std::string& key) {
    1112         [ +  - ]:       1545 :   auto iter = ext.find(key);
    1113                 :            : 
    1114         [ +  + ]:       1545 :   if (iter == ext.end()) {
    1115         [ +  - ]:       1528 :     return "";
    1116                 :            :   }
    1117                 :            : 
    1118         [ +  - ]:         17 :   return iter->second;
    1119                 :            : }
    1120                 :            : 
    1121                 :            : }  // namespace vlink

Generated by: LCOV version 1.14