Remove IPv4/IPv6-specific code in adding peers

This removes the special handling of IP addresses in adding peer
locators from the configuration, instead relying on the general
string-to-locator conversion routines.

* This extends the common IP handling to code to handle the optional
  presence of a port and the use of brackets, allowing them always for
  IPv6 addresses, but requiring them only when needed for disambiguating
  numerical IPv6 addresses when a port is present.

* The "multicast generator" format is now handled in UDPv4 code.

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2020-06-14 15:18:22 +02:00 committed by eboasson
parent e005c89240
commit fe89d216a5
8 changed files with 628 additions and 117 deletions

View file

@ -203,8 +203,8 @@ struct ddsi_tran_qos
void ddsi_tran_factories_fini (struct ddsi_domaingv *gv);
void ddsi_factory_add (struct ddsi_domaingv *gv, ddsi_tran_factory_t factory);
void ddsi_factory_free (ddsi_tran_factory_t factory);
ddsi_tran_factory_t ddsi_factory_find (const struct ddsi_domaingv *gv, const char * type);
DDS_EXPORT void ddsi_factory_free (ddsi_tran_factory_t factory);
DDS_EXPORT ddsi_tran_factory_t ddsi_factory_find (const struct ddsi_domaingv *gv, const char * type);
ddsi_tran_factory_t ddsi_factory_find_supported_kind (const struct ddsi_domaingv *gv, int32_t kind);
void ddsi_factory_conn_init (const struct ddsi_tran_factory *factory, ddsi_tran_conn_t conn);
@ -261,7 +261,7 @@ int ddsi_is_mcaddr (const struct ddsi_domaingv *gv, const nn_locator_t *loc);
int ddsi_is_ssm_mcaddr (const struct ddsi_domaingv *gv, const nn_locator_t *loc);
enum ddsi_nearby_address_result ddsi_is_nearby_address (const nn_locator_t *loc, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface *interf);
enum ddsi_locator_from_string_result ddsi_locator_from_string (const struct ddsi_domaingv *gv, nn_locator_t *loc, const char *str, ddsi_tran_factory_t default_factory);
DDS_EXPORT enum ddsi_locator_from_string_result ddsi_locator_from_string (const struct ddsi_domaingv *gv, nn_locator_t *loc, const char *str, ddsi_tran_factory_t default_factory);
/* 8 for transport/
1 for [

View file

@ -24,7 +24,7 @@ typedef struct nn_udpv4mcgen_address {
uint8_t idx; /* must be last: then sorting will put them consecutively */
} nn_udpv4mcgen_address_t;
int ddsi_udp_init (struct ddsi_domaingv *gv);
DDS_EXPORT int ddsi_udp_init (struct ddsi_domaingv *gv);
#if defined (__cplusplus)
}

View file

@ -77,6 +77,8 @@ enum ddsi_nearby_address_result ddsi_ipaddr_is_nearby_address (const nn_locator_
enum ddsi_locator_from_string_result ddsi_ipaddr_from_string (ddsi_tran_factory_t tran, nn_locator_t *loc, const char *str, int32_t kind)
{
DDSRT_WARNING_MSVC_OFF(4996);
char copy[264];
int af = AF_INET;
struct sockaddr_storage tmpaddr;
@ -94,28 +96,101 @@ enum ddsi_locator_from_string_result ddsi_ipaddr_from_string (ddsi_tran_factory_
return AFSR_MISMATCH;
}
(void)tran;
if (ddsrt_sockaddrfromstr(af, str, (struct sockaddr *) &tmpaddr) != 0) {
#if DDSRT_HAVE_DNS
/* Not a valid IP address. User may have specified a hostname instead. */
ddsrt_hostent_t *hent = NULL;
if (ddsrt_gethostbyname(str, af, &hent) != 0) {
return AFSR_UNKNOWN;
}
memcpy(&tmpaddr, &hent->addrs[0], sizeof(hent->addrs[0]));
ddsrt_free (hent);
#else
// IPv6: we format numeric ones surrounded by brackets and we want to
// parse port numbers, so a copy is the most pragamatic approach. POSIX
// hostnames seem to be limited to 255 characters, add a port of max 5
// digits and a colon, and so 262 should be enough. (Numerical addresses
// add a few other characters, but even so this ought to be plenty.)
const size_t len = strlen(str);
if (len == 0 || len >= sizeof(copy))
return AFSR_INVALID;
memcpy(copy, str, len + 1);
char *ipstr = copy;
char *portstr = strrchr(copy, ':');
if (af == AF_INET6 && portstr != strchr(copy, ':') && ipstr[0] != '[')
{
// IPv6 numerical addresses contain colons, so if there are multiple
// colons, we require disambiguation by enclosing the IP part in
// brackets and hence consider "portstr" only if the first character
// is '['
portstr = NULL;
}
uint16_t port = 0;
if (portstr) {
unsigned tmpport;
int pos;
if (sscanf (portstr + 1, "%u%n", &tmpport, &pos) == 1 && portstr[1 + pos] == 0)
{
if (tmpport < 1 || tmpport > 65535)
return AFSR_INVALID;
*portstr = 0;
port = (uint16_t) tmpport;
}
else if (af == AF_INET)
{
// no colons in IPv4 addresses
return AFSR_INVALID;
}
else
{
// allow for IPv6 address embedding IPv4 ones, like ff02::ffff:239.255.0.1
portstr = NULL;
}
}
#if DDSRT_HAVE_IPV6
if (af == AF_INET6)
{
if (copy[0] == '[') {
// strip brackets: last character before the port must be a ']',
// in the absence of a port, the last character in the string.
ipstr = copy + 1;
if (portstr == NULL) {
if (copy[len - 1] != ']')
return AFSR_INVALID;
copy[len - 1] = 0;
} else {
assert (portstr > copy);
if (portstr[-1] != ']')
return AFSR_INVALID;
portstr[-1] = 0;
}
}
}
#endif
if (ddsrt_sockaddrfromstr(af, ipstr, (struct sockaddr *) &tmpaddr) != 0) {
#if DDSRT_HAVE_DNS
/* Not a valid IP address. User may have specified a hostname instead. */
ddsrt_hostent_t *hent = NULL;
if (ddsrt_gethostbyname(ipstr, af, &hent) != 0) {
return AFSR_UNKNOWN;
}
memcpy(&tmpaddr, &hent->addrs[0], sizeof(hent->addrs[0]));
ddsrt_free (hent);
#else
return AFSR_INVALID;
#endif
}
// patch in port (sin_port/sin6_port is undefined at this point and must always be set
// before calling ddsi_ipaddr_to_loc
if (tmpaddr.ss_family != af) {
return AFSR_MISMATCH;
} else if (af == AF_INET) {
struct sockaddr_in *x = (struct sockaddr_in *) &tmpaddr;
x->sin_port = htons (port);
} else {
#if DDSRT_HAVE_IPV6
assert (af == AF_INET6);
struct sockaddr_in6 *x = (struct sockaddr_in6 *) &tmpaddr;
x->sin6_port = htons (port);
#else
abort ();
#endif
}
ddsi_ipaddr_to_loc (tran, loc, (struct sockaddr *)&tmpaddr, kind);
/* This is just an address, so there is no valid value for port, other than INVALID.
Without a guarantee that tmpaddr has port 0, best is to set it explicitly here */
loc->port = NN_LOCATOR_PORT_INVALID;
return AFSR_OK;
DDSRT_WARNING_MSVC_ON(4996);
}
char *ddsi_ipaddr_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port)

View file

@ -274,7 +274,7 @@ int find_own_ip (struct ddsi_domaingv *gv, const char *requested_address)
if (i < gv->n_interfaces)
selected_idx = i;
else
GVERROR ("%s: does not match an available interface\n", gv->config.networkAddressString);
GVERROR ("%s: does not match an available interface supporting %s\n", gv->config.networkAddressString, gv->m_factory->m_typename);
}
if (selected_idx < 0)

View file

@ -16,6 +16,7 @@
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/sockets.h"
#include "dds/ddsrt/string.h"
#include "ddsi_eth.h"
#include "dds/ddsi/ddsi_tran.h"
#include "dds/ddsi/ddsi_udp.h"
@ -174,7 +175,8 @@ static ssize_t ddsi_udp_conn_write (ddsi_tran_conn_t conn_cmn, const nn_locator_
}
else if (rc != DDS_RETCODE_OK && rc != DDS_RETCODE_NOT_ALLOWED && rc != DDS_RETCODE_NO_CONNECTION)
{
GVERROR ("ddsi_udp_conn_write failed with retcode %"PRId32"\n", rc);
char locbuf[DDSI_LOCSTRLEN];
GVERROR ("ddsi_udp_conn_write to %s failed with retcode %"PRId32"\n", ddsi_locator_to_string (locbuf, sizeof (locbuf), dst), rc);
}
return (rc == DDS_RETCODE_OK) ? ret : -1;
}
@ -699,9 +701,61 @@ static int ddsi_udp_is_ssm_mcaddr (const ddsi_tran_factory_t tran, const nn_loca
}
#endif
static enum ddsi_locator_from_string_result mcgen_address_from_string (ddsi_tran_factory_t tran, nn_locator_t *loc, const char *str)
{
// check for UDPv4MCGEN string, be lazy and refuse to recognize as a MCGEN form if there's anything "wrong" with it
DDSRT_WARNING_MSVC_OFF(4996);
char ipstr[280];
unsigned base, count, idx;
int ipstrlen, pos;
if (strlen (str) + 10 >= sizeof (ipstr)) // + 6 for appending a port
return AFSR_INVALID;
else if (sscanf (str, "%255[^;]%n;%u;%u;%u%n", ipstr, &ipstrlen, &base, &count, &idx, &pos) != 4)
return AFSR_INVALID;
else if (str[pos] != 0 && str[pos] != ':')
return AFSR_INVALID;
else if (!(count > 0 && base < 28 && count < 28 && base + count < 28 && idx < count))
return AFSR_INVALID;
if (str[pos] == ':')
{
unsigned port;
int pos2;
if (sscanf (str + pos, ":%u%n", &port, &pos2) != 1 || str[pos + pos2] != 0)
return AFSR_INVALID;
// append port to IP component so that ddsi_ipaddr_from_string can do all of the work
// except for filling the specials
assert (ipstrlen >= 0 && (size_t) ipstrlen < sizeof (ipstr));
assert (pos2 >= 0 && (size_t) pos2 < sizeof (ipstr) - (size_t) ipstrlen);
ddsrt_strlcpy (ipstr + ipstrlen, str + pos, sizeof (ipstr) - (size_t) ipstrlen);
}
enum ddsi_locator_from_string_result res = ddsi_ipaddr_from_string (tran, loc, ipstr, tran->m_kind);
if (res != AFSR_OK)
return res;
assert (loc->kind == NN_LOCATOR_KIND_UDPv4);
if (!ddsi_udp_is_mcaddr (tran, loc))
return AFSR_INVALID;
nn_udpv4mcgen_address_t x;
DDSRT_STATIC_ASSERT (sizeof (x) <= sizeof (loc->address));
memset (&x, 0, sizeof(x));
memcpy (&x.ipv4, loc->address + 12, 4);
x.base = (unsigned char) base;
x.count = (unsigned char) count;
x.idx = (unsigned char) idx;
memset (loc->address, 0, sizeof (loc->address));
memcpy (loc->address, &x, sizeof (x));
loc->kind = NN_LOCATOR_KIND_UDPv4MCGEN;
return AFSR_OK;
DDSRT_WARNING_MSVC_ON(4996);
}
static enum ddsi_locator_from_string_result ddsi_udp_address_from_string (ddsi_tran_factory_t tran, nn_locator_t *loc, const char *str)
{
return ddsi_ipaddr_from_string (tran, loc, str, tran->m_kind);
if (tran->m_kind == TRANS_UDP && mcgen_address_from_string (tran, loc, str) == AFSR_OK)
return AFSR_OK;
else
return ddsi_ipaddr_from_string (tran, loc, str, tran->m_kind);
}
static char *ddsi_udp_locator_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port)

View file

@ -44,86 +44,46 @@ static int compare_locators_vwrap (const void *va, const void *vb);
static const ddsrt_avl_ctreedef_t addrset_treedef =
DDSRT_AVL_CTREEDEF_INITIALIZER (offsetof (struct addrset_node, avlnode), offsetof (struct addrset_node, loc), compare_locators_vwrap, 0);
static int add_addresses_to_addrset_1 (const struct ddsi_domaingv *gv, struct addrset *as, const char *ip, int port_mode, const char *msgtag, int req_mc, int mcgen_base, int mcgen_count, int mcgen_idx)
static int add_addresses_to_addrset_1 (const struct ddsi_domaingv *gv, struct addrset *as, nn_locator_t *loc, int port_mode, const char *msgtag)
{
char buf[DDSI_LOCSTRLEN];
nn_locator_t loc;
int32_t maxidx;
switch (ddsi_locator_from_string(gv, &loc, ip, gv->m_factory))
// check whether port number, address type and mode make sense, and prepare the
// locator by patching the first port number to use if none is given
if (loc->port != NN_LOCATOR_PORT_INVALID)
{
case AFSR_OK:
break;
case AFSR_INVALID:
GVERROR ("%s: %s: not a valid address\n", msgtag, ip);
return -1;
case AFSR_UNKNOWN:
GVERROR ("%s: %s: unknown address\n", msgtag, ip);
return -1;
case AFSR_MISMATCH:
GVERROR ("%s: %s: address family mismatch\n", msgtag, ip);
if (port_mode >= 0 && loc->port != (uint32_t) port_mode)
{
GVERROR ("%s: %s: port mismatch (expecting no port or %d)\n", msgtag, ddsi_locator_to_string (buf, sizeof(buf), loc), port_mode);
return -1;
}
maxidx = 0;
}
if (req_mc && !ddsi_is_mcaddr (gv, &loc))
else if (port_mode >= 0)
{
GVERROR ("%s: %s: not a multicast address\n", msgtag, ip);
return -1;
loc->port = (uint32_t) port_mode;
maxidx = 0;
}
if (mcgen_base == -1 && mcgen_count == -1 && mcgen_idx == -1)
;
else if (loc.kind == NN_LOCATOR_KIND_UDPv4 && ddsi_is_mcaddr(gv, &loc) && mcgen_base >= 0 && mcgen_count > 0 && mcgen_base + mcgen_count < 28 && mcgen_idx >= 0 && mcgen_idx < mcgen_count)
else if (ddsi_is_mcaddr (gv, loc))
{
nn_udpv4mcgen_address_t x;
memset(&x, 0, sizeof(x));
memcpy(&x.ipv4, loc.address + 12, 4);
x.base = (unsigned char) mcgen_base;
x.count = (unsigned char) mcgen_count;
x.idx = (unsigned char) mcgen_idx;
memset(loc.address, 0, sizeof(loc.address));
memcpy(loc.address, &x, sizeof(x));
loc.kind = NN_LOCATOR_KIND_UDPv4MCGEN;
loc->port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0);
maxidx = 0;
}
else
{
GVERROR ("%s: %s,%d,%d,%d: IPv4 multicast address generator invalid or out of place\n",
msgtag, ip, mcgen_base, mcgen_count, mcgen_idx);
return -1;
loc->port = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DISC, 0);
maxidx = gv->config.maxAutoParticipantIndex;
}
if (port_mode >= 0)
GVLOG (DDS_LC_CONFIG, "%s: add %s", msgtag, ddsi_locator_to_string (buf, sizeof (buf), loc));
add_to_addrset (gv, as, loc);
for (int32_t i = 1; i < maxidx; i++)
{
loc.port = (unsigned) port_mode;
GVLOG (DDS_LC_CONFIG, "%s: add %s", msgtag, ddsi_locator_to_string(buf, sizeof(buf), &loc));
add_to_addrset (gv, as, &loc);
loc->port = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DISC, i);
GVLOG (DDS_LC_CONFIG, ", :%"PRIu32, loc->port);
add_to_addrset (gv, as, loc);
}
else
{
GVLOG (DDS_LC_CONFIG, "%s: add ", msgtag);
if (!ddsi_is_mcaddr (gv, &loc))
{
assert (gv->config.maxAutoParticipantIndex >= 0);
for (int32_t i = 0; i <= gv->config.maxAutoParticipantIndex; i++)
{
loc.port = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DISC, i);
if (i == 0)
GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(buf, sizeof(buf), &loc));
else
GVLOG (DDS_LC_CONFIG, ", :%"PRIu32, loc.port);
add_to_addrset (gv, as, &loc);
}
}
else
{
if (port_mode == -1)
loc.port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0);
else
loc.port = (uint32_t) port_mode;
GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(buf, sizeof(buf), &loc));
add_to_addrset (gv, as, &loc);
}
}
GVLOG (DDS_LC_CONFIG, "\n");
return 0;
}
@ -134,50 +94,43 @@ int add_addresses_to_addrset (const struct ddsi_domaingv *gv, struct addrset *as
port_mode >= 0 => always set port to port_mode
*/
DDSRT_WARNING_MSVC_OFF(4996);
char *addrs_copy, *ip, *cursor, *a;
char *addrs_copy, *cursor, *a;
int retval = -1;
addrs_copy = ddsrt_strdup (addrs);
ip = ddsrt_malloc (strlen (addrs) + 1);
cursor = addrs_copy;
while ((a = ddsrt_strsep (&cursor, ",")) != NULL)
{
int port = 0, pos;
int mcgen_base = -1, mcgen_count = -1, mcgen_idx = -1;
if (gv->config.transport_selector == TRANS_UDP || gv->config.transport_selector == TRANS_TCP)
nn_locator_t loc;
char buf[DDSI_LOCSTRLEN];
switch (ddsi_locator_from_string (gv, &loc, a, gv->m_factory))
{
if (port_mode == -1 && sscanf (a, "%[^:]:%d%n", ip, &port, &pos) == 2 && a[pos] == 0)
; /* XYZ:PORT */
else if (sscanf (a, "%[^;];%d;%d;%d%n", ip, &mcgen_base, &mcgen_count, &mcgen_idx, &pos) == 4 && a[pos] == 0)
port = port_mode; /* XYZ;BASE;COUNT;IDX for IPv4 MC address generators */
else if (sscanf (a, "%[^:]%n", ip, &pos) == 1 && a[pos] == 0)
port = port_mode; /* XYZ */
else { /* XY:Z -- illegal, but conversion routine should flag it */
strcpy (ip, a);
port = 0;
}
}
else
{
if (port_mode == -1 && sscanf (a, "[%[^]]]:%d%n", ip, &port, &pos) == 2 && a[pos] == 0)
; /* [XYZ]:PORT */
else if (sscanf (a, "[%[^]]]%n", ip, &pos) == 1 && a[pos] == 0)
port = port_mode; /* [XYZ] */
else { /* XYZ -- let conversion routines handle errors */
strcpy (ip, a);
port = 0;
}
case AFSR_OK:
break;
case AFSR_INVALID:
GVERROR ("%s: %s: not a valid address\n", msgtag, a);
goto error;
case AFSR_UNKNOWN:
GVERROR ("%s: %s: unknown address\n", msgtag, a);
goto error;
case AFSR_MISMATCH:
GVERROR ("%s: %s: address family mismatch\n", msgtag, a);
goto error;
}
if ((port > 0 && port <= 65535) || (port_mode == -1 && port == -1)) {
if (add_addresses_to_addrset_1 (gv, as, ip, port, msgtag, req_mc, mcgen_base, mcgen_count, mcgen_idx) < 0)
goto error;
} else {
GVERROR ("%s: %s: port %d invalid\n", msgtag, a, port);
if (req_mc && !ddsi_is_mcaddr (gv, &loc))
{
GVERROR ("%s: %s: not a multicast address\n", msgtag, ddsi_locator_to_string_no_port (buf, sizeof(buf), &loc));
goto error;
}
if (add_addresses_to_addrset_1 (gv, as, &loc, port_mode, msgtag) < 0)
{
goto error;
}
}
retval = 0;
error:
ddsrt_free (ip);
ddsrt_free (addrs_copy);
return retval;
DDSRT_WARNING_MSVC_ON(4996);

View file

@ -12,6 +12,7 @@
include(CUnit)
set(ddsi_test_sources
"locators.c"
"plist_generic.c"
"plist.c"
"mem_ser.h")

View file

@ -0,0 +1,428 @@
/*
* Copyright(c) 2020 ADLINK Technology Limited 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 <string.h>
#include <assert.h>
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/sockets.h"
#include "dds/ddsi/ddsi_tran.h"
#include "dds/ddsi/ddsi_domaingv.h"
#include "dds/ddsi/ddsi_udp.h"
#include "dds/ddsi/ddsi_tcp.h"
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_rtps.h"
#include "CUnit/Theory.h"
static bool prefix_zero (const nn_locator_t *loc, size_t n)
{
assert (n <= sizeof (loc->address));
for (size_t i = 0; i < n; i++)
if (loc->address[i] != 0)
return false;
return true;
}
static bool check_ipv4_address (const nn_locator_t *loc, const uint8_t x[4])
{
return prefix_zero (loc, 12) && memcmp (loc->address + 12, x, 4) == 0;
}
static bool check_ipv64_address (const nn_locator_t *loc, const uint8_t x[4])
{
return prefix_zero (loc, 10) && loc->address[10] == 0xff && loc->address[11] == 0xff && memcmp (loc->address + 12, x, 4) == 0;
}
static struct ddsi_tran_factory *init (struct ddsi_domaingv *gv, enum transport_selector tr)
{
memset (gv, 0, sizeof (*gv));
gv->config.transport_selector = tr;
ddsi_udp_init (gv);
ddsi_tcp_init (gv);
switch (tr)
{
case TRANS_UDP: return ddsi_factory_find (gv, "udp");
case TRANS_TCP: return ddsi_factory_find (gv, "tcp");
case TRANS_UDP6: return ddsi_factory_find (gv, "udp6");
case TRANS_TCP6: return ddsi_factory_find (gv, "tcp6");
default: return NULL;
}
}
static void fini (struct ddsi_domaingv *gv)
{
while (gv->ddsi_tran_factories)
{
struct ddsi_tran_factory *f = gv->ddsi_tran_factories;
gv->ddsi_tran_factories = f->m_factory;
ddsi_factory_free (f);
}
}
CU_Test (ddsi_locator_from_string, bogusproto)
{
struct ddsi_domaingv gv;
struct ddsi_tran_factory * const fact = init (&gv, TRANS_UDP);
nn_locator_t loc;
enum ddsi_locator_from_string_result res;
res = ddsi_locator_from_string (&gv, &loc, "bogusproto/xyz", fact);
CU_ASSERT_FATAL (res == AFSR_UNKNOWN);
res = ddsi_locator_from_string (&gv, &loc, "bogusproto/xyz:1234", fact);
CU_ASSERT_FATAL (res == AFSR_UNKNOWN);
res = ddsi_locator_from_string (&gv, &loc, "bogusproto/1.2.3.4:1234", fact);
CU_ASSERT_FATAL (res == AFSR_UNKNOWN);
fini (&gv);
}
CU_TheoryDataPoints(ddsi_locator_from_string, ipv4_invalid) = {
CU_DataPoints(enum transport_selector, TRANS_UDP, TRANS_TCP)
};
CU_Theory ((enum transport_selector tr), ddsi_locator_from_string, ipv4_invalid)
{
struct ddsi_domaingv gv;
struct ddsi_tran_factory * const fact = init (&gv, tr);
nn_locator_t loc;
enum ddsi_locator_from_string_result res;
char astr[40];
snprintf (astr, sizeof (astr), "%s/", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID);
snprintf (astr, sizeof (astr), "%s/:", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID);
snprintf (astr, sizeof (astr), "%s/1.2:", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID);
snprintf (astr, sizeof (astr), "%s/1.2:99999", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID);
// if DNS is supported, a hostname lookup is tried whenever parsing as a numerical address fails
// which means we may get UNKNOWN
snprintf (astr, sizeof (astr), "%s/:1234", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
snprintf (astr, sizeof (astr), "%s/[1.2.3.4]", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
snprintf (astr, sizeof (astr), "%s/[1.2.3.4]:1234", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
fini (&gv);
}
CU_TheoryDataPoints(ddsi_locator_from_string, ipv4) = {
CU_DataPoints(enum transport_selector, TRANS_UDP, TRANS_TCP)
};
CU_Theory ((enum transport_selector tr), ddsi_locator_from_string, ipv4)
{
struct ddsi_domaingv gv;
struct ddsi_tran_factory * const fact = init (&gv, tr);
nn_locator_t loc;
enum ddsi_locator_from_string_result res;
char astr[40];
#if DDSRT_HAVE_DNS
{
enum ddsi_locator_from_string_result exp;
struct sockaddr_in localhost;
ddsrt_hostent_t *hent = NULL;
if (ddsrt_gethostbyname ("localhost", AF_INET, &hent) != 0)
exp = AFSR_UNKNOWN;
else
{
CU_ASSERT_FATAL (hent->addrs[0].ss_family == AF_INET);
memcpy (&localhost, &hent->addrs[0], sizeof (localhost));
ddsrt_free (hent);
exp = AFSR_OK;
}
res = ddsi_locator_from_string (&gv, &loc, "localhost", fact);
CU_ASSERT_FATAL (res == exp);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == NN_LOCATOR_PORT_INVALID);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (prefix_zero (&loc, 12) && memcmp (loc.address + 12, &localhost.sin_addr.s_addr, 4) == 0);
}
res = ddsi_locator_from_string (&gv, &loc, "localhost:1234", fact);
CU_ASSERT_FATAL (res == exp);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == 1234);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (prefix_zero (&loc, 12) && memcmp (loc.address + 12, &localhost.sin_addr.s_addr, 4) == 0);
}
}
#endif
res = ddsi_locator_from_string (&gv, &loc, "1.2.3.4", fact);
CU_ASSERT_FATAL (res == AFSR_OK);
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == NN_LOCATOR_PORT_INVALID);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (check_ipv4_address (&loc, (uint8_t[]){1,2,3,4}));
snprintf (astr, sizeof (astr), "%s/1.2.3.4", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_OK);
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == NN_LOCATOR_PORT_INVALID);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (check_ipv4_address (&loc, (uint8_t[]){1,2,3,4}));
snprintf (astr, sizeof (astr), "%s/1.2.3.4:1234", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_OK);
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == 1234);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (check_ipv4_address (&loc, (uint8_t[]){1,2,3,4}));
fini (&gv);
}
CU_Test (ddsi_locator_from_string, ipv4_cross1)
{
struct ddsi_domaingv gv;
struct ddsi_tran_factory * const fact = init (&gv, TRANS_UDP);
nn_locator_t loc;
enum ddsi_locator_from_string_result res;
res = ddsi_locator_from_string (&gv, &loc, "tcp/1.2.3.4:1234", fact);
CU_ASSERT_FATAL (res == AFSR_OK);
CU_ASSERT_FATAL (loc.kind == NN_LOCATOR_KIND_TCPv4);
CU_ASSERT_FATAL (loc.port == 1234);
CU_ASSERT_FATAL (loc.tran != fact);
CU_ASSERT_FATAL (check_ipv4_address (&loc, (uint8_t[]){1,2,3,4}));
fini (&gv);
}
CU_Test (ddsi_locator_from_string, ipv4_cross2)
{
struct ddsi_domaingv gv;
struct ddsi_tran_factory * const fact = init (&gv, TRANS_TCP);
nn_locator_t loc;
enum ddsi_locator_from_string_result res;
res = ddsi_locator_from_string (&gv, &loc, "udp/1.2.3.4:1234", fact);
CU_ASSERT_FATAL (res == AFSR_OK);
CU_ASSERT_FATAL (loc.kind == NN_LOCATOR_KIND_UDPv4);
CU_ASSERT_FATAL (loc.port == 1234);
CU_ASSERT_FATAL (loc.tran != fact);
CU_ASSERT_FATAL (check_ipv4_address (&loc, (uint8_t[]){1,2,3,4}));
fini (&gv);
}
CU_Test (ddsi_locator_from_string, udpv4mcgen)
{
struct ddsi_domaingv gv;
struct ddsi_tran_factory * const fact = init (&gv, TRANS_UDP);
nn_locator_t loc;
enum ddsi_locator_from_string_result res;
res = ddsi_locator_from_string (&gv, &loc, "239.255.0.1;4;8;1:1234", fact);
CU_ASSERT_FATAL (res == AFSR_OK);
CU_ASSERT_FATAL (loc.kind == NN_LOCATOR_KIND_UDPv4MCGEN);
CU_ASSERT_FATAL (loc.port == 1234);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (loc.address[0] == 239 && loc.address[1] == 255 && loc.address[2] == 0 && loc.address[3] == 1);
CU_ASSERT_FATAL (loc.address[4] == 4 && loc.address[5] == 8 && loc.address[6] == 1);
CU_ASSERT_FATAL (loc.address[7] == 0 && loc.address[8] == 0 && loc.address[9] == 0);
CU_ASSERT_FATAL (loc.address[10] == 0 && loc.address[11] == 0 && loc.address[12] == 0);
CU_ASSERT_FATAL (loc.address[13] == 0 && loc.address[14] == 0 && loc.address[15] == 0);
res = ddsi_locator_from_string (&gv, &loc, "239.255.0.1;4;0;1:1234", fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
res = ddsi_locator_from_string (&gv, &loc, "239.255.0.1;4;0;1:2345", fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
res = ddsi_locator_from_string (&gv, &loc, "239.255.0.1;30;1;1:3456", fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
res = ddsi_locator_from_string (&gv, &loc, "239.255.0.1;4;24;1:4567", fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
res = ddsi_locator_from_string (&gv, &loc, "239.255.0.1;4;3;3:5678", fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
fini (&gv);
}
CU_TheoryDataPoints(ddsi_locator_from_string, ipv6_invalid) = {
CU_DataPoints(enum transport_selector, TRANS_UDP6, TRANS_TCP6)
};
CU_Theory ((enum transport_selector tr), ddsi_locator_from_string, ipv6_invalid)
{
#if DDSRT_HAVE_IPV6
struct ddsi_domaingv gv;
struct ddsi_tran_factory * const fact = init (&gv, tr);
nn_locator_t loc;
enum ddsi_locator_from_string_result res;
char astr[40];
snprintf (astr, sizeof (astr), "%s/", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID);
// if DNS is supported, a hostname lookup is tried whenever parsing as a numerical address fails
// which means we may get UNKNOWN
snprintf (astr, sizeof (astr), "%s/::1:31415", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
snprintf (astr, sizeof (astr), "%s/:", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
snprintf (astr, sizeof (astr), "%s/1.2:", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
snprintf (astr, sizeof (astr), "%s/]:", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
snprintf (astr, sizeof (astr), "%s/[", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
snprintf (astr, sizeof (astr), "%s/[]", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
snprintf (astr, sizeof (astr), "%s/:1234", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_INVALID || res == AFSR_UNKNOWN);
fini (&gv);
#else
CU_PASS ("No IPv6 support");
#endif
}
CU_TheoryDataPoints(ddsi_locator_from_string, ipv6) = {
CU_DataPoints(enum transport_selector, TRANS_UDP6, TRANS_TCP6)
};
CU_Theory ((enum transport_selector tr), ddsi_locator_from_string, ipv6)
{
#if DDSRT_HAVE_IPV6
struct ddsi_domaingv gv;
struct ddsi_tran_factory * const fact = init (&gv, tr);
nn_locator_t loc;
enum ddsi_locator_from_string_result res;
char astr[40];
#if DDSRT_HAVE_DNS
{
enum ddsi_locator_from_string_result exp;
struct sockaddr_in6 localhost;
ddsrt_hostent_t *hent = NULL;
if (ddsrt_gethostbyname ("localhost", AF_INET6, &hent) != 0)
exp = AFSR_UNKNOWN;
else
{
CU_ASSERT_FATAL (hent->addrs[0].ss_family == AF_INET6);
memcpy (&localhost, &hent->addrs[0], sizeof (localhost));
ddsrt_free (hent);
exp = AFSR_OK;
}
res = ddsi_locator_from_string (&gv, &loc, "localhost", fact);
CU_ASSERT_FATAL (res == exp);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == NN_LOCATOR_PORT_INVALID);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (memcmp (loc.address, &localhost.sin6_addr.s6_addr, 16) == 0);
}
res = ddsi_locator_from_string (&gv, &loc, "[localhost]", fact);
CU_ASSERT_FATAL (res == exp);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == NN_LOCATOR_PORT_INVALID);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (memcmp (loc.address, &localhost.sin6_addr.s6_addr, 16) == 0);
}
res = ddsi_locator_from_string (&gv, &loc, "localhost:1234", fact);
CU_ASSERT_FATAL (res == exp);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == 1234);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (memcmp (loc.address, &localhost.sin6_addr.s6_addr, 16) == 0);
}
res = ddsi_locator_from_string (&gv, &loc, "[localhost]:4567", fact);
CU_ASSERT_FATAL (res == exp);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == 4567);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (memcmp (loc.address, &localhost.sin6_addr.s6_addr, 16) == 0);
}
}
#endif
res = ddsi_locator_from_string (&gv, &loc, "1.2.3.4", fact);
CU_ASSERT_FATAL (res == AFSR_OK || res == AFSR_UNKNOWN);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == NN_LOCATOR_PORT_INVALID);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (check_ipv64_address (&loc, (uint8_t[]){1,2,3,4}));
}
res = ddsi_locator_from_string (&gv, &loc, "[1.2.3.4]", fact);
CU_ASSERT_FATAL (res == AFSR_OK || res == AFSR_UNKNOWN);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == NN_LOCATOR_PORT_INVALID);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (check_ipv64_address (&loc, (uint8_t[]){1,2,3,4}));
}
snprintf (astr, sizeof (astr), "%s/1.2.3.4", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_OK || res == AFSR_UNKNOWN); if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == NN_LOCATOR_PORT_INVALID);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (check_ipv64_address (&loc, (uint8_t[]){1,2,3,4}));
}
snprintf (astr, sizeof (astr), "%s/1.2.3.4:6789", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_OK || res == AFSR_UNKNOWN);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == 6789);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (check_ipv64_address (&loc, (uint8_t[]){1,2,3,4}));
}
snprintf (astr, sizeof (astr), "%s/[1.2.3.4]:7890", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
if (res == AFSR_OK)
{
CU_ASSERT_FATAL (res == AFSR_OK || res == AFSR_UNKNOWN);
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == 7890);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (check_ipv64_address (&loc, (uint8_t[]){1,2,3,4}));
}
snprintf (astr, sizeof (astr), "%s/[::1]:8901", fact->m_typename);
res = ddsi_locator_from_string (&gv, &loc, astr, fact);
CU_ASSERT_FATAL (res == AFSR_OK);
CU_ASSERT_FATAL (loc.kind == fact->m_kind);
CU_ASSERT_FATAL (loc.port == 8901);
CU_ASSERT_FATAL (loc.tran == fact);
CU_ASSERT_FATAL (prefix_zero (&loc, 15) && loc.address[15] == 1);
fini (&gv);
#else
CU_PASS ("No IPv6 support");
#endif
}