2019-04-29 09:33:13 +02:00
|
|
|
// Copyright 2019 ADLINK Technology
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2019-12-06 10:21:18 -06:00
|
|
|
#include "serdata.hpp"
|
|
|
|
|
|
|
|
#include <rmw/allocators.h>
|
2019-08-17 15:18:57 +02:00
|
|
|
|
2019-12-05 14:42:11 -06:00
|
|
|
#include <cstring>
|
|
|
|
#include <memory>
|
2019-05-21 16:05:52 +02:00
|
|
|
#include <regex>
|
|
|
|
#include <sstream>
|
2019-08-17 15:18:57 +02:00
|
|
|
#include <string>
|
2019-12-05 14:42:11 -06:00
|
|
|
#include <utility>
|
2019-04-29 09:33:13 +02:00
|
|
|
|
2019-12-05 14:42:11 -06:00
|
|
|
#include "Serialization.hpp"
|
2019-12-06 10:21:18 -06:00
|
|
|
#include "TypeSupport2.hpp"
|
|
|
|
#include "bytewise.hpp"
|
2019-12-05 14:42:11 -06:00
|
|
|
#include "dds/ddsi/q_radmin.h"
|
2019-04-29 09:33:13 +02:00
|
|
|
#include "rmw/error_handling.h"
|
|
|
|
#include "rmw_cyclonedds_cpp/MessageTypeSupport.hpp"
|
|
|
|
#include "rmw_cyclonedds_cpp/ServiceTypeSupport.hpp"
|
|
|
|
#include "rmw_cyclonedds_cpp/serdes.hpp"
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
using MessageTypeSupport_c =
|
|
|
|
rmw_cyclonedds_cpp::MessageTypeSupport<rosidl_typesupport_introspection_c__MessageMembers>;
|
|
|
|
using MessageTypeSupport_cpp =
|
|
|
|
rmw_cyclonedds_cpp::MessageTypeSupport<rosidl_typesupport_introspection_cpp::MessageMembers>;
|
|
|
|
using RequestTypeSupport_c = rmw_cyclonedds_cpp::RequestTypeSupport<
|
|
|
|
rosidl_typesupport_introspection_c__ServiceMembers,
|
|
|
|
rosidl_typesupport_introspection_c__MessageMembers>;
|
|
|
|
using RequestTypeSupport_cpp = rmw_cyclonedds_cpp::RequestTypeSupport<
|
|
|
|
rosidl_typesupport_introspection_cpp::ServiceMembers,
|
|
|
|
rosidl_typesupport_introspection_cpp::MessageMembers>;
|
|
|
|
using ResponseTypeSupport_c = rmw_cyclonedds_cpp::ResponseTypeSupport<
|
|
|
|
rosidl_typesupport_introspection_c__ServiceMembers,
|
|
|
|
rosidl_typesupport_introspection_c__MessageMembers>;
|
|
|
|
using ResponseTypeSupport_cpp = rmw_cyclonedds_cpp::ResponseTypeSupport<
|
|
|
|
rosidl_typesupport_introspection_cpp::ServiceMembers,
|
|
|
|
rosidl_typesupport_introspection_cpp::MessageMembers>;
|
|
|
|
|
|
|
|
static bool using_introspection_c_typesupport(const char * typesupport_identifier)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
return typesupport_identifier == rosidl_typesupport_introspection_c__identifier;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static bool using_introspection_cpp_typesupport(const char * typesupport_identifier)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
return typesupport_identifier == rosidl_typesupport_introspection_cpp::typesupport_identifier;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
void * create_message_type_support(
|
|
|
|
const void * untyped_members,
|
|
|
|
const char * typesupport_identifier)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
if (using_introspection_c_typesupport(typesupport_identifier)) {
|
|
|
|
auto members =
|
|
|
|
static_cast<const rosidl_typesupport_introspection_c__MessageMembers *>(untyped_members);
|
|
|
|
return new MessageTypeSupport_c(members);
|
|
|
|
} else if (using_introspection_cpp_typesupport(typesupport_identifier)) {
|
|
|
|
auto members =
|
|
|
|
static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(untyped_members);
|
|
|
|
return new MessageTypeSupport_cpp(members);
|
|
|
|
}
|
|
|
|
RMW_SET_ERROR_MSG("Unknown typesupport identifier");
|
|
|
|
return nullptr;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
void * create_request_type_support(
|
|
|
|
const void * untyped_members,
|
|
|
|
const char * typesupport_identifier)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
if (using_introspection_c_typesupport(typesupport_identifier)) {
|
|
|
|
auto members =
|
|
|
|
static_cast<const rosidl_typesupport_introspection_c__ServiceMembers *>(untyped_members);
|
|
|
|
return new RequestTypeSupport_c(members);
|
|
|
|
} else if (using_introspection_cpp_typesupport(typesupport_identifier)) {
|
|
|
|
auto members =
|
|
|
|
static_cast<const rosidl_typesupport_introspection_cpp::ServiceMembers *>(untyped_members);
|
|
|
|
return new RequestTypeSupport_cpp(members);
|
|
|
|
}
|
|
|
|
RMW_SET_ERROR_MSG("Unknown typesupport identifier");
|
|
|
|
return nullptr;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
void * create_response_type_support(
|
|
|
|
const void * untyped_members,
|
|
|
|
const char * typesupport_identifier)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
if (using_introspection_c_typesupport(typesupport_identifier)) {
|
|
|
|
auto members =
|
|
|
|
static_cast<const rosidl_typesupport_introspection_c__ServiceMembers *>(untyped_members);
|
|
|
|
return new ResponseTypeSupport_c(members);
|
|
|
|
} else if (using_introspection_cpp_typesupport(typesupport_identifier)) {
|
|
|
|
auto members =
|
|
|
|
static_cast<const rosidl_typesupport_introspection_cpp::ServiceMembers *>(untyped_members);
|
|
|
|
return new ResponseTypeSupport_cpp(members);
|
|
|
|
}
|
|
|
|
RMW_SET_ERROR_MSG("Unknown typesupport identifier");
|
|
|
|
return nullptr;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static uint32_t serdata_rmw_size(const struct ddsi_serdata * dcmn)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-12-08 16:03:30 -06:00
|
|
|
size_t size = static_cast<const serdata_rmw *>(dcmn)->size();
|
|
|
|
uint32_t size_u32(size);
|
|
|
|
assert(size == size_u32);
|
|
|
|
return size_u32;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static void serdata_rmw_free(struct ddsi_serdata * dcmn)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-12-06 10:21:18 -06:00
|
|
|
auto * d = static_cast<const serdata_rmw *>(dcmn);
|
2019-08-17 15:18:57 +02:00
|
|
|
delete d;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static struct ddsi_serdata * serdata_rmw_from_ser(
|
|
|
|
const struct ddsi_sertopic * topic,
|
|
|
|
enum ddsi_serdata_kind kind,
|
|
|
|
const struct nn_rdata * fragchain, size_t size)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-12-06 10:21:18 -06:00
|
|
|
auto d = std::make_unique<serdata_rmw>(topic, kind);
|
2019-08-17 15:18:57 +02:00
|
|
|
uint32_t off = 0;
|
|
|
|
assert(fragchain->min == 0);
|
|
|
|
assert(fragchain->maxp1 >= off); /* CDR header must be in first fragment */
|
2019-12-06 10:21:18 -06:00
|
|
|
d->resize(size);
|
|
|
|
|
|
|
|
auto cursor = d->data();
|
2019-08-17 15:18:57 +02:00
|
|
|
while (fragchain) {
|
|
|
|
if (fragchain->maxp1 > off) {
|
|
|
|
/* only copy if this fragment adds data */
|
|
|
|
const unsigned char * payload =
|
|
|
|
NN_RMSG_PAYLOADOFF(fragchain->rmsg, NN_RDATA_PAYLOAD_OFF(fragchain));
|
2019-12-06 10:21:18 -06:00
|
|
|
auto src = payload + off - fragchain->min;
|
|
|
|
auto n_bytes = fragchain->maxp1 - off;
|
|
|
|
memcpy(cursor, src, n_bytes);
|
|
|
|
cursor = byte_offset(cursor, n_bytes);
|
2019-08-17 15:18:57 +02:00
|
|
|
off = fragchain->maxp1;
|
2019-12-08 16:03:30 -06:00
|
|
|
assert(off <= size);
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
2019-08-17 15:18:57 +02:00
|
|
|
fragchain = fragchain->nextfrag;
|
|
|
|
}
|
2019-12-06 10:21:18 -06:00
|
|
|
return d.release();
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static struct ddsi_serdata * serdata_rmw_from_keyhash(
|
|
|
|
const struct ddsi_sertopic * topic,
|
|
|
|
const struct nn_keyhash * keyhash)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
static_cast<void>(keyhash); // unused
|
|
|
|
/* there is no key field, so from_keyhash is trivial */
|
2019-12-06 10:21:18 -06:00
|
|
|
return new serdata_rmw(topic, SDK_KEY);
|
2019-12-05 14:42:11 -06:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static struct ddsi_serdata * serdata_rmw_from_sample(
|
|
|
|
const struct ddsi_sertopic * topiccmn,
|
|
|
|
enum ddsi_serdata_kind kind,
|
|
|
|
const void * sample)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-09-19 11:56:26 +02:00
|
|
|
try {
|
|
|
|
const struct sertopic_rmw * topic = static_cast<const struct sertopic_rmw *>(topiccmn);
|
2019-12-06 10:21:18 -06:00
|
|
|
auto d = std::make_unique<serdata_rmw>(topic, kind);
|
2019-09-19 11:56:26 +02:00
|
|
|
if (kind != SDK_DATA) {
|
|
|
|
/* ROS2 doesn't do keys, so SDK_KEY is trivial */
|
|
|
|
} else if (!topic->is_request_header) {
|
2019-12-05 14:42:11 -06:00
|
|
|
size_t sz = rmw_cyclonedds_cpp::get_serialized_size(sample, topic->value_type.get());
|
2019-12-06 10:21:18 -06:00
|
|
|
d->resize(sz);
|
|
|
|
rmw_cyclonedds_cpp::serialize(d->data(), sample, topic->value_type.get());
|
2019-09-19 11:56:26 +02:00
|
|
|
} else {
|
2019-12-05 14:42:11 -06:00
|
|
|
/* inject the service invocation header data into the CDR stream --
|
|
|
|
* I haven't checked how it is done in the official RMW implementations, so it is
|
|
|
|
* probably incompatible. */
|
|
|
|
auto wrap = *static_cast<const cdds_request_wrapper_t *>(sample);
|
|
|
|
|
|
|
|
size_t sz = rmw_cyclonedds_cpp::get_serialized_size(wrap, topic->value_type.get());
|
2019-12-06 10:21:18 -06:00
|
|
|
d->resize(sz);
|
|
|
|
rmw_cyclonedds_cpp::serialize(d->data(), wrap, topic->value_type.get());
|
2019-05-03 17:12:51 +08:00
|
|
|
}
|
2019-12-06 10:21:18 -06:00
|
|
|
return d.release();
|
2019-12-05 14:42:11 -06:00
|
|
|
} catch (std::exception & e) {
|
2019-09-19 11:56:26 +02:00
|
|
|
RMW_SET_ERROR_MSG(e.what());
|
|
|
|
return nullptr;
|
2019-08-17 15:18:57 +02:00
|
|
|
}
|
2019-05-05 12:36:58 +08:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
struct ddsi_serdata * serdata_rmw_from_serialized_message(
|
|
|
|
const struct ddsi_sertopic * topiccmn,
|
|
|
|
const void * raw, size_t size)
|
2019-05-05 12:36:58 +08:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
const struct sertopic_rmw * topic = static_cast<const struct sertopic_rmw *>(topiccmn);
|
2019-12-06 10:21:18 -06:00
|
|
|
auto d = new serdata_rmw(topic, SDK_DATA);
|
|
|
|
d->resize(size);
|
|
|
|
memcpy(d->data(), raw, size);
|
2019-08-17 15:18:57 +02:00
|
|
|
return d;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static struct ddsi_serdata * serdata_rmw_to_topicless(const struct ddsi_serdata * dcmn)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-12-06 10:21:18 -06:00
|
|
|
auto d = static_cast<const serdata_rmw *>(dcmn);
|
|
|
|
auto d1 = new serdata_rmw(d->topic, SDK_KEY);
|
2019-08-17 15:18:57 +02:00
|
|
|
d1->topic = nullptr;
|
|
|
|
return d1;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static void serdata_rmw_to_ser(const struct ddsi_serdata * dcmn, size_t off, size_t sz, void * buf)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-12-06 10:21:18 -06:00
|
|
|
auto d = static_cast<const serdata_rmw *>(dcmn);
|
|
|
|
memcpy(buf, byte_offset(d->data(), off), sz);
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static struct ddsi_serdata * serdata_rmw_to_ser_ref(
|
|
|
|
const struct ddsi_serdata * dcmn, size_t off,
|
|
|
|
size_t sz, ddsrt_iovec_t * ref)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-12-06 10:21:18 -06:00
|
|
|
auto d = static_cast<const serdata_rmw *>(dcmn);
|
|
|
|
ref->iov_base = byte_offset(d->data(), off);
|
2019-08-17 15:18:57 +02:00
|
|
|
ref->iov_len = (ddsrt_iov_len_t) sz;
|
|
|
|
return ddsi_serdata_ref(d);
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static void serdata_rmw_to_ser_unref(struct ddsi_serdata * dcmn, const ddsrt_iovec_t * ref)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
static_cast<void>(ref); // unused
|
2019-12-06 10:21:18 -06:00
|
|
|
ddsi_serdata_unref(static_cast<serdata_rmw *>(dcmn));
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static bool serdata_rmw_to_sample(
|
|
|
|
const struct ddsi_serdata * dcmn, void * sample, void ** bufptr,
|
|
|
|
void * buflim)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-09-19 11:56:26 +02:00
|
|
|
try {
|
|
|
|
static_cast<void>(bufptr); // unused
|
|
|
|
static_cast<void>(buflim); // unused
|
2019-12-06 10:21:18 -06:00
|
|
|
auto d = static_cast<const serdata_rmw *>(dcmn);
|
2019-09-19 11:56:26 +02:00
|
|
|
const struct sertopic_rmw * topic = static_cast<const struct sertopic_rmw *>(d->topic);
|
|
|
|
assert(bufptr == NULL);
|
|
|
|
assert(buflim == NULL);
|
|
|
|
if (d->kind != SDK_DATA) {
|
|
|
|
/* ROS2 doesn't do keys in a meaningful way yet */
|
|
|
|
} else if (!topic->is_request_header) {
|
2019-12-06 10:21:18 -06:00
|
|
|
cycdeser sd(d->data(), d->size());
|
2019-09-19 11:56:26 +02:00
|
|
|
if (using_introspection_c_typesupport(topic->type_support.typesupport_identifier_)) {
|
|
|
|
auto typed_typesupport =
|
|
|
|
static_cast<MessageTypeSupport_c *>(topic->type_support.type_support_);
|
|
|
|
return typed_typesupport->deserializeROSmessage(sd, sample);
|
|
|
|
} else if (using_introspection_cpp_typesupport(topic->type_support.typesupport_identifier_)) {
|
|
|
|
auto typed_typesupport =
|
|
|
|
static_cast<MessageTypeSupport_cpp *>(topic->type_support.type_support_);
|
|
|
|
return typed_typesupport->deserializeROSmessage(sd, sample);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* The "prefix" lambda is there to inject the service invocation header data into the CDR
|
|
|
|
stream -- I haven't checked how it is done in the official RMW implementations, so it is
|
|
|
|
probably incompatible. */
|
|
|
|
cdds_request_wrapper_t * const wrap = static_cast<cdds_request_wrapper_t *>(sample);
|
|
|
|
auto prefix = [wrap](cycdeser & ser) {ser >> wrap->header.guid; ser >> wrap->header.seq;};
|
2019-12-06 10:21:18 -06:00
|
|
|
cycdeser sd(d->data(), d->size());
|
2019-09-19 11:56:26 +02:00
|
|
|
if (using_introspection_c_typesupport(topic->type_support.typesupport_identifier_)) {
|
|
|
|
auto typed_typesupport =
|
|
|
|
static_cast<MessageTypeSupport_c *>(topic->type_support.type_support_);
|
|
|
|
return typed_typesupport->deserializeROSmessage(sd, wrap->data, prefix);
|
|
|
|
} else if (using_introspection_cpp_typesupport(topic->type_support.typesupport_identifier_)) {
|
|
|
|
auto typed_typesupport =
|
|
|
|
static_cast<MessageTypeSupport_cpp *>(topic->type_support.type_support_);
|
|
|
|
return typed_typesupport->deserializeROSmessage(sd, wrap->data, prefix);
|
|
|
|
}
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
2019-09-19 11:56:26 +02:00
|
|
|
} catch (rmw_cyclonedds_cpp::Exception & e) {
|
|
|
|
RMW_SET_ERROR_MSG(e.what());
|
|
|
|
return false;
|
|
|
|
} catch (std::runtime_error & e) {
|
|
|
|
RMW_SET_ERROR_MSG(e.what());
|
|
|
|
return false;
|
2019-08-17 15:18:57 +02:00
|
|
|
}
|
2019-09-19 11:56:26 +02:00
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
return false;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static bool serdata_rmw_topicless_to_sample(
|
|
|
|
const struct ddsi_sertopic * topic,
|
|
|
|
const struct ddsi_serdata * dcmn, void * sample,
|
|
|
|
void ** bufptr, void * buflim)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
static_cast<void>(topic);
|
|
|
|
static_cast<void>(dcmn);
|
|
|
|
static_cast<void>(sample);
|
|
|
|
static_cast<void>(bufptr);
|
|
|
|
static_cast<void>(buflim);
|
|
|
|
/* ROS2 doesn't do keys in a meaningful way yet */
|
|
|
|
return true;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static bool serdata_rmw_eqkey(const struct ddsi_serdata * a, const struct ddsi_serdata * b)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
static_cast<void>(a);
|
|
|
|
static_cast<void>(b);
|
|
|
|
/* ROS2 doesn't do keys in a meaningful way yet */
|
|
|
|
return true;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-09-01 15:32:04 +02:00
|
|
|
#if DDSI_SERDATA_HAS_PRINT
|
|
|
|
static size_t serdata_rmw_print(
|
|
|
|
const struct ddsi_sertopic * tpcmn, const struct ddsi_serdata * dcmn, char * buf, size_t bufsize)
|
|
|
|
{
|
2019-09-19 11:56:26 +02:00
|
|
|
try {
|
2019-12-06 10:21:18 -06:00
|
|
|
auto d = static_cast<const serdata_rmw *>(dcmn);
|
2019-09-19 11:56:26 +02:00
|
|
|
const struct sertopic_rmw * topic = static_cast<const struct sertopic_rmw *>(tpcmn);
|
|
|
|
if (d->kind != SDK_DATA) {
|
|
|
|
/* ROS2 doesn't do keys in a meaningful way yet */
|
|
|
|
return static_cast<size_t>(snprintf(buf, bufsize, ":k:{}"));
|
|
|
|
} else if (!topic->is_request_header) {
|
2019-12-06 10:21:18 -06:00
|
|
|
cycprint sd(buf, bufsize, d->data(), d->size());
|
2019-09-19 11:56:26 +02:00
|
|
|
if (using_introspection_c_typesupport(topic->type_support.typesupport_identifier_)) {
|
|
|
|
auto typed_typesupport =
|
|
|
|
static_cast<MessageTypeSupport_c *>(topic->type_support.type_support_);
|
|
|
|
return typed_typesupport->printROSmessage(sd);
|
|
|
|
} else if (using_introspection_cpp_typesupport(topic->type_support.typesupport_identifier_)) {
|
|
|
|
auto typed_typesupport =
|
|
|
|
static_cast<MessageTypeSupport_cpp *>(topic->type_support.type_support_);
|
|
|
|
return typed_typesupport->printROSmessage(sd);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* The "prefix" lambda is there to inject the service invocation header data into the CDR
|
|
|
|
stream -- I haven't checked how it is done in the official RMW implementations, so it is
|
|
|
|
probably incompatible. */
|
|
|
|
cdds_request_wrapper_t wrap;
|
|
|
|
auto prefix = [&wrap](cycprint & ser) {
|
|
|
|
ser >> wrap.header.guid; ser.print_constant(","); ser >> wrap.header.seq;
|
|
|
|
};
|
2019-12-06 10:21:18 -06:00
|
|
|
cycprint sd(buf, bufsize, d->data(), d->size());
|
2019-09-19 11:56:26 +02:00
|
|
|
if (using_introspection_c_typesupport(topic->type_support.typesupport_identifier_)) {
|
|
|
|
auto typed_typesupport =
|
|
|
|
static_cast<MessageTypeSupport_c *>(topic->type_support.type_support_);
|
|
|
|
return typed_typesupport->printROSmessage(sd, prefix);
|
|
|
|
} else if (using_introspection_cpp_typesupport(topic->type_support.typesupport_identifier_)) {
|
|
|
|
auto typed_typesupport =
|
|
|
|
static_cast<MessageTypeSupport_cpp *>(topic->type_support.type_support_);
|
|
|
|
return typed_typesupport->printROSmessage(sd, prefix);
|
|
|
|
}
|
2019-09-01 15:32:04 +02:00
|
|
|
}
|
2019-09-19 11:56:26 +02:00
|
|
|
} catch (rmw_cyclonedds_cpp::Exception & e) {
|
|
|
|
RMW_SET_ERROR_MSG(e.what());
|
|
|
|
return false;
|
|
|
|
} catch (std::runtime_error & e) {
|
|
|
|
RMW_SET_ERROR_MSG(e.what());
|
|
|
|
return false;
|
2019-09-01 15:32:04 +02:00
|
|
|
}
|
2019-09-19 11:56:26 +02:00
|
|
|
|
2019-09-01 15:32:04 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-04-29 09:33:13 +02:00
|
|
|
static const struct ddsi_serdata_ops serdata_rmw_ops = {
|
2019-08-17 15:18:57 +02:00
|
|
|
serdata_rmw_eqkey,
|
|
|
|
serdata_rmw_size,
|
|
|
|
serdata_rmw_from_ser,
|
|
|
|
serdata_rmw_from_keyhash,
|
|
|
|
serdata_rmw_from_sample,
|
|
|
|
serdata_rmw_to_ser,
|
|
|
|
serdata_rmw_to_ser_ref,
|
|
|
|
serdata_rmw_to_ser_unref,
|
|
|
|
serdata_rmw_to_sample,
|
|
|
|
serdata_rmw_to_topicless,
|
|
|
|
serdata_rmw_topicless_to_sample,
|
|
|
|
serdata_rmw_free
|
2019-09-01 15:32:04 +02:00
|
|
|
#if DDSI_SERDATA_HAS_PRINT
|
|
|
|
, serdata_rmw_print
|
|
|
|
#endif
|
2019-04-29 09:33:13 +02:00
|
|
|
};
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static void sertopic_rmw_free(struct ddsi_sertopic * tpcmn)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
struct sertopic_rmw * tp = static_cast<struct sertopic_rmw *>(tpcmn);
|
2019-08-21 15:14:44 +02:00
|
|
|
#if DDSI_SERTOPIC_HAS_TOPICKIND_NO_KEY
|
|
|
|
ddsi_sertopic_fini(tpcmn);
|
|
|
|
#endif
|
2019-08-17 15:18:57 +02:00
|
|
|
delete tp;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static void sertopic_rmw_zero_samples(const struct ddsi_sertopic * d, void * samples, size_t count)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
static_cast<void>(d);
|
|
|
|
static_cast<void>(samples);
|
|
|
|
static_cast<void>(count);
|
|
|
|
/* Not using code paths that rely on the samples getting zero'd out */
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static void sertopic_rmw_realloc_samples(
|
|
|
|
void ** ptrs, const struct ddsi_sertopic * d, void * old,
|
|
|
|
size_t oldcount, size_t count)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
static_cast<void>(ptrs);
|
|
|
|
static_cast<void>(d);
|
|
|
|
static_cast<void>(old);
|
|
|
|
static_cast<void>(oldcount);
|
|
|
|
static_cast<void>(count);
|
|
|
|
/* Not using code paths that rely on this (loans, dispose, unregister with instance handle,
|
|
|
|
content filters) */
|
|
|
|
abort();
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static void sertopic_rmw_free_samples(
|
|
|
|
const struct ddsi_sertopic * d, void ** ptrs, size_t count,
|
|
|
|
dds_free_op_t op)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
static_cast<void>(d); // unused
|
|
|
|
static_cast<void>(ptrs); // unused
|
|
|
|
static_cast<void>(count); // unused
|
|
|
|
/* Not using code paths that rely on this (dispose, unregister with instance handle, content
|
|
|
|
filters) */
|
|
|
|
assert(!(op & DDS_FREE_ALL_BIT));
|
|
|
|
(void) op;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct ddsi_sertopic_ops sertopic_rmw_ops = {
|
2019-08-17 15:18:57 +02:00
|
|
|
sertopic_rmw_free,
|
|
|
|
sertopic_rmw_zero_samples,
|
|
|
|
sertopic_rmw_realloc_samples,
|
|
|
|
sertopic_rmw_free_samples
|
2019-04-29 09:33:13 +02:00
|
|
|
};
|
|
|
|
|
2019-05-21 16:05:52 +02:00
|
|
|
template<typename MembersType>
|
|
|
|
ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_LOCAL
|
2019-08-17 15:18:57 +02:00
|
|
|
inline std::string create_type_name(const void * untyped_members)
|
2019-05-21 16:05:52 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
auto members = static_cast<const MembersType *>(untyped_members);
|
2019-05-21 16:05:52 +02:00
|
|
|
if (!members) {
|
|
|
|
RMW_SET_ERROR_MSG("members handle is null");
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostringstream ss;
|
2019-08-17 15:18:57 +02:00
|
|
|
std::string message_namespace(members->message_namespace_);
|
2019-05-21 16:05:52 +02:00
|
|
|
// Find and replace C namespace separator with C++, in case this is using C typesupport
|
2019-08-17 15:18:57 +02:00
|
|
|
message_namespace = std::regex_replace(message_namespace, std::regex("__"), "::");
|
|
|
|
std::string message_name(members->message_name_);
|
|
|
|
if (!message_namespace.empty()) {
|
2019-05-21 16:05:52 +02:00
|
|
|
ss << message_namespace << "::";
|
|
|
|
}
|
|
|
|
ss << "dds_::" << message_name << "_";
|
2019-08-17 15:18:57 +02:00
|
|
|
return ss.str();
|
2019-05-21 16:05:52 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
static std::string get_type_name(const char * type_support_identifier, void * type_support)
|
2019-05-21 16:05:52 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
if (using_introspection_c_typesupport(type_support_identifier)) {
|
|
|
|
auto typed_typesupport = static_cast<MessageTypeSupport_c *>(type_support);
|
|
|
|
return typed_typesupport->getName();
|
|
|
|
} else if (using_introspection_cpp_typesupport(type_support_identifier)) {
|
|
|
|
auto typed_typesupport = static_cast<MessageTypeSupport_cpp *>(type_support);
|
|
|
|
return typed_typesupport->getName();
|
|
|
|
} else {
|
|
|
|
return "absent";
|
|
|
|
}
|
2019-05-21 16:05:52 +02:00
|
|
|
}
|
|
|
|
|
2019-08-17 15:18:57 +02:00
|
|
|
struct sertopic_rmw * create_sertopic(
|
|
|
|
const char * topicname, const char * type_support_identifier,
|
2019-12-05 14:42:11 -06:00
|
|
|
void * type_support, bool is_request_header,
|
|
|
|
std::unique_ptr<rmw_cyclonedds_cpp::StructValueType> message_type)
|
2019-04-29 09:33:13 +02:00
|
|
|
{
|
2019-08-17 15:18:57 +02:00
|
|
|
struct sertopic_rmw * st = new struct sertopic_rmw;
|
2019-08-21 15:14:44 +02:00
|
|
|
#if DDSI_SERTOPIC_HAS_TOPICKIND_NO_KEY
|
|
|
|
std::string type_name = get_type_name(type_support_identifier, type_support);
|
|
|
|
ddsi_sertopic_init(static_cast<struct ddsi_sertopic *>(st), topicname,
|
|
|
|
type_name.c_str(), &sertopic_rmw_ops, &serdata_rmw_ops, true);
|
|
|
|
#else
|
2019-08-17 15:18:57 +02:00
|
|
|
memset(st, 0, sizeof(struct ddsi_sertopic));
|
|
|
|
st->cpp_name = std::string(topicname);
|
|
|
|
st->cpp_type_name = get_type_name(type_support_identifier, type_support);
|
|
|
|
st->cpp_name_type_name = st->cpp_name + std::string(";") + std::string(st->cpp_type_name);
|
|
|
|
st->ops = &sertopic_rmw_ops;
|
|
|
|
st->serdata_ops = &serdata_rmw_ops;
|
|
|
|
st->serdata_basehash = ddsi_sertopic_compute_serdata_basehash(st->serdata_ops);
|
|
|
|
st->name_type_name = const_cast<char *>(st->cpp_name_type_name.c_str());
|
|
|
|
st->name = const_cast<char *>(st->cpp_name.c_str());
|
|
|
|
st->type_name = const_cast<char *>(st->cpp_type_name.c_str());
|
|
|
|
st->iid = ddsi_iid_gen();
|
|
|
|
ddsrt_atomic_st32(&st->refc, 1);
|
2019-08-21 15:14:44 +02:00
|
|
|
#endif
|
2019-08-17 15:18:57 +02:00
|
|
|
st->type_support.typesupport_identifier_ = type_support_identifier;
|
|
|
|
st->type_support.type_support_ = type_support;
|
|
|
|
st->is_request_header = is_request_header;
|
2019-12-05 14:42:11 -06:00
|
|
|
st->value_type = std::move(message_type);
|
2019-08-17 15:18:57 +02:00
|
|
|
return st;
|
2019-04-29 09:33:13 +02:00
|
|
|
}
|
2019-12-06 10:21:18 -06:00
|
|
|
|
2019-12-08 16:03:30 -06:00
|
|
|
void serdata_rmw::resize(size_t requested_size)
|
2019-12-06 10:21:18 -06:00
|
|
|
{
|
|
|
|
if (!requested_size) {
|
|
|
|
m_size = 0;
|
|
|
|
m_data.reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: CDR padding in DDSI makes me do this to avoid reading beyond the bounds
|
|
|
|
when copying data to network. Should fix Cyclone to handle that more elegantly. */
|
|
|
|
size_t n_pad_bytes = (-requested_size) % 4;
|
|
|
|
m_data.reset(new byte[requested_size + n_pad_bytes]);
|
|
|
|
m_size = requested_size + n_pad_bytes;
|
|
|
|
|
|
|
|
// zero the very end. The caller isn't necessarily going to overwrite it.
|
|
|
|
std::memset(byte_offset(m_data.get(), requested_size), '\0', n_pad_bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
serdata_rmw::serdata_rmw(const ddsi_sertopic * topic, ddsi_serdata_kind kind)
|
|
|
|
: ddsi_serdata{}
|
|
|
|
{
|
|
|
|
ddsi_serdata_init(this, topic, kind);
|
|
|
|
}
|