7.7.7. NETIO Datagram Transport

This section describes the built-in Connext Cert Datagram transport and how to configure it.

The built-in Datagram transport (DGRAM) is a generic transport plugin service. DGRAM is part of the Connext Cert core library that is compiled for a specific CPU architecture with a specific compiler. However, the DGRAM transport does not include integration with any particular network stack. Instead, the DGRAM transport provides a simplified interface which can integrate with a variety of different networking technologies.

The DGRAM plugin supports transmission and reception of RTPS messages over a connectionless network link. Note that while the DGRAM transport itself has no knowledge of the underlying network stack, the DGRAM API does not include an API related to establishing connections, such as TCP.

7.7.7.1. Registering a Datagram interface

DGRAM is a Connext Cert component that can be registered with NETIO_DGRAM_InterfaceFactory_register() as shown below:

DDS_DomainParticipantFactory *factory = NULL;
RT_Registry_T *registry = NULL;

factory = DDS_DomainParticipantFactory_get_instance();
registry = DDS_DomainParticipantFactory_get_registry(factory);

The factory gets the registry. The registry then registers the Datagram.

When a component is registered, the registration parses the DGRAM interface as the third parameter and the properties as the fourth parameter. In general, the caller is responsible to manage the memory for the properties and ensure they are valid as long as the DGRAM transport is registered. There is no guarantee that a component makes a copy.

The DGRAM interface is a component that interfaces with the Connext Cert core library. You must implement the NETIO_DGRAM_InterfaceI, which integrates with a specific network technology. This struct must be compliant with the NETIO_DGRAM_InterfaceI structure, as shown below:

 /* Create the DGRAM User Interface property struct */
 struct MyDgramInterfaceProperty
 {
     RTI_INT32 a_property;
     struct UTEST_Context *setting;
 } MyDgramInterfaceProperty = {10,NULL};

/* Example operation */
 struct NETIO_Interface*
 MyDgramInterface_create_instance(NETIO_Interface_T *upstream,void *property)
 {
     /* Perform operations */
 ...
    return myInterface;
 }
 ...

 /* Create the DGRAM Interface struct where each member points to it's
  * respective operation */
 RTI_PRIVATE struct NETIO_DGRAM_InterfaceI MyDgramInterface =
 {
     MyDgramInterface_create_instance,
     MyDgramInterface_get_interface_list,
     MyDgramInterface_release_address,
     MyDgramInterface_resolve_address_udpv4,
     MyDgramInterface_send,
     MyDgramInterface_get_route_table,
     MyDgramInterface_bind_address
 };

The following code snippet shows how to register the DGRAM interface with new parameters. The Datagram needs to register the DGRAM interface with a property that has the interface to call:

/* Register the transport again, using the builtin name
    */
if (!NETIO_DGRAM_InterfaceFactory_register(registry,
                "name",
                &MyDgramInterface,
                &MyDgramInterfaceProperty))
{
    /* ERROR */
}

Note

The Datagram transport can be registered with any name, but all transport QoS policies and initial peers must refer to this name. If a transport is referred to and it does not exist, an error message will be logged.

7.7.7.2. Addressing a Datagram transport

The interface may also set the enabled transports to receive data, as shown below:

struct DDS_DomainParticipantQos dp_qos =
                                    DDS_DomainParticipantQos_INITIALIZER;

/* Datagram enable transport xyz. A second transport can be added
 * by setting the enabled_transports value to 2 and adding a second
 * transport name. enabled_transport indicates what addresses the entity is
 * listening on.
 */
DDS_StringSeq_set_maximum(&dp_qos.transports.enabled_transports,1);
DDS_StringSeq_set_length(&dp_qos.transports.enabled_transports,1);
*DDS_StringSeq_get_reference(&dp_qos.transports.enabled_transports,0) =
                                            DDS_String_dup("xyz");

/* Receive discovery traffic on xyz */
DDS_StringSeq_set_maximum(&dp_qos.discovery.enabled_transports,1);
DDS_StringSeq_set_length(&dp_qos.discovery.enabled_transports,1);
*DDS_StringSeq_get_reference(&dp_qos.discovery.enabled_transports,0) =
                                            DDS_String_dup("xyz://");

/* Receive user-data traffic on xyz. */
DDS_StringSeq_set_maximum(&dp_qos.user_traffic.enabled_transports,1);
DDS_StringSeq_set_length(&dp_qos.user_traffic.enabled_transports,1);
*DDS_StringSeq_get_reference(&dp_qos.user_traffic.enabled_transports,0) =
                                            DDS_String_dup("xyz://");

An address may set up peers to send messages over this interface. For example, interface xyz may set its initial peers as:

 /* Send discovery data on address 0x0A00020F*/
DDS_StringSeq_set_maximum(&dp_qos.discovery.initial_peers,1);
DDS_StringSeq_set_length(&dp_qos.discovery.initial_peers,1);
*DDS_StringSeq_get_reference(&dp_qos.discovery.initial_peers,0) =
DDS_String_dup("0x0A00020F");

7.7.7.3. Setting up the Datagram UDP

The built-in Datagram transport can support integration with a UDP transport. This usually happens via invocation of a UDP transport convenience function like UDPv4_Interface_register() with UDP properties to create the datagram instance for UDP, as described in the following table:

Table 7.1 UDP Transport Functions and Properties

Name

Description

UDPv4_Interface_register

Function that registers the UDP interface.

UDPv4_TransportProperty_set_max_message_size

Property that sets the maximum message size for the UDP transport.

UDPv4_TransportProperty_set_max_receive_buffer_size

Property that sets the maximum size of the UDP transport buffer for receiving messages.

UDPv4_TransportProperty_set_max_send_buffer_size

Property that sets the maximum size of the UDP transport buffer for sending messages.

Warning

The UDPv4_Interface_register function and UDP properties are included in the reference Platform Support Library (PSL) provided by RTI, not the Connext Cert Platform Independent Library (PIL). This means they are not part of the certifiable code in Connext Cert. A different UDP transport implementation (as provided by your own PSL) may require different functions and properties.

Refer to the following code snippet for an example:

UDPv4_TransportProperty_T *udp_property = UDPv4_TransportProperty_new();

/* Add a network interface to the UDPv4 transport.
 * This function takes the following arguments:
 * Param 1 is the UDP property
 * Param 2 is the IP address of the interface in host order
 * Param 3 is the Netmask of the interface
 * Param 4 is the name of the interface
 * Param 5 are flags. The following flags are supported (use OR for multiple):
 *      UDP_INTERFACE_INTERFACE_UP_FLAG - Interface is up
 *      UDP_INTERFACE_INTERFACE_MULTICAST_FLAG - Interface supports multicast
 */
if (!UDPv4_InterfaceTable_add_entry(
            udp_property,
            0x7f000001,
            0xff000000,
            "lo",
            UDP_INTERFACE_INTERFACE_UP_FLAG |
            UDP_INTERFACE_INTERFACE_MULTICAST_FLAG))
{
    /* error */
}

/* Set the UDPv4 transport's buffer properties. Error checking is omitted for
 * the sake of brevity. */
UDPv4_TransportProperty_set_max_send_buffer_size(udp_property, MAX_SEND_BUFFER_SIZE);
UDPv4_TransportProperty_set_max_receive_buffer_size(udp_property, MAX_RECV_BUFFER_SIZE);
UDPv4_TransportProperty_set_max_message_size(udp_property, MAX_MESSAGE_SIZE);

/* Call the UDPv4 transport's convenience function to register it via the
 * Datagram transport. */
if (!UDPv4_Interface_register(registry, "_udp", udp_property))
{
    /* error */
}

Enabled transports can be configured with "_udp://". This will use all interfaces. Enabling UDP is similar to generic addressing, as shown below:

struct DDS_DomainParticipantQos dp_qos =
                                    DDS_DomainParticipantQos_INITIALIZER;

DDS_StringSeq_set_maximum(&dp_qos.transports.enabled_transports,1);
DDS_StringSeq_set_length(&dp_qos.transports.enabled_transports,1);
DDS_StringSeq_set_maximum(&dp_qos.discovery.enabled_transports,1);
DDS_StringSeq_set_length(&dp_qos.discovery.enabled_transports,1);
DDS_StringSeq_set_maximum(&dp_qos.user_traffic.enabled_transports,1);
DDS_StringSeq_set_length(&dp_qos.user_traffic.enabled_transports,1);

/* This only requires the name that the transport was registered with */
*DDS_StringSeq_get_reference(&dp_qos.transports.enabled_transports,0) =
                                            DDS_String_dup("_udp");

/* _udp:// indicates to use all available locators */
*DDS_StringSeq_get_reference(&dp_qos.discovery.enabled_transports,0) =
                                        DDS_String_dup("_udp://");

/* _udp://10.10.0.1 would indicate to use only that address */
*DDS_StringSeq_get_reference(&dp_qos.user_traffic.enabled_transports,0) =
                                            DDS_String_dup("_udp://");

7.7.7.3.1. Datagram shared port flag

Connext Cert can work with two different types of transports: ones that use shared ports and ones that do not. Connext Cert supports a flag for the Datagram transport, NETIO_DGRAM_INTERFACE_SHARED_PORT_FLAG, to enable the use of shared ports on a per-transport basis.

When the shared port flag is enabled, it doesn’t matter which network interface the transport receives messages on; only the port matters. For example, consider a computer with two network interfaces, A and B, which is listening for messages on port P. As long as the message is received on any network interface capable of receiving on port P, the transport will accept the message; it doesn’t matter if the message is received on A or B.

However, when the shared port flag is not enabled, it does matter which network interface the transport receives messages on. For example, consider a computer with two network interfaces, A and B, which is listening for messages on port P like before. However, this computer has specified that network interface A should only receive on port P. The transport will then ignore messages received on network interface B and port P.

When the transport accepts a message, the transport routes it to all relevant DataReaders and DataWriters; thus, the NETIO_DGRAM_INTERFACE_SHARED_PORT_FLAG cannot be used to control whether some DDS topics should only be accepted when received on a specific network interface. However, this feature allows different DomainParticipants to use the same port with different network interfaces.

7.7.7.4. User interface

NETIO_DGRAM_InterfaceFactory_register() registers a user interface structure that is passed in via user_intf. The DomainParticipant utilizes these functions for network operations, such as creating a Datagram interface instance and getting the interface list.

Table 7.2 Structure for the User Interface

Interface Attribute

Description

create_instance

Creates an instance of the NETIO_DGRAM interface.

delete_instance

Deletes an instance of the NETIO_DGRAM interface.

get_interface_list

Reads the available interfaces from the NETIO_DGRAM interface.

release_address

Instructs the NETIO_DGRAM interface to stop listening for messages on the source address.

resolve_address

Instructs the NETIO_DGRAM interface to determine if the address string is valid.

send

Instructs the NETIO_DGRAM interface to send a message.

get_route_table

Instructs the NETIO_DGRAM interface netio_intf to return a sequence of address and netmask pairs that this interface can send to.

bind_address

Instructs the NETIO_DGRAM interface to listen for messages on the source address.