diff --git a/docs/manual/options.md b/docs/manual/options.md index a5534b2..fbdd2aa 100644 --- a/docs/manual/options.md +++ b/docs/manual/options.md @@ -554,7 +554,7 @@ The default value is: "default". ### //CycloneDDS/Domain/Internal -Children: [AccelerateRexmitBlockSize](#cycloneddsdomaininternalacceleraterexmitblocksize), [AssumeMulticastCapable](#cycloneddsdomaininternalassumemulticastcapable), [AutoReschedNackDelay](#cycloneddsdomaininternalautoreschednackdelay), [BuiltinEndpointSet](#cycloneddsdomaininternalbuiltinendpointset), [ControlTopic](#cycloneddsdomaininternalcontroltopic), [DDSI2DirectMaxThreads](#cycloneddsdomaininternalddsi2directmaxthreads), [DefragReliableMaxSamples](#cycloneddsdomaininternaldefragreliablemaxsamples), [DefragUnreliableMaxSamples](#cycloneddsdomaininternaldefragunreliablemaxsamples), [DeliveryQueueMaxSamples](#cycloneddsdomaininternaldeliveryqueuemaxsamples), [EnableExpensiveChecks](#cycloneddsdomaininternalenableexpensivechecks), [GenerateKeyhash](#cycloneddsdomaininternalgeneratekeyhash), [HeartbeatInterval](#cycloneddsdomaininternalheartbeatinterval), [LateAckMode](#cycloneddsdomaininternallateackmode), [LeaseDuration](#cycloneddsdomaininternalleaseduration), [LivelinessMonitoring](#cycloneddsdomaininternallivelinessmonitoring), [MaxParticipants](#cycloneddsdomaininternalmaxparticipants), [MaxQueuedRexmitBytes](#cycloneddsdomaininternalmaxqueuedrexmitbytes), [MaxQueuedRexmitMessages](#cycloneddsdomaininternalmaxqueuedrexmitmessages), [MaxSampleSize](#cycloneddsdomaininternalmaxsamplesize), [MeasureHbToAckLatency](#cycloneddsdomaininternalmeasurehbtoacklatency), [MinimumSocketReceiveBufferSize](#cycloneddsdomaininternalminimumsocketreceivebuffersize), [MinimumSocketSendBufferSize](#cycloneddsdomaininternalminimumsocketsendbuffersize), [MonitorPort](#cycloneddsdomaininternalmonitorport), [MultipleReceiveThreads](#cycloneddsdomaininternalmultiplereceivethreads), [NackDelay](#cycloneddsdomaininternalnackdelay), [PreEmptiveAckDelay](#cycloneddsdomaininternalpreemptiveackdelay), [PrimaryReorderMaxSamples](#cycloneddsdomaininternalprimaryreordermaxsamples), [PrioritizeRetransmit](#cycloneddsdomaininternalprioritizeretransmit), [RediscoveryBlacklistDuration](#cycloneddsdomaininternalrediscoveryblacklistduration), [RetransmitMerging](#cycloneddsdomaininternalretransmitmerging), [RetransmitMergingPeriod](#cycloneddsdomaininternalretransmitmergingperiod), [RetryOnRejectBestEffort](#cycloneddsdomaininternalretryonrejectbesteffort), [SPDPResponseMaxDelay](#cycloneddsdomaininternalspdpresponsemaxdelay), [ScheduleTimeRounding](#cycloneddsdomaininternalscheduletimerounding), [SecondaryReorderMaxSamples](#cycloneddsdomaininternalsecondaryreordermaxsamples), [SendAsync](#cycloneddsdomaininternalsendasync), [SquashParticipants](#cycloneddsdomaininternalsquashparticipants), [SynchronousDeliveryLatencyBound](#cycloneddsdomaininternalsynchronousdeliverylatencybound), [SynchronousDeliveryPriorityThreshold](#cycloneddsdomaininternalsynchronousdeliveryprioritythreshold), [Test](#cycloneddsdomaininternaltest), [UnicastResponseToSPDPMessages](#cycloneddsdomaininternalunicastresponsetospdpmessages), [UseMulticastIfMreqn](#cycloneddsdomaininternalusemulticastifmreqn), [Watermarks](#cycloneddsdomaininternalwatermarks), [WriteBatch](#cycloneddsdomaininternalwritebatch), [WriterLingerDuration](#cycloneddsdomaininternalwriterlingerduration) +Children: [AccelerateRexmitBlockSize](#cycloneddsdomaininternalacceleraterexmitblocksize), [AssumeMulticastCapable](#cycloneddsdomaininternalassumemulticastcapable), [AutoReschedNackDelay](#cycloneddsdomaininternalautoreschednackdelay), [BindUnicastToInterfaceAddr](#cycloneddsdomaininternalbindunicasttointerfaceaddr), [BuiltinEndpointSet](#cycloneddsdomaininternalbuiltinendpointset), [ControlTopic](#cycloneddsdomaininternalcontroltopic), [DDSI2DirectMaxThreads](#cycloneddsdomaininternalddsi2directmaxthreads), [DefragReliableMaxSamples](#cycloneddsdomaininternaldefragreliablemaxsamples), [DefragUnreliableMaxSamples](#cycloneddsdomaininternaldefragunreliablemaxsamples), [DeliveryQueueMaxSamples](#cycloneddsdomaininternaldeliveryqueuemaxsamples), [EnableExpensiveChecks](#cycloneddsdomaininternalenableexpensivechecks), [GenerateKeyhash](#cycloneddsdomaininternalgeneratekeyhash), [HeartbeatInterval](#cycloneddsdomaininternalheartbeatinterval), [LateAckMode](#cycloneddsdomaininternallateackmode), [LeaseDuration](#cycloneddsdomaininternalleaseduration), [LivelinessMonitoring](#cycloneddsdomaininternallivelinessmonitoring), [MaxParticipants](#cycloneddsdomaininternalmaxparticipants), [MaxQueuedRexmitBytes](#cycloneddsdomaininternalmaxqueuedrexmitbytes), [MaxQueuedRexmitMessages](#cycloneddsdomaininternalmaxqueuedrexmitmessages), [MaxSampleSize](#cycloneddsdomaininternalmaxsamplesize), [MeasureHbToAckLatency](#cycloneddsdomaininternalmeasurehbtoacklatency), [MinimumSocketReceiveBufferSize](#cycloneddsdomaininternalminimumsocketreceivebuffersize), [MinimumSocketSendBufferSize](#cycloneddsdomaininternalminimumsocketsendbuffersize), [MonitorPort](#cycloneddsdomaininternalmonitorport), [MultipleReceiveThreads](#cycloneddsdomaininternalmultiplereceivethreads), [NackDelay](#cycloneddsdomaininternalnackdelay), [PreEmptiveAckDelay](#cycloneddsdomaininternalpreemptiveackdelay), [PrimaryReorderMaxSamples](#cycloneddsdomaininternalprimaryreordermaxsamples), [PrioritizeRetransmit](#cycloneddsdomaininternalprioritizeretransmit), [RediscoveryBlacklistDuration](#cycloneddsdomaininternalrediscoveryblacklistduration), [RetransmitMerging](#cycloneddsdomaininternalretransmitmerging), [RetransmitMergingPeriod](#cycloneddsdomaininternalretransmitmergingperiod), [RetryOnRejectBestEffort](#cycloneddsdomaininternalretryonrejectbesteffort), [SPDPResponseMaxDelay](#cycloneddsdomaininternalspdpresponsemaxdelay), [ScheduleTimeRounding](#cycloneddsdomaininternalscheduletimerounding), [SecondaryReorderMaxSamples](#cycloneddsdomaininternalsecondaryreordermaxsamples), [SendAsync](#cycloneddsdomaininternalsendasync), [SquashParticipants](#cycloneddsdomaininternalsquashparticipants), [SynchronousDeliveryLatencyBound](#cycloneddsdomaininternalsynchronousdeliverylatencybound), [SynchronousDeliveryPriorityThreshold](#cycloneddsdomaininternalsynchronousdeliveryprioritythreshold), [Test](#cycloneddsdomaininternaltest), [UnicastResponseToSPDPMessages](#cycloneddsdomaininternalunicastresponsetospdpmessages), [UseMulticastIfMreqn](#cycloneddsdomaininternalusemulticastifmreqn), [Watermarks](#cycloneddsdomaininternalwatermarks), [WriteBatch](#cycloneddsdomaininternalwritebatch), [WriterLingerDuration](#cycloneddsdomaininternalwriterlingerduration) The Internal elements deal with a variety of settings that evolving and @@ -600,6 +600,15 @@ Valid values are finite durations with an explicit unit or the keyword The default value is: "1 s". +#### //CycloneDDS/Domain/Internal/BindUnicastToInterfaceAddr +Boolean + +Bind unicast sockets to the address of the preferred interface; if false, +bind to 0.0.0.0 (IPv4) or its equivalent + +The default value is: "true". + + #### //CycloneDDS/Domain/Internal/BuiltinEndpointSet One of: full, writers, minimal diff --git a/etc/cyclonedds.rnc b/etc/cyclonedds.rnc index 0edc899..f3e4395 100644 --- a/etc/cyclonedds.rnc +++ b/etc/cyclonedds.rnc @@ -491,6 +491,13 @@ day.
The default value is: "1 s".
""" ] ] duration_inf }? & [ a:documentation [ xml:lang="en" """ +Bind unicast sockets to the address of the preferred interface; if +false, bind to 0.0.0.0 (IPv4) or its equivalent
The default value +is: "true".
""" ] ] + element BindUnicastToInterfaceAddr { + xsd:boolean + }? + & [ a:documentation [ xml:lang="en" """This element controls which participants will have which built-in endpoints for the discovery and liveliness protocols. Valid values are:
diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd index 49d4378..dbcab47 100644 --- a/etc/cyclonedds.xsd +++ b/etc/cyclonedds.xsd @@ -638,6 +638,7 @@ reserved. This includes renaming or moving options.</p>This element controls whether retransmits are prioritized over new data, speeding up recovery.
") }, { LEAF("UseMulticastIfMreqn"), 1, "0", ABSOFF(use_multicast_if_mreqn), 0, uf_int, 0, pf_int, BLURB("Do not use.
") }, + { LEAF("BindUnicastToInterfaceAddr"), 1, "true", ABSOFF(bind_unicast_to_interface_addr), 0, uf_boolean, 0, pf_boolean, + BLURB("Bind unicast sockets to the address of the preferred interface; if false, bind to 0.0.0.0 (IPv4) or its equivalent
") }, { LEAF("SendAsync"), 1, "false", ABSOFF(xpack_send_async), 0, uf_boolean, 0, pf_boolean, BLURB("This element controls whether the actual sending of packets occurs on the same thread that prepares them, or is done asynchronously by another thread.
") }, { LEAF_W_ATTRS("RediscoveryBlacklistDuration", rediscovery_blacklist_duration_attrs), 1, "10s", ABSOFF(prune_deleted_ppant.delay), 0, uf_duration_inf, 0, pf_duration, diff --git a/src/core/ddsi/src/q_nwif.c b/src/core/ddsi/src/q_nwif.c index 7b96a2f..5789983 100644 --- a/src/core/ddsi/src/q_nwif.c +++ b/src/core/ddsi/src/q_nwif.c @@ -214,32 +214,39 @@ static int set_reuse_options (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t return 0; } -static int bind_socket (ddsrt_socket_t socket, unsigned short port, const struct ddsi_domaingv *gv) +static int bind_socket (ddsrt_socket_t socket, unsigned short port, bool multicast, 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) { - struct sockaddr_in6 socketname; - memset (&socketname, 0, sizeof (socketname)); - socketname.sin6_family = AF_INET6; - socketname.sin6_port = htons (port); - socketname.sin6_addr = ddsrt_in6addr_any; - if (IN6_IS_ADDR_LINKLOCAL (&socketname.sin6_addr)) { - socketname.sin6_scope_id = gv->interfaceNo; + union { + struct sockaddr_storage x; + struct sockaddr_in6 a; + } socketname; + ddsi_ipaddr_from_loc (&socketname.x, &gv->ownloc); + if (multicast || !gv->config.bind_unicast_to_interface_addr) + 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, sizeof (socketname)); + 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) { - struct sockaddr_in socketname; - socketname.sin_family = AF_INET; - socketname.sin_port = htons (port); - socketname.sin_addr.s_addr = htonl (INADDR_ANY); - rc = ddsrt_bind (socket, (struct sockaddr *) &socketname, sizeof (socketname)); + union { + struct sockaddr_storage x; + struct sockaddr_in a; + } socketname; + ddsi_ipaddr_from_loc (&socketname.x, &gv->ownloc); + if (multicast || !gv->config.bind_unicast_to_interface_addr) + 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) { @@ -338,7 +345,7 @@ static int set_mc_options_transmit (ddsrt_socket_t socket, const struct ddsi_dom } } -int make_socket (ddsrt_socket_t *sock, uint16_t port, bool stream, bool reuse, const struct ddsi_domaingv *gv) +int make_socket (ddsrt_socket_t *sock, uint16_t port, bool stream, bool multicast, const struct ddsi_domaingv *gv) { /* FIXME: this stuff has to move to the transports */ int rc = -2; @@ -366,7 +373,7 @@ int make_socket (ddsrt_socket_t *sock, uint16_t port, bool stream, bool reuse, c return rc; } - if (port && reuse && ((rc = set_reuse_options (&gv->logconfig, *sock)) < 0)) + if (port && multicast && ((rc = set_reuse_options (&gv->logconfig, *sock)) < 0)) { goto fail; } @@ -376,7 +383,7 @@ int make_socket (ddsrt_socket_t *sock, uint16_t port, bool stream, bool reuse, c (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, gv)) < 0) + ((rc = bind_socket (*sock, port, multicast, gv)) < 0) ) { goto fail;