Move all socket creation stuff to transport code
Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
59459b9b8b
commit
4df38f5bf9
11 changed files with 758 additions and 834 deletions
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
|
@ -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"
|
||||||
|
|
||||||
|
|
304
src/core/ddsi/src/ddsi_ownip.c
Normal file
304
src/core/ddsi/src/ddsi_ownip.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
||||||
|
|
|
@ -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,21 +932,17 @@ 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;
|
dds_return_t ret;
|
||||||
tl = (ddsi_tcp_listener_t) ddsrt_malloc (sizeof (*tl));
|
ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) ddsrt_malloc (sizeof (*tl));
|
||||||
memset (tl, 0, sizeof (*tl));
|
memset (tl, 0, sizeof (*tl));
|
||||||
|
|
||||||
tl->m_sock = sock;
|
tl->m_sock = sock;
|
||||||
|
@ -884,19 +957,20 @@ static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact,
|
||||||
tl->m_base.m_base.m_handle_fn = ddsi_tcp_listener_handle;
|
tl->m_base.m_base.m_handle_fn = ddsi_tcp_listener_handle;
|
||||||
tl->m_base.m_locator_fn = ddsi_tcp_locator;
|
tl->m_base.m_locator_fn = ddsi_tcp_locator;
|
||||||
|
|
||||||
ret = ddsrt_getsockname(sock, (struct sockaddr *)&addr, &addrlen);
|
struct sockaddr_storage addr;
|
||||||
if (ret != DDS_RETCODE_OK) {
|
socklen_t addrlen = sizeof (addr);
|
||||||
DDS_CERROR (&fact->gv->logconfig, "ddsi_tcp_create_listener: ddsrt_getsockname returned %"PRId32"\n", ret);
|
if ((ret = ddsrt_getsockname (sock, (struct sockaddr *) &addr, &addrlen)) != DDS_RETCODE_OK)
|
||||||
|
{
|
||||||
|
GVERROR ("ddsi_tcp_create_listener: ddsrt_getsockname returned %"PRId32"\n", ret);
|
||||||
ddsi_tcp_sock_free (&fact->gv->logconfig, sock, NULL);
|
ddsi_tcp_sock_free (&fact->gv->logconfig, sock, NULL);
|
||||||
ddsrt_free (tl);
|
ddsrt_free (tl);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char buff[DDSI_LOCSTRLEN];
|
||||||
sockaddr_to_string_with_port (fact_tcp, buff, sizeof (buff), (struct sockaddr *) &addr);
|
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);
|
GVLOG (DDS_LC_TCP, "tcp create listener socket %"PRIdSOCK" on %s\n", sock, buff);
|
||||||
}
|
return &tl->m_base;
|
||||||
|
|
||||||
return tl ? &tl->m_base : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ddsi_tcp_conn_delete (ddsi_tcp_conn_t conn)
|
static void ddsi_tcp_conn_delete (ddsi_tcp_conn_t conn)
|
||||||
|
@ -948,43 +1022,42 @@ 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;
|
struct sockaddr_storage addr;
|
||||||
socklen_t addrlen = sizeof (addr);
|
socklen_t addrlen = sizeof (addr);
|
||||||
|
if ((ret = ddsrt_getsockname (tl->m_sock, (struct sockaddr *) &addr, &addrlen)) != DDS_RETCODE_OK)
|
||||||
ret = ddsrt_getsockname(tl->m_sock, (struct sockaddr *)&addr, &addrlen);
|
|
||||||
if (ret != DDS_RETCODE_OK) {
|
|
||||||
DDS_CWARNING (&listener->m_base.gv->logconfig, "tcp failed to get listener address error %"PRId32"\n", ret);
|
|
||||||
} else {
|
|
||||||
switch (addr.ss_family) {
|
|
||||||
case AF_INET:
|
|
||||||
{
|
{
|
||||||
|
GVWARNING ("tcp failed to get listener address error %"PRId32"\n", ret);
|
||||||
|
goto fail_w_socket;
|
||||||
|
}
|
||||||
|
switch (addr.ss_family)
|
||||||
|
{
|
||||||
|
case AF_INET: {
|
||||||
struct sockaddr_in *socketname = (struct sockaddr_in *) &addr;
|
struct sockaddr_in *socketname = (struct sockaddr_in *) &addr;
|
||||||
if (socketname->sin_addr.s_addr == htonl (INADDR_ANY)) {
|
if (socketname->sin_addr.s_addr == htonl (INADDR_ANY))
|
||||||
socketname->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
socketname->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
#if DDSRT_HAVE_IPV6
|
#if DDSRT_HAVE_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6: {
|
||||||
{
|
|
||||||
struct sockaddr_in6 *socketname = (struct sockaddr_in6 *) &addr;
|
struct sockaddr_in6 *socketname = (struct sockaddr_in6 *) &addr;
|
||||||
if (memcmp(&socketname->sin6_addr, &ddsrt_in6addr_any, sizeof(socketname->sin6_addr)) == 0) {
|
if (memcmp (&socketname->sin6_addr, &ddsrt_in6addr_any, sizeof (socketname->sin6_addr)) == 0)
|
||||||
socketname->sin6_addr = ddsrt_in6addr_loopback;
|
socketname->sin6_addr = ddsrt_in6addr_loopback;
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
do
|
|
||||||
{
|
do {
|
||||||
ret = ddsrt_connect (sock, (struct sockaddr *) &addr, ddsrt_sockaddr_get_size ((struct sockaddr *) &addr));
|
ret = ddsrt_connect (sock, (struct sockaddr *) &addr, ddsrt_sockaddr_get_size ((struct sockaddr *) &addr));
|
||||||
} while (ret == DDS_RETCODE_INTERRUPTED);
|
} while (ret == DDS_RETCODE_INTERRUPTED);
|
||||||
if (ret != DDS_RETCODE_OK)
|
if (ret != DDS_RETCODE_OK)
|
||||||
|
@ -992,11 +1065,13 @@ static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener)
|
||||||
struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) listener->m_factory;
|
struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) listener->m_factory;
|
||||||
char buff[DDSI_LOCSTRLEN];
|
char buff[DDSI_LOCSTRLEN];
|
||||||
sockaddr_to_string_with_port (fact, buff, sizeof (buff), (struct sockaddr *) &addr);
|
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);
|
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);
|
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)
|
||||||
|
|
|
@ -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,13 +406,105 @@ 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;
|
||||||
|
switch (fact->m_kind)
|
||||||
|
{
|
||||||
|
case NN_LOCATOR_KIND_UDPv4:
|
||||||
|
af = AF_INET;
|
||||||
|
break;
|
||||||
|
#if DDSRT_HAVE_IPV6
|
||||||
|
case NN_LOCATOR_KIND_UDPv6:
|
||||||
|
af = AF_INET6;
|
||||||
|
ipv6 = true;
|
||||||
|
break;
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reuse_addr && (rc = ddsrt_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one))) != DDS_RETCODE_OK)
|
||||||
|
{
|
||||||
|
GVERROR ("ddsi_udp_create_conn: failed to enable address reuse: %s\n", dds_strretcode (rc));
|
||||||
|
if (rc != DDS_RETCODE_BAD_PARAMETER)
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc = set_rcvbuf (gv, sock, &gv->config.socket_min_rcvbuf_size)) != DDS_RETCODE_OK)
|
||||||
|
goto fail_w_socket;
|
||||||
|
if ((rc = set_sndbuf (gv, sock, gv->config.socket_min_sndbuf_size)) != DDS_RETCODE_OK)
|
||||||
|
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;
|
||||||
|
|
||||||
|
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
|
||||||
|
if ((qos->m_diffserv != 0) && (fact->m_kind == NN_LOCATOR_KIND_UDPv4))
|
||||||
|
{
|
||||||
|
if ((rc = ddsrt_setsockopt (sock, IPPROTO_IP, IP_TOS, (char *) &qos->m_diffserv, sizeof (qos->m_diffserv))) != DDS_RETCODE_OK)
|
||||||
|
{
|
||||||
|
GVERROR ("ddsi_udp_create_conn: set diffserv retcode %"PRId32"\n", rc);
|
||||||
|
goto fail_w_socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ddsi_udp_conn_t uc = (ddsi_udp_conn_t) ddsrt_malloc (sizeof (*uc));
|
||||||
memset (uc, 0, sizeof (*uc));
|
memset (uc, 0, sizeof (*uc));
|
||||||
|
|
||||||
uc->m_sock = sock;
|
uc->m_sock = sock;
|
||||||
|
@ -263,7 +515,7 @@ static ddsi_tran_conn_t ddsi_udp_create_conn (ddsi_tran_factory_t fact, uint32_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ddsi_factory_conn_init (fact, &uc->m_base);
|
ddsi_factory_conn_init (fact, &uc->m_base);
|
||||||
uc->m_base.m_base.m_port = get_socket_port (&fact->gv->logconfig, sock);
|
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_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_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_base.m_handle_fn = ddsi_udp_conn_handle;
|
||||||
|
@ -273,30 +525,15 @@ static ddsi_tran_conn_t ddsi_udp_create_conn (ddsi_tran_factory_t fact, uint32_t
|
||||||
uc->m_base.m_disable_multiplexing_fn = ddsi_udp_disable_multiplexing;
|
uc->m_base.m_disable_multiplexing_fn = ddsi_udp_disable_multiplexing;
|
||||||
uc->m_base.m_locator_fn = ddsi_udp_conn_locator;
|
uc->m_base.m_locator_fn = ddsi_udp_conn_locator;
|
||||||
|
|
||||||
DDS_CTRACE (&fact->gv->logconfig,
|
GVTRACE ("ddsi_udp_create_conn %s socket %"PRIdSOCK" port %"PRIu32"\n", purpose_str, uc->m_sock, uc->m_base.m_base.m_port);
|
||||||
"ddsi_udp_create_conn %s socket %"PRIdSOCK" port %"PRIu32"\n",
|
return &uc->m_base;
|
||||||
purpose_str,
|
|
||||||
uc->m_sock,
|
|
||||||
uc->m_base.m_base.m_port);
|
|
||||||
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
|
|
||||||
if ((uc->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)
|
|
||||||
{
|
|
||||||
DDS_CERROR (&fact->gv->logconfig, "UDP make_socket failed for %s port %"PRIu32"\n", purpose_str, port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return uc ? &uc->m_base : NULL;
|
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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue