Move all socket creation stuff to transport code

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2020-03-10 12:59:20 +01:00 committed by eboasson
parent 59459b9b8b
commit 4df38f5bf9
11 changed files with 758 additions and 834 deletions

View file

@ -35,6 +35,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_plist.c ddsi_plist.c
ddsi_cdrstream.c ddsi_cdrstream.c
ddsi_time.c ddsi_time.c
ddsi_ownip.c
q_addrset.c q_addrset.c
q_bitset_inlines.c q_bitset_inlines.c
q_bswap.c q_bswap.c
@ -47,7 +48,6 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
q_lat_estim.c q_lat_estim.c
q_lease.c q_lease.c
q_misc.c q_misc.c
q_nwif.c
q_pcap.c q_pcap.c
q_qosmatch.c q_qosmatch.c
q_radmin.c q_radmin.c
@ -100,6 +100,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_xqos.h ddsi_xqos.h
ddsi_cdrstream.h ddsi_cdrstream.h
ddsi_time.h ddsi_time.h
ddsi_ownip.h
q_addrset.h q_addrset.h
q_bitset.h q_bitset.h
q_bswap.h q_bswap.h
@ -115,7 +116,6 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
q_lease.h q_lease.h
q_log.h q_log.h
q_misc.h q_misc.h
q_nwif.h
q_pcap.h q_pcap.h
q_protocol.h q_protocol.h
q_qosmatch.h q_qosmatch.h

View file

@ -21,8 +21,8 @@
#include "dds/ddsrt/fibheap.h" #include "dds/ddsrt/fibheap.h"
#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/ddsi_plist.h"
#include "dds/ddsi/ddsi_ownip.h"
#include "dds/ddsi/q_protocol.h" #include "dds/ddsi/q_protocol.h"
#include "dds/ddsi/q_nwif.h"
#include "dds/ddsi/q_sockwaitset.h" #include "dds/ddsi/q_sockwaitset.h"
#include "dds/ddsi/q_config.h" #include "dds/ddsi/q_config.h"

View file

@ -9,8 +9,8 @@
* *
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/ */
#ifndef Q_NWIF_H #ifndef DDSI_OWNIP_H
#define Q_NWIF_H #define DDSI_OWNIP_H
#include <stdbool.h> #include <stdbool.h>
@ -35,12 +35,10 @@ struct nn_interface {
char *name; char *name;
}; };
int make_socket (ddsrt_socket_t *socket, uint16_t port, bool stream, bool reuse_addr, bool bind_to_any, const struct ddsi_domaingv *gv);
int find_own_ip (struct ddsi_domaingv *gv, const char *requested_address); int find_own_ip (struct ddsi_domaingv *gv, const char *requested_address);
uint32_t locator_to_hopefully_unique_uint32 (const nn_locator_t *src);
#if defined (__cplusplus) #if defined (__cplusplus)
} }
#endif #endif
#endif /* Q_NWIF_H */ #endif /* DDSI_OWNIP_H */

View file

@ -17,7 +17,6 @@
#include "dds/ddsrt/log.h" #include "dds/ddsrt/log.h"
#include "dds/ddsrt/sockets.h" #include "dds/ddsrt/sockets.h"
#include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsi/ddsi_ipaddr.h"
#include "dds/ddsi/q_nwif.h"
#include "dds/ddsi/q_config.h" #include "dds/ddsi/q_config.h"
#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_domaingv.h"

View file

@ -0,0 +1,304 @@
/*
* Copyright(c) 2006 to 2018 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 <ctype.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "dds/ddsrt/ifaddrs.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/md5.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/sockets.h"
#include "dds/ddsi/q_log.h"
#include "dds/ddsi/ddsi_ownip.h"
#include "dds/ddsi/ddsi_domaingv.h"
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_unused.h"
#include "dds/ddsi/q_misc.h"
#include "dds/ddsi/q_addrset.h" /* unspec locator */
#include "dds/ddsi/q_feature_check.h"
#include "dds/ddsi/ddsi_ipaddr.h"
#include "dds/ddsrt/avl.h"
static int multicast_override(const char *ifname, const struct config *config)
{
char *copy = ddsrt_strdup (config->assumeMulticastCapable), *cursor = copy, *tok;
int match = 0;
if (copy != NULL)
{
while ((tok = ddsrt_strsep (&cursor, ",")) != NULL)
{
if (ddsi2_patmatch (tok, ifname))
match = 1;
}
}
ddsrt_free (copy);
return match;
}
#ifdef __linux
/* FIMXE: HACK HACK */
#include <linux/if_packet.h>
#endif
int find_own_ip (struct ddsi_domaingv *gv, const char *requested_address)
{
const char *sep = " ";
char last_if_name[80] = "";
int quality = -1;
int i;
ddsrt_ifaddrs_t *ifa, *ifa_root = NULL;
int maxq_list[MAX_INTERFACES];
int maxq_count = 0;
size_t maxq_strlen = 0;
int selected_idx = -1;
char addrbuf[DDSI_LOCSTRLEN];
GVLOG (DDS_LC_CONFIG, "interfaces:");
{
int ret;
ret = ddsi_enumerate_interfaces(gv->m_factory, gv->config.transport_selector, &ifa_root);
if (ret < 0) {
GVERROR ("ddsi_enumerate_interfaces(%s): %d\n", gv->m_factory->m_typename, ret);
return 0;
}
}
gv->n_interfaces = 0;
last_if_name[0] = 0;
for (ifa = ifa_root; ifa != NULL; ifa = ifa->next)
{
char if_name[sizeof (last_if_name)];
int q = 0;
(void) ddsrt_strlcpy(if_name, ifa->name, sizeof(if_name));
if (strcmp (if_name, last_if_name))
GVLOG (DDS_LC_CONFIG, "%s%s", sep, if_name);
(void) ddsrt_strlcpy(last_if_name, if_name, sizeof(last_if_name));
/* interface must be up */
if ((ifa->flags & IFF_UP) == 0) {
GVLOG (DDS_LC_CONFIG, " (interface down)");
continue;
} else if (ddsrt_sockaddr_isunspecified(ifa->addr)) {
GVLOG (DDS_LC_CONFIG, " (address unspecified)");
continue;
}
switch (ifa->type)
{
case DDSRT_IFTYPE_WIFI:
DDS_LOG(DDS_LC_CONFIG, " wireless");
break;
case DDSRT_IFTYPE_WIRED:
DDS_LOG(DDS_LC_CONFIG, " wired");
break;
case DDSRT_IFTYPE_UNKNOWN:
break;
}
#if defined(__linux) && !LWIP_SOCKET
if (ifa->addr->sa_family == AF_PACKET)
{
/* FIXME: weirdo warning warranted */
nn_locator_t *l = &gv->interfaces[gv->n_interfaces].loc;
l->kind = NN_LOCATOR_KIND_RAWETH;
l->port = NN_LOCATOR_PORT_INVALID;
memset(l->address, 0, 10);
memcpy(l->address + 10, ((struct sockaddr_ll *)ifa->addr)->sll_addr, 6);
}
else
#endif
{
ddsi_ipaddr_to_loc(gv->m_factory, &gv->interfaces[gv->n_interfaces].loc, ifa->addr, gv->m_factory->m_kind);
}
ddsi_locator_to_string_no_port(addrbuf, sizeof(addrbuf), &gv->interfaces[gv->n_interfaces].loc);
GVLOG (DDS_LC_CONFIG, " %s(", addrbuf);
if (!(ifa->flags & IFF_MULTICAST) && multicast_override (if_name, &gv->config))
{
GVLOG (DDS_LC_CONFIG, "assume-mc:");
ifa->flags |= IFF_MULTICAST;
}
if (ifa->flags & IFF_LOOPBACK)
{
/* Loopback device has the lowest priority of every interface
available, because the other interfaces at least in principle
allow communicating with other machines. */
q += 0;
#if DDSRT_HAVE_IPV6
if (!(ifa->addr->sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *)ifa->addr)->sin6_addr)))
q += 1;
#endif
}
else
{
#if DDSRT_HAVE_IPV6
/* We accept link-local IPv6 addresses, but an interface with a
link-local address will end up lower in the ordering than one
with a global address. When forced to use a link-local
address, we restrict ourselves to operating on that one
interface only and assume any advertised (incoming) link-local
address belongs to that interface. FIXME: this is wrong, and
should be changed to tag addresses with the interface over
which it was received. But that means proper multi-homing
support and has quite an impact in various places, not least of
which is the abstraction layer. */
if (!(ifa->addr->sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *)ifa->addr)->sin6_addr)))
q += 5;
#endif
/* We strongly prefer a multicast capable interface, if that's
not available anything that's not point-to-point, or else we
hope IP routing will take care of the issues. */
if (ifa->flags & IFF_MULTICAST)
q += 4;
else if (!(ifa->flags & IFF_POINTOPOINT))
q += 3;
else
q += 2;
}
GVLOG (DDS_LC_CONFIG, "q%d)", q);
if (q == quality) {
maxq_list[maxq_count] = gv->n_interfaces;
maxq_strlen += 2 + strlen (if_name);
maxq_count++;
} else if (q > quality) {
maxq_list[0] = gv->n_interfaces;
maxq_strlen += 2 + strlen (if_name);
maxq_count = 1;
quality = q;
}
if (ifa->addr->sa_family == AF_INET && ifa->netmask)
{
ddsi_ipaddr_to_loc(gv->m_factory, &gv->interfaces[gv->n_interfaces].netmask, ifa->netmask, gv->m_factory->m_kind);
}
else
{
gv->interfaces[gv->n_interfaces].netmask.kind = gv->m_factory->m_kind;
gv->interfaces[gv->n_interfaces].netmask.port = NN_LOCATOR_PORT_INVALID;
memset(&gv->interfaces[gv->n_interfaces].netmask.address, 0, sizeof(gv->interfaces[gv->n_interfaces].netmask.address));
}
gv->interfaces[gv->n_interfaces].mc_capable = ((ifa->flags & IFF_MULTICAST) != 0);
gv->interfaces[gv->n_interfaces].mc_flaky = ((ifa->type == DDSRT_IFTYPE_WIFI) != 0);
gv->interfaces[gv->n_interfaces].point_to_point = ((ifa->flags & IFF_POINTOPOINT) != 0);
gv->interfaces[gv->n_interfaces].if_index = ifa->index;
gv->interfaces[gv->n_interfaces].name = ddsrt_strdup (if_name);
gv->n_interfaces++;
}
GVLOG (DDS_LC_CONFIG, "\n");
ddsrt_freeifaddrs (ifa_root);
if (requested_address == NULL)
{
if (maxq_count > 1)
{
const int idx = maxq_list[0];
char *names;
int p;
ddsi_locator_to_string_no_port (addrbuf, sizeof(addrbuf), &gv->interfaces[idx].loc);
names = ddsrt_malloc (maxq_strlen + 1);
p = 0;
for (i = 0; i < maxq_count && (size_t) p < maxq_strlen; i++)
p += snprintf (names + p, maxq_strlen - (size_t) p, ", %s", gv->interfaces[maxq_list[i]].name);
GVWARNING ("using network interface %s (%s) selected arbitrarily from: %s\n",
gv->interfaces[idx].name, addrbuf, names + 2);
ddsrt_free (names);
}
if (maxq_count > 0)
selected_idx = maxq_list[0];
else
GVERROR ("failed to determine default own IP address\n");
}
else
{
nn_locator_t req;
/* Presumably an interface name */
for (i = 0; i < gv->n_interfaces; i++)
{
if (strcmp (gv->interfaces[i].name, gv->config.networkAddressString) == 0)
break;
}
if (i < gv->n_interfaces)
; /* got a match */
else if (ddsi_locator_from_string(gv, &req, gv->config.networkAddressString, gv->m_factory) != AFSR_OK)
; /* not good, i = gv->n_interfaces, so error handling will kick in */
else
{
/* Try an exact match on the address */
for (i = 0; i < gv->n_interfaces; i++)
if (compare_locators(&gv->interfaces[i].loc, &req) == 0)
break;
if (i == gv->n_interfaces && req.kind == NN_LOCATOR_KIND_UDPv4)
{
/* Try matching on network portion only, where the network
portion is based on the netmask of the interface under
consideration */
for (i = 0; i < gv->n_interfaces; i++)
{
uint32_t req1, ip1, nm1;
memcpy (&req1, req.address + 12, sizeof (req1));
memcpy (&ip1, gv->interfaces[i].loc.address + 12, sizeof (ip1));
memcpy (&nm1, gv->interfaces[i].netmask.address + 12, sizeof (nm1));
/* If the host portion of the requested address is non-zero,
skip this interface */
if (req1 & ~nm1)
continue;
if ((req1 & nm1) == (ip1 & nm1))
break;
}
}
}
if (i < gv->n_interfaces)
selected_idx = i;
else
GVERROR ("%s: does not match an available interface\n", gv->config.networkAddressString);
}
if (selected_idx < 0)
return 0;
else
{
gv->ownloc = gv->interfaces[selected_idx].loc;
gv->selected_interface = selected_idx;
gv->interfaceNo = gv->interfaces[selected_idx].if_index;
#if DDSRT_HAVE_IPV6
if (gv->extloc.kind == NN_LOCATOR_KIND_TCPv6 || gv->extloc.kind == NN_LOCATOR_KIND_UDPv6)
{
struct sockaddr_in6 addr;
memcpy(&addr.sin6_addr, gv->ownloc.address, sizeof(addr.sin6_addr));
gv->ipv6_link_local = IN6_IS_ADDR_LINKLOCAL (&addr.sin6_addr) != 0;
}
else
{
gv->ipv6_link_local = 0;
}
#endif
GVLOG (DDS_LC_CONFIG, "selected interface: %s (index %u)\n",
gv->interfaces[selected_idx].name, gv->interfaceNo);
return 1;
}
}

View file

@ -13,7 +13,6 @@
#include "dds/ddsi/ddsi_raweth.h" #include "dds/ddsi/ddsi_raweth.h"
#include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsi/ddsi_ipaddr.h"
#include "dds/ddsi/ddsi_mcgroup.h" #include "dds/ddsi/ddsi_mcgroup.h"
#include "dds/ddsi/q_nwif.h"
#include "dds/ddsi/q_config.h" #include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_log.h" #include "dds/ddsi/q_log.h"
#include "dds/ddsi/q_pcap.h" #include "dds/ddsi/q_pcap.h"

View file

@ -21,7 +21,6 @@
#include "dds/ddsi/ddsi_tcp.h" #include "dds/ddsi/ddsi_tcp.h"
#include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsi/ddsi_ipaddr.h"
#include "dds/ddsrt/avl.h" #include "dds/ddsrt/avl.h"
#include "dds/ddsi/q_nwif.h"
#include "dds/ddsi/q_config.h" #include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_log.h" #include "dds/ddsi/q_log.h"
#include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_entity.h"
@ -165,12 +164,94 @@ static void ddsi_tcp_sock_free (const struct ddsrt_log_cfg *logcfg, ddsrt_socket
} }
} }
static void ddsi_tcp_sock_new (ddsrt_socket_t *sock, unsigned short port, const struct ddsi_domaingv *gv) static dds_return_t ddsi_tcp_sock_new (struct ddsi_tran_factory_tcp * const fact, ddsrt_socket_t *sock, uint16_t port)
{ {
if (make_socket (sock, port, true, true, true, gv) != 0) struct ddsi_domaingv * const gv = fact->fact.gv;
const int one = 1;
dds_return_t rc;
{ {
*sock = DDSRT_INVALID_SOCKET; int af = AF_UNSPEC;
switch (fact->fact.m_kind)
{
case NN_LOCATOR_KIND_TCPv4:
af = AF_INET;
break;
#if DDSRT_HAVE_IPV6
case NN_LOCATOR_KIND_TCPv6:
af = AF_INET6;
break;
#endif
default:
DDS_FATAL ("ddsi_tcp_sock_new: unsupported kind %"PRId32"\n", fact->fact.m_kind);
}
assert (af != AF_UNSPEC);
if ((rc = ddsrt_socket (sock, af, SOCK_STREAM, 0)) != DDS_RETCODE_OK)
{
GVERROR ("ddsi_tcp_sock_new: failed to create socket: %s\n", dds_strretcode (rc));
goto fail;
}
} }
/* REUSEADDR if we're binding to a port number */
if (port && (rc = ddsrt_setsockopt (*sock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one))) != DDS_RETCODE_OK)
{
GVERROR ("ddsi_tcp_sock_new: failed to enable address reuse: %s\n", dds_strretcode (rc));
goto fail_w_socket;
}
{
union {
struct sockaddr_storage x;
struct sockaddr_in a4;
struct sockaddr_in6 a6;
} socketname;
memset (&socketname.x, 0, sizeof (socketname.x));
switch (fact->fact.m_kind)
{
case NN_LOCATOR_KIND_TCPv4:
socketname.a4.sin_family = AF_INET;
socketname.a4.sin_addr.s_addr = htonl (INADDR_ANY);
socketname.a4.sin_port = htons (port);
break;
#if DDSRT_HAVE_IPV6
case NN_LOCATOR_KIND_TCPv6:
socketname.a4.sin_family = AF_INET6;
socketname.a6.sin6_addr = ddsrt_in6addr_any;
socketname.a6.sin6_port = htons (port);
break;
#endif
default:
DDS_FATAL ("ddsi_tcp_sock_new: unsupported kind %"PRId32"\n", fact->fact.m_kind);
}
if ((rc = ddsrt_bind (*sock, (struct sockaddr *) &socketname, ddsrt_sockaddr_get_size ((struct sockaddr *) &socketname))) != DDS_RETCODE_OK)
{
GVERROR ("ddsi_tcp_sock_new: failed to bind to ANY:%"PRIu16": %s\n", port, dds_strretcode (rc));
goto fail_w_socket;
}
}
#ifdef SO_NOSIGPIPE
if (ddsrt_setsockopt (*sock, SOL_SOCKET, SO_NOSIGPIPE, (char *) &one, sizeof (one)) != DDS_RETCODE_OK)
{
GVERROR ("ddsi_tcp_sock_new: failed to set NOSIGPIPE: %s\n", dds_strretcode (rc));
goto fail_w_socket;
}
#endif
#ifdef TCP_NODELAY
if (gv->config.tcp_nodelay && (rc = ddsrt_setsockopt (*sock, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof (one))) != DDS_RETCODE_OK)
{
GVERROR ("ddsi_tcp_sock_new: failed to set NODELAY: %s\n", dds_strretcode (rc));
goto fail_w_socket;
}
#endif
return DDS_RETCODE_OK;
fail_w_socket:
ddsrt_close (*sock);
fail:
*sock = DDSRT_INVALID_SOCKET;
return rc;
} }
static void ddsi_tcp_node_free (void * ptr) static void ddsi_tcp_node_free (void * ptr)
@ -187,16 +268,12 @@ static void ddsi_tcp_conn_connect (ddsi_tcp_conn_t conn, const ddsrt_msghdr_t *
ddsrt_socket_t sock; ddsrt_socket_t sock;
dds_return_t ret; dds_return_t ret;
ddsi_tcp_sock_new (&sock, 0, conn->m_base.m_base.gv); if (ddsi_tcp_sock_new (fact, &sock, 0) == DDS_RETCODE_OK)
if (sock != DDSRT_INVALID_SOCKET)
{ {
/* Attempt to connect, expected that may fail */ /* Attempt to connect, expected that may fail */
do {
do
{
ret = ddsrt_connect(sock, msg->msg_name, msg->msg_namelen); ret = ddsrt_connect(sock, msg->msg_name, msg->msg_namelen);
} } while (ret == DDS_RETCODE_INTERRUPTED);
while (ret == DDS_RETCODE_INTERRUPTED);
if (ret != DDS_RETCODE_OK) if (ret != DDS_RETCODE_OK)
{ {
@ -855,48 +932,45 @@ static ddsi_tcp_conn_t ddsi_tcp_new_conn (struct ddsi_tran_factory_tcp *fact, dd
static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, uint32_t port, const struct ddsi_tran_qos *qos) static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, uint32_t port, const struct ddsi_tran_qos *qos)
{ {
char buff[DDSI_LOCSTRLEN];
ddsrt_socket_t sock;
struct sockaddr_storage addr;
socklen_t addrlen = sizeof (addr);
ddsi_tcp_listener_t tl = NULL;
struct ddsi_tran_factory_tcp * const fact_tcp = (struct ddsi_tran_factory_tcp *) fact; struct ddsi_tran_factory_tcp * const fact_tcp = (struct ddsi_tran_factory_tcp *) fact;
struct ddsi_domaingv * const gv = fact_tcp->fact.gv;
ddsrt_socket_t sock;
(void) qos; (void) qos;
ddsi_tcp_sock_new (&sock, (unsigned short) port, fact->gv); if (ddsi_tcp_sock_new (fact_tcp, &sock, (unsigned short) port) != DDS_RETCODE_OK)
return NULL;
if (sock != DDSRT_INVALID_SOCKET) dds_return_t ret;
ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) ddsrt_malloc (sizeof (*tl));
memset (tl, 0, sizeof (*tl));
tl->m_sock = sock;
tl->m_base.m_base.gv = fact->gv;
tl->m_base.m_listen_fn = ddsi_tcp_listen;
tl->m_base.m_accept_fn = ddsi_tcp_accept;
tl->m_base.m_factory = fact;
tl->m_base.m_base.m_port = get_socket_port (&fact->gv->logconfig, sock);
tl->m_base.m_base.m_trantype = DDSI_TRAN_LISTENER;
tl->m_base.m_base.m_handle_fn = ddsi_tcp_listener_handle;
tl->m_base.m_locator_fn = ddsi_tcp_locator;
struct sockaddr_storage addr;
socklen_t addrlen = sizeof (addr);
if ((ret = ddsrt_getsockname (sock, (struct sockaddr *) &addr, &addrlen)) != DDS_RETCODE_OK)
{ {
dds_return_t ret; GVERROR ("ddsi_tcp_create_listener: ddsrt_getsockname returned %"PRId32"\n", ret);
tl = (ddsi_tcp_listener_t) ddsrt_malloc (sizeof (*tl)); ddsi_tcp_sock_free (&fact->gv->logconfig, sock, NULL);
memset (tl, 0, sizeof (*tl)); ddsrt_free (tl);
return NULL;
tl->m_sock = sock;
tl->m_base.m_base.gv = fact->gv;
tl->m_base.m_listen_fn = ddsi_tcp_listen;
tl->m_base.m_accept_fn = ddsi_tcp_accept;
tl->m_base.m_factory = fact;
tl->m_base.m_base.m_port = get_socket_port (&fact->gv->logconfig, sock);
tl->m_base.m_base.m_trantype = DDSI_TRAN_LISTENER;
tl->m_base.m_base.m_handle_fn = ddsi_tcp_listener_handle;
tl->m_base.m_locator_fn = ddsi_tcp_locator;
ret = ddsrt_getsockname(sock, (struct sockaddr *)&addr, &addrlen);
if (ret != DDS_RETCODE_OK) {
DDS_CERROR (&fact->gv->logconfig, "ddsi_tcp_create_listener: ddsrt_getsockname returned %"PRId32"\n", ret);
ddsi_tcp_sock_free(&fact->gv->logconfig, sock, NULL);
ddsrt_free(tl);
return NULL;
}
sockaddr_to_string_with_port(fact_tcp, buff, sizeof(buff), (struct sockaddr *)&addr);
DDS_CLOG (DDS_LC_TCP, &fact->gv->logconfig, "tcp create listener socket %"PRIdSOCK" on %s\n", sock, buff);
} }
return tl ? &tl->m_base : NULL; char buff[DDSI_LOCSTRLEN];
sockaddr_to_string_with_port (fact_tcp, buff, sizeof (buff), (struct sockaddr *) &addr);
GVLOG (DDS_LC_TCP, "tcp create listener socket %"PRIdSOCK" on %s\n", sock, buff);
return &tl->m_base;
} }
static void ddsi_tcp_conn_delete (ddsi_tcp_conn_t conn) static void ddsi_tcp_conn_delete (ddsi_tcp_conn_t conn)
@ -948,55 +1022,56 @@ static void ddsi_tcp_release_conn (ddsi_tran_conn_t conn)
static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener) static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener)
{ {
struct ddsi_tran_factory_tcp * const fact_tcp = (struct ddsi_tran_factory_tcp *) listener->m_factory;
struct ddsi_domaingv * const gv = fact_tcp->fact.gv;
ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) listener; ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) listener;
ddsrt_socket_t sock; ddsrt_socket_t sock;
dds_return_t ret; dds_return_t ret;
/* Connect to own listener socket to wake listener from blocking 'accept()' */ /* Connect to own listener socket to wake listener from blocking 'accept()' */
ddsi_tcp_sock_new (&sock, 0, listener->m_base.gv); if (ddsi_tcp_sock_new (fact_tcp, &sock, 0) != DDS_RETCODE_OK)
if (sock != DDSRT_INVALID_SOCKET) goto fail;
{
struct sockaddr_storage addr;
socklen_t addrlen = sizeof (addr);
ret = ddsrt_getsockname(tl->m_sock, (struct sockaddr *)&addr, &addrlen); struct sockaddr_storage addr;
if (ret != DDS_RETCODE_OK) { socklen_t addrlen = sizeof (addr);
DDS_CWARNING (&listener->m_base.gv->logconfig, "tcp failed to get listener address error %"PRId32"\n", ret); if ((ret = ddsrt_getsockname (tl->m_sock, (struct sockaddr *) &addr, &addrlen)) != DDS_RETCODE_OK)
} else { {
switch (addr.ss_family) { GVWARNING ("tcp failed to get listener address error %"PRId32"\n", ret);
case AF_INET: goto fail_w_socket;
{
struct sockaddr_in *socketname = (struct sockaddr_in*)&addr;
if (socketname->sin_addr.s_addr == htonl (INADDR_ANY)) {
socketname->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
}
}
break;
#if DDSRT_HAVE_IPV6
case AF_INET6:
{
struct sockaddr_in6 *socketname = (struct sockaddr_in6*)&addr;
if (memcmp(&socketname->sin6_addr, &ddsrt_in6addr_any, sizeof(socketname->sin6_addr)) == 0) {
socketname->sin6_addr = ddsrt_in6addr_loopback;
}
}
break;
#endif
}
do
{
ret = ddsrt_connect(sock, (struct sockaddr *)&addr, ddsrt_sockaddr_get_size((struct sockaddr *)&addr));
} while (ret == DDS_RETCODE_INTERRUPTED);
if (ret != DDS_RETCODE_OK)
{
struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) listener->m_factory;
char buff[DDSI_LOCSTRLEN];
sockaddr_to_string_with_port(fact, buff, sizeof(buff), (struct sockaddr *)&addr);
DDS_CWARNING (&listener->m_base.gv->logconfig, "tcp failed to connect to own listener (%s) error %"PRId32"\n", buff, ret);
}
}
ddsi_tcp_sock_free (&listener->m_base.gv->logconfig, sock, NULL);
} }
switch (addr.ss_family)
{
case AF_INET: {
struct sockaddr_in *socketname = (struct sockaddr_in *) &addr;
if (socketname->sin_addr.s_addr == htonl (INADDR_ANY))
socketname->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
break;
}
#if DDSRT_HAVE_IPV6
case AF_INET6: {
struct sockaddr_in6 *socketname = (struct sockaddr_in6 *) &addr;
if (memcmp (&socketname->sin6_addr, &ddsrt_in6addr_any, sizeof (socketname->sin6_addr)) == 0)
socketname->sin6_addr = ddsrt_in6addr_loopback;
break;
}
#endif
}
do {
ret = ddsrt_connect (sock, (struct sockaddr *) &addr, ddsrt_sockaddr_get_size ((struct sockaddr *) &addr));
} while (ret == DDS_RETCODE_INTERRUPTED);
if (ret != DDS_RETCODE_OK)
{
struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) listener->m_factory;
char buff[DDSI_LOCSTRLEN];
sockaddr_to_string_with_port (fact, buff, sizeof (buff), (struct sockaddr *) &addr);
GVWARNING ("tcp failed to connect to own listener (%s) error %"PRId32"\n", buff, ret);
}
fail_w_socket:
ddsi_tcp_sock_free (&listener->m_base.gv->logconfig, sock, NULL);
fail:
return;
} }
static void ddsi_tcp_release_listener (ddsi_tran_listener_t listener) static void ddsi_tcp_release_listener (ddsi_tran_listener_t listener)

View file

@ -21,7 +21,6 @@
#include "dds/ddsi/ddsi_udp.h" #include "dds/ddsi/ddsi_udp.h"
#include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsi/ddsi_ipaddr.h"
#include "dds/ddsi/ddsi_mcgroup.h" #include "dds/ddsi/ddsi_mcgroup.h"
#include "dds/ddsi/q_nwif.h"
#include "dds/ddsi/q_config.h" #include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_log.h" #include "dds/ddsi/q_log.h"
#include "dds/ddsi/q_pcap.h" #include "dds/ddsi/q_pcap.h"
@ -202,28 +201,189 @@ static int ddsi_udp_conn_locator (ddsi_tran_factory_t fact, ddsi_tran_base_t bas
return ret; return ret;
} }
static unsigned short get_socket_port (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket) static uint16_t get_socket_port (struct ddsi_domaingv * const gv, ddsrt_socket_t sock)
{ {
dds_return_t ret; dds_return_t ret;
struct sockaddr_storage addr; struct sockaddr_storage addr;
socklen_t addrlen = sizeof (addr); socklen_t addrlen = sizeof (addr);
ret = ddsrt_getsockname (socket, (struct sockaddr *)&addr, &addrlen); ret = ddsrt_getsockname (sock, (struct sockaddr *)&addr, &addrlen);
if (ret != DDS_RETCODE_OK) if (ret != DDS_RETCODE_OK)
{ {
DDS_CERROR (logcfg, "ddsi_udp_get_socket_port: getsockname returned %"PRId32"\n", ret); GVERROR ("ddsi_udp_get_socket_port: getsockname returned %"PRId32"\n", ret);
return 0; return 0;
} }
return ddsrt_sockaddr_get_port((struct sockaddr *)&addr); return ddsrt_sockaddr_get_port ((struct sockaddr *)&addr);
}
static dds_return_t set_dont_route (struct ddsi_domaingv * const gv, ddsrt_socket_t socket, bool ipv6)
{
dds_return_t rc;
#if DDSRT_HAVE_IPV6
if (ipv6)
{
const unsigned ipv6Flag = 1;
if ((rc = ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ipv6Flag, sizeof (ipv6Flag))) != DDS_RETCODE_OK)
GVERROR ("ddsi_udp_create_conn: set IPV6_UNICAST_HOPS = 1 failed: %s\n", dds_strretcode (rc));
return rc;
}
#endif
const int one = 1;
if ((rc = ddsrt_setsockopt (socket, SOL_SOCKET, SO_DONTROUTE, (char *) &one, sizeof (one))) != DDS_RETCODE_OK)
GVERROR ("ddsi_udp_create_conn: set SO_DONTROUTE = 1 failed: %s\n", dds_strretcode (rc));
return rc;
}
static dds_return_t set_rcvbuf (struct ddsi_domaingv * const gv, ddsrt_socket_t sock, const struct config_maybe_uint32 *min_size)
{
uint32_t ReceiveBufferSize;
socklen_t optlen = (socklen_t) sizeof (ReceiveBufferSize);
uint32_t socket_min_rcvbuf_size;
dds_return_t rc;
if (min_size->isdefault)
socket_min_rcvbuf_size = 1048576;
else
socket_min_rcvbuf_size = min_size->value;
rc = ddsrt_getsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &ReceiveBufferSize, &optlen);
if (rc == DDS_RETCODE_BAD_PARAMETER)
{
/* not all stacks support getting/setting RCVBUF */
GVLOG (DDS_LC_CONFIG, "cannot retrieve socket receive buffer size\n");
return DDS_RETCODE_OK;
}
if (rc != DDS_RETCODE_OK)
{
GVERROR ("ddsi_udp_create_conn: get SO_RCVBUF failed: %s\n", dds_strretcode (rc));
goto fail;
}
if (ReceiveBufferSize < socket_min_rcvbuf_size)
{
/* make sure the receive buffersize is at least the minimum required */
ReceiveBufferSize = socket_min_rcvbuf_size;
(void) ddsrt_setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (const char *) &ReceiveBufferSize, sizeof (ReceiveBufferSize));
/* We don't check the return code from setsockopt, because some O/Ss tend
to silently cap the buffer size. The only way to make sure is to read
the option value back and check it is now set correctly. */
if ((rc = ddsrt_getsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &ReceiveBufferSize, &optlen)) != DDS_RETCODE_OK)
{
GVERROR ("ddsi_udp_create_conn: get SO_RCVBUF failed: %s\n", dds_strretcode (rc));
goto fail;
}
if (ReceiveBufferSize >= socket_min_rcvbuf_size)
GVLOG (DDS_LC_CONFIG, "socket receive buffer size set to %"PRIu32" bytes\n", ReceiveBufferSize);
else
GVLOG (min_size->isdefault ? DDS_LC_CONFIG : DDS_LC_ERROR,
"failed to increase socket receive buffer size to %"PRIu32" bytes, continuing with %"PRIu32" bytes\n",
socket_min_rcvbuf_size, ReceiveBufferSize);
}
fail:
return rc;
}
static dds_return_t set_sndbuf (struct ddsi_domaingv * const gv, ddsrt_socket_t sock, uint32_t min_size)
{
unsigned SendBufferSize;
socklen_t optlen = (socklen_t) sizeof(SendBufferSize);
dds_return_t rc;
rc = ddsrt_getsockopt(sock, SOL_SOCKET, SO_SNDBUF,(char *)&SendBufferSize, &optlen);
if (rc == DDS_RETCODE_BAD_PARAMETER)
{
/* not all stacks support getting/setting SNDBUF */
GVLOG (DDS_LC_CONFIG, "cannot retrieve socket send buffer size\n");
return DDS_RETCODE_OK;
}
if (rc != DDS_RETCODE_OK)
{
GVERROR ("ddsi_udp_create_conn: get SO_SNDBUF failed: %s\n", dds_strretcode (rc));
goto fail;
}
if (SendBufferSize < min_size)
{
/* make sure the send buffersize is at least the minimum required */
SendBufferSize = min_size;
if ((rc = ddsrt_setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (const char *) &SendBufferSize, sizeof (SendBufferSize))) != DDS_RETCODE_OK)
{
GVERROR ("ddsi_udp_create_conn: set SO_SNDBUF failed: %s\n", dds_strretcode (rc));
goto fail;
}
}
fail:
return rc;
}
static dds_return_t set_mc_options_transmit_ipv6 (struct ddsi_domaingv * const gv, ddsrt_socket_t sock)
{
#if DDSRT_HAVE_IPV6
const unsigned interfaceNo = gv->interfaceNo;
const unsigned ttl = (unsigned) gv->config.multicast_ttl;
const unsigned loop = (unsigned) !!gv->config.enableMulticastLoopback;
dds_return_t rc;
if ((rc = ddsrt_setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interfaceNo, sizeof (interfaceNo))) != DDS_RETCODE_OK)
GVERROR ("ddsi_udp_create_conn: set IPV6_MULTICAST_IF failed: %s\n", dds_strretcode (rc));
else if ((rc = ddsrt_setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl, sizeof (ttl))) != DDS_RETCODE_OK)
GVERROR ("ddsi_udp_create_conn: set IPV6_MULTICAST_HOPS failed: %s\n", dds_strretcode (rc));
else if ((rc = ddsrt_setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof (loop))) != DDS_RETCODE_OK)
GVERROR ("ddsi_udp_create_conn: set IPV6_MULTICAST_LOOP failed: %s\n", dds_strretcode (rc));
return rc;
#else
(void) gv; (void) sock;
return DDS_RETCODE_ERROR;
#endif
}
static dds_return_t set_mc_options_transmit_ipv4_if (struct ddsi_domaingv * const gv, ddsrt_socket_t sock)
{
#if (defined(__linux) || defined(__APPLE__)) && !LWIP_SOCKET
if (gv->config.use_multicast_if_mreqn)
{
struct ip_mreqn mreqn;
memset (&mreqn, 0, sizeof (mreqn));
/* looks like imr_multiaddr is not relevant, not sure about imr_address */
mreqn.imr_multiaddr.s_addr = htonl (INADDR_ANY);
if (gv->config.use_multicast_if_mreqn > 1)
memcpy (&mreqn.imr_address.s_addr, gv->ownloc.address + 12, 4);
else
mreqn.imr_address.s_addr = htonl (INADDR_ANY);
mreqn.imr_ifindex = (int) gv->interfaceNo;
return ddsrt_setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof (mreqn));
}
#endif
return ddsrt_setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, gv->ownloc.address + 12, 4);
}
static dds_return_t set_mc_options_transmit_ipv4 (struct ddsi_domaingv * const gv, ddsrt_socket_t sock)
{
const unsigned char ttl = (unsigned char) gv->config.multicast_ttl;
const unsigned char loop = (unsigned char) !!gv->config.enableMulticastLoopback;
dds_return_t rc;
if ((rc = set_mc_options_transmit_ipv4_if (gv, sock)) != DDS_RETCODE_OK)
GVERROR ("ddsi_udp_create_conn: set IP_MULTICAST_IF failed: %s\n", dds_strretcode (rc));
else if ((rc = ddsrt_setsockopt (sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttl, sizeof (ttl))) != DDS_RETCODE_OK)
GVERROR ("ddsi_udp_create_conn: set IP_MULTICAST_TTL failed: %s\n", dds_strretcode (rc));
else if ((rc = ddsrt_setsockopt (sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof (loop))) != DDS_RETCODE_OK)
GVERROR ("ddsi_udp_create_conn: set IP_MULTICAST_LOOP failed: %s\n", dds_strretcode (rc));
return rc;
} }
static ddsi_tran_conn_t ddsi_udp_create_conn (ddsi_tran_factory_t fact, uint32_t port, const ddsi_tran_qos_t *qos) static ddsi_tran_conn_t ddsi_udp_create_conn (ddsi_tran_factory_t fact, uint32_t port, const ddsi_tran_qos_t *qos)
{ {
int ret; struct ddsi_domaingv * const gv = fact->gv;
const int one = 1;
dds_return_t rc;
ddsrt_socket_t sock; ddsrt_socket_t sock;
ddsi_udp_conn_t uc = NULL; bool reuse_addr = false, bind_to_any = false, ipv6 = false;
bool reuse_addr = false, bind_to_any = false;
const char *purpose_str = NULL; const char *purpose_str = NULL;
switch (qos->m_purpose) switch (qos->m_purpose)
@ -246,57 +406,134 @@ static ddsi_tran_conn_t ddsi_udp_create_conn (ddsi_tran_factory_t fact, uint32_t
} }
assert (purpose_str != NULL); assert (purpose_str != NULL);
/* If port is zero, need to create dynamic port */
ret = make_socket (&sock, (unsigned short) port, false, reuse_addr, bind_to_any, fact->gv);
if (ret == 0)
{ {
uc = (ddsi_udp_conn_t) ddsrt_malloc (sizeof (*uc)); int af = AF_UNSPEC;
memset (uc, 0, sizeof (*uc)); switch (fact->m_kind)
{
uc->m_sock = sock; case NN_LOCATOR_KIND_UDPv4:
uc->m_diffserv = qos->m_diffserv; af = AF_INET;
#if defined _WIN32 && !defined WINCE break;
uc->m_sockEvent = WSACreateEvent(); #if DDSRT_HAVE_IPV6
WSAEventSelect(uc->m_sock, uc->m_sockEvent, FD_WRITE); case NN_LOCATOR_KIND_UDPv6:
af = AF_INET6;
ipv6 = true;
break;
#endif #endif
default:
DDS_FATAL ("ddsi_udp_create_conn: unsupported kind %"PRId32"\n", fact->m_kind);
}
assert (af != AF_UNSPEC);
if ((rc = ddsrt_socket (&sock, af, SOCK_DGRAM, 0)) != DDS_RETCODE_OK)
{
GVERROR ("ddsi_udp_create_conn: failed to create socket: %s\n", dds_strretcode (rc));
goto fail;
}
}
ddsi_factory_conn_init (fact, &uc->m_base); if (reuse_addr && (rc = ddsrt_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one))) != DDS_RETCODE_OK)
uc->m_base.m_base.m_port = get_socket_port (&fact->gv->logconfig, sock); {
uc->m_base.m_base.m_trantype = DDSI_TRAN_CONN; GVERROR ("ddsi_udp_create_conn: failed to enable address reuse: %s\n", dds_strretcode (rc));
uc->m_base.m_base.m_multicast = (qos->m_purpose == DDSI_TRAN_QOS_RECV_MC); if (rc != DDS_RETCODE_BAD_PARAMETER)
uc->m_base.m_base.m_handle_fn = ddsi_udp_conn_handle; {
/* There must at some point have been an implementation that refused to do SO_REUSEADDR, but I
don't know which */
goto fail_w_socket;
}
}
uc->m_base.m_read_fn = ddsi_udp_conn_read; if ((rc = set_rcvbuf (gv, sock, &gv->config.socket_min_rcvbuf_size)) != DDS_RETCODE_OK)
uc->m_base.m_write_fn = ddsi_udp_conn_write; goto fail_w_socket;
uc->m_base.m_disable_multiplexing_fn = ddsi_udp_disable_multiplexing; if ((rc = set_sndbuf (gv, sock, gv->config.socket_min_sndbuf_size)) != DDS_RETCODE_OK)
uc->m_base.m_locator_fn = ddsi_udp_conn_locator; goto fail_w_socket;
if (gv->config.dontRoute && (rc = set_dont_route (gv, sock, ipv6)) != DDS_RETCODE_OK)
goto fail_w_socket;
{
union {
struct sockaddr_storage x;
struct sockaddr_in a4;
struct sockaddr_in6 a6;
} socketname;
nn_locator_t ownloc_w_port = gv->ownloc;
assert (ownloc_w_port.port == NN_LOCATOR_PORT_INVALID);
if (port) {
/* PORT_INVALID maps to 0 in ipaddr_from_loc */
ownloc_w_port.port = port;
}
ddsi_ipaddr_from_loc (&socketname.x, &ownloc_w_port);
if (bind_to_any)
{
switch (fact->m_kind)
{
case NN_LOCATOR_KIND_UDPv4:
socketname.a4.sin_addr.s_addr = htonl (INADDR_ANY);
break;
#if DDSRT_HAVE_IPV6
case NN_LOCATOR_KIND_UDPv6:
socketname.a6.sin6_addr = ddsrt_in6addr_any;
break;
#endif
default:
DDS_FATAL ("ddsi_udp_create_conn: unsupported kind %"PRId32"\n", fact->m_kind);
}
}
if ((rc = ddsrt_bind (sock, (struct sockaddr *) &socketname, ddsrt_sockaddr_get_size ((struct sockaddr *) &socketname))) != DDS_RETCODE_OK)
{
char buf[DDSI_LOCATORSTRLEN];
if (bind_to_any)
snprintf (buf, sizeof (buf), "ANY:%"PRIu32, port);
else
ddsi_locator_to_string (buf, sizeof (buf), &ownloc_w_port);
GVERROR ("ddsi_udp_create_conn: failed to bind to %s: %s\n", buf, dds_strretcode (rc));
goto fail_w_socket;
}
}
rc = ipv6 ? set_mc_options_transmit_ipv6 (gv, sock) : set_mc_options_transmit_ipv4 (gv, sock);
if (rc != DDS_RETCODE_OK)
goto fail_w_socket;
DDS_CTRACE (&fact->gv->logconfig,
"ddsi_udp_create_conn %s socket %"PRIdSOCK" port %"PRIu32"\n",
purpose_str,
uc->m_sock,
uc->m_base.m_base.m_port);
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS #ifdef DDSI_INCLUDE_NETWORK_CHANNELS
if ((uc->m_diffserv != 0) && (fact->m_kind == NN_LOCATOR_KIND_UDPv4)) if ((qos->m_diffserv != 0) && (fact->m_kind == NN_LOCATOR_KIND_UDPv4))
{
dds_return_t rc;
rc = ddsrt_setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&uc->m_diffserv, sizeof(uc->m_diffserv));
if (rc != DDS_RETCODE_OK)
DDS_CERROR (fact->gv->logconfig, "ddsi_udp_create_conn: set diffserv retcode %"PRId32"\n", rc);
}
#endif
}
else
{ {
if (fact->gv->config.participantIndex != PARTICIPANT_INDEX_AUTO) if ((rc = ddsrt_setsockopt (sock, IPPROTO_IP, IP_TOS, (char *) &qos->m_diffserv, sizeof (qos->m_diffserv))) != DDS_RETCODE_OK)
{ {
DDS_CERROR (&fact->gv->logconfig, "UDP make_socket failed for %s port %"PRIu32"\n", purpose_str, port); GVERROR ("ddsi_udp_create_conn: set diffserv retcode %"PRId32"\n", rc);
goto fail_w_socket;
} }
} }
#endif
return uc ? &uc->m_base : NULL; ddsi_udp_conn_t uc = (ddsi_udp_conn_t) ddsrt_malloc (sizeof (*uc));
memset (uc, 0, sizeof (*uc));
uc->m_sock = sock;
uc->m_diffserv = qos->m_diffserv;
#if defined _WIN32 && !defined WINCE
uc->m_sockEvent = WSACreateEvent();
WSAEventSelect(uc->m_sock, uc->m_sockEvent, FD_WRITE);
#endif
ddsi_factory_conn_init (fact, &uc->m_base);
uc->m_base.m_base.m_port = get_socket_port (gv, sock);
uc->m_base.m_base.m_trantype = DDSI_TRAN_CONN;
uc->m_base.m_base.m_multicast = (qos->m_purpose == DDSI_TRAN_QOS_RECV_MC);
uc->m_base.m_base.m_handle_fn = ddsi_udp_conn_handle;
uc->m_base.m_read_fn = ddsi_udp_conn_read;
uc->m_base.m_write_fn = ddsi_udp_conn_write;
uc->m_base.m_disable_multiplexing_fn = ddsi_udp_disable_multiplexing;
uc->m_base.m_locator_fn = ddsi_udp_conn_locator;
GVTRACE ("ddsi_udp_create_conn %s socket %"PRIdSOCK" port %"PRIu32"\n", purpose_str, uc->m_sock, uc->m_base.m_base.m_port);
return &uc->m_base;
fail_w_socket:
ddsrt_close (sock);
fail:
if (fact->gv->config.participantIndex != PARTICIPANT_INDEX_AUTO)
GVERROR ("ddsi_udp_create_conn: failed for %s port %"PRIu32"\n", purpose_str, port);
return NULL;
} }
static int joinleave_asm_mcgroup (ddsrt_socket_t socket, int join, const nn_locator_t *mcloc, const struct nn_interface *interf) static int joinleave_asm_mcgroup (ddsrt_socket_t socket, int join, const nn_locator_t *mcloc, const struct nn_interface *interf)

View file

@ -30,7 +30,6 @@
#include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_unused.h"
#include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_misc.h"
#include "dds/ddsi/q_addrset.h" #include "dds/ddsi/q_addrset.h"
#include "dds/ddsi/q_nwif.h"
#include "dds/ddsrt/xmlparser.h" #include "dds/ddsrt/xmlparser.h"

View file

@ -41,7 +41,7 @@
#include "dds/ddsi/q_lease.h" #include "dds/ddsi/q_lease.h"
#include "dds/ddsi/q_gc.h" #include "dds/ddsi/q_gc.h"
#include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_entity.h"
#include "dds/ddsi/q_nwif.h" #include "dds/ddsi/ddsi_ownip.h"
#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_domaingv.h"
#include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_xmsg.h"
#include "dds/ddsi/q_receive.h" #include "dds/ddsi/q_receive.h"

View file

@ -1,687 +0,0 @@
/*
* Copyright(c) 2006 to 2018 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 <ctype.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "dds/ddsrt/ifaddrs.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/md5.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsrt/sockets.h"
#include "dds/ddsi/q_log.h"
#include "dds/ddsi/q_nwif.h"
#include "dds/ddsi/ddsi_domaingv.h"
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_unused.h"
#include "dds/ddsi/q_misc.h"
#include "dds/ddsi/q_addrset.h" /* unspec locator */
#include "dds/ddsi/q_feature_check.h"
#include "dds/ddsi/ddsi_ipaddr.h"
#include "dds/ddsrt/avl.h"
static void print_sockerror (const struct ddsrt_log_cfg *logcfg, const char *msg)
{
DDS_CERROR (logcfg, "SOCKET %s\n", msg);
}
uint32_t locator_to_hopefully_unique_uint32 (const nn_locator_t *src)
{
uint32_t id = 0;
if (src->kind == NN_LOCATOR_KIND_UDPv4 || src->kind == NN_LOCATOR_KIND_TCPv4)
memcpy (&id, src->address + 12, sizeof (id));
else
{
#if DDSRT_HAVE_IPV6
ddsrt_md5_state_t st;
ddsrt_md5_byte_t digest[16];
ddsrt_md5_init (&st);
ddsrt_md5_append (&st, (const ddsrt_md5_byte_t *) ((const struct sockaddr_in6 *) src)->sin6_addr.s6_addr, 16);
ddsrt_md5_finish (&st, digest);
memcpy (&id, digest, sizeof (id));
#else
DDS_FATAL ("IPv6 unavailable\n");
#endif
}
return id;
}
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
void set_socket_diffserv (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t sock, int diffserv)
{
if (ddsrt_setsockopt (sock, IPPROTO_IP, IP_TOS, (char*) &diffserv, sizeof (diffserv)) != DDS_RETCODE_OK)
{
print_sockerror (logcfg, "IP_TOS");
}
}
#endif
#ifdef SO_NOSIGPIPE
static void set_socket_nosigpipe (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t sock)
{
int val = 1;
if (ddsrt_setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, (char*) &val, sizeof (val)) != DDS_RETCODE_OK)
{
print_sockerror (logcfg, "SO_NOSIGPIPE");
}
}
#endif
#ifdef TCP_NODELAY
static void set_socket_nodelay (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t sock)
{
int val = 1;
if (ddsrt_setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char*) &val, sizeof (val)) != DDS_RETCODE_OK)
{
print_sockerror (logcfg, "TCP_NODELAY");
}
}
#endif
static int set_rcvbuf (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket, const struct config_maybe_uint32 *min_size)
{
uint32_t ReceiveBufferSize;
socklen_t optlen = (socklen_t) sizeof (ReceiveBufferSize);
uint32_t socket_min_rcvbuf_size;
dds_return_t rc;
if (min_size->isdefault)
socket_min_rcvbuf_size = 1048576;
else
socket_min_rcvbuf_size = min_size->value;
rc = ddsrt_getsockopt(
socket, SOL_SOCKET, SO_RCVBUF, (char *) &ReceiveBufferSize, &optlen);
/* TCP/IP stack may not support SO_RCVBUF. */
if (rc == DDS_RETCODE_BAD_PARAMETER) {
DDS_CLOG (DDS_LC_CONFIG, logcfg, "cannot retrieve socket receive buffer size\n");
return 0;
} else if (rc != DDS_RETCODE_OK) {
print_sockerror (logcfg, "get SO_RCVBUF");
return -2;
}
if (ReceiveBufferSize < socket_min_rcvbuf_size)
{
/* make sure the receive buffersize is at least the minimum required */
ReceiveBufferSize = socket_min_rcvbuf_size;
(void) ddsrt_setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (const char *) &ReceiveBufferSize, sizeof (ReceiveBufferSize));
/* We don't check the return code from setsockopt, because some O/Ss tend
to silently cap the buffer size. The only way to make sure is to read
the option value back and check it is now set correctly. */
if (ddsrt_getsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) &ReceiveBufferSize, &optlen) != DDS_RETCODE_OK)
{
print_sockerror (logcfg, "get SO_RCVBUF");
return -2;
}
if (ReceiveBufferSize < socket_min_rcvbuf_size)
{
/* NN_ERROR does more than just DDS_ERROR(), hence the duplication */
DDS_CLOG (min_size->isdefault ? DDS_LC_CONFIG : DDS_LC_ERROR, logcfg,
"failed to increase socket receive buffer size to %"PRIu32" bytes, continuing with %"PRIu32" bytes\n",
socket_min_rcvbuf_size, ReceiveBufferSize);
}
else
{
DDS_CLOG (DDS_LC_CONFIG, logcfg, "socket receive buffer size set to %"PRIu32" bytes\n", ReceiveBufferSize);
}
}
return 0;
}
static int set_sndbuf (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket, uint32_t min_size)
{
unsigned SendBufferSize;
socklen_t optlen = (socklen_t) sizeof(SendBufferSize);
dds_return_t rc;
rc = ddsrt_getsockopt(
socket, SOL_SOCKET, SO_SNDBUF,(char *)&SendBufferSize, &optlen);
if (rc == DDS_RETCODE_BAD_PARAMETER) {
DDS_CLOG (DDS_LC_CONFIG, logcfg, "cannot retrieve socket send buffer size\n");
return 0;
} else if (rc != DDS_RETCODE_OK) {
print_sockerror (logcfg, "get SO_SNDBUF");
return -2;
}
if (SendBufferSize < min_size )
{
/* make sure the send buffersize is at least the minimum required */
SendBufferSize = min_size;
if (ddsrt_setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (const char *)&SendBufferSize, sizeof (SendBufferSize)) != DDS_RETCODE_OK)
{
print_sockerror (logcfg, "SO_SNDBUF");
return -2;
}
}
return 0;
}
static int maybe_set_dont_route (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket, const struct config *config)
{
if (config->dontRoute)
{
#if DDSRT_HAVE_IPV6
if (config->transport_selector == TRANS_TCP6 || config->transport_selector == TRANS_UDP6)
{
unsigned ipv6Flag = 1;
if (ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ipv6Flag, sizeof (ipv6Flag)) != DDS_RETCODE_OK)
{
print_sockerror (logcfg, "IPV6_UNICAST_HOPS");
return -2;
}
}
else
#endif
if (config->transport_selector == TRANS_TCP || config->transport_selector == TRANS_UDP)
{
int one = 1;
if (ddsrt_setsockopt (socket, SOL_SOCKET, SO_DONTROUTE, (char *) &one, sizeof (one)) != DDS_RETCODE_OK)
{
print_sockerror (logcfg, "SO_DONTROUTE");
return -2;
}
}
}
return 0;
}
static int set_reuse_options (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket)
{
/* Set REUSEADDR (if available on platform) for
multicast sockets, leave unicast sockets alone. */
int one = 1;
dds_return_t rc = ddsrt_setsockopt (
socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one));
if (rc == DDS_RETCODE_BAD_PARAMETER) {
DDS_CLOG (DDS_LC_CONFIG, logcfg, "cannot enable address reuse on socket\n");
return 0;
} else if (rc != DDS_RETCODE_OK) {
print_sockerror (logcfg, "SO_REUSEADDR");
return -2;
}
return 0;
}
static int bind_socket (ddsrt_socket_t socket, unsigned short port, bool bind_to_any, const struct ddsi_domaingv *gv)
{
dds_return_t rc = DDS_RETCODE_ERROR;
#if DDSRT_HAVE_IPV6
if (gv->config.transport_selector == TRANS_TCP6 || gv->config.transport_selector == TRANS_UDP6)
{
union {
struct sockaddr_storage x;
struct sockaddr_in6 a;
} socketname;
ddsi_ipaddr_from_loc (&socketname.x, &gv->ownloc);
if (bind_to_any)
socketname.a.sin6_addr = ddsrt_in6addr_any;
socketname.a.sin6_port = htons (port);
if (IN6_IS_ADDR_LINKLOCAL (&socketname.a.sin6_addr)) {
socketname.a.sin6_scope_id = gv->interfaceNo;
}
rc = ddsrt_bind (socket, (struct sockaddr *) &socketname.a, sizeof (socketname.a));
}
else
#endif
if (gv->config.transport_selector == TRANS_TCP || gv->config.transport_selector == TRANS_UDP)
{
union {
struct sockaddr_storage x;
struct sockaddr_in a;
} socketname;
ddsi_ipaddr_from_loc (&socketname.x, &gv->ownloc);
if (bind_to_any)
socketname.a.sin_addr.s_addr = htonl (INADDR_ANY);
socketname.a.sin_port = htons (port);
rc = ddsrt_bind (socket, (struct sockaddr *) &socketname.a, sizeof (socketname.a));
}
if (rc != DDS_RETCODE_OK && rc != DDS_RETCODE_PRECONDITION_NOT_MET)
{
print_sockerror (&gv->logconfig, "bind");
}
return (rc == DDS_RETCODE_OK) ? 0 : -1;
}
#if DDSRT_HAVE_IPV6
static int set_mc_options_transmit_ipv6 (ddsrt_socket_t socket, const struct ddsi_domaingv *gv)
{
unsigned interfaceNo = gv->interfaceNo;
unsigned ttl = (unsigned) gv->config.multicast_ttl;
unsigned loop;
if (ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interfaceNo, sizeof (interfaceNo)) != DDS_RETCODE_OK)
{
print_sockerror (&gv->logconfig, "IPV6_MULTICAST_IF");
return -2;
}
if (ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl, sizeof (ttl)) != DDS_RETCODE_OK)
{
print_sockerror (&gv->logconfig, "IPV6_MULTICAST_HOPS");
return -2;
}
loop = (unsigned) !!gv->config.enableMulticastLoopback;
if (ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof (loop)) != DDS_RETCODE_OK)
{
print_sockerror (&gv->logconfig, "IPV6_MULTICAST_LOOP");
return -2;
}
return 0;
}
#endif
static int set_mc_options_transmit_ipv4 (ddsrt_socket_t socket, const struct ddsi_domaingv *gv)
{
unsigned char ttl = (unsigned char) gv->config.multicast_ttl;
unsigned char loop;
dds_return_t ret;
#if (defined(__linux) || defined(__APPLE__)) && !LWIP_SOCKET
if (gv->config.use_multicast_if_mreqn)
{
struct ip_mreqn mreqn;
memset (&mreqn, 0, sizeof (mreqn));
/* looks like imr_multiaddr is not relevant, not sure about imr_address */
mreqn.imr_multiaddr.s_addr = htonl (INADDR_ANY);
if (gv->config.use_multicast_if_mreqn > 1)
memcpy (&mreqn.imr_address.s_addr, gv->ownloc.address + 12, 4);
else
mreqn.imr_address.s_addr = htonl (INADDR_ANY);
mreqn.imr_ifindex = (int) gv->interfaceNo;
ret = ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof (mreqn));
}
else
#endif
{
ret = ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, gv->ownloc.address + 12, 4);
}
if (ret != DDS_RETCODE_OK)
{
print_sockerror (&gv->logconfig, "IP_MULTICAST_IF");
return -2;
}
if (ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttl, sizeof (ttl)) != DDS_RETCODE_OK)
{
print_sockerror (&gv->logconfig, "IP_MULICAST_TTL");
return -2;
}
loop = (unsigned char) gv->config.enableMulticastLoopback;
if (ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof (loop)) != DDS_RETCODE_OK)
{
print_sockerror (&gv->logconfig, "IP_MULTICAST_LOOP");
return -2;
}
return 0;
}
static int set_mc_options_transmit (ddsrt_socket_t socket, const struct ddsi_domaingv *gv)
{
#if DDSRT_HAVE_IPV6
if (gv->config.transport_selector == TRANS_TCP6 || gv->config.transport_selector == TRANS_UDP6)
{
return set_mc_options_transmit_ipv6 (socket, gv);
}
else
#endif
if (gv->config.transport_selector == TRANS_TCP || gv->config.transport_selector == TRANS_UDP)
{
return set_mc_options_transmit_ipv4 (socket, gv);
}
else
{
return -2;
}
}
int make_socket (ddsrt_socket_t *sock, uint16_t port, bool stream, bool reuse_addr, bool bind_to_any, const struct ddsi_domaingv *gv)
{
/* FIXME: this stuff has to move to the transports */
int rc = -2;
dds_return_t ret;
#if DDSRT_HAVE_IPV6
if (gv->config.transport_selector == TRANS_TCP6 || gv->config.transport_selector == TRANS_UDP6)
{
ret = ddsrt_socket(sock, AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
}
else
#endif
if (gv->config.transport_selector == TRANS_TCP || gv->config.transport_selector == TRANS_UDP)
{
ret = ddsrt_socket(sock, AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
}
else
{
return -2;
}
if (ret != DDS_RETCODE_OK)
{
print_sockerror (&gv->logconfig, "socket");
return rc;
}
if (port && reuse_addr && ((rc = set_reuse_options (&gv->logconfig, *sock)) < 0))
{
goto fail;
}
if ((rc = set_rcvbuf (&gv->logconfig, *sock, &gv->config.socket_min_rcvbuf_size) < 0) ||
(rc = set_sndbuf (&gv->logconfig, *sock, gv->config.socket_min_sndbuf_size) < 0) ||
((rc = maybe_set_dont_route (&gv->logconfig, *sock, &gv->config)) < 0) ||
((rc = bind_socket (*sock, port, bind_to_any, gv)) < 0))
{
goto fail;
}
if (! stream)
{
if ((rc = set_mc_options_transmit (*sock, gv)) < 0)
{
goto fail;
}
}
if (stream)
{
#ifdef SO_NOSIGPIPE
set_socket_nosigpipe (&gv->logconfig, *sock);
#endif
#ifdef TCP_NODELAY
if (gv->config.tcp_nodelay)
{
set_socket_nodelay (&gv->logconfig, *sock);
}
#endif
}
return 0;
fail:
ddsrt_close(*sock);
*sock = DDSRT_INVALID_SOCKET;
return rc;
}
static int multicast_override(const char *ifname, const struct config *config)
{
char *copy = ddsrt_strdup (config->assumeMulticastCapable), *cursor = copy, *tok;
int match = 0;
if (copy != NULL)
{
while ((tok = ddsrt_strsep (&cursor, ",")) != NULL)
{
if (ddsi2_patmatch (tok, ifname))
match = 1;
}
}
ddsrt_free (copy);
return match;
}
#ifdef __linux
/* FIMXE: HACK HACK */
#include <linux/if_packet.h>
#endif
int find_own_ip (struct ddsi_domaingv *gv, const char *requested_address)
{
const char *sep = " ";
char last_if_name[80] = "";
int quality = -1;
int i;
ddsrt_ifaddrs_t *ifa, *ifa_root = NULL;
int maxq_list[MAX_INTERFACES];
int maxq_count = 0;
size_t maxq_strlen = 0;
int selected_idx = -1;
char addrbuf[DDSI_LOCSTRLEN];
GVLOG (DDS_LC_CONFIG, "interfaces:");
{
int ret;
ret = ddsi_enumerate_interfaces(gv->m_factory, gv->config.transport_selector, &ifa_root);
if (ret < 0) {
GVERROR ("ddsi_enumerate_interfaces(%s): %d\n", gv->m_factory->m_typename, ret);
return 0;
}
}
gv->n_interfaces = 0;
last_if_name[0] = 0;
for (ifa = ifa_root; ifa != NULL; ifa = ifa->next)
{
char if_name[sizeof (last_if_name)];
int q = 0;
(void) ddsrt_strlcpy(if_name, ifa->name, sizeof(if_name));
if (strcmp (if_name, last_if_name))
GVLOG (DDS_LC_CONFIG, "%s%s", sep, if_name);
(void) ddsrt_strlcpy(last_if_name, if_name, sizeof(last_if_name));
/* interface must be up */
if ((ifa->flags & IFF_UP) == 0) {
GVLOG (DDS_LC_CONFIG, " (interface down)");
continue;
} else if (ddsrt_sockaddr_isunspecified(ifa->addr)) {
GVLOG (DDS_LC_CONFIG, " (address unspecified)");
continue;
}
switch (ifa->type)
{
case DDSRT_IFTYPE_WIFI:
DDS_LOG(DDS_LC_CONFIG, " wireless");
break;
case DDSRT_IFTYPE_WIRED:
DDS_LOG(DDS_LC_CONFIG, " wired");
break;
case DDSRT_IFTYPE_UNKNOWN:
break;
}
#if defined(__linux) && !LWIP_SOCKET
if (ifa->addr->sa_family == AF_PACKET)
{
/* FIXME: weirdo warning warranted */
nn_locator_t *l = &gv->interfaces[gv->n_interfaces].loc;
l->kind = NN_LOCATOR_KIND_RAWETH;
l->port = NN_LOCATOR_PORT_INVALID;
memset(l->address, 0, 10);
memcpy(l->address + 10, ((struct sockaddr_ll *)ifa->addr)->sll_addr, 6);
}
else
#endif
{
ddsi_ipaddr_to_loc(gv->m_factory, &gv->interfaces[gv->n_interfaces].loc, ifa->addr, gv->m_factory->m_kind);
}
ddsi_locator_to_string_no_port(addrbuf, sizeof(addrbuf), &gv->interfaces[gv->n_interfaces].loc);
GVLOG (DDS_LC_CONFIG, " %s(", addrbuf);
if (!(ifa->flags & IFF_MULTICAST) && multicast_override (if_name, &gv->config))
{
GVLOG (DDS_LC_CONFIG, "assume-mc:");
ifa->flags |= IFF_MULTICAST;
}
if (ifa->flags & IFF_LOOPBACK)
{
/* Loopback device has the lowest priority of every interface
available, because the other interfaces at least in principle
allow communicating with other machines. */
q += 0;
#if DDSRT_HAVE_IPV6
if (!(ifa->addr->sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *)ifa->addr)->sin6_addr)))
q += 1;
#endif
}
else
{
#if DDSRT_HAVE_IPV6
/* We accept link-local IPv6 addresses, but an interface with a
link-local address will end up lower in the ordering than one
with a global address. When forced to use a link-local
address, we restrict ourselves to operating on that one
interface only and assume any advertised (incoming) link-local
address belongs to that interface. FIXME: this is wrong, and
should be changed to tag addresses with the interface over
which it was received. But that means proper multi-homing
support and has quite an impact in various places, not least of
which is the abstraction layer. */
if (!(ifa->addr->sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *)ifa->addr)->sin6_addr)))
q += 5;
#endif
/* We strongly prefer a multicast capable interface, if that's
not available anything that's not point-to-point, or else we
hope IP routing will take care of the issues. */
if (ifa->flags & IFF_MULTICAST)
q += 4;
else if (!(ifa->flags & IFF_POINTOPOINT))
q += 3;
else
q += 2;
}
GVLOG (DDS_LC_CONFIG, "q%d)", q);
if (q == quality) {
maxq_list[maxq_count] = gv->n_interfaces;
maxq_strlen += 2 + strlen (if_name);
maxq_count++;
} else if (q > quality) {
maxq_list[0] = gv->n_interfaces;
maxq_strlen += 2 + strlen (if_name);
maxq_count = 1;
quality = q;
}
if (ifa->addr->sa_family == AF_INET && ifa->netmask)
{
ddsi_ipaddr_to_loc(gv->m_factory, &gv->interfaces[gv->n_interfaces].netmask, ifa->netmask, gv->m_factory->m_kind);
}
else
{
gv->interfaces[gv->n_interfaces].netmask.kind = gv->m_factory->m_kind;
gv->interfaces[gv->n_interfaces].netmask.port = NN_LOCATOR_PORT_INVALID;
memset(&gv->interfaces[gv->n_interfaces].netmask.address, 0, sizeof(gv->interfaces[gv->n_interfaces].netmask.address));
}
gv->interfaces[gv->n_interfaces].mc_capable = ((ifa->flags & IFF_MULTICAST) != 0);
gv->interfaces[gv->n_interfaces].mc_flaky = ((ifa->type == DDSRT_IFTYPE_WIFI) != 0);
gv->interfaces[gv->n_interfaces].point_to_point = ((ifa->flags & IFF_POINTOPOINT) != 0);
gv->interfaces[gv->n_interfaces].if_index = ifa->index;
gv->interfaces[gv->n_interfaces].name = ddsrt_strdup (if_name);
gv->n_interfaces++;
}
GVLOG (DDS_LC_CONFIG, "\n");
ddsrt_freeifaddrs (ifa_root);
if (requested_address == NULL)
{
if (maxq_count > 1)
{
const int idx = maxq_list[0];
char *names;
int p;
ddsi_locator_to_string_no_port (addrbuf, sizeof(addrbuf), &gv->interfaces[idx].loc);
names = ddsrt_malloc (maxq_strlen + 1);
p = 0;
for (i = 0; i < maxq_count && (size_t) p < maxq_strlen; i++)
p += snprintf (names + p, maxq_strlen - (size_t) p, ", %s", gv->interfaces[maxq_list[i]].name);
GVWARNING ("using network interface %s (%s) selected arbitrarily from: %s\n",
gv->interfaces[idx].name, addrbuf, names + 2);
ddsrt_free (names);
}
if (maxq_count > 0)
selected_idx = maxq_list[0];
else
GVERROR ("failed to determine default own IP address\n");
}
else
{
nn_locator_t req;
/* Presumably an interface name */
for (i = 0; i < gv->n_interfaces; i++)
{
if (strcmp (gv->interfaces[i].name, gv->config.networkAddressString) == 0)
break;
}
if (i < gv->n_interfaces)
; /* got a match */
else if (ddsi_locator_from_string(gv, &req, gv->config.networkAddressString, gv->m_factory) != AFSR_OK)
; /* not good, i = gv->n_interfaces, so error handling will kick in */
else
{
/* Try an exact match on the address */
for (i = 0; i < gv->n_interfaces; i++)
if (compare_locators(&gv->interfaces[i].loc, &req) == 0)
break;
if (i == gv->n_interfaces && req.kind == NN_LOCATOR_KIND_UDPv4)
{
/* Try matching on network portion only, where the network
portion is based on the netmask of the interface under
consideration */
for (i = 0; i < gv->n_interfaces; i++)
{
uint32_t req1, ip1, nm1;
memcpy (&req1, req.address + 12, sizeof (req1));
memcpy (&ip1, gv->interfaces[i].loc.address + 12, sizeof (ip1));
memcpy (&nm1, gv->interfaces[i].netmask.address + 12, sizeof (nm1));
/* If the host portion of the requested address is non-zero,
skip this interface */
if (req1 & ~nm1)
continue;
if ((req1 & nm1) == (ip1 & nm1))
break;
}
}
}
if (i < gv->n_interfaces)
selected_idx = i;
else
GVERROR ("%s: does not match an available interface\n", gv->config.networkAddressString);
}
if (selected_idx < 0)
return 0;
else
{
gv->ownloc = gv->interfaces[selected_idx].loc;
gv->selected_interface = selected_idx;
gv->interfaceNo = gv->interfaces[selected_idx].if_index;
#if DDSRT_HAVE_IPV6
if (gv->extloc.kind == NN_LOCATOR_KIND_TCPv6 || gv->extloc.kind == NN_LOCATOR_KIND_UDPv6)
{
struct sockaddr_in6 addr;
memcpy(&addr.sin6_addr, gv->ownloc.address, sizeof(addr.sin6_addr));
gv->ipv6_link_local = IN6_IS_ADDR_LINKLOCAL (&addr.sin6_addr) != 0;
}
else
{
gv->ipv6_link_local = 0;
}
#endif
GVLOG (DDS_LC_CONFIG, "selected interface: %s (index %u)\n",
gv->interfaces[selected_idx].name, gv->interfaceNo);
return 1;
}
}