As part of an effort to convert a legacy system to DDS I'm working on a Routing Service Adapter that commmunicates over a socket with the legacy system. For messages that only go one place we just pull them off the wire and pull out some key fields to filter on but the message is basicly a variable length binary blob.
The .idl looks like this.
struct LegacyEvents
{
int32 message_type;
sequence<char,LEGACY_BODY_MAX_LENGTH> body;
};
I'm basing this off the adapter example so using the dynamic data API. (I only started with DDS 6 months ago). The question is:
What is the best way to deal with the body field? It would be nice for it to be variable length for efficiency. You can access the elements of a sequence normally but is there some way to get a pointer to do a block copy (memcopy?). Would be nice to be able to recieve into the field also, but not sure if that is possible.
Can't imagine this is the first time this has come up. Thank you.
Hi jnugent,
The `body` member is already of variable size, since it's defined as a sequence, which is a dynamically-sized container: samples shared over DDS will only contain elements up to the sequence field's actual length, not its maximum (as would have instead been the case, had the member been declared as an array). My only suggestion is to consider changing the element type from `char` to `octet` in order to guarantee that the included bytes will never be interpreted as anything but a raw chunk of bytes by any of the various DDS language mappings (unless the contents are actually to be considered (utf-8) characters).
You can access the "contiguous buffer" associated with a sequence using FooSeq_get_contiguous_buffer (in C, but the same operation is also exposed in other language mappings). You should be able to receive from the socket directly into the sequence buffer with the following pattern:
Finally, you might be interested in taking a look the RTI Connext Gateway repository, which contains a collection of more advanced plugins for Routing Service, including some custom Adapters, that may prove useful as a reference to go beyond "trivial" examples.
Thanks for the info. I'll give it a try.
I didn't know about the gateway repository. That looks usefull. Thank you.
I have thought of one possible caveat that I neglected to mention in my previous post: while it is true that you should be able to receive from the UDP socket into the buffer of a sequence (e.g. `DDS_OctetSeq`, which is the type of `LegacyEvents::data` in C if element is changed to `octet`) you will still need to perform one copy when setting this value into the DynamicData sample that will be propagated through RoutingService.
This is because DDS_DynamicData_set_octet_seq() (and other setters for sequence members) implicitly perform a copy of the sequence passed as input. The same is true for the corresponding getters, which also copy the sequence buffer into a user supplied sequence. There is no way currently to access a raw pointer to the buffer backing the sequence member of a DynamicData sample.
Because of this copy, you might want to consider using a sequence to simply wrap the receive buffer allocated by your application, instead of using the sequence API to do memory management of this buffer as suggested in my previous post (via the `set_maximum()` and `set_length()` operations), which would be mostly useful if you were to draw memory from the actual sample (which is possible for statically typed data, but as I said, it's not possible with DynamicData samples).
Instead, you could keep using your own buffer, "loan it" to a sequence via the FooSeq_loan_contiguous() operation, and then pass the value to `DynamicData_seq_XXX_seq()` to actually store it in a sample.
Hope this helps! Let me know if you have any questions.
Hi James,
I will post our off-line email yesterday:
struct LegacyEvents
{
int32 message_type;
Body body;
};
Below is code I used for a project that copied a deviceID into an octet array - I modified it (semi-pseudocode) to give you a flavor of what I did relative to your structure.