From 4df38f5bf9de41c0691c7336df3782d5e40e09f9 Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Tue, 10 Mar 2020 12:59:20 +0100 Subject: [PATCH] Move all socket creation stuff to transport code Signed-off-by: Erik Boasson --- src/core/ddsi/CMakeLists.txt | 4 +- .../ddsi/include/dds/ddsi/ddsi_domaingv.h | 2 +- .../dds/ddsi/{q_nwif.h => ddsi_ownip.h} | 8 +- src/core/ddsi/src/ddsi_ipaddr.c | 1 - src/core/ddsi/src/ddsi_ownip.c | 304 ++++++++ src/core/ddsi/src/ddsi_raweth.c | 1 - src/core/ddsi/src/ddsi_tcp.c | 249 ++++--- src/core/ddsi/src/ddsi_udp.c | 333 +++++++-- src/core/ddsi/src/q_config.c | 1 - src/core/ddsi/src/q_init.c | 2 +- src/core/ddsi/src/q_nwif.c | 687 ------------------ 11 files changed, 758 insertions(+), 834 deletions(-) rename src/core/ddsi/include/dds/ddsi/{q_nwif.h => ddsi_ownip.h} (78%) create mode 100644 src/core/ddsi/src/ddsi_ownip.c delete mode 100644 src/core/ddsi/src/q_nwif.c diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt index af84a9b..60d91dd 100644 --- a/src/core/ddsi/CMakeLists.txt +++ b/src/core/ddsi/CMakeLists.txt @@ -35,6 +35,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" ddsi_plist.c ddsi_cdrstream.c ddsi_time.c + ddsi_ownip.c q_addrset.c q_bitset_inlines.c q_bswap.c @@ -47,7 +48,6 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" q_lat_estim.c q_lease.c q_misc.c - q_nwif.c q_pcap.c q_qosmatch.c q_radmin.c @@ -100,6 +100,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" ddsi_xqos.h ddsi_cdrstream.h ddsi_time.h + ddsi_ownip.h q_addrset.h q_bitset.h q_bswap.h @@ -115,7 +116,6 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" q_lease.h q_log.h q_misc.h - q_nwif.h q_pcap.h q_protocol.h q_qosmatch.h diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h b/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h index 27c9d3a..4c96ef1 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h @@ -21,8 +21,8 @@ #include "dds/ddsrt/fibheap.h" #include "dds/ddsi/ddsi_plist.h" +#include "dds/ddsi/ddsi_ownip.h" #include "dds/ddsi/q_protocol.h" -#include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_sockwaitset.h" #include "dds/ddsi/q_config.h" diff --git a/src/core/ddsi/include/dds/ddsi/q_nwif.h b/src/core/ddsi/include/dds/ddsi/ddsi_ownip.h similarity index 78% rename from src/core/ddsi/include/dds/ddsi/q_nwif.h rename to src/core/ddsi/include/dds/ddsi/ddsi_ownip.h index 12f232e..caf6a2d 100644 --- a/src/core/ddsi/include/dds/ddsi/q_nwif.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_ownip.h @@ -9,8 +9,8 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef Q_NWIF_H -#define Q_NWIF_H +#ifndef DDSI_OWNIP_H +#define DDSI_OWNIP_H #include @@ -35,12 +35,10 @@ struct nn_interface { 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); -uint32_t locator_to_hopefully_unique_uint32 (const nn_locator_t *src); #if defined (__cplusplus) } #endif -#endif /* Q_NWIF_H */ +#endif /* DDSI_OWNIP_H */ diff --git a/src/core/ddsi/src/ddsi_ipaddr.c b/src/core/ddsi/src/ddsi_ipaddr.c index a68021e..b6c6b71 100644 --- a/src/core/ddsi/src/ddsi_ipaddr.c +++ b/src/core/ddsi/src/ddsi_ipaddr.c @@ -17,7 +17,6 @@ #include "dds/ddsrt/log.h" #include "dds/ddsrt/sockets.h" #include "dds/ddsi/ddsi_ipaddr.h" -#include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/ddsi_domaingv.h" diff --git a/src/core/ddsi/src/ddsi_ownip.c b/src/core/ddsi/src/ddsi_ownip.c new file mode 100644 index 0000000..d53fe85 --- /dev/null +++ b/src/core/ddsi/src/ddsi_ownip.c @@ -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 +#include +#include +#include +#include + +#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 +#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; + } +} diff --git a/src/core/ddsi/src/ddsi_raweth.c b/src/core/ddsi/src/ddsi_raweth.c index 6e0bca2..7237e4a 100644 --- a/src/core/ddsi/src/ddsi_raweth.c +++ b/src/core/ddsi/src/ddsi_raweth.c @@ -13,7 +13,6 @@ #include "dds/ddsi/ddsi_raweth.h" #include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsi/ddsi_mcgroup.h" -#include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_pcap.h" diff --git a/src/core/ddsi/src/ddsi_tcp.c b/src/core/ddsi/src/ddsi_tcp.c index 5a87fd1..5cf5b62 100644 --- a/src/core/ddsi/src/ddsi_tcp.c +++ b/src/core/ddsi/src/ddsi_tcp.c @@ -21,7 +21,6 @@ #include "dds/ddsi/ddsi_tcp.h" #include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsrt/avl.h" -#include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.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) @@ -187,16 +268,12 @@ static void ddsi_tcp_conn_connect (ddsi_tcp_conn_t conn, const ddsrt_msghdr_t * ddsrt_socket_t sock; dds_return_t ret; - ddsi_tcp_sock_new (&sock, 0, conn->m_base.m_base.gv); - if (sock != DDSRT_INVALID_SOCKET) + if (ddsi_tcp_sock_new (fact, &sock, 0) == DDS_RETCODE_OK) { /* Attempt to connect, expected that may fail */ - - do - { + do { 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) { @@ -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) { - 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_domaingv * const gv = fact_tcp->fact.gv; + ddsrt_socket_t sock; (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; - 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; - - 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); + GVERROR ("ddsi_tcp_create_listener: ddsrt_getsockname returned %"PRId32"\n", ret); + ddsi_tcp_sock_free (&fact->gv->logconfig, sock, NULL); + ddsrt_free (tl); + return NULL; } - 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) @@ -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) { + 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; ddsrt_socket_t sock; dds_return_t ret; /* Connect to own listener socket to wake listener from blocking 'accept()' */ - ddsi_tcp_sock_new (&sock, 0, listener->m_base.gv); - if (sock != DDSRT_INVALID_SOCKET) - { - struct sockaddr_storage addr; - socklen_t addrlen = sizeof (addr); + if (ddsi_tcp_sock_new (fact_tcp, &sock, 0) != DDS_RETCODE_OK) + goto fail; - 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: - { - 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); + struct sockaddr_storage addr; + socklen_t addrlen = sizeof (addr); + if ((ret = ddsrt_getsockname (tl->m_sock, (struct sockaddr *) &addr, &addrlen)) != DDS_RETCODE_OK) + { + 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; + 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) diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c index d30d319..382f029 100644 --- a/src/core/ddsi/src/ddsi_udp.c +++ b/src/core/ddsi/src/ddsi_udp.c @@ -21,7 +21,6 @@ #include "dds/ddsi/ddsi_udp.h" #include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsi/ddsi_mcgroup.h" -#include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.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; } -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; struct sockaddr_storage 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) { - 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 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) { - int ret; + struct ddsi_domaingv * const gv = fact->gv; + const int one = 1; + + dds_return_t rc; ddsrt_socket_t sock; - ddsi_udp_conn_t uc = NULL; - bool reuse_addr = false, bind_to_any = false; + bool reuse_addr = false, bind_to_any = false, ipv6 = false; const char *purpose_str = NULL; 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); - /* 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)); - 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); + 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; + } + } - 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_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; + 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; + } + } - 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; + 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; - 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 - 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 ((qos->m_diffserv != 0) && (fact->m_kind == NN_LOCATOR_KIND_UDPv4)) { - 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) diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c index c8d0e40..7165bbe 100644 --- a/src/core/ddsi/src/q_config.c +++ b/src/core/ddsi/src/q_config.c @@ -30,7 +30,6 @@ #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_addrset.h" -#include "dds/ddsi/q_nwif.h" #include "dds/ddsrt/xmlparser.h" diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c index 226d75d..1a1a0cb 100644 --- a/src/core/ddsi/src/q_init.c +++ b/src/core/ddsi/src/q_init.c @@ -41,7 +41,7 @@ #include "dds/ddsi/q_lease.h" #include "dds/ddsi/q_gc.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/q_xmsg.h" #include "dds/ddsi/q_receive.h" diff --git a/src/core/ddsi/src/q_nwif.c b/src/core/ddsi/src/q_nwif.c deleted file mode 100644 index 9bbbb5c..0000000 --- a/src/core/ddsi/src/q_nwif.c +++ /dev/null @@ -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 -#include -#include -#include -#include - -#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 -#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; - } -}