LCOV - code coverage report
Current view: top level - DCPS - DCPS_Utils.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 11 252 4.4 %
Date: 2023-04-30 01:32:43 Functions: 2 24 8.3 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *
       4             :  * Distributed under the OpenDDS License.
       5             :  * See: http://www.opendds.org/license.html
       6             :  */
       7             : 
       8             : #include "DCPS/DdsDcps_pch.h"
       9             : #include "DCPS_Utils.h"
      10             : 
      11             : #include "Qos_Helper.h"
      12             : #include "Definitions.h"
      13             : #include "SafetyProfileStreams.h"
      14             : 
      15             : #include <ace/ACE.h> /* For ACE::wild_match() */
      16             : #include <ace/OS_NS_string.h>
      17             : 
      18             : #ifdef OPENDDS_SECURITY
      19             : #  include "dds/DdsSecurityCoreC.h"
      20             : #endif
      21             : 
      22             : #include <cstring>
      23             : 
      24             : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
      25             : 
      26             : namespace OpenDDS {
      27             : namespace DCPS {
      28             : 
      29           8 : const char* retcode_to_string(DDS::ReturnCode_t value)
      30             : {
      31           8 :   switch (value) {
      32           0 :   case DDS::RETCODE_OK:
      33           0 :     return "OK";
      34           8 :   case DDS::RETCODE_ERROR:
      35           8 :     return "Error";
      36           0 :   case DDS::RETCODE_UNSUPPORTED:
      37           0 :     return "Unsupported";
      38           0 :   case DDS::RETCODE_BAD_PARAMETER:
      39           0 :     return "Bad parameter";
      40           0 :   case DDS::RETCODE_PRECONDITION_NOT_MET:
      41           0 :     return "Precondition not met";
      42           0 :   case DDS::RETCODE_OUT_OF_RESOURCES:
      43           0 :     return "Out of resources";
      44           0 :   case DDS::RETCODE_NOT_ENABLED:
      45           0 :     return "Not enabled";
      46           0 :   case DDS::RETCODE_IMMUTABLE_POLICY:
      47           0 :     return "Immutable policy";
      48           0 :   case DDS::RETCODE_INCONSISTENT_POLICY:
      49           0 :     return "Inconsistent policy";
      50           0 :   case DDS::RETCODE_ALREADY_DELETED:
      51           0 :     return "Already deleted";
      52           0 :   case DDS::RETCODE_TIMEOUT:
      53           0 :     return "Timeout";
      54           0 :   case DDS::RETCODE_NO_DATA:
      55           0 :     return "No data";
      56           0 :   case DDS::RETCODE_ILLEGAL_OPERATION:
      57           0 :     return "Illegal operation";
      58             : #ifdef OPENDDS_SECURITY
      59           0 :   case DDS::Security::RETCODE_NOT_ALLOWED_BY_SECURITY:
      60           0 :     return "Not allowed by security";
      61             : #endif
      62           0 :   default:
      63           0 :     ACE_ERROR((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: retcode_to_string: ")
      64             :       ACE_TEXT("%d is either invalid or not recognized.\n"),
      65             :       value));
      66           0 :     return "Invalid return code";
      67             :   }
      68             : }
      69             : 
      70           0 : const char* topicstatus_to_string(TopicStatus value)
      71             : {
      72           0 :   switch (value) {
      73           0 :   case CREATED:
      74           0 :     return "Created";
      75           0 :   case ENABLED:
      76           0 :     return "Enabled";
      77           0 :   case FOUND:
      78           0 :     return "Found";
      79           0 :   case NOT_FOUND:
      80           0 :     return "Not found";
      81           0 :   case REMOVED:
      82           0 :     return "Removed";
      83           0 :   case CONFLICTING_TYPENAME:
      84           0 :     return "Conflicting typename";
      85           0 :   case PRECONDITION_NOT_MET:
      86           0 :     return "Precondition not met";
      87           0 :   case INTERNAL_ERROR:
      88           0 :     return "Internal error";
      89           0 :   case TOPIC_DISABLED:
      90           0 :     return "Topic disabled";
      91           0 :   default:
      92           0 :     ACE_ERROR((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: topicstatus_to_string: ")
      93             :       ACE_TEXT("%d is either invalid or not recognized.\n"),
      94             :       value));
      95           0 :     return "Invalid topic status";
      96             :   }
      97             : }
      98             : 
      99             : bool
     100           0 : is_wildcard(const char *str)
     101             : {
     102             :   static const char wild[] = "?*[";
     103             : 
     104           0 :   while (*str) {
     105           0 :     size_t i = ACE_OS::strcspn(str, wild);
     106             : 
     107           0 :     if (!str[i]) return false; // no wildcard
     108             : 
     109           0 :     if (i > 0 && str[i-1] == '\\') str += i + 1; // escaped wildcard
     110             : 
     111           0 :     else return true;
     112             :   }
     113             : 
     114           0 :   return false;
     115             : }
     116             : 
     117             : class PartitionName {
     118             : public:
     119           0 :   PartitionName(const char* name)
     120           0 :     : name_(name),
     121           0 :       wildcard_(is_wildcard(name)) {}
     122             : 
     123           0 :   bool matches(const PartitionName& n) {
     124           0 :     if (wildcard_ && n.wildcard_)
     125           0 :       return false; // wildcards never match
     126             : 
     127           0 :     if (wildcard_)
     128           0 :       return ACE::wild_match(n.name_, name_, true, true);
     129             : 
     130           0 :     else if (n.wildcard_)
     131           0 :       return ACE::wild_match(name_, n.name_, true, true);
     132             : 
     133             :     else
     134           0 :       return ACE_OS::strcmp(name_, n.name_) == 0;
     135             :   }
     136             : 
     137             : private:
     138             :   const char* name_;
     139             :   bool wildcard_;
     140             : };
     141             : 
     142             : bool
     143           0 : matches_name(const DDS::PartitionQosPolicy& qos, const PartitionName& name)
     144             : {
     145           0 :   for (CORBA::ULong i = 0; i < qos.name.length(); ++i) {
     146           0 :     PartitionName qos_name(qos.name[i]);
     147             : 
     148           0 :     if (qos_name.matches(name))
     149           0 :       return true;
     150             :   }
     151             : 
     152           0 :   return false;
     153             : }
     154             : 
     155             : bool
     156           0 : matches_default(const DDS::PartitionQosPolicy& qos)
     157             : {
     158           0 :   if (qos.name.length() == 0)
     159           0 :     return true; // default
     160             : 
     161           0 :   for (CORBA::ULong i = 0; i < qos.name.length(); ++i) {
     162           0 :     if (*qos.name[i] == 0)
     163           0 :       return true; // default (empty string)
     164             :   }
     165             : 
     166           0 :   return false;
     167             : }
     168             : 
     169             : bool
     170           0 : matching_partitions(const DDS::PartitionQosPolicy& pub,
     171             :                     const DDS::PartitionQosPolicy& sub)
     172             : {
     173           0 :   if (matches_default(pub)) {
     174           0 :     if (matches_default(sub))
     175           0 :       return true;
     176             : 
     177             :     // Zero-length sequences should be treated the same as a
     178             :     // sequence of length 1 that contains an empty string:
     179           0 :     if (pub.name.length() == 0)
     180           0 :       return matches_name(sub, "");
     181             :   }
     182             : 
     183           0 :   for (CORBA::ULong i = 0; i < pub.name.length(); ++i) {
     184           0 :     const char* name = pub.name[i];
     185             : 
     186           0 :     if (matches_name(sub, name))
     187           0 :       return true;
     188             :   }
     189             : 
     190           0 :   return false;
     191             : }
     192             : 
     193             : void
     194           0 : increment_incompatibility_count(OpenDDS::DCPS::IncompatibleQosStatus* status,
     195             :                                 DDS::QosPolicyId_t incompatible_policy)
     196             : {
     197           0 :   if (!status) return;
     198             : 
     199           0 :   ++status->total_count;
     200           0 :   ++status->count_since_last_send;
     201           0 :   status->last_policy_id = incompatible_policy;
     202           0 :   CORBA::ULong const size = status->policies.length();
     203           0 :   CORBA::ULong count = 0;
     204           0 :   bool updated = false;
     205             : 
     206           0 :   for (; !updated && count < size; ++count) {
     207           0 :     if (status->policies[count].policy_id == incompatible_policy) {
     208           0 :       ++status->policies[count].count;
     209           0 :       updated = true;
     210             :     }
     211             :   }
     212             : 
     213           0 :   if (!updated) {
     214             :     DDS::QosPolicyCount policy;
     215           0 :     policy.policy_id = incompatible_policy;
     216           0 :     policy.count = 1;
     217           0 :     status->policies.length(count + 1);
     218           0 :     status->policies[count] = policy;
     219             :   }
     220             : }
     221             : 
     222             : bool
     223           0 : compatibleTransports(const OpenDDS::DCPS::TransportLocatorSeq& s1,
     224             :                      const OpenDDS::DCPS::TransportLocatorSeq& s2)
     225             : {
     226           0 :   for (CORBA::ULong i = 0; i < s1.length(); ++i) {
     227           0 :     for (CORBA::ULong j = 0; j < s2.length(); ++j) {
     228           0 :       if (0 == std::strcmp(s1[i].transport_type, s2[j].transport_type)) {
     229           0 :         return true;
     230             :       }
     231             :     }
     232             :   }
     233           0 :   return false;
     234             : }
     235             : 
     236             : bool
     237           0 : compatibleQOS(OpenDDS::DCPS::IncompatibleQosStatus* writerStatus,
     238             :               OpenDDS::DCPS::IncompatibleQosStatus* readerStatus,
     239             :               const OpenDDS::DCPS::TransportLocatorSeq& pubTLS,
     240             :               const OpenDDS::DCPS::TransportLocatorSeq& subTLS,
     241             :               DDS::DataWriterQos const * const writerQos,
     242             :               DDS::DataReaderQos const * const readerQos,
     243             :               DDS::PublisherQos const * const pubQos,
     244             :               DDS::SubscriberQos const * const subQos)
     245             : {
     246           0 :   bool compatible = true;
     247             : 
     248             :   // Check transport-type compatibility
     249           0 :   if (!compatibleTransports(pubTLS, subTLS)) {
     250           0 :     compatible = false;
     251           0 :     increment_incompatibility_count(writerStatus,
     252             :                                     OpenDDS::TRANSPORTTYPE_QOS_POLICY_ID);
     253           0 :     increment_incompatibility_count(readerStatus,
     254             :                                     OpenDDS::TRANSPORTTYPE_QOS_POLICY_ID);
     255             :   }
     256             : 
     257             :   // Verify compatibility of DataWriterQos and DataReaderQos
     258           0 :   compatible = compatible && compatibleQOS(writerQos, readerQos,
     259             :                                            writerStatus, readerStatus);
     260             : 
     261             :   // Verify compatibility of PublisherQos and SubscriberQos
     262           0 :   compatible = compatible && compatibleQOS(pubQos, subQos,
     263             :                                            writerStatus, readerStatus);
     264             : 
     265             :   // Verify publisher and subscriber are in a matching partition.
     266             :   //
     267             :   // According to the DDS spec:
     268             :   //
     269             :   //   Failure to match partitions is not considered an incompatible
     270             :   //   QoS and does not trigger any listeners nor conditions.
     271             :   //
     272             :   // Don't increment the incompatibity count.
     273           0 :   compatible = compatible && matching_partitions(pubQos->partition,
     274           0 :                                                  subQos->partition);
     275             : 
     276           0 :   return compatible;
     277             : }
     278             : 
     279             : bool
     280           0 : compatibleQOS(const DDS::PublisherQos*  pubQos,
     281             :               const DDS::SubscriberQos* subQos,
     282             :               OpenDDS::DCPS::IncompatibleQosStatus* writerStatus,
     283             :               OpenDDS::DCPS::IncompatibleQosStatus* readerStatus)
     284             : {
     285           0 :   bool compatible = true;
     286             : 
     287             :   // PARTITION, GROUP_DATA, and ENTITY_FACTORY are RxO==no.
     288             : 
     289             :   // Check the PRESENTATION_QOS_POLICY_ID
     290           0 :   if ((pubQos->presentation.access_scope < subQos->presentation.access_scope)
     291           0 :       || (!pubQos->presentation.coherent_access && subQos->presentation.coherent_access)
     292           0 :       || (!pubQos->presentation.ordered_access && subQos->presentation.ordered_access)) {
     293           0 :     compatible = false;
     294             : 
     295           0 :     increment_incompatibility_count(writerStatus,
     296             :                                     DDS::PRESENTATION_QOS_POLICY_ID);
     297           0 :     increment_incompatibility_count(readerStatus,
     298             :                                     DDS::PRESENTATION_QOS_POLICY_ID);
     299             :   }
     300             : 
     301           0 :   return compatible;
     302             : }
     303             : 
     304             : bool
     305           0 : compatibleQOS(const DDS::DataWriterQos * writerQos,
     306             :               const DDS::DataReaderQos * readerQos,
     307             :               OpenDDS::DCPS::IncompatibleQosStatus* writerStatus,
     308             :               OpenDDS::DCPS::IncompatibleQosStatus* readerStatus)
     309             : {
     310           0 :   bool compatible = true;
     311             : 
     312             :   // Check the RELIABILITY_QOS_POLICY_ID
     313           0 :   if (writerQos->reliability.kind < readerQos->reliability.kind) {
     314           0 :     compatible = false;
     315             : 
     316           0 :     increment_incompatibility_count(writerStatus,
     317             :                                     DDS::RELIABILITY_QOS_POLICY_ID);
     318           0 :     increment_incompatibility_count(readerStatus,
     319             :                                     DDS::RELIABILITY_QOS_POLICY_ID);
     320             :   }
     321             : 
     322             :   // Check the DURABILITY_QOS_POLICY_ID
     323           0 :   if (writerQos->durability.kind < readerQos->durability.kind) {
     324           0 :     compatible = false;
     325             : 
     326           0 :     increment_incompatibility_count(writerStatus,
     327             :                                     DDS::DURABILITY_QOS_POLICY_ID);
     328           0 :     increment_incompatibility_count(readerStatus,
     329             :                                     DDS::DURABILITY_QOS_POLICY_ID);
     330             :   }
     331             : 
     332             :   // Check the LIVELINESS_QOS_POLICY_ID
     333             :   // invalid if offered kind is less than requested kind OR
     334             :   //         if offered liveliness duration greater than requested
     335             :   //         liveliness duration
     336             :   using OpenDDS::DCPS::operator>;
     337           0 :   if (writerQos->liveliness.kind < readerQos->liveliness.kind
     338           0 :       || writerQos->liveliness.lease_duration
     339           0 :       > readerQos->liveliness.lease_duration) {
     340             : 
     341           0 :     compatible = false;
     342             : 
     343           0 :     increment_incompatibility_count(writerStatus,
     344             :                                     DDS::LIVELINESS_QOS_POLICY_ID);
     345           0 :     increment_incompatibility_count(readerStatus,
     346             :                                     DDS::LIVELINESS_QOS_POLICY_ID);
     347             :   }
     348             : 
     349             :   // Check the DEADLINE_QOS_POLICY_ID
     350             :   //   Offered deadline must be less than or equal to the requested
     351             :   //   deadline.
     352           0 :   if (writerQos->deadline.period > readerQos->deadline.period) {
     353             : 
     354           0 :     compatible = false;
     355             : 
     356           0 :     increment_incompatibility_count(writerStatus,
     357             :                                     DDS::DEADLINE_QOS_POLICY_ID);
     358           0 :     increment_incompatibility_count(readerStatus,
     359             :                                     DDS::DEADLINE_QOS_POLICY_ID);
     360             :   }
     361             : 
     362             :   // Check the LATENCY_BUDGET
     363             :   //   The reader's duration must be greater than or equal to the writer's
     364             :   using OpenDDS::DCPS::operator<;
     365           0 :   if (readerQos->latency_budget.duration < writerQos->latency_budget.duration) {
     366             : 
     367           0 :     compatible = false;
     368             : 
     369           0 :     increment_incompatibility_count(writerStatus,
     370             :                                     DDS::LATENCYBUDGET_QOS_POLICY_ID);
     371           0 :     increment_incompatibility_count(readerStatus,
     372             :                                     DDS::LATENCYBUDGET_QOS_POLICY_ID);
     373             :   }
     374             : 
     375             :   // The value of the OWNERSHIP kind offered must exactly match the one
     376             :   // requested or else they are considered incompatible.
     377           0 :   if (writerQos->ownership.kind != readerQos->ownership.kind) {
     378           0 :     compatible = false;
     379             : 
     380           0 :     increment_incompatibility_count(writerStatus,
     381             :                                     DDS::OWNERSHIP_QOS_POLICY_ID);
     382           0 :     increment_incompatibility_count(readerStatus,
     383             :                                     DDS::OWNERSHIP_QOS_POLICY_ID);
     384             :   }
     385             : 
     386             :   {
     387             :     // Find a common data representation
     388           0 :     bool found = false;
     389           0 :     const CORBA::ULong reader_count = readerQos->representation.value.length();
     390           0 :     const CORBA::ULong writer_count = writerQos->representation.value.length();
     391           0 :     for (CORBA::ULong wi = 0; !found && wi < writer_count; ++wi) {
     392           0 :       for (CORBA::ULong ri = 0; !found && ri < reader_count; ++ri) {
     393           0 :         if (readerQos->representation.value[ri] == writerQos->representation.value[wi]) {
     394           0 :           found = true;
     395           0 :           break;
     396             :         }
     397             :       }
     398             :     }
     399             : 
     400           0 :     if (!found) {
     401           0 :       increment_incompatibility_count(writerStatus,
     402             :         DDS::DATA_REPRESENTATION_QOS_POLICY_ID);
     403           0 :       increment_incompatibility_count(readerStatus,
     404             :         DDS::DATA_REPRESENTATION_QOS_POLICY_ID);
     405           0 :       compatible = false;
     406             :     }
     407             :   }
     408             : 
     409           0 :   return compatible;
     410             : }
     411             : 
     412             : #ifndef OPENDDS_SAFETY_PROFILE
     413             : using OpenDDS::DCPS::operator==;
     414             : #endif
     415           0 : bool should_check_association_upon_change(const DDS::DataReaderQos & qos1,
     416             :                                           const DDS::DataReaderQos & qos2)
     417             : {
     418           0 :   return !(
     419           0 :            (qos1.deadline == qos2.deadline) &&
     420           0 :            (qos1.latency_budget == qos2.latency_budget));
     421             : }
     422             : 
     423           0 : bool should_check_association_upon_change(const DDS::DataWriterQos & qos1,
     424             :                                           const DDS::DataWriterQos & qos2)
     425             : {
     426           0 :   return !(
     427           0 :            (qos1.deadline == qos2.deadline) &&
     428           0 :            (qos1.latency_budget == qos2.latency_budget));
     429             : }
     430             : 
     431           0 : bool should_check_association_upon_change(const DDS::SubscriberQos & qos1,
     432             :                                           const DDS::SubscriberQos & qos2)
     433             : {
     434           0 :   return !(qos1.partition == qos2.partition);
     435             : }
     436             : 
     437           0 : bool should_check_association_upon_change(const DDS::PublisherQos & qos1,
     438             :                                           const DDS::PublisherQos & qos2)
     439             : {
     440           0 :   return !(qos1.partition == qos2.partition);
     441             : }
     442             : 
     443           0 : bool should_check_association_upon_change(const DDS::TopicQos & /*qos1*/,
     444             :                                           const DDS::TopicQos & /*qos2*/)
     445             : {
     446           0 :   return false;
     447             : }
     448             : 
     449           0 : bool should_check_association_upon_change(const DDS::DomainParticipantQos & /*qos1*/,
     450             :                                           const DDS::DomainParticipantQos & /*qos2*/)
     451             : {
     452           0 :   return false;
     453             : }
     454             : 
     455           0 : bool repr_to_encoding_kind(DDS::DataRepresentationId_t repr, Encoding::Kind& kind)
     456             : {
     457           0 :   switch(repr) {
     458           0 :   case DDS::XCDR_DATA_REPRESENTATION:
     459           0 :     kind = Encoding::KIND_XCDR1;
     460           0 :     break;
     461           0 :   case DDS::XCDR2_DATA_REPRESENTATION:
     462           0 :     kind = Encoding::KIND_XCDR2;
     463           0 :     break;
     464           0 :   case OpenDDS::DCPS::UNALIGNED_CDR_DATA_REPRESENTATION:
     465           0 :     kind = Encoding::KIND_UNALIGNED_CDR;
     466           0 :     break;
     467           0 :   default:
     468           0 :     return false;
     469             :   }
     470           0 :   return true;
     471             : }
     472             : 
     473           0 : DCPS::String repr_to_string(const DDS::DataRepresentationId_t& repr)
     474             : {
     475           0 :   DCPS::String repr_string;
     476           0 :   switch (repr) {
     477           0 :   case DDS::XCDR_DATA_REPRESENTATION:
     478           0 :     repr_string = "XCDR_DATA_REPRESENTATION";
     479           0 :     break;
     480           0 :   case DDS::XML_DATA_REPRESENTATION:
     481           0 :     repr_string = "XML_DATA_REPRESENTATION";
     482           0 :     break;
     483           0 :   case DDS::XCDR2_DATA_REPRESENTATION:
     484           0 :     repr_string = "XCDR2_DATA_REPRESENTATION";
     485           0 :     break;
     486           0 :   case OpenDDS::DCPS::UNALIGNED_CDR_DATA_REPRESENTATION:
     487           0 :     repr_string = "UNALIGNED_CDR_DATA_REPRESENTATION";
     488           0 :     break;
     489           0 :   default:
     490           0 :     repr_string = to_dds_string(repr);
     491             :   }
     492           0 :   return repr_string;
     493           0 : }
     494             : 
     495           0 : DCPS::String repr_seq_to_string(const DDS::DataRepresentationIdSeq& id_seq, bool is_data_writer)
     496             : {
     497           0 :   DCPS::String repr_string;
     498           0 :   const ACE_CDR::ULong length = is_data_writer ? 1 : id_seq.length();
     499           0 :   for (ACE_CDR::ULong i = 0; i < length; ++i) {
     500           0 :     if (i > 0) {
     501           0 :       repr_string += ", ";
     502             :     }
     503           0 :     repr_string += repr_to_string(id_seq[i]);
     504             :   }
     505           0 :   return repr_string;
     506           0 : }
     507             : 
     508           0 : void set_writer_effective_data_rep_qos(DDS::DataRepresentationIdSeq& qos,
     509             :   bool cdr_encapsulated)
     510             : {
     511           0 :   if (qos.length() == 0) {
     512           0 :     qos.length(1);
     513           0 :     qos[0] = cdr_encapsulated ? DDS::XCDR2_DATA_REPRESENTATION : OpenDDS::DCPS::UNALIGNED_CDR_DATA_REPRESENTATION;
     514             :   }
     515           0 : }
     516             : 
     517          81 : void set_reader_effective_data_rep_qos(DDS::DataRepresentationIdSeq& qos)
     518             : {
     519          81 :   if (qos.length() == 0) {
     520          81 :     qos.length(3);
     521          81 :     qos[0] = DDS::XCDR2_DATA_REPRESENTATION;
     522          81 :     qos[1] = DDS::XCDR_DATA_REPRESENTATION;
     523          81 :     qos[2] = OpenDDS::DCPS::UNALIGNED_CDR_DATA_REPRESENTATION;
     524             :   }
     525          81 : }
     526             : 
     527             : } // namespace DCPS
     528             : } // namespace OpenDDS
     529             : 
     530             : OPENDDS_END_VERSIONED_NAMESPACE_DECL

Generated by: LCOV version 1.16