Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/manual/config/config_file_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2795,8 +2795,8 @@ The default value is: ``none``

..
generated from ddsi_config.h[6b6cd6f2af797765bc3753758bdd5f166f64b418]
generated from ddsi_config.c[a48ec3d818f2ad852949a7832951709c3488dc10]
generated from ddsi__cfgelems.h[32ba43b085108475f0fc5041d4593a9926c0f6f9]
generated from ddsi_config.c[98a66b82efe4476934c17d3df879e70add3b65a2]
generated from ddsi__cfgelems.h[7fe8f980955d7eab1f9515a474d5a51042698343]
generated from cfgunits.h[05f093223fce107d24dd157ebaafa351dc9df752]
generated from _confgen.h[bb9a0fc6ef1f7f7c46790ee00132e340e5fff36d]
generated from _confgen.c[0d833a6f2c98902f1249e63aed03a6164f0791d6]
Expand Down
4 changes: 2 additions & 2 deletions docs/manual/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -1961,8 +1961,8 @@ The categorisation of tracing output is incomplete and hence most of the verbosi

The default value is: `none`
<!--- generated from ddsi_config.h[6b6cd6f2af797765bc3753758bdd5f166f64b418] -->
<!--- generated from ddsi_config.c[a48ec3d818f2ad852949a7832951709c3488dc10] -->
<!--- generated from ddsi__cfgelems.h[32ba43b085108475f0fc5041d4593a9926c0f6f9] -->
<!--- generated from ddsi_config.c[98a66b82efe4476934c17d3df879e70add3b65a2] -->
<!--- generated from ddsi__cfgelems.h[7fe8f980955d7eab1f9515a474d5a51042698343] -->
<!--- generated from cfgunits.h[05f093223fce107d24dd157ebaafa351dc9df752] -->
<!--- generated from _confgen.h[bb9a0fc6ef1f7f7c46790ee00132e340e5fff36d] -->
<!--- generated from _confgen.c[0d833a6f2c98902f1249e63aed03a6164f0791d6] -->
Expand Down
4 changes: 2 additions & 2 deletions etc/cyclonedds.rnc
Original file line number Diff line number Diff line change
Expand Up @@ -1360,8 +1360,8 @@ MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==<br>
maybe_memsize = xsd:token { pattern = "default|0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([kMG]i?)?B" }
}
# generated from ddsi_config.h[6b6cd6f2af797765bc3753758bdd5f166f64b418]
# generated from ddsi_config.c[a48ec3d818f2ad852949a7832951709c3488dc10]
# generated from ddsi__cfgelems.h[32ba43b085108475f0fc5041d4593a9926c0f6f9]
# generated from ddsi_config.c[98a66b82efe4476934c17d3df879e70add3b65a2]
# generated from ddsi__cfgelems.h[7fe8f980955d7eab1f9515a474d5a51042698343]
# generated from cfgunits.h[05f093223fce107d24dd157ebaafa351dc9df752]
# generated from _confgen.h[bb9a0fc6ef1f7f7c46790ee00132e340e5fff36d]
# generated from _confgen.c[0d833a6f2c98902f1249e63aed03a6164f0791d6]
Expand Down
4 changes: 2 additions & 2 deletions etc/cyclonedds.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -2047,8 +2047,8 @@ MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==&lt;br&gt;
</xs:simpleType>
</xs:schema>
<!--- generated from ddsi_config.h[6b6cd6f2af797765bc3753758bdd5f166f64b418] -->
<!--- generated from ddsi_config.c[a48ec3d818f2ad852949a7832951709c3488dc10] -->
<!--- generated from ddsi__cfgelems.h[32ba43b085108475f0fc5041d4593a9926c0f6f9] -->
<!--- generated from ddsi_config.c[98a66b82efe4476934c17d3df879e70add3b65a2] -->
<!--- generated from ddsi__cfgelems.h[7fe8f980955d7eab1f9515a474d5a51042698343] -->
<!--- generated from cfgunits.h[05f093223fce107d24dd157ebaafa351dc9df752] -->
<!--- generated from _confgen.h[bb9a0fc6ef1f7f7c46790ee00132e340e5fff36d] -->
<!--- generated from _confgen.c[0d833a6f2c98902f1249e63aed03a6164f0791d6] -->
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ option(ENABLE_TYPELIB "Enable Type Library support" ON)
option(ENABLE_TYPE_DISCOVERY "Enable Type Discovery support" ON)
option(ENABLE_TOPIC_DISCOVERY "Enable Topic Discovery support" ON)
option(ENABLE_QOS_PROVIDER "Enable Qos Provider support" ON)
option(ENABLE_TCP "Enable PoC support for DDS-over-TCP" OFF)
if(ENABLE_TYPE_DISCOVERY)
if(NOT ENABLE_TYPELIB)
message(FATAL_ERROR "ENABLE_TYPE_DISCOVERY requires ENABLE_TYPELIB to be enabled")
Expand Down
5 changes: 5 additions & 0 deletions src/core/ddsc/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ if(ENABLE_QOS_PROVIDER)
"qos_provider.c")
endif()

if(ENABLE_TCP)
list(APPEND ddsc_test_sources
"tcp.c")
endif()

add_cunit_executable(cunit_ddsc ${ddsc_test_sources})

if(MSVC)
Expand Down
246 changes: 246 additions & 0 deletions src/core/ddsc/tests/tcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
// Copyright(c) 2025 ZettaScale Technology and others
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
// v. 1.0 which is available at
// http://www.eclipse.org/org/documents/edl-v10.php.
//
// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause

#include <stdio.h>
#include <ctype.h>

#include "dds/ddsi/ddsi_protocol.h"
#include "dds/ddsi/ddsi_thread.h"
#include "dds/ddsrt/time.h"
#include "dds__guid.h"
#include "ddsi__tran.h"
#include "test_common.h"
#include "dds/ddsi/ddsi_entity_index.h"
#include "dds/ddsi/ddsi_proxy_participant.h"
#include "dds/ddsi/ddsi_addrset.h"

#include "dds/dds.h"
#include "dds/ddsrt/io.h"
#include "dds/ddsrt/heap.h"
#include "ddsi__addrset.h"

static ddsrt_atomic_uint32_t framing_errors;

static void scan_for_framing_error (void *ptr, const dds_log_data_t *data)
{
(void) ptr;
//tprintf ("[%"PRIu32"] %s", data->domid, data->message);
if (strstr (data->message, "framing error, dropping connection") != NULL)
ddsrt_atomic_or32 (&framing_errors, 1u << data->domid);
}

static void do_tcp (void (*action) (dds_entity_t rd, dds_entity_t wr, void *arg), void *arg)
{
const char *config_fmt =
"<General>"
" <Interfaces>"
" <NetworkInterface address=\"127.0.0.1\"/>"
" </Interfaces>"
" <Transport>tcp</Transport>"
"</General>"
"<Discovery>"
" <ExternalDomainId>0</ExternalDomainId>"
" <Tag>${CYCLONEDDS_PID}</Tag>"
" <Peers>"
" %s"
" </Peers>"
"</Discovery>"
"<TCP>"
" <Port>%d</Port>"
"</TCP>"
"<Tracing><Category>trace,tcp</Category><OutputFile>stdout</OutputFile></Tracing>";

ddsrt_atomic_st32 (&framing_errors, 0);
dds_set_log_sink (scan_for_framing_error, NULL);
dds_set_trace_sink (scan_for_framing_error, NULL);

// Start up a new domain listening to an ephemeral TCP port
char *configs = NULL;
(void) ddsrt_asprintf (&configs, config_fmt, "", 0);
const dds_entity_t doms = dds_create_domain (0, configs);
ddsrt_free (configs);

#ifdef DDS_HAS_TCP
CU_ASSERT_GT_FATAL (doms, 0);
struct ddsi_domaingv * const gvs = get_domaingv (doms);
CU_ASSERT_NEQ_FATAL (gvs, NULL);

// Create a second domain instance without a server socket and with the
// first domain's ephemeral port as the peer
char peerlocbuf[DDSI_LOCSTRLEN];
char *peerstr = NULL;
(void) ddsrt_asprintf (&peerstr, "<Peer address=\"%s\"/>", ddsi_locator_to_string (peerlocbuf, sizeof (peerlocbuf), &gvs->loc_meta_uc));
char *configc = NULL;
(void) ddsrt_asprintf (&configc, config_fmt, peerstr, -1);
const dds_entity_t domc = dds_create_domain (1, configc);
CU_ASSERT_GT_FATAL (domc, 0);
ddsrt_free (configc);
ddsrt_free (peerstr);

const dds_entity_t pp_pub = dds_create_participant (0, NULL, NULL);
CU_ASSERT_GT_FATAL (pp_pub, 0);
const dds_entity_t pp_sub = dds_create_participant (1, NULL, NULL);
CU_ASSERT_GT_FATAL (pp_sub, 0);
char topicname[100];
create_unique_topic_name ("tcp_basic", topicname, sizeof (topicname));
dds_qos_t *qos = dds_create_qos ();
dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY);
const dds_entity_t tp_pub = dds_create_topic (pp_pub, &Space_Type1_desc, topicname, qos, NULL);
const dds_entity_t tp_sub = dds_create_topic (pp_sub, &Space_Type1_desc, topicname, qos, NULL);
dds_delete_qos (qos);

const dds_entity_t wr = dds_create_writer (pp_pub, tp_pub, NULL, NULL);
const dds_entity_t rd = dds_create_reader (pp_sub, tp_sub, NULL, NULL);
sync_reader_writer (pp_sub, rd, pp_pub, wr);

action (rd, wr, arg);

dds_return_t rc;
rc = dds_delete (domc);
CU_ASSERT_EQ_FATAL (rc, 0);
rc = dds_delete (doms);
CU_ASSERT_EQ_FATAL (rc, 0);
#else // DDS_HAS_TCP
(void) action;
(void) arg;
CU_ASSERT_LT_FATAL (doms, 0);
#endif // DDS_HAS_TCP

dds_set_log_sink (scan_for_framing_error, NULL);
dds_set_trace_sink (scan_for_framing_error, NULL);
}

static void do_basic_write (dds_entity_t rd, dds_entity_t wr, void *varg)
{
(void) varg;

dds_return_t rc;
rc = dds_write (wr, &(Space_Type1){345,678,101});
CU_ASSERT_EQ_FATAL (rc, 0);

const dds_entity_t ws = dds_create_waitset (dds_get_participant (rd));
CU_ASSERT_GT_FATAL (ws, 0);
rc = dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS);
CU_ASSERT_EQ_FATAL (rc, 0);
rc = dds_waitset_attach (ws, rd, 0);
CU_ASSERT_EQ_FATAL (rc, 0);
rc = dds_waitset_wait (ws, NULL, 0, DDS_MSECS (5000));
CU_ASSERT_EQ (rc, 1);

Space_Type1 sample;
void *rawsample = &sample;
dds_sample_info_t si;
rc = dds_take (rd, &rawsample, &si, 1, 1);
CU_ASSERT_EQ_FATAL (rc, 1);
CU_ASSERT_FATAL(si.valid_data);
CU_ASSERT_EQ_FATAL (sample.long_1, 345);
CU_ASSERT_EQ_FATAL (sample.long_2, 678);
CU_ASSERT_EQ_FATAL (sample.long_3, 101);
}

CU_Test (ddsc_tcp, basic)
{
do_tcp (do_basic_write, NULL);
}

struct inject_arg {
ddsrt_iovec_t data;
};

static void do_inject (dds_entity_t rd, dds_entity_t wr, void *varg)
{
const struct inject_arg *arg = varg;
struct ddsi_domaingv * const gvwr = get_domaingv (wr);

// Find reader's proxy participant in writer's domain
dds_guid_t rdguid;
dds_get_guid (rd, &rdguid);
ddsi_guid_t rdpp_guid = dds_guid_to_ddsi_guid (rdguid);
rdpp_guid.entityid.u = DDSI_ENTITYID_PARTICIPANT;
ddsi_thread_state_awake (ddsi_lookup_thread_state (), gvwr);
struct ddsi_proxy_participant *rdproxypp = ddsi_entidx_lookup_proxy_participant_guid (gvwr->entity_index, &rdpp_guid);
CU_ASSERT_NEQ_FATAL (rdproxypp, NULL);
ddsi_thread_state_asleep (ddsi_lookup_thread_state ());
// ... because we need the address
ddsi_xlocator_t xloc;
ddsi_addrset_any_uc (rdproxypp->as_default, &xloc);

// Make writer's domain mute so we can inject garbage in the TCP connection without
// interfering with RTPS messages being sent in the background
dds_domain_set_deafmute (wr, false, true, DDS_INFINITY);

DDSI_DECL_TRAN_WRITE_MSGFRAGS_PTR(mf, 1);
mf->niov = 1;
mf->iov[0] = arg->data;
ddsi_conn_write (xloc.conn, &xloc.c, mf, 0);

// logger should
dds_domainid_t rd_domain_id;
dds_return_t rc;
rc = dds_get_domainid (rd, &rd_domain_id);
CU_ASSERT_EQ_FATAL (rc, 0);
while (ddsrt_atomic_ld32 (&framing_errors) == 0)
dds_sleepfor (DDS_MSECS (10));
CU_ASSERT_EQ_FATAL (ddsrt_atomic_ld32 (&framing_errors), (1u << rd_domain_id));
}

CU_Test (ddsc_tcp, inject_wrong_smid)
{
unsigned char msg[] = {
'R', 'T', 'P', 'S', /* version (don't care): */ 2,5,
/* vendor id (don't care, 1.16 = Cyclone */ 1,16,
/* GUID prefix (don't care) */ 1,16,3,4, 5,6,7,8, 9,10,11,12,
/* SMID_ADLINK_MSG_LEN, big-endian, 4 octets-to-next-header */ 130,0,0,4,
/* fake length */ 0x0,0x0,0x0,0x20
};
struct inject_arg arg = {
.data = {
.iov_len = 28,
.iov_base = msg
}
};
do_tcp (do_inject, &arg);
}

CU_Test (ddsc_tcp, inject_short_length)
{
unsigned char msg[] = {
'R', 'T', 'P', 'S', /* version (don't care): */ 2,5,
/* vendor id (don't care, 1.16 = Cyclone */ 1,16,
/* GUID prefix (don't care) */ 1,16,3,4, 5,6,7,8, 9,10,11,12,
/* SMID_ADLINK_MSG_LEN, big-endian, 4 octets-to-next-header */ 129,0,0,4,
/* fake length */ 0x0,0x0,0x0,0x3
};
struct inject_arg arg = {
.data = {
.iov_len = 28,
.iov_base = msg
}
};
do_tcp (do_inject, &arg);
}

CU_Test (ddsc_tcp, inject_oversize_length)
{
unsigned char msg[] = {
'R', 'T', 'P', 'S', /* version (don't care): */ 2,5,
/* vendor id (don't care, 1.16 = Cyclone */ 1,16,
/* GUID prefix (don't care) */ 1,16,3,4, 5,6,7,8, 9,10,11,12,
/* SMID_ADLINK_MSG_LEN, big-endian, 4 octets-to-next-header */ 129,0,0,4,
/* fake length */ 0x33,0x44,0x55,0x66
};
struct inject_arg arg = {
.data = {
.iov_len = 28,
.iov_base = msg
}
};
do_tcp (do_inject, &arg);
}
4 changes: 2 additions & 2 deletions src/core/ddsi/defconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ void ddsi_config_init_default (struct ddsi_config *cfg)
#endif /* DDS_HAS_TCP_TLS */
}
/* generated from ddsi_config.h[6b6cd6f2af797765bc3753758bdd5f166f64b418] */
/* generated from ddsi_config.c[a48ec3d818f2ad852949a7832951709c3488dc10] */
/* generated from ddsi__cfgelems.h[32ba43b085108475f0fc5041d4593a9926c0f6f9] */
/* generated from ddsi_config.c[98a66b82efe4476934c17d3df879e70add3b65a2] */
/* generated from ddsi__cfgelems.h[7fe8f980955d7eab1f9515a474d5a51042698343] */
/* generated from cfgunits.h[05f093223fce107d24dd157ebaafa351dc9df752] */
/* generated from _confgen.h[bb9a0fc6ef1f7f7c46790ee00132e340e5fff36d] */
/* generated from _confgen.c[0d833a6f2c98902f1249e63aed03a6164f0791d6] */
Expand Down
16 changes: 16 additions & 0 deletions src/core/ddsi/src/ddsi__cfgelems.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,13 +306,23 @@ static struct cfgelem general_cfgelems[] = {
FUNCTIONS(0, uf_boolean_default, 0, pf_nop),
DESCRIPTION("<p>Deprecated (use Transport instead)</p>"),
VALUES("false","true","default")),
#ifdef DDS_HAS_TCP
ENUM("Transport", NULL, 1, "default",
MEMBER(transport_selector),
FUNCTIONS(0, uf_transport_selector, 0, pf_transport_selector),
DESCRIPTION(
"<p>This element allows selecting the transport to be used (udp, udp6, "
"tcp, tcp6, raweth)</p>"),
VALUES("default","udp","udp6","tcp","tcp6","raweth")),
#else
ENUM("Transport", NULL, 1, "default",
MEMBER(transport_selector),
FUNCTIONS(0, uf_transport_selector, 0, pf_transport_selector),
DESCRIPTION(
"<p>This element allows selecting the transport to be used (udp, udp6, "
"raweth)</p>"),
VALUES("default","udp","udp6","raweth")),
#endif
BOOL("EnableMulticastLoopback", NULL, 1, "true",
MEMBER(enableMulticastLoopback),
FUNCTIONS(0, uf_boolean, 0, pf_boolean),
Expand Down Expand Up @@ -1712,6 +1722,7 @@ static struct cfgelem discovery_ports_cfgelems[] = {
END_MARKER
};

#ifdef DDS_HAS_TCP
static struct cfgelem tcp_cfgelems[] = {
ENUM("Enable", NULL, 1, "default",
MEMBER(compat_tcp_enable),
Expand Down Expand Up @@ -1764,6 +1775,7 @@ static struct cfgelem tcp_cfgelems[] = {
)),
END_MARKER
};
#endif

#ifdef DDS_HAS_TCP_TLS
static struct cfgelem ssl_cfgelems[] = {
Expand Down Expand Up @@ -2249,13 +2261,15 @@ static struct cfgelem domain_cfgelems[] = {
"functionality is reserved. This includes renaming or moving "
"options.</p>"
)),
#ifdef DDS_HAS_TCP
GROUP("TCP", tcp_cfgelems, NULL, 1,
NOMEMBER,
NOFUNCTIONS,
DESCRIPTION(
"<p>The TCP element allows you to specify various parameters related to "
"running DDSI over TCP.</p>"
)),
#endif
#ifdef DDS_HAS_TCP_TLS
GROUP("SSL", ssl_cfgelems, NULL, 1,
NOMEMBER,
Expand Down Expand Up @@ -2294,7 +2308,9 @@ static struct cfgelem root_cfgelems[] = {
MOVED("Discovery", "CycloneDDS/Domain/Discovery"),
MOVED("Tracing", "CycloneDDS/Domain/Tracing"),
MOVED("Internal|Unsupported", "CycloneDDS/Domain/Internal"),
#if DDS_HAS_TCP
MOVED("TCP", "CycloneDDS/Domain/TCP"),
#endif
#if DDS_HAS_SECURITY
MOVED("DDSSecurity", "CycloneDDS/Domain/Security"),
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/core/ddsi/src/ddsi__receive.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ int ddsi_user_dqueue_handler (const struct ddsi_rsample_info *sampleinfo, const
int ddsi_add_gap (struct ddsi_xmsg *msg, struct ddsi_writer *wr, struct ddsi_proxy_reader *prd, ddsi_seqno_t start, ddsi_seqno_t base, uint32_t numbits, const uint32_t *bits);

/** @component incoming_rtps */
void ddsi_handle_rtps_message (struct ddsi_thread_state * const thrst, struct ddsi_domaingv *gv, struct ddsi_tran_conn * conn, const ddsi_guid_prefix_t *guidprefix, struct ddsi_rbufpool *rbpool, struct ddsi_rmsg *rmsg, size_t sz, unsigned char *msg, const struct ddsi_network_packet_info *pktinfo);
void ddsi_handle_rtps_message (struct ddsi_thread_state * const thrst, struct ddsi_domaingv *gv, struct ddsi_tran_conn * conn, const ddsi_guid_prefix_t *guidprefix, struct ddsi_rbufpool *rbpool, struct ddsi_rmsg *rmsg, size_t sz, const struct ddsi_network_packet_info *pktinfo);

#if defined (__cplusplus)
}
Expand Down
Loading
Loading