Accessing DomainParticipant's GUID

6 posts / 0 new
Last post
njc
Offline
Last seen: 10 years 6 days ago
Joined: 08/09/2012
Posts: 17
Accessing DomainParticipant's GUID

DomainParticipants will automatically generate a GUID based on rtps_host_id, rtps_app_id, and rtps_instance_id in the wire protocol QoS settings. Is there any way to access this GUID through the domain participant? We have one domain participant per app, and each app needs a GUID for som app-level logic, so I was hoping to just use the GUID that DDS generates without having to generate my own.

 

Edit:

On a somewhat related qeustion: How is the instance handle computed for a DomainParticipant. As I mentioned, I have one DomainParticipant per application. Under this, there are multiple publishers/subscribers. I want subscribers to ignore publishers within the same application, so I used 

participant->ignore_participant(participant->get_instance_handle())


Which does block communication between local entties, but if I spawn two separate applications (separate domain participants) on the same machine, they ignore each other as well. Why do two separate Domain Participants in separate address spaces and processes have the same isntance handle?

 

Thanks,

-Neal

Gerardo Pardo's picture
Offline
Last seen: 1 day 5 hours ago
Joined: 06/02/2010
Posts: 601

Hello Neal,

The GUID is available as part of the DomainParticipantQos

For a locally-created DomainParticipant you can call get_qos() to get the DomainParticipantQos. There you will see an attribute called wire_protocol of type WireProtocolQosPolicy. The combination of the first four attributes: participant_id, rtps_host_id, rtps_app_id, and rtps_instance_id form the 16-byte GUID.

If it is a remote DomainParticipant, then you can find its GUID on the DomainParticipantBuiltinTopicData that is propagated via DDS discovery and accessible via the builtin ParticipantBuiltinTopicDataDataReader.  Within that structure, the  attribute named key contains the 16-byte GUID for the DomainParticipant.

Regarding your question on how the InstanceHandle for the DomainParticipant, the InstanceHandle is essentially the GUID. However the formatting is a little bit different and the implementation is opaque meaning an application should not rely on the format. It is just a unique way to refer to a participant that has been discovered...

What you are doing to have subscribers ignore publisher from the same application seems correct to me and it should only ignore the one DomainParticipant not the other ones on the same computer.  To be more precice,  DomainParticipants will have different values for IntanceHandle.  This is true wether the DomainParticipant entities are in different computers, different processes in the same computer, or even different participants created within the same process.   I do not understand why it is not working for you... I can try to reproduce it in a simple example... What platform are you running on?

Gerardo

 

 

 

 

Offline
Last seen: 9 years 6 months ago
Joined: 12/08/2011
Posts: 10

I am still somwhat struggeling to understand the interconnection between a participant GUID, an instance handel, and a topic key with the main problem being how they are interdependent and when which should be used.

Some facts I collected so far on the related (C++) types:

  • A GUID seems to be stored as a DDS_GUID_t, an array of 16 bytes, i. e. a total of 128 bits.
  • A participant instance handle seems to be stored as a DDS_InstanceHandle_t, which (on my machine, x86_64 linux) is a typedef to DDS_HANDLE_TYPE_NATIVE which is typedefed to PRESInstanceHandle wich contains a MIGRtpsKeyHash called keyHash which contains an RTICdrOctec[16] array called value.  Long story short, a DDS_InstanceHandle_t struct starts with a 128 bit data array (and some more flags after that).
  • A topic key seems to stored as a DDS_BuiltinTopicKey_t, which  has a public array called value, which (on my machine, x86_64 linux) is a RTI_UINT32[4] array, i. e. a 128 bit structure.

From what I gathered so far, those three things (GUID, instance handle, and the topic key) are more or less the same thing when related to a participant. This assumption is mainly based upon  this post by Gerardo where lists the locations where the GUID of a remote participant appears:

  1. as the ParticipantBuiltinTopicData key attribute
  2. as the PublicationBuiltinTopicData  participant_key attribute.
  3. as the SubscriptionBuiltinTopicData  participant_key attribute.

All the referenced attributes, however, are topic keys and in his post Gerardo uses a type cast from an instance handle to a GUID, essentially implying that all those 128bit constructs (topic key, instance handel, GUID) are more or less the same.

A problem arises as to determining the GUID of the local participant.

This post most likely presents the quickest way, calling  get_instance_handle() on the local participant. Where it gets a little confusing is this post where the internal structure of a participant GUID is explained: according to the post a GUID is actually only a 64 bit value and is comprised of

  • 32 bits for the host ID. The host ID is currently based upon the IP address (although this might change in future versions). In the above case, a GUID of c0c80aa3 translates to IP address 192.200.10.163. This will allow you to determine the node having the GUID problem. 
  • 16 low bits for the process ID.
    • If the originating node is a Windows system, the relevant "process ID" will be the value of GetCurrentProcessId().
    • On a VxWorks system, it will be the task ID of a specific task.
    • On a Linux system, it will be the process ID that you can see as the output of the command ps -ef.
  • 8 bits for an internal counter. This counter allows an application to create multiple DomainParticipants in the same domain.
  • 8 bits containing a constant value (0x01).

This structure seems to be in line with Gerardo's explenations above, where the GUID is related to the WireProtocolQosPolicy. However, there is some room for ambiguity as the Wire Protocol only seems to control 96 bits of the 128 bit GUID (compare §8.5.9.4 in the RTI User Manual, "Controlling How the GUID is Set (rtps_auto_id_kind)").  Gerarodo seems to say that the  participant_id is used to fill the missing 32bits, however on my machine the last 32 bits always end up being 0x1C1, which is neither nor.

 qDebug() << q->qualifiedName() << "Ownship Instance Handle:" << participant->get_instance_handle();
    
    participant->get_qos(participant_qos);
    qDebug() << "RTPS Host ID :" 
      << participant_qos.wire_protocol.rtps_host_id << ","
      << QString::number(participant_qos.wire_protocol.rtps_host_id,16).toUpper().prepend("0x");
    qDebug() << "RTPS App ID :"
      << participant_qos.wire_protocol.rtps_app_id << ","
      << QString::number(participant_qos.wire_protocol.rtps_app_id,16).toUpper().prepend("0x");
    qDebug() << "RTPS Instance ID :"
      << participant_qos.wire_protocol.rtps_instance_id << ","
      << QString::number(participant_qos.wire_protocol.rtps_instance_id,16).toUpper().prepend("0x");
    qDebug() << "RTPS Participant ID :"
      << participant_qos.wire_protocol.participant_id << ","
      << QString::number(participant_qos.wire_protocol.participant_id,16).toUpper().prepend("0x");
    qDebug() << "DDS Domain ID :"
      << participant->get_domain_id() << ","
      << QString::number(participant->get_domain_id(),16).toUpper().prepend("0x");

The debug code above created the following output:

"GCS/DDS" Ownship Instance Handle: "{C0:A8:36:96-0:0:1E:E4-0:0:0:1-0:0:1:C1}" 
RTPS Host ID : 3232249494 , "0xC0A83696" 
RTPS App ID : 7908 , "0x1EE4" 
RTPS Instance ID : 1 , "0x1" 
RTPS Participant ID : 0 , "0x0" 
DDS Domain ID : 0 , "0x0" 

Besides the obivous solution of simply using   get_instance_handle() and not messing with the participant GUID's building blocks, could somebody shed some light on those last 32bits?

Offline
Last seen: 9 years 6 months ago
Joined: 12/08/2011
Posts: 10

On re-reading my previous post I realized that my actual question got totally lost in the details. So here another attempt at paraphrasing it:

Task

The task is to find a way to use DDS built in methods to uniquly identify participants in the user code. The goal is to enable participant user code to realize who they are, and whom they are talking to.
All involveld, however, need to use the same GUIDs so that when participant A and B "talk" about participant C, they both mean the same participant.

Accessing GUID data of other participants

Getting access to GUIDs of other participants is easily accomplished via getting the respective GUID data during discovery from

  1. the ParticipantBuiltinTopicData key attribute
  2. the PublicationBuiltinTopicData  participant_key attribute.
  3. the SubscriptionBuiltinTopicData  participant_key attribute.

During regular data messaging, this data is recoverable via

// ...
DDS_PublicationBuiltinTopicData publicationData;
narrow_reader->get_matched_publication_data(publicationData, info.publication_handle);
publicationData.participant_key;

Accessing GUID data of the local participant

Getting the GUID of the local participant appears to be the simplest when using participant->get_instance_handle(). , especially when considering the alternatives of rebuliding the GUID from the underlying sources (see the section with the Wire QoS in my post above).

The Problem

How can I savely compare the local participants GUID data, which is of type DDS_InstanceHandle_t, to the GUID data of the other participants, which are given as a DDS_BuiltinTopicKey_t.
What is a safe way to check thos two for equality? Do I need to be conserned about endianess issues when comparing the (potentially not intended to be public) underlying "raw" 128 bit of data?

 

Gerardo Pardo's picture
Offline
Last seen: 1 day 5 hours ago
Joined: 06/02/2010
Posts: 601

Hello Neal,

Thank you for the follow-up clarification. It helps a lot to understand what you are trying to do...

To answer your question: The BuiltinTopicKey_t and the InstanceHandle_t contain the same information about the DDS_GUID_t, but as you stated they represent it differently. The BuiltinTopicKey_t represents GUID_t information as 4 integers. On the other hand the InstanceHandle_t represents it using a 16-byte array. As you suspected, the fact that they are different representations (one as 4 integers, and the other as 16 bytes) means that endianess issues do get it the way and you cannot compare them directly. See below for one proper way to compare.

For clarity lets use the DDS_GUID_t as the normalized representation, so DDS_GUID_t comparison can be done with the function DDS_GUID_equals().

These two utility functions DDS_InstanceHandle_to_GUID and DDS_BuiltinTopicKey_to_GUID shown below perform conversions from InstanceHandle_t and BuiltinTopicKey_t to GUID_t. Note that I have not tested them do I am not 100% sure I got them right, but you can see the idea here of what needs to be done.

 

void DDS_InstanceHandle_to_GUID( struct DDS_GUID_t *guid, DDS_InstanceHandle_t *instanceHandle )
{
    memcpy(guid->value, (DDS_Octet *)instanceHandle, 16);
}

void DDS_BuiltinTopicKey_to_GUID(struct DDS_GUID_t *guid, DDS_BuiltinTopicKey_t *buitinTopicKey )
{
#if RTI_ENDIAN_LITTLE
    /* Little Endian */
    int i;
    DDS_Octet *guidElement;
    DDS_Octet *topicKeyBuffer   = (DDS_Octet *)buitinTopicKey;
    DDS_Octet *keyBufferElement;
    for ( i=0; i< 4; ++i ) {
        DDS_Octet *guidElement       = &guid->value[i*4];
        DDS_Octet *keyBufferElement  = (DDS_Octet *)(&buitinTopicKey[i*4]);
        guidElement[0] = keyBufferElement[3];
        guidElement[1] = keyBufferElement[2];
        guidElement[2] = keyBufferElement[1];
        guidElement[3] = keyBufferElement[0];
    }
#else
    /* Big Endian */
    memcpy(guid->value, (DDS_Octet *)buitinTopicKey, 16);
#endif
}

Gerardo

 

Offline
Last seen: 9 years 6 months ago
Joined: 12/08/2011
Posts: 10

Hi Gerardo

Thank you for this tremendeoulsy helpful post, I appreciate the effort of providing sample code.

/** Taken from http://community.rti.com/comment/689#comment-689 */
DDS_GUID_t convertToGuid ( const DDS_InstanceHandle_t& instanceHandle )
{
  DDS_GUID_t guid;
  memcpy(guid.value,reinterpret_cast<DDS_Octet const *>(&instanceHandle ),16);
  return guid;
}

/** Taken from http://community.rti.com/comment/689#comment-689 */
DDS_GUID_t convertToGuid ( const DDS_BuiltinTopicKey_t& builtinTopicKey )
{
  DDS_GUID_t guid;
#if RTI_ENDIAN_LITTLE
  {
    /* Little Endian */
    DDS_Octet const * topicKeyBuffer   = reinterpret_cast<DDS_Octet const *>(&builtinTopicKey);
    for ( uint i=0; i< 4; ++i ) {
        DDS_Octet* guidElement       = &(guid.value[i*4]);
        DDS_Octet const * keyBufferElement  = topicKeyBuffer + i*4;
        guidElement[0] = keyBufferElement[3];
        guidElement[1] = keyBufferElement[2];
        guidElement[2] = keyBufferElement[1];
        guidElement[3] = keyBufferElement[0];
    }
  }
#else /* Big Endian */
  {
    memcpy(guid.value,reinterpret_cast<DDS_Octet const *>(&builtinTopicKey), 16);
  }
#endif
  return guid;
}

And here some related operators to make working with DDS_GUID_t a little easier:

inline bool operator==(DDS_GUID_t const & lhs, DDS_GUID_t const & rhs)
{ 
  /** http://community.rti.com/rti-doc/500/ndds.5.0.0/doc/html/api_cpp/group__DDSGUIDSupportModule.html# */
  return DDS_BOOLEAN_TRUE == DDS_GUID_equals(&lhs,&rhs);
};

inline bool operator!=(DDS_GUID_t const & lhs, DDS_GUID_t const & rhs){return !operator==(lhs,rhs);};

inline bool operator< (DDS_GUID_t const & lhs, DDS_GUID_t const & rhs)
{ 
  /** http://community.rti.com/rti-doc/500/ndds.5.0.0/doc/html/api_cpp/group__DDSGUIDSupportModule.html# */
  return DDS_GUID_compare(&lhs,&rhs) < 0;
};

inline bool operator> (DDS_GUID_t const & lhs, DDS_GUID_t const & rhs){return  operator< (rhs,lhs);};
inline bool operator<=(DDS_GUID_t const & lhs, DDS_GUID_t const & rhs){return !operator> (lhs,rhs);};
inline bool operator>=(DDS_GUID_t const & lhs, DDS_GUID_t const & rhs){return !operator< (lhs,rhs);};