5.6.10. NETIO Datagram Transport

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

The built-in Datagram transport (DGRAM) is a generic transport plugin service.

DGRAM is part of the RTI Connext Micro 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 API related to establishing connections, such as TCP.

5.6.10.1. Registering a Datagram Interface

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

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

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

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

When a component is registered, the registration takes the DGRAM interface as the 3rd parameter and the properties as the 4th parameter. In general, it is up to the caller 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 interfaces the Connext Micro core library’. The user is responsible for implementing the NETIO_DGRAM_InterfaceI` which integrates with a specific network technology. This struct must be compliant with the NETIO_DGRAM_InterfaceI structure.

 /* 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 */
}

It should be noted that 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.

5.6.10.2. Addressing a Datagram Transport

The interface may also set the enabled transports to receive data as follows:

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 setup 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");

5.6.10.3. Datagram UDP Setup

The built-in Datagram transport can support UDP integration.

The registering the built-in Datagram transport for UDP registers differently than the generic Datagram component. Use UDP_Interface_register() with UDP properties to create the datagram instance for UDP.

struct UDP_InterfaceFactoryProperty udp_property =
                                UDP_InterfaceFactoryProperty_INITIALIZER;

/* To enable sharing this property must be set to RTI_FALSE */
udp_property->enable_interface_bind = RTI_TRUE;

/*  */
REDA_StringSeq_set_maximum(&udp_property->allow_interface,1);
REDA_StringSeq_set_length(&udp_property->allow_interface,1);
*REDA_StringSeq_get_reference(&udp_property->allow_interface,0) =
                                                REDA_String_dup(intf);

/* To enable multicast operations the multicast flag and multicast_interface
 * property must be set */
if (is_multicast)
{
    flags |= UDP_INTERFACE_INTERFACE_MULTICAST_FLAG;
    udp_property->multicast_interface = DDS_String_dup(intf);
}
else
{
    /* Set the mutlicast interface to NULL when not used*/
    udp_property->multicast_interface = NULL;
}

/* Add an available interface for UDP */
if (!UDP_InterfaceTable_add_entry(&udp_property->if_table,
                    address, netmask, intf_name, flags))

{
    /* error */
}

/* Buffer properties */
udp_property->max_send_buffer_size = MAX_SEND_BUFFER_SIZE;
udp_property->max_receive_buffer_size = MAX_RECV_BUFFER_SIZE;
udp_property->max_message_size = MAX_RECV_BUFFER_SIZE;

/* Register the datagram */
if(!UDP_Interface_register(registry, "_udp", udp_property))
{
    /* error */
}

Enabled transports can be configured with “_udp://”. This will use all interfaces. Enabling a UDP is similar to generic addressing:

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 transport name */
*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://");

5.6.10.3.1. Datagram Shared flag

RTI Connext Micro uses Locators to specify transport addresses to send and receive data. A Locator consists of a kind, port, and a transport address. The kind indicates the type of transport, such as UDPv4, the port is used to reach a DDS DomainParticipant and the address is used to reach the destination transport. RTI Connext Micro can work with two different types of transports, one that uses shared ports and one that does not.

When a transport uses shared ports it means it does not matter which transport address a message was received on, only the port matters. For example, if a computer has two network interfaces A and B and is listening for messages on port P, it does not matter if the message is received on A or B. That is, as long as the message is received on any network interface capable of receiving on port P, the message is accepted.

When a transport does not use shared ports it means it does matter which transport address a message was received on. For example, if a computer has two network interfaces A and B and is listening for messages on port P, but has only specified that the A should receive on port P, then messages received on interface B and port P are ignored.

RTI Connext Micro support this flag on per RTI Connext Micro transport basis. It is important to note that when a message is accepted, it is routed to all relevant DDS datareaders and datawriters. Thus, this feature cannot be used to control that some DDS topics should only be accepted when received on a specific transport interface. However, this feature could be useful to allow different DDS DomainParticipants to use the same port, but with different network interfaces.

5.6.10.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 5.1 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.