Merge pull request #360 from martinbremmer/merge6

Merge master into security
This commit is contained in:
eboasson 2019-12-13 14:40:50 +02:00 committed by GitHub
commit 80d0be83e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
124 changed files with 5049 additions and 1672 deletions

View file

@ -68,9 +68,9 @@ linux_clang: &linux_clang
install:
- pip install conan --upgrade --user
osx_xcode10_3: &osx_xcode10_3
osx_xcode: &osx_xcode
os: osx
osx_image: xcode10.3
osx_image: xcode11.1
compiler: clang
addons:
homebrew:
@ -84,12 +84,8 @@ osx_xcode10_3: &osx_xcode10_3
- python3 -m pip install conan --upgrade --user
osx_xcode9: &osx_xcode9
<<: *osx_xcode10_3
<<: *osx_xcode
osx_image: xcode9
cache:
directories:
- $HOME/Library/Caches/Homebrew
- /usr/local/Homebrew
addons:
homebrew:
packages: [ python3 ]
@ -99,11 +95,6 @@ osx_xcode9: &osx_xcode9
# used to ensure Homebrew is kept up-to-date and build times are kept to
# a minimum.
update: true
before_cache:
- brew cleanup
- find /usr/local/Homebrew -type d -name .git |
xargs -I {} dirname {} |
xargs -I {} git --git-dir={}/.git --work-tree={} clean -f -d -x
windows_vs2017: &windows_vs2017
os: windows
@ -169,9 +160,12 @@ jobs:
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode9
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode10_3
if: type = cron
- <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, GENERATOR="Unix Makefiles", MACOSX_DEPLOYMENT_TARGET=10.12 ]
- <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode10_3
- <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, GENERATOR="Unix Makefiles" ]
- <<: *windows_vs2017
env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, GENERATOR="Visual Studio 15 2017" ]
@ -201,11 +195,12 @@ before_script:
# code has been vetted, the test has been run a great many times (with the odd
# failure), and so we now simply skip the test to avoid the spurious failures.
script:
- INSTALLPREFIX="$(pwd)/install"
- mkdir build
- cd build
- conan install -b missing -s arch=${ARCH} -s build_type=${BUILD_TYPE} ..
- cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX=$(pwd)/install
-DCMAKE_INSTALL_PREFIX=${INSTALLPREFIX}
-DUSE_SANITIZER=${ASAN}
-DENABLE_SSL=${SSL}
-DENABLE_SECURITY=${SECURITY}
@ -228,12 +223,15 @@ script:
CMAKE_LINKER_FLAGS="-DCMAKE_LINKER_FLAGS=-fsanitize=${USE_SANITIZER}";
CMAKE_C_FLAGS="-DCMAKE_C_FLAGS=-fsanitize=${USE_SANITIZER}";
fi
- mkdir install/share/CycloneDDS/examples/helloworld/build
- cd install/share/CycloneDDS/examples/helloworld/build
- cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
- cd ..
- mkdir helloworld_build
- cd helloworld_build
- cmake -DCMAKE_PREFIX_PATH=${INSTALLPREFIX}
-DCMAKE_BUILD_TYPE=${BUILD_TYPE}
${CMAKE_C_FLAGS}
${CMAKE_LINKER_FLAGS}
-G "${GENERATOR}" ..
-G "${GENERATOR}"
${INSTALLPREFIX}/share/CycloneDDS/examples/helloworld
- cmake --build . --config ${BUILD_TYPE}
- cd "${TRAVIS_BUILD_DIR}/build"

View file

@ -10,7 +10,7 @@
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.7)
project(CycloneDDS VERSION 0.1.0)
project(CycloneDDS VERSION 0.5.0)
# Set a default build type if none was specified
set(default_build_type "RelWithDebInfo")
@ -23,11 +23,6 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
# By default the Java-based components get built, but make it possible to disable that: if only the
# core library is required, there's no need to build them, and that in turn eliminates the Maven and
# JDK dependency.
option(BUILD_IDLC "Build IDL preprocessor" ON)
# By default don't treat warnings as errors, else anyone building it with a different compiler that
# just happens to generate a warning, as well as anyone adding or modifying something and making a
# small mistake would run into errors. CI builds can be configured differently.
@ -50,6 +45,15 @@ string(REPLACE " " "-" PROJECT_NAME_DASHED "${PROJECT_NAME_FULL}")
string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_CAPS)
string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_SMALL)
# By default the Java-based components get built, but make it possible to disable that: if only the
# core library is required, there's no need to build them, and that in turn eliminates the Maven and
# JDK dependency.
option(BUILD_IDLC "Build IDL preprocessor" ON)
if(BUILD_IDLC STREQUAL "AUTO")
find_package(Maven 3.0 QUIET)
set(BUILD_IDLC ${Maven_FOUND})
endif()
set(CMAKE_C_STANDARD 99)
if(CMAKE_SYSTEM_NAME STREQUAL "VxWorks")
add_definitions(-std=c99)

View file

@ -124,11 +124,10 @@ We will show you how to build and run an example program that measures latency.
built automatically when you build Cyclone DDS, so you don't need to follow these steps to be able
to run the program, it is merely to illustrate the process.
$ cd cyclonedds/examples/roundtrip
$ mkdir build
$ cd build
$ cmake ..
$ make
$ mkdir roundtrip
$ cd roundtrip
$ cmake <install-location>/share/CycloneDDS/examples/roundtrip
$ cmake --build .
On one terminal start the application that will be responding to pings:
@ -186,12 +185,11 @@ point to it. E.g. (on Linux):
$ cat cyclonedds.xml
<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://github.com/eclipse-cyclonedds/cyclonedds/etc/cyclonedds.xsd">
<CycloneDDS>
<CycloneDDS xmlns="https://cdds.io/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd">
<Domain id="any">
<General>
<NetworkInterfaceAddress>auto</NetworkInterfaceAddress>
<AllowMulticast>auto</AllowMulticast>
<AllowMulticast>default</AllowMulticast>
<MaxMessageSize>65500B</MaxMessageSize>
<FragmentSize>4000B</FragmentSize>
</General>

View file

@ -41,7 +41,7 @@ build_script:
- cd install/share/CycloneDDS/examples/helloworld
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G "%GENERATOR%" ..
- cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_PREFIX_PATH=%CD%/../../../../.. -G "%GENERATOR%" ..
- cmake --build . --config %CONFIGURATION% -- /nologo /verbosity:minimal /maxcpucount /p:CL_MPCount=2
- cd ../../../../../..

View file

@ -274,7 +274,7 @@ function(add_cunit_executable TARGET)
add_test(
NAME ${ctest}
COMMAND ${TARGET} -a -r "${suite}-${test}" -s ${suite} -t ${test})
COMMAND ${TARGET} -s ${suite} -t ${test})
set_property(TEST ${ctest} PROPERTY TIMEOUT ${timeout})
set_property(TEST ${ctest} PROPERTY DISABLED ${disabled})
if(APPLE)

View file

@ -222,6 +222,7 @@ int main(int argc, char *argv[])
}
CU_automated_run_tests();
} else {
CU_set_fail_on_inactive(0);
CU_basic_set_mode(opts.mode);
CU_basic_run_tests();
}

View file

@ -18,20 +18,13 @@ include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
set(PACKAGING_MODULE_DIR "${PROJECT_SOURCE_DIR}/cmake/Modules/Packaging")
set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}")
set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
# Generates <Package>Config.cmake.
if(BUILD_IDLC)
configure_package_config_file(
configure_package_config_file(
"${PACKAGING_MODULE_DIR}/PackageConfig.cmake.in"
"${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
else()
configure_package_config_file(
"${PACKAGING_MODULE_DIR}/PackageConfigNoIdlc.cmake.in"
"${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
endif()
# Generates <Package>Version.cmake.
write_basic_package_version_file(
@ -83,11 +76,13 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/license.txt")
# Although that does not make sense from a technical point-of-view, it
# does help to clearify which settings are required for a platform.
set(CPACK_COMPONENTS_ALL dev lib)
set(CPACK_COMPONENTS_ALL dev lib idlc)
set(CPACK_COMPONENT_LIB_DISPLAY_NAME "${PROJECT_NAME_FULL} library")
set(CPACK_COMPONENT_LIB_DESCRIPTION "Library used to run programs with ${PROJECT_NAME_FULL}")
set(CPACK_COMPONENT_DEV_DISPLAY_NAME "${PROJECT_NAME_FULL} development")
set(CPACK_COMPONENT_DEV_DESCRIPTION "Development files for use with ${PROJECT_NAME_FULL}")
set(CPACK_COMPONENT_IDLC_DISPLAY_NAME "${PROJECT_NAME_FULL} IDL Compiler")
set(CPACK_COMPONENT_IDLC_DESCRIPTION "Utility for turning IDL files into C++ source for ${PROJECT_NAME_FULL}")
if(WIN32 AND NOT UNIX)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)

View file

@ -12,4 +12,27 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/idlc/IdlcGenerate.cmake")
option("@PROJECT_NAME@_IDLC_ALWAYS" "Should we include idlc even if the user didn't request the idlc component?" ON)
set("@PROJECT_NAME@_idlc_FOUND" FALSE)
if ("idlc" IN_LIST "@PROJECT_NAME@_FIND_COMPONENTS" OR "@PROJECT_NAME@_IDLC_ALWAYS")
include("${CMAKE_CURRENT_LIST_DIR}/idlc/IdlcGenerate.cmake" OPTIONAL RESULT_VARIABLE _IdlcGenerate)
if(NOT _IdlcGenerate STREQUAL "NOTFOUND")
set("@PROJECT_NAME@_idlc_FOUND" TRUE)
endif()
endif()
if ("${@PROJECT_NAME@_IDLC_ALWAYS}"
AND "${@PROJECT_NAME@_idlc_FOUND}"
AND (NOT "idlc" IN_LIST "@PROJECT_NAME@_FIND_COMPONENTS")
)
message(AUTHOR_WARNING "\
The IDL Compiler 'idlc' has not been requested but has been built is automatically included. \
This will change in a future release. \
If you need the idlc compiler, please add idlc to the COMPONENTS or OPTIONAL_COMPONENTS list in \
find_package(@PROJECT_NAME@ ...). \
If you don't need it, set the @PROJECT_NAME@_IDLC_ALWAYS=OFF to suppress this message .\
")
endif()
check_required_components("@PROJECT_NAME@")

View file

@ -1,14 +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
#
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")

View file

@ -1,3 +1,3 @@
{
"cmake-args": [ "-DBUILD_IDLC=OFF" ]
"cmake-args": [ "-DBUILD_IDLC=AUTO" ]
}

View file

@ -8,5 +8,43 @@
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
add_subdirectory(manual)
include(FindPerl)
if(PERL_FOUND)
add_custom_command(
OUTPUT
options.md cyclonedds.rnc
COMMAND
${PERL_EXECUTABLE} -w "${CMAKE_CURRENT_SOURCE_DIR}/makernc.pl" "${CMAKE_CURRENT_SOURCE_DIR}/../src/core/ddsi/src/q_config.c" options.md cyclonedds.rnc
COMMAND
${PERL_EXECUTABLE} -w "${CMAKE_CURRENT_SOURCE_DIR}/compare.pl" options.md "${CMAKE_CURRENT_SOURCE_DIR}/manual/options.md"
COMMAND
${PERL_EXECUTABLE} -w "${CMAKE_CURRENT_SOURCE_DIR}/compare.pl" cyclonedds.rnc "${CMAKE_CURRENT_SOURCE_DIR}/../etc/cyclonedds.rnc"
DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/makernc.pl"
"${CMAKE_CURRENT_SOURCE_DIR}/../src/core/ddsi/src/q_config.c")
add_custom_target(options_doc ALL DEPENDS "options.md" "cyclonedds.rnc")
find_package(Java COMPONENTS Runtime)
if(JAVA_FOUND AND EXISTS "${TRANG_PATH}" OR EXISTS "$ENV{TRANG}")
if(NOT EXISTS "${TRANG_PATH}" AND EXISTS "$ENV{TRANG}")
message(STATUS "Setting TRANG_PATH to $ENV{TRANG}")
set(TRANG_PATH "$ENV{TRANG}" CACHE FILEPATH "Location of 'trang' for converting XML schemas" FORCE)
endif()
add_custom_command(
OUTPUT
cyclonedds.xsd
COMMAND
${Java_JAVA_EXECUTABLE} -jar "${TRANG_PATH}" -I rnc -O xsd cyclonedds.rnc cyclonedds.xsd
COMMAND
${PERL_EXECUTABLE} -w "${CMAKE_CURRENT_SOURCE_DIR}/compare.pl" cyclonedds.xsd "${CMAKE_CURRENT_SOURCE_DIR}/../etc/cyclonedds.xsd"
DEPENDS
"cyclonedds.rnc")
add_custom_target(options_xsd ALL DEPENDS "cyclonedds.xsd")
else()
message(STATUS "Java or not trang not found: not converting/checking RNC to XSD")
endif()
else()
message(STATUS "perl not found: not generating/checking options documentation and RNC")
endif()
add_subdirectory(manual)

8
docs/compare.pl Normal file
View file

@ -0,0 +1,8 @@
open A, "< $ARGV[0]" or die "can't open $ARGV[0]";
open B, "< $ARGV[1]" or die "can't open $ARGV[1]";
while (defined ($a = <A>) && defined ($b = <B>)) {
$a =~ s/[\r\n]+$//s;
$b =~ s/[\r\n]+$//s;
print "$ARGV[0] difference detected\n" and exit 1 unless $a eq $b;
}
exit 0;

View file

@ -156,7 +156,8 @@ my %tables;
my @root = read_config ($input);
{
open my $fh, ">", "$output_rnc" or die "can't open $output_rnc";
open my $fh, ">:unix", "$output_rnc" or die "can't open $output_rnc";
print $fh "default namespace = \"https://cdds.io/config\"\n";
print $fh "namespace a = \"http://relaxng.org/ns/compatibility/annotations/1.0\"\n";
print $fh "grammar {\n";
print $fh " start =\n";
@ -170,7 +171,7 @@ my @root = read_config ($input);
}
{
open my $fh, ">", "$output_md" or die "can't open $output_md";
open my $fh, ">:unix", "$output_md" or die "can't open $output_md";
my $sep_blurb = "";
conv_table($fh, \&conv_to_md, \@root, "/", " ", "", \$sep_blurb);
close $fh;
@ -315,12 +316,14 @@ sub conv_to_rnc {
print_description_rnc ($fh, $fs->{description}, $indent);
printf $fh "${indent}%s %s {\n", ($fs->{kind} eq "ATTR" ? "attribute" : "element"), $name;
if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
my $sub_isfirst = 1;
conv_table($fh, \&conv_to_rnc, $fs->{subtables}, $fqname, "${indent} ", $prefix, \$sub_isfirst);
printf $fh "${indent} empty\n" if $sub_isfirst;
my $sep = $sub_isfirst ? "" : "& ";
if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
printf $fh "${indent} ${sep}empty\n" if $sub_isfirst;
} elsif ($fs->{kstr} eq "Boolean") {
printf $fh "${indent} xsd:boolean\n";
printf $fh "${indent} ${sep}xsd:boolean\n";
} elsif ($fs->{kstr} eq "Comma") {
die unless exists $comma_values{$fs->{typehint}};
my $pat = "";
@ -337,13 +340,13 @@ sub conv_to_rnc {
}
}
$pat .= "|" if $allowempty;
printf $fh "${indent} xsd:token { pattern = \"%s\" }\n", $pat;
printf $fh "${indent} ${sep}xsd:token { pattern = \"%s\" }\n", $pat;
} elsif ($fs->{kstr} eq "Enum") {
die unless exists $enum_values{$fs->{typehint}};
my @vs = split /;/, $enum_values{$fs->{typehint}};
printf $fh "${indent} %s\n", (join '|', map { "\"$_\"" } @vs);
printf $fh "${indent} ${sep}%s\n", (join '|', map { "\"$_\"" } @vs);
} elsif ($fs->{kstr} eq "Int") {
printf $fh "${indent} xsd:integer\n";
printf $fh "${indent} ${sep}xsd:integer\n";
#if (exists $range{$lctn} || exists $range{$fs->{typehint}}) {
# # integer with range
# my $rr = exists $range{$lctn} ? $range{$lctn} : $range{$fs->{typehint}};
@ -351,9 +354,9 @@ sub conv_to_rnc {
#}
} elsif ($typehint2unit{$fs->{typehint}}) {
# number with unit
printf $fh "${indent} $typehint2unit{$fs->{typehint}}\n";
printf $fh "${indent} ${sep}$typehint2unit{$fs->{typehint}}\n";
} elsif ($typehint2xmltype{$fs->{typehint}} =~ /String$/) {
printf $fh "${indent} text\n";
printf $fh "${indent} ${sep}text\n";
} else {
die;
}
@ -393,7 +396,7 @@ sub conv_to_md {
# Describe type (boolean, integer, &c.); for a group list its attributes and children as
# links to their descriptions
if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
{
my %children = ("attributes" => [], "elements" => []);
conv_table($fh, \&list_children_md, $fs->{subtables}, "", "${indent} ", $prefix, \%children);
if (@{$children{attributes}} > 0) {
@ -406,6 +409,10 @@ sub conv_to_md {
my @ys = map { my $lt = lc "$fqname\[\@$_]"; $lt =~ s/[^a-z0-9]//g; "[$_](#$lt)" } @xs;
printf $fh "Children: %s\n\n", (join ', ', @ys);
}
}
if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
# nothing to see here
} elsif ($fs->{kstr} eq "Boolean") {
printf $fh "Boolean\n";
} elsif ($fs->{kstr} eq "Comma") {
@ -451,9 +458,7 @@ sub conv_to_md {
print_description_md ($fh, $fs->{description}, $indent);
# Generate attributes & children
if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
conv_table($fh, \&conv_to_md, $fs->{subtables}, $fqname, "${indent} ", $prefix, $separator_blurb_ref);
}
}
sub conv_table {
@ -481,6 +486,7 @@ sub read_config {
'DDSI_INCLUDE_SSL' => 1,
'DDSI_INCLUDE_NETWORK_PARTITIONS' => 1,
'DDSI_INCLUDE_SSM' => 1,
'DDSI_INCLUDE_SECURITY' => 1,
# excluded options
'DDSI_INCLUDE_NETWORK_CHANNELS' => 0,
'DDSI_INCLUDE_BANDWIDTH_LIMITING' => 0);
@ -490,7 +496,7 @@ sub read_config {
my @stk = (); # stack of conditional nesting, for each: copy/discard/ignore
open FH, "<", $input or die "can't open $input\n";
while (<FH>) {
chomp;
s/[\r\n]+$//s;
# ignore parts guarded by #if/#ifdef/#if!/#ifndef if $incl says so
if (/^\s*\#\s*if(n?def|\s*!)?\s*([A-Za-z_][A-Za-z_0-9]*)\s*(?:\/(?:\/.*|\*.*?\*\/)\s*)?$/) {

View file

@ -46,99 +46,7 @@ used for building your own applications.
Build Files
===========
Three files are available *Hello World!* root directory to support
building the example. Both
:ref:`Windows native <WindowsNativeBuild>` (HelloWorld.sln) and
:ref:`Linux native <LinuxNativeBuild>` (Makefile) build files
will only be available for this *Hello World!* example. All the
other examples make use of the :ref:`CMake <CMakeIntro>` build
system and thus only have the CMakeLists.txt build related file.
.. _`LinuxNativeBuild`:
Linux Native Build
==================
A Linux native :code:`Makefile` is provided in the
:code:`examples/helloworld` directory within the destination location
entered in the
:ref:`vdds_install_examples script <CopyLinuxExamplesToUserFriendlyLocation>`.
In a terminal, go to that directory and type
::
make
The build process should have access to the include files and
the ddsc library. The Makefile expects them to be present at
system default locations so that it can find them automatically.
If this isn't the case on your machine, then please
update the commented out :code:`CFLAGS` and :code:`LDFLAGS` within the
:code:`Makefile` to point to the proper locations.
This will build the HelloworldSubscriber and HelloworldPublisher
executables in the helloworld source directory (not the bin
directory that contains the pre-build binaries).
The *Hello World!* example can now be executed,
like described in :ref:`Test your installation <TestYourInstallation>`,
using the binaries that were just build. Be sure to use the right directories.
.. _`WindowsNativeBuild`:
Windows Native Build
====================
For the Windows Native Build, a Visual Studio solution file is
available in the :code:`examples/helloworld` directory. Use a
file explorer to navigate to that directory and double click on
the :code:`HelloWorld.sln` file. Visual Studio should now start
with the HelloWorld solution that contains three projects.
+----------------------+-------------------------------------------------+
| Project | Description |
+======================+=================================================+
| HelloWorldPublisher | Information to build the example publisher. |
+----------------------+-------------------------------------------------+
| HelloWorldSubscriber | Information to build the example subcriber. |
+----------------------+-------------------------------------------------+
| HelloWorldType | Information to (re)generate |
| | :ref:`HelloWorldData_Msg <HelloWorldDataFiles>` |
| | data type. |
+----------------------+-------------------------------------------------+
Creating the *Hello World!* example executables is as simple as
selecting the required configuration and building the solution.
:code:`helloworld\vs\directories.props` contains the location of where
the Eclipse Cyclone DDS header files and libraries are be placed. These locations
are based on the default installation directory structure. When Eclipse Cyclone DDS
is installed in a different directory, the following paths in
:code:`helloworld\vs\directories.props` should be changed, like:
.. code-block:: xml
<CycloneDDS_lib_dir>C:/Path/To/CycloneDDS/Installation/lib</CycloneDDS_lib_dir>
<CycloneDDS_inc_dir>C:/Path/To/CycloneDDS/Installation/include</CycloneDDS_inc_dir>
<CycloneDDS_idlc_dir>C:/Path/To/CycloneDDS/Installation/share/CycloneDDS/idlc</CycloneDDS_idlc_dir>
To run the example, Visual Studio should run both the publisher
and subscriber simultaneously. It is capable of doing so, but
it's not its default setting. To change it, open the HelloWorld
solution property page by right clicking the solution and
selecting :code:`Properties`. Then go to :code:`Common Properties`
-> :code:`Startup Project`, select :code:`Multiple startup project`
and set :code:`Action "Start"` for HelloWorldPublisher and
HelloWorldSubscriber. Finish the change by selecting :code:`OK`.
Visual Studio is now ready to actually run the *Hello World!*
example, which can be done by selecting :code:`Debug` ->
:code:`Start without debugging`.
Both the HelloworldSubscriber and the HelloworldPublisher will be
started and the HelloworldPublisher will write a message that is
received by the HelloworldSubscriber.
.. _`BuildingWithCMake`:
@ -146,11 +54,6 @@ received by the HelloworldSubscriber.
Building With CMake
*******************
In the earlier chapters, building the *Hello World!* example is done
natively. However, the *Hello World!* example can also be build using the
`CMake tool <http://cmake.org>`_. This is what is recommended. In fact,
all the other examples don't provide native makefiles, only CMake files.
.. _`CMakeIntro`:
@ -190,10 +93,8 @@ scope of this document.
Hello World! CMake (CycloneDDS Package)
=======================================
After the CMake digression, we're back with the *Hello World!*
example. Apart from the native build files, CMake build files
are provided as well. See
:code:`examples/helloworld/CMakeLists.txt`
Specifying how to build the *Hello World!* example requires only a few
lines of configuration in :code:`examples/helloworld/CMakeLists.txt`
.. literalinclude:: ../../../examples/helloworld/CMakeLists.export
:linenos:
@ -206,13 +107,12 @@ look in the default locations for the code:`CycloneDDS` package.
.. _`IdlcGenerate`:
The :code:`CycloneDDS` package provides the :code:`ddsc` library
that contains the DDS API that the application needs. But apart
from that, it also contains helper functionality
(:code:`idlc_generate`) to generate library targets from IDL
files. These library targets can be easily used when compiling
an application that depends on a data type described
in an IDL file.
The :code:`CycloneDDS` package provides the :code:`ddsc` library that
contains the DDS API that the application needs. It also provides a
component "idlc" that provides helper functionality for generating
library targets from IDL files (:code:`idlc_generate`). These library
targets can be easily used when compiling an application that depends on
a data type described in an IDL file.
Two applications will be created, :code:`HelloworldPublisher`
and :code:`HelloworldSubscriber`. Both consist only out of one
@ -241,7 +141,7 @@ Here, we can let CMake configure the build environment for
us by typing:
::
cmake ../
cmake ..
.. note::
CMake does a pretty good job at guessing which generator to use, but some

View file

@ -1110,21 +1110,3 @@ an endless loop.
There is furthermore also a difference of interpretation of the meaning of the
autodispose_unregistered_instances QoS on the writer. Eclipse Cyclone DDS aligns with
OpenSplice.
.. _`Compatibility issues with TwinOaks`:
Compatibility issues with TwinOaks
----------------------------------
In the default configuration there should be no interoperability issues with TwinOaks CoreDX,
although there is the aforementioned difference in interpretation of the meaning of the
autodispose_unregistered_instances QoS on the writer.
Interoperability with very old versions of CoreDX may require setting:
+ ``Compatibility/ManySocketsMode``: *true*
+ ``Compatibility/ExplicitlyPublishQosSetToDefault``: *true*
The exact version number of CoreDX starting with which these settings are no longer needed is
unknown, but it has certainly not been needed for several years.

View file

@ -8,7 +8,7 @@ CycloneDDS configuration
## //CycloneDDS/Domain
Attributes: [Id](#cycloneddsdomainid)
Children: [Compatibility](#cycloneddsdomaincompatibility), [Discovery](#cycloneddsdomaindiscovery), [General](#cycloneddsdomaingeneral), [Internal](#cycloneddsdomaininternal), [Partitioning](#cycloneddsdomainpartitioning), [SSL](#cycloneddsdomainssl), [Sizing](#cycloneddsdomainsizing), [TCP](#cycloneddsdomaintcp), [ThreadPool](#cycloneddsdomainthreadpool), [Threads](#cycloneddsdomainthreads), [Tracing](#cycloneddsdomaintracing)
Children: [Compatibility](#cycloneddsdomaincompatibility), [DDSSecurity](#cycloneddsdomainddssecurity), [Discovery](#cycloneddsdomaindiscovery), [General](#cycloneddsdomaingeneral), [Internal](#cycloneddsdomaininternal), [Partitioning](#cycloneddsdomainpartitioning), [SSL](#cycloneddsdomainssl), [Sizing](#cycloneddsdomainsizing), [TCP](#cycloneddsdomaintcp), [ThreadPool](#cycloneddsdomainthreadpool), [Threads](#cycloneddsdomainthreads), [Tracing](#cycloneddsdomaintracing)
The General element specifying Domain related settings.
@ -100,8 +100,354 @@ The default setting is "lax".
The default value is: "lax".
### //CycloneDDS/Domain/DDSSecurity
Children: [AccessControl](#cycloneddsdomainddssecurityaccesscontrol), [Authentication](#cycloneddsdomainddssecurityauthentication), [Cryptographic](#cycloneddsdomainddssecuritycryptographic)
This element is used to configure Cyclone DDS with the DDS Security
specification plugins and settings.
#### //CycloneDDS/Domain/DDSSecurity/AccessControl
Children: [Governance](#cycloneddsdomainddssecurityaccesscontrolgovernance), [Library](#cycloneddsdomainddssecurityaccesscontrollibrary), [Permissions](#cycloneddsdomainddssecurityaccesscontrolpermissions), [PermissionsCA](#cycloneddsdomainddssecurityaccesscontrolpermissionsca)
This element configures the Access Control plugin of the DDS Security
specification.
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Governance
RELOFF (cfg.access_control_properties.governance), pf_string, BLURB("
URI to the shared Governance Document signed by the Permissions CA in
S/MIME format
URI schemes: file, data<br>
Examples file URIs:
<Governance>file:governance.smime</Governance>
<Governance>file:/home/myuser/governance.smime</Governance><br>
<Governance><![CDATA[data:,MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature";
micalg="sha-256"; boundary="----F9A8A198D6F08E1285A292ADF14DD04F"
This is an S/MIME signed message
------F9A8A198D6F08E1285A292ADF14DD04F
<?xml version="1.0" encoding="UTF-8"?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="omg_shared_ca_governance.xsd">
<domain_access_rules>
. . .
</domain_access_rules>
</dds>
...
------F9A8A198D6F08E1285A292ADF14DD04F
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
MIIDuAYJKoZIhv ...al5s=
------F9A8A198D6F08E1285A292ADF14DD04F-]]</Governance>
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library
Children: [finalizeFunction](#cycloneddsdomainddssecurityaccesscontrollibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecurityaccesscontrollibraryinitfunction), [path](#cycloneddsdomainddssecurityaccesscontrollibrarypath)
RELOFF (cfg.access_control_plugin), pf_string, BLURB("
This element specifies the library to be loaded as the DDS Security
Access Control plugin.
###### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library/finalizeFunction
RELOFF (cfg.access_control_plugin.library_finalize), pf_string, BLURB("
This element names the finalization function of Access Control plugin.
This function is called to let the plugin release its resources.
###### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library/initFunction
RELOFF (cfg.access_control_plugin.library_init), pf_string, BLURB("
This element names the initialization function of Access Control plugin.
This function is called after loading the plugin library for
instantiation purposes. Init function must return an object that
implements DDS Security Access Control interface.
###### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library/path
RELOFF (cfg.access_control_plugin.library_path), pf_string, BLURB("
This element points to the path of Access Control plugin library.
It can be either absolute path excluding file extension (
/usr/lib/dds_security_ac ) or single file without extension (
dds_security_ac ).
If single file is supplied, the library located by way of the current
working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for
Windows systems.
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Permissions
RELOFF (cfg.access_control_properties.permissions), pf_string, BLURB("
URI to the DomainParticipant permissions document signed by the
Permissions CA in S/MIME format
The permissions document specifies the permissions to be applied to a
domain.<br>
Example file URIs:
<Permissions>file:permissions_document.p7s</Permissions>
<Permissions>file:/path_to/permissions_document.p7s</Permissions>
Example data URI:
<Permissions><![CDATA[data:,.........]]</Permissions>
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/PermissionsCA
RELOFF (cfg.access_control_properties.permissions_ca), pf_string, BLURB("
URI to a X509 certificate for the PermissionsCA in PEM format.
Supported URI schemes: file, data
The file and data schemas shall refer to a X.509 v3 certificate (see
X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.<br>
Examples:<br>
<PermissionsCA>file:permissions_ca.pem</PermissionsCA>
<PermissionsCA>file:/home/myuser/permissions_ca.pem</PermissionsCA><br>
<PermissionsCA>data:<strong>,</strong>-----BEGIN CERTIFICATE-----
MIIC3DCCAcQCCQCWE5x+Z ... PhovK0mp2ohhRLYI0ZiyYQ==
-----END CERTIFICATE-----</PermissionsCA>
#### //CycloneDDS/Domain/DDSSecurity/Authentication
Children: [IdentityCA](#cycloneddsdomainddssecurityauthenticationidentityca), [IdentityCertificate](#cycloneddsdomainddssecurityauthenticationidentitycertificate), [Library](#cycloneddsdomainddssecurityauthenticationlibrary), [Password](#cycloneddsdomainddssecurityauthenticationpassword), [PrivateKey](#cycloneddsdomainddssecurityauthenticationprivatekey), [TrustedCADirectory](#cycloneddsdomainddssecurityauthenticationtrustedcadirectory)
This element configures the Authentication plugin of the DDS Security
specification.
##### //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCA
RELOFF (cfg.authentication_properties.identity_ca), pf_string, BLURB("
URI to the X509 certificate [39] of the Identity CA that is the signer of
Identity Certificate.
Supported URI schemes: file, data
The file and data schemas shall refer to a X.509 v3 certificate (see
X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.
Examples:
<IdentityCA>file:identity_ca.pem</IdentityCA>
<IdentityCA>data:,-----BEGIN CERTIFICATE-----<br>
MIIC3DCCAcQCCQCWE5x+Z...PhovK0mp2ohhRLYI0ZiyYQ==<br>
-----END CERTIFICATE-----</IdentityCA>
##### //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCertificate
RELOFF (cfg.authentication_properties.identity_certificate), pf_string,
BLURB("
Identity certificate that will be used for identifying all participants
in the OSPL instance.<br>The content is URI to a X509 certificate signed
by the IdentityCA in PEM format containing the signed public key.
Supported URI schemes: file, data
Examples:
<IdentityCertificate>file:participant1_identity_cert.pem</IdentityCertificate>
<IdentityCertificate>data:,-----BEGIN CERTIFICATE-----<br>
MIIDjjCCAnYCCQDCEu9...6rmT87dhTo=<br>
-----END CERTIFICATE-----</IdentityCertificate>
##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library
Children: [finalizeFunction](#cycloneddsdomainddssecurityauthenticationlibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecurityauthenticationlibraryinitfunction), [path](#cycloneddsdomainddssecurityauthenticationlibrarypath)
RELOFF (cfg.authentication_plugin), pf_string, BLURB("
This element specifies the library to be loaded as the DDS Security
Access Control plugin.
###### //CycloneDDS/Domain/DDSSecurity/Authentication/Library/finalizeFunction
RELOFF (cfg.authentication_plugin.library_finalize), pf_string, BLURB("
This element names the finalization function of Authentication plugin.
This function is called to let the plugin release its resources.
###### //CycloneDDS/Domain/DDSSecurity/Authentication/Library/initFunction
RELOFF (cfg.authentication_plugin.library_init), pf_string, BLURB("
This element names the initialization function of Authentication plugin.
This function is called after loading the plugin library for
instantiation purposes. Init function must return an object that
implements DDS Security Authentication interface.
###### //CycloneDDS/Domain/DDSSecurity/Authentication/Library/path
RELOFF (cfg.authentication_plugin.library_path), pf_string, BLURB("
This element points to the path of Authentication plugin library.
It can be either absolute path excluding file extension (
/usr/lib/dds_security_auth ) or single file without extension (
dds_security_auth ).
If single file is supplied, the library located by way of the current
working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for
Windows systems.
##### //CycloneDDS/Domain/DDSSecurity/Authentication/Password
RELOFF (cfg.authentication_properties.password), pf_string, BLURB("
A password used to decrypt the private_key.
The value of the password property shall be interpreted as the Base64
encoding of the AES-128 key that shall be used to decrypt the private_key
using AES128-CBC.
If the password property is not present, then the value supplied in the
private_key property must contain the unencrypted private key.
##### //CycloneDDS/Domain/DDSSecurity/Authentication/PrivateKey
RELOFF (cfg.authentication_properties.private_key), pf_string, BLURB("
URI to access the private Private Key for all of the participants in the
OSPL federation.
Supported URI schemes: file, data
Examples:
<PrivateKey>file:identity_ca_private_key.pem</PrivateKey>
<PrivateKey>data:,-----BEGIN RSA PRIVATE KEY-----<br>
MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==<br>
-----END RSA PRIVATE KEY-----</PrivateKey>
##### //CycloneDDS/Domain/DDSSecurity/Authentication/TrustedCADirectory
RELOFF (cfg.authentication_properties.trusted_ca_dir), pf_string, BLURB("
Trusted CA Directory which contains trusted CA certificates as separated
files.
#### //CycloneDDS/Domain/DDSSecurity/Cryptographic
Children: [Library](#cycloneddsdomainddssecuritycryptographiclibrary)
This element configures the Cryptographic plugin of the DDS Security
specification.
##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library
Children: [finalizeFunction](#cycloneddsdomainddssecuritycryptographiclibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecuritycryptographiclibraryinitfunction), [path](#cycloneddsdomainddssecuritycryptographiclibrarypath)
RELOFF (cfg.cryptography_plugin), pf_string, BLURB("
This element specifies the library to be loaded as the DDS Security
Cryptographic plugin.
###### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library/finalizeFunction
RELOFF (cfg.cryptography_plugin.library_finalize), pf_string, BLURB("
This element names the finalization function of Cryptographic plugin.
This function is called to let the plugin release its resources.
###### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library/initFunction
RELOFF (cfg.cryptography_plugin.library_init), pf_string, BLURB("
This element names the initialization function of Cryptographic plugin.
This function is called after loading the plugin library for
instantiation purposes. Init function must return an object that
implements DDS Security Cryptographic interface.
###### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library/path
RELOFF (cfg.cryptography_plugin.library_path), pf_string, BLURB("
This element points to the path of Cryptographic plugin library.
It can be either absolute path excluding file extension (
/usr/lib/dds_security_crypto ) or single file without extension (
dds_security_crypto ).
If single file is supplied, the library located by way of the current
working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for
Windows systems.
### //CycloneDDS/Domain/Discovery
Children: [DSGracePeriod](#cycloneddsdomaindiscoverydsgraceperiod), [DefaultMulticastAddress](#cycloneddsdomaindiscoverydefaultmulticastaddress), [EnableTopicDiscovery](#cycloneddsdomaindiscoveryenabletopicdiscovery), [MaxAutoParticipantIndex](#cycloneddsdomaindiscoverymaxautoparticipantindex), [ParticipantIndex](#cycloneddsdomaindiscoveryparticipantindex), [Peers](#cycloneddsdomaindiscoverypeers), [Ports](#cycloneddsdomaindiscoveryports), [SPDPInterval](#cycloneddsdomaindiscoveryspdpinterval), [SPDPMulticastAddress](#cycloneddsdomaindiscoveryspdpmulticastaddress)
Children: [DSGracePeriod](#cycloneddsdomaindiscoverydsgraceperiod), [DefaultMulticastAddress](#cycloneddsdomaindiscoverydefaultmulticastaddress), [EnableTopicDiscovery](#cycloneddsdomaindiscoveryenabletopicdiscovery), [ExternalDomainId](#cycloneddsdomaindiscoveryexternaldomainid), [MaxAutoParticipantIndex](#cycloneddsdomaindiscoverymaxautoparticipantindex), [ParticipantIndex](#cycloneddsdomaindiscoveryparticipantindex), [Peers](#cycloneddsdomaindiscoverypeers), [Ports](#cycloneddsdomaindiscoveryports), [SPDPInterval](#cycloneddsdomaindiscoveryspdpinterval), [SPDPMulticastAddress](#cycloneddsdomaindiscoveryspdpmulticastaddress), [Tag](#cycloneddsdomaindiscoverytag)
The Discovery element allows specifying various parameters related to the
@ -140,6 +486,17 @@ Do not use.
The default value is: "true".
#### //CycloneDDS/Domain/Discovery/ExternalDomainId
Text
An override for the domain id, to be used in discovery and for
determining the port number mapping. This allows creating multiple
domains in a single process while making them appear as a single domain
on the network. The value "default" disables the override.
The default value is: "default".
#### //CycloneDDS/Domain/Discovery/MaxAutoParticipantIndex
Integer
@ -261,7 +618,7 @@ The default value is: "250".
##### //CycloneDDS/Domain/Discovery/Ports/MulticastDataOffset
Integer
This element specifies the port number for multicast meta traffic (refer
This element specifies the port number for multicast data traffic (refer
to the DDSI 2.1 specification, section 9.6.1, constant d2).
The default value is: "1".
@ -289,7 +646,7 @@ The default value is: "2".
##### //CycloneDDS/Domain/Discovery/Ports/UnicastDataOffset
Integer
This element specifies the port number for unicast meta traffic (refer to
This element specifies the port number for unicast data traffic (refer to
the DDSI 2.1 specification, section 9.6.1, constant d3).
The default value is: "11".
@ -328,6 +685,15 @@ address.
The default value is: "239.255.0.1".
#### //CycloneDDS/Domain/Discovery/Tag
Text
String extension for domain id that remote participants must match to be
discovered.
The default value is: "".
### //CycloneDDS/Domain/General
Children: [AllowMulticast](#cycloneddsdomaingeneralallowmulticast), [DontRoute](#cycloneddsdomaingeneraldontroute), [EnableMulticastLoopback](#cycloneddsdomaingeneralenablemulticastloopback), [ExternalNetworkAddress](#cycloneddsdomaingeneralexternalnetworkaddress), [ExternalNetworkMask](#cycloneddsdomaingeneralexternalnetworkmask), [FragmentSize](#cycloneddsdomaingeneralfragmentsize), [MaxMessageSize](#cycloneddsdomaingeneralmaxmessagesize), [MulticastRecvNetworkInterfaceAddresses](#cycloneddsdomaingeneralmulticastrecvnetworkinterfaceaddresses), [MulticastTimeToLive](#cycloneddsdomaingeneralmulticasttimetolive), [NetworkInterfaceAddress](#cycloneddsdomaingeneralnetworkinterfaceaddress), [PreferMulticast](#cycloneddsdomaingeneralprefermulticast), [Transport](#cycloneddsdomaingeneraltransport), [UseIPv6](#cycloneddsdomaingeneraluseipv6)
@ -672,6 +1038,8 @@ The default value is: "false".
#### //CycloneDDS/Domain/Internal/HeartbeatInterval
Attributes: [max](#cycloneddsdomaininternalheartbeatintervalmax), [min](#cycloneddsdomaininternalheartbeatintervalmin), [minsched](#cycloneddsdomaininternalheartbeatintervalminsched)
Number-with-unit
This elemnents allows configuring the base interval for sending writer
@ -683,6 +1051,42 @@ Valid values are finite durations with an explicit unit or the keyword
The default value is: "100 ms".
#### //CycloneDDS/Domain/Internal/HeartbeatInterval[@max]
Number-with-unit
This attribute sets the maximum interval for periodic heartbeats.
Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.
The default value is: "8 s".
#### //CycloneDDS/Domain/Internal/HeartbeatInterval[@min]
Number-with-unit
This attribute sets the minimum interval that must have passed since the
most recent heartbeat from a writer, before another asynchronous (not
directly related to writing) will be sent.
Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.
The default value is: "5 ms".
#### //CycloneDDS/Domain/Internal/HeartbeatInterval[@minsched]
Number-with-unit
This attribute sets the minimum interval for periodic heartbeats. Other
events may still cause heartbeats to go out.
Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.
The default value is: "20 ms".
#### //CycloneDDS/Domain/Internal/LateAckMode
Boolean
@ -704,6 +1108,8 @@ The default value is: "10 s".
#### //CycloneDDS/Domain/Internal/LivelinessMonitoring
Attributes: [Interval](#cycloneddsdomaininternallivelinessmonitoringinterval), [StackTraces](#cycloneddsdomaininternallivelinessmonitoringstacktraces)
Boolean
This element controls whether or not implementation should internally
@ -714,6 +1120,28 @@ stopped making progress.
The default value is: "false".
#### //CycloneDDS/Domain/Internal/LivelinessMonitoring[@Interval]
Number-with-unit
This element controls the interval at which to check whether threads have
been making progress.
The unit must be specified explicitly. Recognised units: ns, us, ms, s,
min, hr, day.
The default value is: "1s".
#### //CycloneDDS/Domain/Internal/LivelinessMonitoring[@StackTraces]
Boolean
This element controls whether or not to write stack traces to the Cyclone
DDS trace when a thread fails to make progress (on select platforms
only).
The default value is: "true".
#### //CycloneDDS/Domain/Internal/MaxParticipants
Integer
@ -819,6 +1247,8 @@ The default value is: "-1".
#### //CycloneDDS/Domain/Internal/MultipleReceiveThreads
Attributes: [maxretries](#cycloneddsdomaininternalmultiplereceivethreadsmaxretries)
Boolean
This element controls whether all traffic is handled by a single receive
@ -830,6 +1260,18 @@ single (the default).
The default value is: "true".
#### //CycloneDDS/Domain/Internal/MultipleReceiveThreads[@maxretries]
Integer
Receive threads dedicated to a single socket can only be triggered for
termination by sending a packet. Reception of any packet will do, so
termination failure due to packet loss is exceedingly unlikely, but to
eliminate all risks, it will retry as many times as specified by this
attribute before aborting.
The default value is: "4294967295".
#### //CycloneDDS/Domain/Internal/NackDelay
Number-with-unit
@ -880,6 +1322,8 @@ The default value is: "true".
#### //CycloneDDS/Domain/Internal/RediscoveryBlacklistDuration
Attributes: [enforce](#cycloneddsdomaininternalrediscoveryblacklistdurationenforce)
Number-with-unit
This element controls for how long a remote participant that was
@ -898,6 +1342,18 @@ Valid values are finite durations with an explicit unit or the keyword
The default value is: "10s".
#### //CycloneDDS/Domain/Internal/RediscoveryBlacklistDuration[@enforce]
Boolean
This attribute controls whether the configured time during which recently
deleted participants will not be rediscovered (i.e., "black listed") is
enforced and following complete removal of the participant in Cyclone
DDS, or whether it can be rediscovered earlier provided all traces of
that participant have been removed already.
The default value is: "false".
#### //CycloneDDS/Domain/Internal/RetransmitMerging
One of: never, adaptive, always

View file

@ -1,3 +1,4 @@
default namespace = "https://cdds.io/config"
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
grammar {
start =
@ -79,8 +80,320 @@ though there is no good reason not to.</li></ul>
element StandardsConformance {
"lax"|"strict"|"pedantic"
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>This element is used to configure Cyclone DDS with the DDS Security
specification plugins and settings.</p>""" ] ]
element DDSSecurity {
[ a:documentation [ xml:lang="en" """
<p>This element configures the Access Control plugin of the DDS Security
specification.</p>""" ] ]
element AccessControl {
[ a:documentation [ xml:lang="en" """
RELOFF (cfg.access_control_properties.governance), pf_string,
BLURB("<p>URI to the shared Governance Document signed by the Permissions
CA in S/MIME format</p>
<p>URI schemes: file, data</p><br>
<p>Examples file URIs:</p>
<p><Governance>file:governance.smime</Governance></p>
<p><Governance>file:/home/myuser/governance.smime</Governance></p><br>
<p><Governance><![CDATA[data:,MIME-Version: 1.0</p>
<p>Content-Type: multipart/signed;
protocol="application/x-pkcs7-signature"; micalg="sha-256";
boundary="----F9A8A198D6F08E1285A292ADF14DD04F"</p>
<p>This is an S/MIME signed message </p>
<p>------F9A8A198D6F08E1285A292ADF14DD04F</p>
<p><?xml version="1.0" encoding="UTF-8"?></p>
<p><dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</p>
<p>xsi:noNamespaceSchemaLocation="omg_shared_ca_governance.xsd"></p>
<p><domain_access_rules></p>
<p> . . . </p>
<p></domain_access_rules></p>
<p></dds></p>
<p>...</p>
<p>------F9A8A198D6F08E1285A292ADF14DD04F</p>
<p>Content-Type: application/x-pkcs7-signature; name="smime.p7s"</p>
<p>Content-Transfer-Encoding: base64</p>
<p>Content-Disposition: attachment; filename="smime.p7s"</p>
<p>MIIDuAYJKoZIhv ...al5s=</p>
<p>------F9A8A198D6F08E1285A292ADF14DD04F-]]</Governance></p>""" ] ]
element Governance {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.access_control_plugin), pf_string, BLURB("<p>This element
specifies the library to be loaded as the DDS Security Access Control
plugin.</p>""" ] ]
element Library {
[ a:documentation [ xml:lang="en" """
RELOFF (cfg.access_control_plugin.library_finalize), pf_string,
BLURB("<p>This element names the finalization function of Access Control
plugin. This function is called to let the plugin release its
resources.</p>""" ] ]
element finalizeFunction {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.access_control_plugin.library_init), pf_string,
BLURB("<p>This element names the initialization function of Access
Control plugin. This function is called after loading the plugin library
for instantiation purposes. Init function must return an object that
implements DDS Security Access Control interface.</p>""" ] ]
element initFunction {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.access_control_plugin.library_path), pf_string,
BLURB("<p>This element points to the path of Access Control plugin
library.</p>
<p>It can be either absolute path excluding file extension (
/usr/lib/dds_security_ac ) or single file without extension (
dds_security_ac ).</p>
<p>If single file is supplied, the library located by way of the current
working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for
Windows systems.</p>""" ] ]
element path {
empty
}?
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.access_control_properties.permissions), pf_string,
BLURB("<p>URI to the DomainParticipant permissions document signed by the
Permissions CA in S/MIME format</p>
<p>The permissions document specifies the permissions to be applied to a
domain.</p><br>
<p>Example file URIs:</p>
<p><Permissions>file:permissions_document.p7s</Permissions></p>
<p><Permissions>file:/path_to/permissions_document.p7s</Permissions></p>
<p>Example data URI:</p>
<p><Permissions><![CDATA[data:,.........]]</Permissions></p>""" ] ]
element Permissions {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.access_control_properties.permissions_ca), pf_string,
BLURB("<p>URI to a X509 certificate for the PermissionsCA in PEM
format.</p>
<p>Supported URI schemes: file, data</p>
<p>The file and data schemas shall refer to a X.509 v3 certificate (see
X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.</p><br>
<p>Examples:</p><br>
<p><PermissionsCA>file:permissions_ca.pem</PermissionsCA></p>
<p><PermissionsCA>file:/home/myuser/permissions_ca.pem</PermissionsCA></p><br>
<p><PermissionsCA>data:<strong>,</strong>-----BEGIN CERTIFICATE-----</p>
<p>MIIC3DCCAcQCCQCWE5x+Z ... PhovK0mp2ohhRLYI0ZiyYQ==</p>
<p>-----END CERTIFICATE-----</PermissionsCA></p>""" ] ]
element PermissionsCA {
empty
}?
}?
& [ a:documentation [ xml:lang="en" """
<p>This element configures the Authentication plugin of the DDS Security
specification.</p>""" ] ]
element Authentication {
[ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_properties.identity_ca), pf_string,
BLURB("<p>URI to the X509 certificate [39] of the Identity CA that is the
signer of Identity Certificate.</p>
<p>Supported URI schemes: file, data</p>
<p>The file and data schemas shall refer to a X.509 v3 certificate (see
X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.</p>
<p>Examples:</p>
<p><IdentityCA>file:identity_ca.pem</IdentityCA></p>
<p><IdentityCA>data:,-----BEGIN CERTIFICATE-----<br>
MIIC3DCCAcQCCQCWE5x+Z...PhovK0mp2ohhRLYI0ZiyYQ==<br>
-----END CERTIFICATE-----</IdentityCA></p>""" ] ]
element IdentityCA {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_properties.identity_certificate), pf_string,
BLURB("<p>Identity certificate that will be used for identifying all
participants in the OSPL instance.<br>The content is URI to a X509
certificate signed by the IdentityCA in PEM format containing the signed
public key.</p>
<p>Supported URI schemes: file, data</p>
<p>Examples:</p>
<p><IdentityCertificate>file:participant1_identity_cert.pem</IdentityCertificate></p>
<p><IdentityCertificate>data:,-----BEGIN CERTIFICATE-----<br>
MIIDjjCCAnYCCQDCEu9...6rmT87dhTo=<br>
-----END CERTIFICATE-----</IdentityCertificate></p>""" ] ]
element IdentityCertificate {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_plugin), pf_string, BLURB("<p>This element
specifies the library to be loaded as the DDS Security Access Control
plugin.</p>""" ] ]
element Library {
[ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_plugin.library_finalize), pf_string,
BLURB("<p>This element names the finalization function of Authentication
plugin. This function is called to let the plugin release its
resources.</p>""" ] ]
element finalizeFunction {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_plugin.library_init), pf_string,
BLURB("<p>This element names the initialization function of
Authentication plugin. This function is called after loading the plugin
library for instantiation purposes. Init function must return an object
that implements DDS Security Authentication interface.</p>""" ] ]
element initFunction {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_plugin.library_path), pf_string,
BLURB("<p>This element points to the path of Authentication plugin
library.</p>
<p>It can be either absolute path excluding file extension (
/usr/lib/dds_security_auth ) or single file without extension (
dds_security_auth ).</p>
<p>If single file is supplied, the library located by way of the current
working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for
Windows systems.</p>""" ] ]
element path {
empty
}?
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_properties.password), pf_string, BLURB("<p>A
password used to decrypt the private_key.</p>
The value of the password property shall be interpreted as the Base64
encoding of the AES-128 key that shall be used to decrypt the private_key
using AES128-CBC.</p>
If the password property is not present, then the value supplied in the
private_key property must contain the unencrypted private key. </p>""" ] ]
element Password {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_properties.private_key), pf_string,
BLURB("<p>URI to access the private Private Key for all of the
participants in the OSPL federation.</p>
<p>Supported URI schemes: file, data</p>
<p>Examples:</p>
<p><PrivateKey>file:identity_ca_private_key.pem</PrivateKey></p>
<p><PrivateKey>data:,-----BEGIN RSA PRIVATE KEY-----<br>
MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==<br>
-----END RSA PRIVATE KEY-----</PrivateKey></p>""" ] ]
element PrivateKey {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.authentication_properties.trusted_ca_dir), pf_string,
BLURB("<p>Trusted CA Directory which contains trusted CA certificates as
separated files.</p>""" ] ]
element TrustedCADirectory {
empty
}?
}?
& [ a:documentation [ xml:lang="en" """
<p>This element configures the Cryptographic plugin of the DDS Security
specification.</p>""" ] ]
element Cryptographic {
[ a:documentation [ xml:lang="en" """
RELOFF (cfg.cryptography_plugin), pf_string, BLURB("<p>This element
specifies the library to be loaded as the DDS Security Cryptographic
plugin.</p>""" ] ]
element Library {
[ a:documentation [ xml:lang="en" """
RELOFF (cfg.cryptography_plugin.library_finalize), pf_string,
BLURB("<p>This element names the finalization function of Cryptographic
plugin. This function is called to let the plugin release its
resources.</p>""" ] ]
element finalizeFunction {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.cryptography_plugin.library_init), pf_string, BLURB("<p>This
element names the initialization function of Cryptographic plugin. This
function is called after loading the plugin library for instantiation
purposes. Init function must return an object that implements DDS
Security Cryptographic interface.</p>""" ] ]
element initFunction {
empty
}?
& [ a:documentation [ xml:lang="en" """
RELOFF (cfg.cryptography_plugin.library_path), pf_string, BLURB("<p>This
element points to the path of Cryptographic plugin library.</p>
<p>It can be either absolute path excluding file extension (
/usr/lib/dds_security_crypto ) or single file without extension (
dds_security_crypto ).</p>
<p>If single file is supplied, the library located by way of the current
working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for
Windows systems.</p>""" ] ]
element path {
empty
}?
}?
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>The Discovery element allows specifying various parameters related to
the discovery of peers.</p>""" ] ]
element Discovery {
@ -110,6 +423,15 @@ Discovery/SPDPMulticastAddress.</p><p>The default value is:
xsd:boolean
}?
& [ a:documentation [ xml:lang="en" """
<p>An override for the domain id, to be used in discovery and for
determining the port number mapping. This allows creating multiple
domains in a single process while making them appear as a single domain
on the network. The value "default" disables the override.</p><p>The
default value is: &quot;default&quot;.</p>""" ] ]
element ExternalDomainId {
text
}?
& [ a:documentation [ xml:lang="en" """
<p>This element specifies the maximum DDSI participant index selected by
this instance of the Cyclone DDS service if the
Discovery/ParticipantIndex is "auto".</p><p>The default value is:
@ -202,7 +524,7 @@ constant DG).</p><p>The default value is: &quot;250&quot;.</p>""" ] ]
xsd:integer
}?
& [ a:documentation [ xml:lang="en" """
<p>This element specifies the port number for multicast meta traffic
<p>This element specifies the port number for multicast data traffic
(refer to the DDSI 2.1 specification, section 9.6.1, constant
d2).</p><p>The default value is: &quot;1&quot;.</p>""" ] ]
element MulticastDataOffset {
@ -224,7 +546,7 @@ section 9.6.1, constant PG).</p><p>The default value is:
xsd:integer
}?
& [ a:documentation [ xml:lang="en" """
<p>This element specifies the port number for unicast meta traffic (refer
<p>This element specifies the port number for unicast data traffic (refer
to the DDSI 2.1 specification, section 9.6.1, constant d3).</p><p>The
default value is: &quot;11&quot;.</p>""" ] ]
element UnicastDataOffset {
@ -256,7 +578,13 @@ address.</p><p>The default value is: &quot;239.255.0.1&quot;.</p>""" ] ]
element SPDPMulticastAddress {
text
}?
& [ a:documentation [ xml:lang="en" """
<p>String extension for domain id that remote participants must match to
be discovered.</p><p>The default value is: &quot;&quot;.</p>""" ] ]
element Tag {
text
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>The General element specifies overall Cyclone DDS service
settings.</p>""" ] ]
@ -558,9 +886,39 @@ heartbeats and the bounds within it can vary.</p>
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.</p><p>The default value is: &quot;100 ms&quot;.</p>""" ] ]
element HeartbeatInterval {
[ a:documentation [ xml:lang="en" """
<p>This attribute sets the maximum interval for periodic heartbeats.</p>
<p>Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.</p><p>The default value is: &quot;8 s&quot;.</p>""" ] ]
attribute max {
duration_inf
}?
& [ a:documentation [ xml:lang="en" """
<p>This attribute sets the minimum interval that must have passed since
the most recent heartbeat from a writer, before another asynchronous (not
directly related to writing) will be sent.</p>
<p>Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.</p><p>The default value is: &quot;5 ms&quot;.</p>""" ] ]
attribute min {
duration_inf
}?
& [ a:documentation [ xml:lang="en" """
<p>This attribute sets the minimum interval for periodic heartbeats.
Other events may still cause heartbeats to go out.</p>
<p>Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.</p><p>The default value is: &quot;20 ms&quot;.</p>""" ] ]
attribute minsched {
duration_inf
}?
& duration_inf
}?
& [ a:documentation [ xml:lang="en" """
<p>Ack a sample only when it has been delivered, instead of when
committed to delivering it.</p><p>The default value is:
&quot;false&quot;.</p>""" ] ]
@ -582,8 +940,24 @@ traces can be dumped automatically when some thread appears to have
stopped making progress.</p><p>The default value is:
&quot;false&quot;.</p>""" ] ]
element LivelinessMonitoring {
[ a:documentation [ xml:lang="en" """
<p>This element controls the interval at which to check whether threads
have been making progress.</p>
<p>The unit must be specified explicitly. Recognised units: ns, us, ms,
s, min, hr, day.</p><p>The default value is: &quot;1s&quot;.</p>""" ] ]
attribute Interval {
duration
}?
& [ a:documentation [ xml:lang="en" """
<p>This element controls whether or not to write stack traces to the
Cyclone DDS trace when a thread fails to make progress (on select
platforms only).</p><p>The default value is: &quot;true&quot;.</p>""" ] ]
attribute StackTraces {
xsd:boolean
}?
& xsd:boolean
}?
& [ a:documentation [ xml:lang="en" """
<p>This elements configures the maximum number of DCPS domain
participants this Cyclone DDS instance is willing to service. 0 is
@ -678,7 +1052,17 @@ latency. Currently multiple receive threads are only used for
connectionless transport (e.g., UDP) and ManySocketsMode not set to
single (the default).</p><p>The default value is: &quot;true&quot;.</p>""" ] ]
element MultipleReceiveThreads {
xsd:boolean
[ a:documentation [ xml:lang="en" """
<p>Receive threads dedicated to a single socket can only be triggered for
termination by sending a packet. Reception of any packet will do, so
termination failure due to packet loss is exceedingly unlikely, but to
eliminate all risks, it will retry as many times as specified by this
attribute before aborting.</p><p>The default value is:
&quot;4294967295&quot;.</p>""" ] ]
attribute maxretries {
xsd:integer
}?
& xsd:boolean
}?
& [ a:documentation [ xml:lang="en" """
<p>This setting controls the delay between receipt of a HEARTBEAT
@ -734,7 +1118,17 @@ is therefore recommended to set it to at least several seconds.</p>
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.</p><p>The default value is: &quot;10s&quot;.</p>""" ] ]
element RediscoveryBlacklistDuration {
duration_inf
[ a:documentation [ xml:lang="en" """
<p>This attribute controls whether the configured time during which
recently deleted participants will not be rediscovered (i.e., "black
listed") is enforced and following complete removal of the participant in
Cyclone DDS, or whether it can be rediscovered earlier provided all
traces of that participant have been removed already.</p><p>The default
value is: &quot;false&quot;.</p>""" ] ]
attribute enforce {
xsd:boolean
}?
& duration_inf
}?
& [ a:documentation [ xml:lang="en" """
<p>This elements controls the addressing and timing of retransmits.
@ -939,7 +1333,7 @@ s, min, hr, day.</p><p>The default value is: &quot;1 s&quot;.</p>""" ] ]
element WriterLingerDuration {
duration
}?
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>The Partitioning element specifies Cyclone DDS network partitions and
how DCPS partition/topic combinations are mapped onto the network
@ -1029,7 +1423,7 @@ DCPSPartitionTopic attribute within this PartitionMapping element.</p>""" ] ]
}
}*
}*
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>The SSL element allows specifying various parameters related to using
SSL/TLS for DDSI over TCP.</p>""" ] ]
@ -1089,7 +1483,7 @@ connecting client.</p><p>The default value is: &quot;true&quot;.</p>""" ] ]
element VerifyClient {
xsd:boolean
}?
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>The Sizing element specifies a variety of configuration settings
dealing with expected system sizes, buffer sizes, &c.</p>""" ] ]
@ -1120,7 +1514,7 @@ MiB&quot;.</p>""" ] ]
element ReceiveBufferSize {
memsize
}?
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>The TCP element allows specifying various parameters related to
running DDSI over TCP.</p>""" ] ]
@ -1177,7 +1571,7 @@ s, min, hr, day.</p><p>The default value is: &quot;2 s&quot;.</p>""" ] ]
element WriteTimeout {
duration
}?
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>The ThreadPool element allows specifying various parameters related to
using a thread pool to send DDSI messages to multiple unicast addresses
@ -1201,7 +1595,7 @@ pool.</p><p>The default value is: &quot;4&quot;.</p>""" ] ]
element Threads {
xsd:integer
}?
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>This element is used to set thread properties.</p>""" ] ]
element Threads {
@ -1270,7 +1664,7 @@ default.</p>
memsize
}?
}*
}?
}*
& [ a:documentation [ xml:lang="en" """
<p>The Tracing element controls the amount and type of information that
is written into the tracing log by the DDSI service. This is useful to
@ -1387,8 +1781,8 @@ verbosity levels are <i>config</i>, <i>fine</i> and
element Verbosity {
"finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none"
}?
}?
}?
}*
}*
}
bandwidth = xsd:token { pattern = "0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([kMG]i?)?[Bb][p/]s" }
duration = xsd:token { pattern = "0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([num]?s|min|hr|day)" }

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="https://cdds.io/config" xmlns:config="https://cdds.io/config">
<xs:element name="CycloneDDS">
<xs:annotation>
<xs:documentation>
@ -7,7 +7,7 @@ CycloneDDS configuration</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="Domain"/>
<xs:element minOccurs="0" ref="config:Domain"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@ -18,15 +18,15 @@ CycloneDDS configuration</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="Compatibility"/>
<xs:element minOccurs="0" ref="Discovery"/>
<xs:element minOccurs="0" ref="General"/>
<xs:element minOccurs="0" ref="Internal"/>
<xs:element minOccurs="0" ref="Partitioning"/>
<xs:element minOccurs="0" ref="SSL"/>
<xs:element minOccurs="0" ref="Sizing"/>
<xs:element minOccurs="0" ref="TCP"/>
<xs:element minOccurs="0" ref="ThreadPool"/>
<xs:element minOccurs="0" ref="config:Compatibility"/>
<xs:element minOccurs="0" ref="config:Discovery"/>
<xs:element minOccurs="0" ref="config:General"/>
<xs:element minOccurs="0" ref="config:Internal"/>
<xs:element minOccurs="0" ref="config:Partitioning"/>
<xs:element minOccurs="0" ref="config:SSL"/>
<xs:element minOccurs="0" ref="config:Sizing"/>
<xs:element minOccurs="0" ref="config:TCP"/>
<xs:element minOccurs="0" ref="config:ThreadPool"/>
<xs:element minOccurs="0" name="Threads">
<xs:annotation>
<xs:documentation>
@ -34,11 +34,11 @@ CycloneDDS configuration</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="Thread"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="config:Thread"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" ref="Tracing"/>
<xs:element minOccurs="0" ref="config:Tracing"/>
</xs:all>
<xs:attribute name="Id">
<xs:annotation>
@ -57,10 +57,10 @@ to compatability with standards and with other DDSI implementations.&lt;/p&gt;</
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="AssumeRtiHasPmdEndpoints"/>
<xs:element minOccurs="0" ref="ExplicitlyPublishQosSetToDefault"/>
<xs:element minOccurs="0" ref="ManySocketsMode"/>
<xs:element minOccurs="0" ref="StandardsConformance"/>
<xs:element minOccurs="0" ref="config:AssumeRtiHasPmdEndpoints"/>
<xs:element minOccurs="0" ref="config:ExplicitlyPublishQosSetToDefault"/>
<xs:element minOccurs="0" ref="config:ManySocketsMode"/>
<xs:element minOccurs="0" ref="config:StandardsConformance"/>
</xs:all>
</xs:complexType>
</xs:element>
@ -154,19 +154,21 @@ the discovery of peers.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="DSGracePeriod"/>
<xs:element minOccurs="0" ref="DefaultMulticastAddress"/>
<xs:element minOccurs="0" ref="EnableTopicDiscovery"/>
<xs:element minOccurs="0" ref="MaxAutoParticipantIndex"/>
<xs:element minOccurs="0" ref="ParticipantIndex"/>
<xs:element minOccurs="0" ref="Peers"/>
<xs:element minOccurs="0" ref="Ports"/>
<xs:element minOccurs="0" ref="SPDPInterval"/>
<xs:element minOccurs="0" ref="SPDPMulticastAddress"/>
<xs:element minOccurs="0" ref="config:DSGracePeriod"/>
<xs:element minOccurs="0" ref="config:DefaultMulticastAddress"/>
<xs:element minOccurs="0" ref="config:EnableTopicDiscovery"/>
<xs:element minOccurs="0" ref="config:ExternalDomainId"/>
<xs:element minOccurs="0" ref="config:MaxAutoParticipantIndex"/>
<xs:element minOccurs="0" ref="config:ParticipantIndex"/>
<xs:element minOccurs="0" ref="config:Peers"/>
<xs:element minOccurs="0" ref="config:Ports"/>
<xs:element minOccurs="0" ref="config:SPDPInterval"/>
<xs:element minOccurs="0" ref="config:SPDPMulticastAddress"/>
<xs:element minOccurs="0" ref="config:Tag"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="DSGracePeriod" type="duration_inf">
<xs:element name="DSGracePeriod" type="config:duration_inf">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls for how long endpoints discovered via a Cloud
@ -194,6 +196,16 @@ Discovery/SPDPMulticastAddress.&lt;/p&gt;&lt;p&gt;The default value is:
&lt;p&gt;Do not use.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;true&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="ExternalDomainId" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;An override for the domain id, to be used in discovery and for
determining the port number mapping. This allows creating multiple
domains in a single process while making them appear as a single domain
on the network. The value "default" disables the override.&lt;/p&gt;&lt;p&gt;The
default value is: &amp;quot;default&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="MaxAutoParticipantIndex" type="xs:integer">
<xs:annotation>
<xs:documentation>
@ -238,8 +250,8 @@ second be option be used.&lt;/p&gt;&lt;p&gt;The default value is:
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Group"/>
<xs:element ref="Peer"/>
<xs:element ref="config:Group"/>
<xs:element ref="config:Peer"/>
</xs:choice>
</xs:complexType>
</xs:element>
@ -252,7 +264,7 @@ succeeds.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="Peer"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="config:Peer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@ -284,13 +296,13 @@ by the DDSI 2.1 specification and rarely need to be changed.&lt;/p&gt;</xs:docum
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="Base"/>
<xs:element minOccurs="0" ref="DomainGain"/>
<xs:element minOccurs="0" ref="MulticastDataOffset"/>
<xs:element minOccurs="0" ref="MulticastMetaOffset"/>
<xs:element minOccurs="0" ref="ParticipantGain"/>
<xs:element minOccurs="0" ref="UnicastDataOffset"/>
<xs:element minOccurs="0" ref="UnicastMetaOffset"/>
<xs:element minOccurs="0" ref="config:Base"/>
<xs:element minOccurs="0" ref="config:DomainGain"/>
<xs:element minOccurs="0" ref="config:MulticastDataOffset"/>
<xs:element minOccurs="0" ref="config:MulticastMetaOffset"/>
<xs:element minOccurs="0" ref="config:ParticipantGain"/>
<xs:element minOccurs="0" ref="config:UnicastDataOffset"/>
<xs:element minOccurs="0" ref="config:UnicastMetaOffset"/>
</xs:all>
</xs:complexType>
</xs:element>
@ -313,7 +325,7 @@ constant DG).&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;250&amp;quot;.&l
<xs:element name="MulticastDataOffset" type="xs:integer">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the port number for multicast meta traffic
&lt;p&gt;This element specifies the port number for multicast data traffic
(refer to the DDSI 2.1 specification, section 9.6.1, constant
d2).&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;1&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
@ -338,7 +350,7 @@ section 9.6.1, constant PG).&lt;/p&gt;&lt;p&gt;The default value is:
<xs:element name="UnicastDataOffset" type="xs:integer">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the port number for unicast meta traffic (refer
&lt;p&gt;This element specifies the port number for unicast data traffic (refer
to the DDSI 2.1 specification, section 9.6.1, constant d3).&lt;/p&gt;&lt;p&gt;The
default value is: &amp;quot;11&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
@ -351,7 +363,7 @@ to the DDSI 2.1 specification, section 9.6.1, constant d1).&lt;/p&gt;&lt;p&gt;Th
default value is: &amp;quot;10&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="SPDPInterval" type="duration">
<xs:element name="SPDPInterval" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the interval between spontaneous transmissions
@ -371,6 +383,13 @@ ff02::ffff:239.255.0.1, which is a non-standardised link-local multicast
address.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;239.255.0.1&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Tag" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;String extension for domain id that remote participants must match to
be discovered.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="General">
<xs:annotation>
<xs:documentation>
@ -379,19 +398,19 @@ settings.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="AllowMulticast"/>
<xs:element minOccurs="0" ref="DontRoute"/>
<xs:element minOccurs="0" ref="EnableMulticastLoopback"/>
<xs:element minOccurs="0" ref="ExternalNetworkAddress"/>
<xs:element minOccurs="0" ref="ExternalNetworkMask"/>
<xs:element minOccurs="0" ref="FragmentSize"/>
<xs:element minOccurs="0" ref="MaxMessageSize"/>
<xs:element minOccurs="0" ref="MulticastRecvNetworkInterfaceAddresses"/>
<xs:element minOccurs="0" ref="MulticastTimeToLive"/>
<xs:element minOccurs="0" ref="NetworkInterfaceAddress"/>
<xs:element minOccurs="0" ref="PreferMulticast"/>
<xs:element minOccurs="0" ref="Transport"/>
<xs:element minOccurs="0" ref="UseIPv6"/>
<xs:element minOccurs="0" ref="config:AllowMulticast"/>
<xs:element minOccurs="0" ref="config:DontRoute"/>
<xs:element minOccurs="0" ref="config:EnableMulticastLoopback"/>
<xs:element minOccurs="0" ref="config:ExternalNetworkAddress"/>
<xs:element minOccurs="0" ref="config:ExternalNetworkMask"/>
<xs:element minOccurs="0" ref="config:FragmentSize"/>
<xs:element minOccurs="0" ref="config:MaxMessageSize"/>
<xs:element minOccurs="0" ref="config:MulticastRecvNetworkInterfaceAddresses"/>
<xs:element minOccurs="0" ref="config:MulticastTimeToLive"/>
<xs:element minOccurs="0" ref="config:NetworkInterfaceAddress"/>
<xs:element minOccurs="0" ref="config:PreferMulticast"/>
<xs:element minOccurs="0" ref="config:Transport"/>
<xs:element minOccurs="0" ref="config:UseIPv6"/>
</xs:all>
</xs:complexType>
</xs:element>
@ -477,7 +496,7 @@ address. This option is IPv4-only.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;0.0.0.0&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="FragmentSize" type="memsize">
<xs:element name="FragmentSize" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the size of DDSI sample fragments generated by
@ -493,7 +512,7 @@ of which the size is at least the minimum of 1025 and FragmentSize.&lt;/p&gt;
B&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="MaxMessageSize" type="memsize">
<xs:element name="MaxMessageSize" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the maximum size of the UDP payload that
@ -616,51 +635,51 @@ reserved. This includes renaming or moving options.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="AccelerateRexmitBlockSize"/>
<xs:element minOccurs="0" ref="AssumeMulticastCapable"/>
<xs:element minOccurs="0" ref="AutoReschedNackDelay"/>
<xs:element minOccurs="0" ref="BuiltinEndpointSet"/>
<xs:element minOccurs="0" ref="ControlTopic"/>
<xs:element minOccurs="0" ref="DDSI2DirectMaxThreads"/>
<xs:element minOccurs="0" ref="DefragReliableMaxSamples"/>
<xs:element minOccurs="0" ref="DefragUnreliableMaxSamples"/>
<xs:element minOccurs="0" ref="DeliveryQueueMaxSamples"/>
<xs:element minOccurs="0" ref="EnableExpensiveChecks"/>
<xs:element minOccurs="0" ref="GenerateKeyhash"/>
<xs:element minOccurs="0" ref="HeartbeatInterval"/>
<xs:element minOccurs="0" ref="LateAckMode"/>
<xs:element minOccurs="0" ref="LeaseDuration"/>
<xs:element minOccurs="0" ref="LivelinessMonitoring"/>
<xs:element minOccurs="0" ref="MaxParticipants"/>
<xs:element minOccurs="0" ref="MaxQueuedRexmitBytes"/>
<xs:element minOccurs="0" ref="MaxQueuedRexmitMessages"/>
<xs:element minOccurs="0" ref="MaxSampleSize"/>
<xs:element minOccurs="0" ref="MeasureHbToAckLatency"/>
<xs:element minOccurs="0" ref="MinimumSocketReceiveBufferSize"/>
<xs:element minOccurs="0" ref="MinimumSocketSendBufferSize"/>
<xs:element minOccurs="0" ref="MonitorPort"/>
<xs:element minOccurs="0" ref="MultipleReceiveThreads"/>
<xs:element minOccurs="0" ref="NackDelay"/>
<xs:element minOccurs="0" ref="PreEmptiveAckDelay"/>
<xs:element minOccurs="0" ref="PrimaryReorderMaxSamples"/>
<xs:element minOccurs="0" ref="PrioritizeRetransmit"/>
<xs:element minOccurs="0" ref="RediscoveryBlacklistDuration"/>
<xs:element minOccurs="0" ref="RetransmitMerging"/>
<xs:element minOccurs="0" ref="RetransmitMergingPeriod"/>
<xs:element minOccurs="0" ref="RetryOnRejectBestEffort"/>
<xs:element minOccurs="0" ref="SPDPResponseMaxDelay"/>
<xs:element minOccurs="0" ref="ScheduleTimeRounding"/>
<xs:element minOccurs="0" ref="SecondaryReorderMaxSamples"/>
<xs:element minOccurs="0" ref="SendAsync"/>
<xs:element minOccurs="0" ref="SquashParticipants"/>
<xs:element minOccurs="0" ref="SynchronousDeliveryLatencyBound"/>
<xs:element minOccurs="0" ref="SynchronousDeliveryPriorityThreshold"/>
<xs:element minOccurs="0" ref="Test"/>
<xs:element minOccurs="0" ref="UnicastResponseToSPDPMessages"/>
<xs:element minOccurs="0" ref="UseMulticastIfMreqn"/>
<xs:element minOccurs="0" ref="Watermarks"/>
<xs:element minOccurs="0" ref="WriteBatch"/>
<xs:element minOccurs="0" ref="WriterLingerDuration"/>
<xs:element minOccurs="0" ref="config:AccelerateRexmitBlockSize"/>
<xs:element minOccurs="0" ref="config:AssumeMulticastCapable"/>
<xs:element minOccurs="0" ref="config:AutoReschedNackDelay"/>
<xs:element minOccurs="0" ref="config:BuiltinEndpointSet"/>
<xs:element minOccurs="0" ref="config:ControlTopic"/>
<xs:element minOccurs="0" ref="config:DDSI2DirectMaxThreads"/>
<xs:element minOccurs="0" ref="config:DefragReliableMaxSamples"/>
<xs:element minOccurs="0" ref="config:DefragUnreliableMaxSamples"/>
<xs:element minOccurs="0" ref="config:DeliveryQueueMaxSamples"/>
<xs:element minOccurs="0" ref="config:EnableExpensiveChecks"/>
<xs:element minOccurs="0" ref="config:GenerateKeyhash"/>
<xs:element minOccurs="0" ref="config:HeartbeatInterval"/>
<xs:element minOccurs="0" ref="config:LateAckMode"/>
<xs:element minOccurs="0" ref="config:LeaseDuration"/>
<xs:element minOccurs="0" ref="config:LivelinessMonitoring"/>
<xs:element minOccurs="0" ref="config:MaxParticipants"/>
<xs:element minOccurs="0" ref="config:MaxQueuedRexmitBytes"/>
<xs:element minOccurs="0" ref="config:MaxQueuedRexmitMessages"/>
<xs:element minOccurs="0" ref="config:MaxSampleSize"/>
<xs:element minOccurs="0" ref="config:MeasureHbToAckLatency"/>
<xs:element minOccurs="0" ref="config:MinimumSocketReceiveBufferSize"/>
<xs:element minOccurs="0" ref="config:MinimumSocketSendBufferSize"/>
<xs:element minOccurs="0" ref="config:MonitorPort"/>
<xs:element minOccurs="0" ref="config:MultipleReceiveThreads"/>
<xs:element minOccurs="0" ref="config:NackDelay"/>
<xs:element minOccurs="0" ref="config:PreEmptiveAckDelay"/>
<xs:element minOccurs="0" ref="config:PrimaryReorderMaxSamples"/>
<xs:element minOccurs="0" ref="config:PrioritizeRetransmit"/>
<xs:element minOccurs="0" ref="config:RediscoveryBlacklistDuration"/>
<xs:element minOccurs="0" ref="config:RetransmitMerging"/>
<xs:element minOccurs="0" ref="config:RetransmitMergingPeriod"/>
<xs:element minOccurs="0" ref="config:RetryOnRejectBestEffort"/>
<xs:element minOccurs="0" ref="config:SPDPResponseMaxDelay"/>
<xs:element minOccurs="0" ref="config:ScheduleTimeRounding"/>
<xs:element minOccurs="0" ref="config:SecondaryReorderMaxSamples"/>
<xs:element minOccurs="0" ref="config:SendAsync"/>
<xs:element minOccurs="0" ref="config:SquashParticipants"/>
<xs:element minOccurs="0" ref="config:SynchronousDeliveryLatencyBound"/>
<xs:element minOccurs="0" ref="config:SynchronousDeliveryPriorityThreshold"/>
<xs:element minOccurs="0" ref="config:Test"/>
<xs:element minOccurs="0" ref="config:UnicastResponseToSPDPMessages"/>
<xs:element minOccurs="0" ref="config:UseMulticastIfMreqn"/>
<xs:element minOccurs="0" ref="config:Watermarks"/>
<xs:element minOccurs="0" ref="config:WriteBatch"/>
<xs:element minOccurs="0" ref="config:WriterLingerDuration"/>
</xs:all>
</xs:complexType>
</xs:element>
@ -684,7 +703,7 @@ wildcards) against which the interface names are matched.&lt;/p&gt;&lt;p&gt;The
default value is: &amp;quot;&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="AutoReschedNackDelay" type="duration_inf">
<xs:element name="AutoReschedNackDelay" type="config:duration_inf">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls the interval with which a reader will continue
@ -794,7 +813,7 @@ checks.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;&amp;quot;.&lt;/p&gt;<
keys.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="HeartbeatInterval" type="duration_inf">
<xs:element name="HeartbeatInterval">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This elemnents allows configuring the base interval for sending writer
@ -804,6 +823,45 @@ heartbeats and the bounds within it can vary.&lt;/p&gt;
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;100 ms&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="config:duration_inf">
<xs:attribute name="max" type="config:duration_inf">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This attribute sets the maximum interval for periodic heartbeats.&lt;/p&gt;
&lt;p&gt;Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;8 s&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="min" type="config:duration_inf">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This attribute sets the minimum interval that must have passed since
the most recent heartbeat from a writer, before another asynchronous (not
directly related to writing) will be sent.&lt;/p&gt;
&lt;p&gt;Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;5 ms&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="minsched" type="config:duration_inf">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This attribute sets the minimum interval for periodic heartbeats.
Other events may still cause heartbeats to go out.&lt;/p&gt;
&lt;p&gt;Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;20 ms&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="LateAckMode" type="xs:boolean">
<xs:annotation>
@ -813,7 +871,7 @@ committed to delivering it.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="LeaseDuration" type="duration">
<xs:element name="LeaseDuration" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls the default participant lease duration. &lt;p&gt;
@ -822,7 +880,7 @@ committed to delivering it.&lt;/p&gt;&lt;p&gt;The default value is:
s, min, hr, day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;10 s&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="LivelinessMonitoring" type="xs:boolean">
<xs:element name="LivelinessMonitoring">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element controls whether or not implementation should internally
@ -831,6 +889,30 @@ traces can be dumped automatically when some thread appears to have
stopped making progress.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:boolean">
<xs:attribute name="Interval" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element controls the interval at which to check whether threads
have been making progress.&lt;/p&gt;
&lt;p&gt;The unit must be specified explicitly. Recognised units: ns, us, ms,
s, min, hr, day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;1s&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="StackTraces" type="xs:boolean">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element controls whether or not to write stack traces to the
Cyclone DDS trace when a thread fails to make progress (on select
platforms only).&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;true&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="MaxParticipants" type="xs:integer">
<xs:annotation>
@ -840,7 +922,7 @@ participants this Cyclone DDS instance is willing to service. 0 is
unlimited.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;0&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="MaxQueuedRexmitBytes" type="memsize">
<xs:element name="MaxQueuedRexmitBytes" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting limits the maximum number of bytes queued for
@ -862,7 +944,7 @@ kB&amp;quot;.&lt;/p&gt;</xs:documentation>
retransmission.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;200&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="MaxSampleSize" type="memsize">
<xs:element name="MaxSampleSize" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls the maximum (CDR) serialised size of samples
@ -885,7 +967,7 @@ measured latencies are quite noisy and are currently not used
anywhere.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="MinimumSocketReceiveBufferSize" type="memsize">
<xs:element name="MinimumSocketReceiveBufferSize" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls the minimum size of socket receive buffers. The
@ -904,7 +986,7 @@ a smaller buffer should that attempt fail.&lt;/p&gt;
&amp;quot;default&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="MinimumSocketSendBufferSize" type="memsize">
<xs:element name="MinimumSocketSendBufferSize" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls the minimum size of socket send buffers. This
@ -927,7 +1009,7 @@ positive number is used as the TCP port number.&lt;/p&gt;&lt;p&gt;The default va
is: &amp;quot;-1&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="MultipleReceiveThreads" type="xs:boolean">
<xs:element name="MultipleReceiveThreads">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element controls whether all traffic is handled by a single
@ -936,8 +1018,25 @@ latency. Currently multiple receive threads are only used for
connectionless transport (e.g., UDP) and ManySocketsMode not set to
single (the default).&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;true&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:boolean">
<xs:attribute name="maxretries" type="xs:integer">
<xs:annotation>
<xs:documentation>
&lt;p&gt;Receive threads dedicated to a single socket can only be triggered for
termination by sending a packet. Reception of any packet will do, so
termination failure due to packet loss is exceedingly unlikely, but to
eliminate all risks, it will retry as many times as specified by this
attribute before aborting.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;4294967295&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="NackDelay" type="duration">
<xs:element name="NackDelay" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls the delay between receipt of a HEARTBEAT
@ -950,7 +1049,7 @@ that NACK will incorporate the latest information.&lt;/p&gt;
s, min, hr, day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;10 ms&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="PreEmptiveAckDelay" type="duration">
<xs:element name="PreEmptiveAckDelay" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls the delay between the discovering a remote
@ -980,7 +1079,7 @@ data, speeding up recovery.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;true&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="RediscoveryBlacklistDuration" type="duration_inf">
<xs:element name="RediscoveryBlacklistDuration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element controls for how long a remote participant that was
@ -997,6 +1096,23 @@ is therefore recommended to set it to at least several seconds.&lt;/p&gt;
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;10s&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:simpleContent>
<xs:extension base="config:duration_inf">
<xs:attribute name="enforce" type="xs:boolean">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This attribute controls whether the configured time during which
recently deleted participants will not be rediscovered (i.e., "black
listed") is enforced and following complete removal of the participant in
Cyclone DDS, or whether it can be rediscovered earlier provided all
traces of that participant have been removed already.&lt;/p&gt;&lt;p&gt;The default
value is: &amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="RetransmitMerging">
<xs:annotation>
@ -1025,7 +1141,7 @@ Internal/RetransmitMergingPeriod.&lt;/p&gt;&lt;p&gt;The default value is:
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="RetransmitMergingPeriod" type="duration">
<xs:element name="RetransmitMergingPeriod" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting determines the size of the time window in which a NACK of
@ -1047,7 +1163,7 @@ into the reader caches when resource limits are reached.&lt;/p&gt;&lt;p&gt;The
default value is: &amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="SPDPResponseMaxDelay" type="duration">
<xs:element name="SPDPResponseMaxDelay" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;Maximum pseudo-random delay in milliseconds between discovering a
@ -1057,7 +1173,7 @@ remote participant and responding to it.&lt;/p&gt;
s, min, hr, day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;0 ms&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="ScheduleTimeRounding" type="duration">
<xs:element name="ScheduleTimeRounding" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting allows the timing of scheduled events to be rounded up so
@ -1099,7 +1215,7 @@ by setting Internal/BuiltinEndpointSet to "minimal" but with less loss of
information).&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="SynchronousDeliveryLatencyBound" type="duration_inf">
<xs:element name="SynchronousDeliveryLatencyBound" type="config:duration_inf">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element controls whether samples sent by a writer with QoS
@ -1133,7 +1249,7 @@ the expense of aggregate bandwidth.&lt;/p&gt;&lt;p&gt;The default value is:
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="XmitLossiness"/>
<xs:element minOccurs="0" ref="config:XmitLossiness"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@ -1167,10 +1283,10 @@ to &lt;i&gt;false&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;t
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="WhcAdaptive"/>
<xs:element minOccurs="0" ref="WhcHigh"/>
<xs:element minOccurs="0" ref="WhcHighInit"/>
<xs:element minOccurs="0" ref="WhcLow"/>
<xs:element minOccurs="0" ref="config:WhcAdaptive"/>
<xs:element minOccurs="0" ref="config:WhcHigh"/>
<xs:element minOccurs="0" ref="config:WhcHighInit"/>
<xs:element minOccurs="0" ref="config:WhcLow"/>
</xs:all>
</xs:complexType>
</xs:element>
@ -1182,7 +1298,7 @@ mark to current traffic conditions, based on retransmit requests and
transmit pressure.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;true&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="WhcHigh" type="memsize">
<xs:element name="WhcHigh" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element sets the maximum allowed high-water mark for the Cyclone
@ -1195,7 +1311,7 @@ this size.&lt;/p&gt;
kB&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="WhcHighInit" type="memsize">
<xs:element name="WhcHighInit" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element sets the initial level of the high-water mark for the
@ -1207,7 +1323,7 @@ Cyclone DDS WHCs, expressed in bytes.&lt;/p&gt;
kB&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="WhcLow" type="memsize">
<xs:element name="WhcLow" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element sets the low-water mark for the Cyclone DDS WHCs,
@ -1233,7 +1349,7 @@ dds_write_flush function to ensure thta all samples are
written.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="WriterLingerDuration" type="duration">
<xs:element name="WriterLingerDuration" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This setting controls the maximum duration for which actual deletion
@ -1253,9 +1369,9 @@ partitions.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="IgnoredPartitions"/>
<xs:element ref="NetworkPartitions"/>
<xs:element ref="PartitionMappings"/>
<xs:element ref="config:IgnoredPartitions"/>
<xs:element ref="config:NetworkPartitions"/>
<xs:element ref="config:PartitionMappings"/>
</xs:choice>
</xs:complexType>
</xs:element>
@ -1267,7 +1383,7 @@ combinations that are not distributed over the network.&lt;/p&gt;</xs:documentat
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="IgnoredPartition"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="config:IgnoredPartition"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@ -1302,7 +1418,7 @@ partitions.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="NetworkPartition"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="config:NetworkPartition"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@ -1347,7 +1463,7 @@ partition/topic combinations to Cyclone DDS network partitions.&lt;/p&gt;</xs:do
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="PartitionMapping"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="config:PartitionMapping"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@ -1390,8 +1506,8 @@ SSL/TLS for DDSI over TCP.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="CertificateVerification"/>
<xs:element minOccurs="0" ref="Ciphers"/>
<xs:element minOccurs="0" ref="config:CertificateVerification"/>
<xs:element minOccurs="0" ref="config:Ciphers"/>
<xs:element minOccurs="0" name="Enable" type="xs:boolean">
<xs:annotation>
<xs:documentation>
@ -1399,12 +1515,12 @@ SSL/TLS for DDSI over TCP.&lt;/p&gt;</xs:documentation>
&amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" ref="EntropyFile"/>
<xs:element minOccurs="0" ref="KeyPassphrase"/>
<xs:element minOccurs="0" ref="KeystoreFile"/>
<xs:element minOccurs="0" ref="MinimumTLSVersion"/>
<xs:element minOccurs="0" ref="SelfSignedCertificates"/>
<xs:element minOccurs="0" ref="VerifyClient"/>
<xs:element minOccurs="0" ref="config:EntropyFile"/>
<xs:element minOccurs="0" ref="config:KeyPassphrase"/>
<xs:element minOccurs="0" ref="config:KeystoreFile"/>
<xs:element minOccurs="0" ref="config:MinimumTLSVersion"/>
<xs:element minOccurs="0" ref="config:SelfSignedCertificates"/>
<xs:element minOccurs="0" ref="config:VerifyClient"/>
</xs:all>
</xs:complexType>
</xs:element>
@ -1473,12 +1589,12 @@ dealing with expected system sizes, buffer sizes, &amp;c.&lt;/p&gt;</xs:document
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="ReceiveBufferChunkSize"/>
<xs:element minOccurs="0" ref="ReceiveBufferSize"/>
<xs:element minOccurs="0" ref="config:ReceiveBufferChunkSize"/>
<xs:element minOccurs="0" ref="config:ReceiveBufferSize"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="ReceiveBufferChunkSize" type="memsize">
<xs:element name="ReceiveBufferChunkSize" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the size of one allocation unit in the receive
@ -1492,7 +1608,7 @@ after processing a message, or freed straightaway.&lt;/p&gt;
KiB&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="ReceiveBufferSize" type="memsize">
<xs:element name="ReceiveBufferSize" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element sets the size of a single receive buffer. Many receive
@ -1514,7 +1630,7 @@ running DDSI over TCP.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="AlwaysUsePeeraddrForUnicast"/>
<xs:element minOccurs="0" ref="config:AlwaysUsePeeraddrForUnicast"/>
<xs:element minOccurs="0" name="Enable">
<xs:annotation>
<xs:documentation>
@ -1530,10 +1646,10 @@ General/Transport instead.&lt;/p&gt;&lt;p&gt;The default value is:
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element minOccurs="0" ref="NoDelay"/>
<xs:element minOccurs="0" ref="Port"/>
<xs:element minOccurs="0" ref="ReadTimeout"/>
<xs:element minOccurs="0" ref="WriteTimeout"/>
<xs:element minOccurs="0" ref="config:NoDelay"/>
<xs:element minOccurs="0" ref="config:Port"/>
<xs:element minOccurs="0" ref="config:ReadTimeout"/>
<xs:element minOccurs="0" ref="config:WriteTimeout"/>
</xs:all>
</xs:complexType>
</xs:element>
@ -1567,7 +1683,7 @@ by establishing connections to other services.&lt;/p&gt;&lt;p&gt;The default val
is: &amp;quot;-1&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="ReadTimeout" type="duration">
<xs:element name="ReadTimeout" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the timeout for blocking TCP read operations.
@ -1577,7 +1693,7 @@ If this timeout expires then the connection is closed.&lt;/p&gt;
s, min, hr, day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;2 s&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="WriteTimeout" type="duration">
<xs:element name="WriteTimeout" type="config:duration">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the timeout for blocking TCP write operations.
@ -1603,7 +1719,7 @@ using a thread pool to send DDSI messages to multiple unicast addresses
is: &amp;quot;false&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" ref="ThreadMax"/>
<xs:element minOccurs="0" ref="config:ThreadMax"/>
<xs:element minOccurs="0" name="Threads" type="xs:integer">
<xs:annotation>
<xs:documentation>
@ -1628,8 +1744,8 @@ pool.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;8&amp;quot;.&lt;/p&gt;</
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="Scheduling"/>
<xs:element minOccurs="0" ref="StackSize"/>
<xs:element minOccurs="0" ref="config:Scheduling"/>
<xs:element minOccurs="0" ref="config:StackSize"/>
</xs:all>
<xs:attribute name="Name" use="required">
<xs:annotation>
@ -1667,8 +1783,8 @@ discovery;&lt;/li&gt;
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="Class"/>
<xs:element minOccurs="0" ref="Priority"/>
<xs:element minOccurs="0" ref="config:Class"/>
<xs:element minOccurs="0" ref="config:Priority"/>
</xs:all>
</xs:complexType>
</xs:element>
@ -1700,7 +1816,7 @@ assign some of the privileged priorities.&lt;/p&gt;&lt;p&gt;The default value is
&amp;quot;default&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="StackSize" type="memsize">
<xs:element name="StackSize" type="config:memsize">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element configures the stack size for this thread. The default
@ -1722,11 +1838,11 @@ track the DDSI service during application development.&lt;/p&gt;</xs:documentati
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="AppendToFile"/>
<xs:element minOccurs="0" ref="Category"/>
<xs:element minOccurs="0" ref="OutputFile"/>
<xs:element minOccurs="0" ref="PacketCaptureFile"/>
<xs:element minOccurs="0" ref="Verbosity"/>
<xs:element minOccurs="0" ref="config:AppendToFile"/>
<xs:element minOccurs="0" ref="config:Category"/>
<xs:element minOccurs="0" ref="config:OutputFile"/>
<xs:element minOccurs="0" ref="config:PacketCaptureFile"/>
<xs:element minOccurs="0" ref="config:Verbosity"/>
</xs:all>
</xs:complexType>
</xs:element>

View file

@ -1,10 +1,8 @@
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
endif()
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../../..")
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.

View file

@ -11,11 +11,9 @@
#
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
endif()
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../../..")
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.

View file

@ -11,11 +11,9 @@
#
cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
endif()
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../../..")
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.

View file

@ -93,7 +93,7 @@ int main (int argc, char **argv)
signal (SIGINT, sigint);
process_samples(reader, maxCycles);
dds_set_status_mask (reader, 0);
(void) dds_set_status_mask (reader, 0);
HandleMap__free (imap);
finalize_dds (participant);
return EXIT_SUCCESS;
@ -154,7 +154,7 @@ static HandleEntry * retrieve_handle (HandleMap *map, dds_instance_handle_t key)
static int do_take (dds_entity_t reader)
{
int samples_received;
dds_sample_info_t info [MAX_SAMPLES];
dds_sample_info_t *info = NULL;
dds_instance_handle_t ph = 0;
HandleEntry * current = NULL;
@ -165,9 +165,14 @@ static int do_take (dds_entity_t reader)
/* Take samples and iterate through them */
info = dds_alloc (sizeof(dds_sample_info_t) * MAX_SAMPLES);
samples_received = dds_take (reader, samples, info, MAX_SAMPLES, MAX_SAMPLES);
if (samples_received < 0)
{
dds_free( info );
DDS_FATAL("dds_take: %s\n", dds_strretcode(-samples_received));
}
for (int i = 0; !done && i < samples_received; i++)
{
@ -196,13 +201,14 @@ static int do_take (dds_entity_t reader)
total_samples++;
}
}
dds_free (info);
return samples_received;
}
static void data_available_handler (dds_entity_t reader, void *arg)
{
(void)arg;
do_take (reader);
(void) do_take (reader);
}
static int parse_args(int argc, char **argv, unsigned long long *maxCycles, char **partitionName)

View file

@ -103,7 +103,8 @@ if(BUILD_DOCS)
"__attribute__="
"__declspec(x)="
"DDS_EXPORT="
"DDS_DEPRECATED_EXPORT=")
"DDS_DEPRECATED_EXPORT="
"DDSRT_STATIC_ASSERT(x)=")
find_package(Doxygen REQUIRED)
doxygen_add_docs(ddsc_api_docs "ddsc/include")
endif()

View file

@ -747,27 +747,50 @@ dds_create_participant(
* @brief Creates a domain with a given configuration
*
* To explicitly create a domain based on a configuration passed as a string.
* Normally, the domain is created implicitly on the first call to
* dds_create_particiant based on the configuration specified throught
* the environment. This function allows to by-pass this behaviour.
*
* It will not be created if a domain with the given domain id already exists.
* This could have been created implicitly by a dds_create_participant().
*
* Please be aware that the given domain_id always takes precedence over the
* configuration.
*
* | domain_id | domain id in config | result
* +-----------+---------------------+----------
* | n | any (or absent) | n, config is used
* | n | m == n | n, config is used
* | n | m != n | n, config is ignored: default
*
* Config models:
* 1: <CycloneDDS>
* <Domain id="X">...</Domain>
* <Domain .../>
* </CycloneDDS>
* where ... is all that can today be set in children of CycloneDDS
* with the exception of the id
* 2: <CycloneDDS>
* <Domain><Id>X</Id></Domain>
* ...
* </CycloneDDS>
* legacy form, domain id must be the first element in the file with
* a value (if nothing has been set previously, it a warning is good
* enough)
*
* Using NULL or "" as config will create a domain with default settings.
*
*
* @param[in] domain The domain to be created. DEFAULT_DOMAIN is not allowed.
* @param[in] config A configuration string containing file names and/or XML fragments representing the configuration.
*
* @returns A return code
* @returns A valid entity handle or an error code.
*
* @retval DDS_RETCODE_OK
* The domain with the domain identifier has been created from
* given configuration string.
* @retval DDS_RETCODE_BAD_PARAMETER
* Illegal value for domain id or the configfile parameter is NULL.
* @retval DDS_PRECONDITION_NOT_MET
* @retval DDS_RETCODE_PRECONDITION_NOT_MET
* The domain already existed and cannot be created again.
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
*/
DDS_EXPORT dds_return_t
DDS_EXPORT dds_entity_t
dds_create_domain(const dds_domainid_t domain, const char *config);
/**
@ -777,15 +800,10 @@ dds_create_domain(const dds_domainid_t domain, const char *config);
* For instance, it will return the Participant that was used when
* creating a Publisher (when that Publisher was provided here).
*
* When a reader or a writer are created with a partition, then a
* subscriber or publisher respectively are created implicitly. These
* implicit subscribers or publishers will be deleted automatically
* when the reader or writer is deleted. However, when this function
* returns such an implicit entity, it is from there on out considered
* 'explicit'. This means that it isn't deleted automatically anymore.
* The application should explicitly call dds_delete on those entities
* now (or delete the parent participant which will delete all entities
* within its hierarchy).
* When a reader or a writer are created with a participant, then a
* subscriber or publisher are created implicitly.
* This function will return the implicit parent and not the used
* participant.
*
* @param[in] entity Entity from which to get its parent.
*
@ -852,15 +870,10 @@ dds_get_participant(dds_entity_t entity);
* When supplying NULL as list and 0 as size, you can use this to acquire
* the number of children without having to pre-allocate a list.
*
* When a reader or a writer are created with a partition, then a
* subscriber or publisher respectively are created implicitly. These
* implicit subscribers or publishers will be deleted automatically
* when the reader or writer is deleted. However, when this function
* returns such an implicit entity, it is from there on out considered
* 'explicit'. This means that it isn't deleted automatically anymore.
* The application should explicitly call dds_delete on those entities
* now (or delete the parent participant which will delete all entities
* within its hierarchy).
* When a reader or a writer are created with a participant, then a
* subscriber or publisher are created implicitly.
* When used on the participant, this function will return the implicit
* subscriber and/or publisher and not the related reader/writer.
*
* @param[in] entity Entity from which to get its children.
* @param[out] children Pre-allocated array to contain the found children.
@ -869,7 +882,7 @@ dds_get_participant(dds_entity_t entity);
* @returns Number of children or an error code.
*
* @retval >=0
* Number of childer found children (can be larger than 'size').
* Number of found children (can be larger than 'size').
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
* @retval DDS_RETCODE_BAD_PARAMETER
@ -1200,6 +1213,7 @@ dds_wait_for_acks(dds_entity_t publisher_or_writer, dds_duration_t timeout);
/**
* @brief Creates a new instance of a DDS reader.
*
* When a participant is used to create a reader, an implicit subscriber is created.
* This implicit subscriber will be deleted automatically when the created reader
* is deleted.
*
@ -1226,6 +1240,7 @@ dds_create_reader(
/**
* @brief Creates a new instance of a DDS reader with a custom history cache.
*
* When a participant is used to create a reader, an implicit subscriber is created.
* This implicit subscriber will be deleted automatically when the created reader
* is deleted.
*
@ -1273,6 +1288,7 @@ dds_reader_wait_for_historical_data(
/**
* @brief Creates a new instance of a DDS writer.
*
* When a participant is used to create a writer, an implicit publisher is created.
* This implicit publisher will be deleted automatically when the created writer
* is deleted.
*
@ -1696,12 +1712,28 @@ DDS_EXPORT void
dds_write_flush(dds_entity_t writer);
/**
* @brief Write a CDR serialized value of a data instance
* @brief Write a serialized value of a data instance
*
* This call causes the writer to write the serialized value that is provided
* in the serdata argument.
*
* @param[in] writer The writer entity.
* @param[in] serdata CDR serialized value to be written.
* @param[in] serdata Serialized value to be written.
*
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* The writer successfully wrote the serialized value.
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
* @retval DDS_RETCODE_BAD_PARAMETER
* One of the given arguments is not valid.
* @retval DDS_RETCODE_ILLEGAL_OPERATION
* The operation is invoked on an inappropriate object.
* @retval DDS_RETCODE_ALREADY_DELETED
* The entity has already been deleted.
* @retval DDS_RETCODE_TIMEOUT
* The writer failed to write the serialized value reliably within the specified max_blocking_time.
*/
DDS_EXPORT dds_return_t
dds_writecdr(dds_entity_t writer, struct ddsi_serdata *serdata);
@ -2652,6 +2684,44 @@ dds_take_mask_wl(
uint32_t maxs,
uint32_t mask);
/**
* @brief Access the collection of serialized data values (of same type) and
* sample info from the data reader, readcondition or querycondition.
*
* This call accesses the serialized data from the data reader, readcondition or
* querycondition and makes it available to the application. The serialized data
* is made available through \ref ddsi_serdata structures. Once read the data is
* removed from the reader and cannot be 'read' or 'taken' again.
*
* Return value provides information about the number of samples read, which will
* be <= maxs. Based on the count, the buffer will contain serialized data to be
* read only when valid_data bit in sample info structure is set.
* The buffer required for data values, could be allocated explicitly or can
* use the memory from data reader to prevent copy. In the latter case, buffer and
* sample_info should be returned back, once it is no longer using the data.
*
* @param[in] reader_or_condition Reader, readcondition or querycondition entity.
* @param[out] buf An array of pointers to \ref ddsi_serdata structures that contain
* the serialized data. The pointers can be NULL.
* @param[in] maxs Maximum number of samples to read.
* @param[out] si Pointer to an array of \ref dds_sample_info_t returned for each data value.
* @param[in] mask Filter the data based on dds_sample_state_t|dds_view_state_t|dds_instance_state_t.
*
* @returns A dds_return_t with the number of samples read or an error code.
*
* @retval >=0
* Number of samples read.
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
* @retval DDS_RETCODE_BAD_PARAMETER
* One of the given arguments is not valid.
* @retval DDS_RETCODE_ILLEGAL_OPERATION
* The operation is invoked on an inappropriate object.
* @retval DDS_RETCODE_ALREADY_DELETED
* The entity has already been deleted.
* @retval DDS_RETCODE_PRECONDITION_NOT_MET
* The precondition for this operation is not met.
*/
DDS_EXPORT dds_return_t
dds_takecdr(
dds_entity_t reader_or_condition,
@ -3244,6 +3314,29 @@ dds_get_matched_publication_data (
dds_entity_t reader,
dds_instance_handle_t ih);
/**
* @brief This operation manually asserts the liveliness of a writer
* or domain participant.
*
* This operation manually asserts the liveliness of a writer
* or domain participant. This is used in combination with the Liveliness
* QoS policy to indicate that the entity remains active. This operation need
* only be used if the liveliness kind in the QoS is either
* DDS_LIVELINESS_MANUAL_BY_PARTICIPANT or DDS_LIVELINESS_MANUAL_BY_TOPIC.
*
* @param[in] entity A domain participant or writer
*
* @returns A dds_return_t indicating success or failure.
*
* @retval DDS_RETCODE_OK
* The operation was successful.
* @retval DDS_RETCODE_ILLEGAL_OPERATION
* The operation is invoked on an inappropriate object.
*/
DDS_EXPORT dds_return_t
dds_assert_liveliness (
dds_entity_t entity);
#if defined (__cplusplus)
}
#endif

View file

@ -18,7 +18,7 @@
extern "C" {
#endif
DDS_EXPORT dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config) ddsrt_nonnull((1,4));
DDS_EXPORT dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool implicit, const char *config) ddsrt_nonnull((1,4));
DDS_EXPORT dds_domain *dds_domain_find_locked (dds_domainid_t id);
#if defined (__cplusplus)

View file

@ -24,6 +24,7 @@ dds_entity_init(
dds_entity * e,
dds_entity * parent,
dds_entity_kind_t kind,
bool implicit,
dds_qos_t * qos,
const dds_listener_t *listener,
status_mask_t mask);
@ -38,6 +39,12 @@ dds_entity_register_child (
DDS_EXPORT void
dds_entity_add_ref_locked(dds_entity *e);
DDS_EXPORT void
dds_entity_drop_ref(dds_entity *e);
DDS_EXPORT void
dds_entity_unpin_and_drop_ref (dds_entity *e);
#define DEFINE_ENTITY_LOCK_UNLOCK(qualifier_, type_, kind_) \
qualifier_ dds_return_t type_##_lock (dds_entity_t hdl, type_ **x) \
{ \
@ -96,6 +103,8 @@ dds_entity_pin (
dds_entity_t hdl,
dds_entity **eptr);
DDS_EXPORT dds_return_t dds_entity_pin_for_delete (dds_entity_t hdl, bool explicit, dds_entity **eptr);
DDS_EXPORT void dds_entity_unpin (
dds_entity *e);

View file

@ -73,8 +73,10 @@ typedef int32_t dds_handle_t;
/* Closing & closed can be combined, but having two gives a means for enforcing
that close() be called first, then close_wait(), and then delete(). */
#define HDL_FLAG_CLOSING (0x80000000u)
#define HDL_FLAG_CLOSED (0x40000000u)
#define HDL_FLAG_DELETE_DEFERRED (0x40000000u)
#define HDL_FLAG_PENDING (0x20000000u)
#define HDL_FLAG_IMPLICIT (0x10000000u)
#define HDL_FLAG_ALLOW_CHILDREN (0x08000000u) /* refc counts children */
struct dds_handle_link {
dds_handle_t hdl;
@ -116,7 +118,9 @@ dds_handle_server_fini(void);
*/
DDS_EXPORT dds_handle_t
dds_handle_create(
struct dds_handle_link *link);
struct dds_handle_link *link,
bool implicit,
bool allow_children);
/*
@ -124,7 +128,7 @@ dds_handle_create(
*/
DDS_EXPORT dds_return_t
dds_handle_register_special (
struct dds_handle_link *link, dds_handle_t handle);
struct dds_handle_link *link, bool implicit, bool allow_children, dds_handle_t handle);
DDS_EXPORT void dds_handle_unpend (struct dds_handle_link *link);
@ -181,6 +185,8 @@ DDS_EXPORT void
dds_handle_unpin(
struct dds_handle_link *link);
int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_handle_link **link);
bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_delete_parent);
/*
* Check if the handle is closed.
@ -195,11 +201,15 @@ dds_handle_unpin(
DDS_EXPORT void dds_handle_add_ref (struct dds_handle_link *link);
DDS_EXPORT bool dds_handle_drop_ref (struct dds_handle_link *link);
DDS_EXPORT bool dds_handle_close (struct dds_handle_link *link);
DDS_EXPORT bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link);
DDS_EXPORT inline bool dds_handle_is_closed (struct dds_handle_link *link) {
return (ddsrt_atomic_ld32 (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING)) != 0;
return (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSING) != 0;
}
DDS_EXPORT bool dds_handle_is_not_refd (struct dds_handle_link *link);
#if defined (__cplusplus)
}
#endif

View file

@ -21,6 +21,13 @@ extern "C" {
DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_publisher, DDS_KIND_PUBLISHER)
dds_entity_t
dds__create_publisher_l(
struct dds_participant *participant, /* entity-lock must be held */
bool implicit,
const dds_qos_t *qos,
const dds_listener_t *listener);
dds_return_t dds_publisher_begin_coherent (dds_entity_t e);
dds_return_t dds_publisher_end_coherent (dds_entity_t e);

View file

@ -24,6 +24,7 @@ DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_subscriber, DDS_KIND_SUBSCRIBER)
dds_entity_t
dds__create_subscriber_l(
struct dds_participant *participant, /* entity-lock must be held */
bool implicit,
const dds_qos_t *qos,
const dds_listener_t *listener);

View file

@ -245,7 +245,7 @@ typedef struct dds_participant {
typedef struct dds_reader {
struct dds_entity m_entity;
const struct dds_topic *m_topic;
struct dds_topic *m_topic;
struct dds_rhc *m_rhc; /* aliases m_rd->rhc with a wider interface, FIXME: but m_rd owns it for resource management */
struct reader *m_rd;
bool m_data_on_readers;
@ -265,7 +265,7 @@ typedef struct dds_reader {
typedef struct dds_writer {
struct dds_entity m_entity;
const struct dds_topic *m_topic;
struct dds_topic *m_topic;
struct nn_xpack *m_xp;
struct writer *m_wr;
struct whc *m_whc; /* FIXME: ownership still with underlying DDSI writer (cos of DDSI built-in writers )*/

View file

@ -131,7 +131,7 @@ bool dds__validate_builtin_reader_qos (const dds_domain *dom, dds_entity_t topic
static dds_entity_t dds__create_builtin_subscriber (dds_participant *participant)
{
dds_qos_t *qos = dds__create_builtin_qos ();
dds_entity_t sub = dds__create_subscriber_l (participant, qos, NULL);
dds_entity_t sub = dds__create_subscriber_l (participant, false, qos, NULL);
dds_delete_qos (qos);
return sub;
}

View file

@ -48,16 +48,14 @@ static int dds_domain_compare (const void *va, const void *vb)
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config)
static dds_entity_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config, bool implicit)
{
dds_return_t ret = DDS_RETCODE_OK;
dds_entity_t domh;
uint32_t len;
dds_entity_t domain_handle;
if ((domain_handle = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, NULL, NULL, 0)) < 0)
return domain_handle;
if ((domh = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, implicit, NULL, NULL, 0)) < 0)
return domh;
domain->m_entity.m_domain = domain;
domain->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
domain->m_entity.m_iid = ddsi_iid_gen ();
domain->gv.tstart = now ();
@ -90,7 +88,7 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (domain->cfgst == NULL)
{
DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration\n");
ret = DDS_RETCODE_ERROR;
domh = DDS_RETCODE_ERROR;
goto fail_config;
}
@ -100,14 +98,14 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (rtps_config_prep (&domain->gv, domain->cfgst) != 0)
{
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to configure RTPS\n");
ret = DDS_RETCODE_ERROR;
domh = DDS_RETCODE_ERROR;
goto fail_rtps_config;
}
if (rtps_init (&domain->gv) < 0)
{
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to initialize RTPS\n");
ret = DDS_RETCODE_ERROR;
domh = DDS_RETCODE_ERROR;
goto fail_rtps_init;
}
@ -122,14 +120,14 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (dds_global.threadmon == NULL)
{
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to create a thread liveliness monitor\n");
ret = DDS_RETCODE_OUT_OF_RESOURCES;
domh = DDS_RETCODE_OUT_OF_RESOURCES;
goto fail_threadmon_new;
}
/* FIXME: thread properties */
if (ddsi_threadmon_start (dds_global.threadmon, "threadmon") < 0)
{
DDS_ILOG (DDS_LC_ERROR, domain->m_id, "Failed to start the thread liveliness monitor\n");
ret = DDS_RETCODE_ERROR;
domh = DDS_RETCODE_ERROR;
goto fail_threadmon_start;
}
}
@ -159,16 +157,17 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (rtps_start (&domain->gv) < 0)
{
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to start RTPS\n");
ret = DDS_RETCODE_ERROR;
domh = DDS_RETCODE_ERROR;
goto fail_rtps_start;
}
if (domain->gv.config.liveliness_monitoring)
ddsi_threadmon_register_domain (dds_global.threadmon, &domain->gv);
dds_entity_init_complete (&domain->m_entity);
return DDS_RETCODE_OK;
return domh;
fail_rtps_start:
dds__builtin_fini (domain);
if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1)
ddsi_threadmon_stop (dds_global.threadmon);
fail_threadmon_start:
@ -184,7 +183,7 @@ fail_rtps_config:
config_fini (domain->cfgst);
fail_config:
dds_handle_delete (&domain->m_entity.m_hdllink);
return ret;
return domh;
}
dds_domain *dds_domain_find_locked (dds_domainid_t id)
@ -192,37 +191,25 @@ dds_domain *dds_domain_find_locked (dds_domainid_t id)
return ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &id);
}
dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config)
dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool implicit, const char *config)
{
struct dds_domain *dom;
dds_return_t ret;
dds_entity_t domh = DDS_RETCODE_ERROR;
/* FIXME: should perhaps lock parent object just like everywhere */
ddsrt_mutex_lock (&dds_global.m_mutex);
retry:
if (id != DDS_DOMAIN_DEFAULT)
{
if ((dom = dds_domain_find_locked (id)) == NULL)
ret = DDS_RETCODE_NOT_FOUND;
dom = dds_domain_find_locked (id);
else
ret = DDS_RETCODE_OK;
}
else
{
if ((dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains)) != NULL)
ret = DDS_RETCODE_OK;
else
ret = DDS_RETCODE_NOT_FOUND;
}
dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains);
switch (ret)
if (dom)
{
case DDS_RETCODE_OK:
if (!use_existing)
if (!implicit)
domh = DDS_RETCODE_PRECONDITION_NOT_MET;
else
{
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
break;
}
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
{
@ -230,52 +217,54 @@ dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t
ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
goto retry;
}
else
{
dds_entity_add_ref_locked (&dom->m_entity);
dds_handle_repin (&dom->m_entity.m_hdllink);
domh = dom->m_entity.m_hdllink.hdl;
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
*domain_out = dom;
}
break;
case DDS_RETCODE_NOT_FOUND:
}
else
{
dom = dds_alloc (sizeof (*dom));
if ((ret = dds_domain_init (dom, id, config)) < 0)
if ((domh = dds_domain_init (dom, id, config, implicit)) < 0)
dds_free (dom);
else
{
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom);
dds_entity_register_child (&dds_global.m_entity, &dom->m_entity);
if (implicit)
{
dds_entity_add_ref_locked (&dom->m_entity);
dds_handle_repin (&dom->m_entity.m_hdllink);
}
domh = dom->m_entity.m_hdllink.hdl;
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
*domain_out = dom;
}
break;
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
return ret;
return domh;
}
dds_return_t dds_create_domain(const dds_domainid_t domain, const char *config)
dds_entity_t dds_create_domain (const dds_domainid_t domain, const char *config)
{
dds_domain *dom;
dds_entity_t ret;
if (domain == DDS_DOMAIN_DEFAULT || config == NULL)
if (domain == DDS_DOMAIN_DEFAULT)
return DDS_RETCODE_BAD_PARAMETER;
if (config == NULL)
config = "";
/* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0)
goto err_dds_init;
return ret;
if ((ret = dds_domain_create_internal (&dom, domain, false, config)) < 0)
goto err_domain_create;
return DDS_RETCODE_OK;
err_domain_create:
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
err_dds_init:
ret = dds_domain_create_internal (&dom, domain, false, config);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return ret;
}
@ -368,5 +357,5 @@ void dds_write_set_batch (bool enable)
}
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
}

View file

@ -22,7 +22,9 @@
#include "dds__qos.h"
#include "dds__topic.h"
#include "dds/version.h"
#include "dds/ddsi/ddsi_pmd.h"
#include "dds/ddsi/q_xqos.h"
#include "dds/ddsi/q_transmit.h"
extern inline dds_entity *dds_entity_from_handle_link (struct dds_handle_link *hdllink);
extern inline bool dds_entity_is_enabled (const dds_entity *e);
@ -80,11 +82,34 @@ const ddsrt_avl_treedef_t dds_entity_children_td = DDSRT_AVL_TREEDEF_INITIALIZER
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status);
static void dds_entity_observers_signal_delete (dds_entity *observed);
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate);
static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, enum delete_impl_state delstate);
void dds_entity_add_ref_locked (dds_entity *e)
{
dds_handle_add_ref (&e->m_hdllink);
}
void dds_entity_drop_ref (dds_entity *e)
{
if (dds_handle_drop_ref (&e->m_hdllink))
{
dds_return_t ret = dds_delete_impl(e->m_hdllink.hdl, DIS_EXPLICIT);
assert (ret == DDS_RETCODE_OK);
(void) ret;
}
}
void dds_entity_unpin_and_drop_ref (dds_entity *e)
{
if (dds_handle_unpin_and_drop_ref (&e->m_hdllink))
{
dds_return_t ret = dds_delete_impl(e->m_hdllink.hdl, DIS_EXPLICIT);
assert (ret == DDS_RETCODE_OK);
(void) ret;
}
}
static bool entity_has_status (const dds_entity *e)
{
switch (e->m_kind)
@ -110,7 +135,7 @@ static bool entity_has_status (const dds_entity *e)
return false;
}
dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask)
dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, bool implicit, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask)
{
dds_handle_t handle;
@ -125,6 +150,8 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
/* TODO: CHAM-96: Implement dynamic enabling of entity. */
e->m_flags |= DDS_ENTITY_ENABLED;
if (implicit)
e->m_flags |= DDS_ENTITY_IMPLICIT;
/* set the status enable based on kind */
if (entity_has_status (e))
@ -162,12 +189,14 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
if (kind == DDS_KIND_CYCLONEDDS)
{
if ((handle = dds_handle_register_special (&e->m_hdllink, DDS_CYCLONEDDS_HANDLE)) <= 0)
if ((handle = dds_handle_register_special (&e->m_hdllink, implicit, true, DDS_CYCLONEDDS_HANDLE)) <= 0)
return (dds_entity_t) handle;
}
else
{
if ((handle = dds_handle_create (&e->m_hdllink)) <= 0)
/* for topics, refc counts readers/writers, for all others, it counts children (this we can get away with
as long as topics can't have children) */
if ((handle = dds_handle_create (&e->m_hdllink, implicit, (kind != DDS_KIND_TOPIC))) <= 0)
return (dds_entity_t) handle;
}
@ -182,22 +211,53 @@ void dds_entity_init_complete (dds_entity *entity)
void dds_entity_register_child (dds_entity *parent, dds_entity *child)
{
/* parent must be tracking children in its refc, or children can't be added */
assert (ddsrt_atomic_ld32 (&parent->m_hdllink.cnt_flags) & HDL_FLAG_ALLOW_CHILDREN);
assert (child->m_iid != 0);
assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &child->m_iid) == NULL);
ddsrt_avl_insert (&dds_entity_children_td, &parent->m_children, child);
dds_entity_add_ref_locked (parent);
}
static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
static dds_entity *get_first_child (ddsrt_avl_tree_t *remaining_children, bool ignore_topics)
{
ddsrt_avl_iter_t it;
for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, remaining_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
{
if (dds_entity_kind (e) != DDS_KIND_TOPIC)
if ((!ignore_topics) || (dds_entity_kind(e) != DDS_KIND_TOPIC))
return e;
}
return NULL;
}
static void delete_children(struct dds_entity *parent, bool ignore_topics)
{
dds_entity *child;
dds_return_t ret;
ddsrt_mutex_lock (&parent->m_mutex);
while ((child = get_first_child(&parent->m_children, ignore_topics)) != NULL)
{
dds_entity_t child_handle = child->m_hdllink.hdl;
/* The child will remove itself from the parent->m_children list. */
ddsrt_mutex_unlock (&parent->m_mutex);
ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
assert (ret == DDS_RETCODE_OK || ret == DDS_RETCODE_BAD_PARAMETER);
ddsrt_mutex_lock (&parent->m_mutex);
/* The dds_delete can fail if the child is being deleted in parallel,
* in which case: wait when its not deleted yet.
* The child will trigger the condition after it removed itself from
* the childrens list. */
if ((ret == DDS_RETCODE_BAD_PARAMETER) &&
(get_first_child(&parent->m_children, ignore_topics) == child))
{
ddsrt_cond_wait (&parent->m_cond, &parent->m_mutex);
}
}
ddsrt_mutex_unlock (&parent->m_mutex);
}
#define TRACE_DELETE 0 /* FIXME: use DDS_LOG for this */
#if TRACE_DELETE
static const char *entity_kindstr (dds_entity_kind_t kind)
@ -227,13 +287,11 @@ static void print_delete (const dds_entity *e, enum delete_impl_state delstate ,
printf ("delete(%p, delstate %s, iid %"PRIx64"): %s%s %d pin %u refc %u %s %s\n",
(void *) e, (delstate == DIS_IMPLICIT) ? "implicit" : (delstate == DIS_EXPLICIT) ? "explicit" : "from_parent", iid,
entity_kindstr (e->m_kind), (e->m_flags & DDS_ENTITY_IMPLICIT) ? " [implicit]" : "",
e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0xffff, (cm & 0x80000000) ? "closed" : "open",
e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0x7fff, (cm & 0x80000000) ? "closed" : "open",
ddsrt_avl_is_empty (&e->m_children) ? "childless" : "has-children");
}
#endif
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate);
dds_return_t dds_delete (dds_entity_t entity)
{
return dds_delete_impl (entity, DIS_EXPLICIT);
@ -252,53 +310,33 @@ static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state
{
dds_entity *e;
dds_return_t ret;
if ((ret = dds_entity_pin (entity, &e)) < 0)
return ret;
else
if ((ret = dds_entity_pin_for_delete (entity, (delstate != DIS_IMPLICIT), &e)) == DDS_RETCODE_OK)
return dds_delete_impl_pinned (e, delstate);
else if (ret == DDS_RETCODE_TRY_AGAIN) /* non-child refs exist */
return DDS_RETCODE_OK;
else
return ret;
}
dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate)
{
dds_entity *child;
dds_return_t ret;
/* Any number of threads pinning it, possibly in delete, or having pinned it and
trying to acquire m_mutex */
ddsrt_mutex_lock (&e->m_mutex);
#if TRACE_DELETE
print_delete (e, delstate, iid);
print_delete (e, delstate, e->m_iid);
#endif
/* If another thread was racing us in delete, it will have set the CLOSING flag
while holding m_mutex and we had better bail out. */
if (dds_handle_is_closed (&e->m_hdllink))
{
dds_entity_unlock (e);
return DDS_RETCODE_OK;
}
assert (dds_handle_is_closed (&e->m_hdllink));
return really_delete_pinned_closed_locked (e, delstate);
}
/* Ignore children calling up to delete an implicit parent if there are still
(or again) children */
if (delstate == DIS_IMPLICIT)
{
if (!((e->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&e->m_children)))
{
dds_entity_unlock (e);
return DDS_RETCODE_OK;
}
}
/* Drop reference, atomically setting CLOSING if no other references remain.
FIXME: that's not quite right: this is really only for topics. After a call
to delete, the handle ought to become invalid even if the topic stays (and
should perhaps even be revivable via find_topic). */
if (! dds_handle_drop_ref (&e->m_hdllink))
{
dds_entity_unlock (e);
return DDS_RETCODE_OK;
}
static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, enum delete_impl_state delstate)
{
dds_return_t ret;
/* No threads pinning it anymore, no need to worry about other threads deleting
it, but there can still be plenty of threads that have it pinned and are
@ -354,24 +392,8 @@ dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delst
*
* To circumvent the problem. We ignore topics in the first loop.
*/
ddsrt_mutex_lock (&e->m_mutex);
while ((child = next_non_topic_child (&e->m_children)) != NULL)
{
/* FIXME: dds_delete can fail if the child is being deleted in parallel, in which case: wait */
dds_entity_t child_handle = child->m_hdllink.hdl;
ddsrt_mutex_unlock (&e->m_mutex);
(void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
ddsrt_mutex_lock (&e->m_mutex);
}
while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL)
{
assert (dds_entity_kind (child) == DDS_KIND_TOPIC);
dds_entity_t child_handle = child->m_hdllink.hdl;
ddsrt_mutex_unlock (&e->m_mutex);
(void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
ddsrt_mutex_lock (&e->m_mutex);
}
ddsrt_mutex_unlock (&e->m_mutex);
delete_children(e, true /* ignore topics */);
delete_children(e, false /* delete topics */);
/* The dds_handle_delete will wait until the last active claim on that handle is
released. It is possible that this last release will be done by a thread that was
@ -391,15 +413,16 @@ dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delst
ddsrt_mutex_lock (&p->m_mutex);
assert (ddsrt_avl_lookup (&dds_entity_children_td, &p->m_children, &e->m_iid) != NULL);
ddsrt_avl_delete (&dds_entity_children_td, &p->m_children, e);
if (dds_handle_drop_childref_and_pin (&p->m_hdllink, delstate != DIS_FROM_PARENT))
{
dds_handle_close(&p->m_hdllink);
assert (dds_handle_is_closed (&p->m_hdllink));
assert (dds_handle_is_not_refd (&p->m_hdllink));
assert (ddsrt_avl_is_empty (&p->m_children));
parent_to_delete = p;
}
/* trigger parent in case it is waiting in delete */
ddsrt_cond_broadcast (&p->m_cond);
if (delstate != DIS_FROM_PARENT && (p->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&p->m_children))
{
if ((ret = dds_entity_pin (p->m_hdllink.hdl, &parent_to_delete)) < 0)
parent_to_delete = NULL;
}
ddsrt_mutex_unlock (&p->m_mutex);
}
@ -1121,6 +1144,19 @@ dds_return_t dds_entity_pin (dds_entity_t hdl, dds_entity **eptr)
}
}
dds_return_t dds_entity_pin_for_delete (dds_entity_t hdl, bool explicit, dds_entity **eptr)
{
dds_return_t hres;
struct dds_handle_link *hdllink;
if ((hres = dds_handle_pin_for_delete (hdl, explicit, &hdllink)) < 0)
return hres;
else
{
*eptr = dds_entity_from_handle_link (hdllink);
return DDS_RETCODE_OK;
}
}
void dds_entity_unpin (dds_entity *e)
{
dds_handle_unpin (&e->m_hdllink);
@ -1349,3 +1385,32 @@ dds_return_t dds_generic_unimplemented_operation (dds_entity_t handle, dds_entit
return dds_generic_unimplemented_operation_manykinds (handle, 1, &kind);
}
dds_return_t dds_assert_liveliness (dds_entity_t entity)
{
dds_return_t rc;
dds_entity *e, *ewr;
if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
return rc;
switch (dds_entity_kind (e))
{
case DDS_KIND_PARTICIPANT: {
write_pmd_message_guid (&e->m_domain->gv, &e->m_guid, PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE);
break;
}
case DDS_KIND_WRITER: {
if ((rc = dds_entity_lock (entity, DDS_KIND_WRITER, &ewr)) != DDS_RETCODE_OK)
return rc;
if ((rc = write_hb_liveliness (&e->m_domain->gv, &e->m_guid, ((struct dds_writer *)ewr)->m_xp)) != DDS_RETCODE_OK)
return rc;
dds_entity_unlock (e);
break;
}
default: {
rc = DDS_RETCODE_ILLEGAL_OPERATION;
break;
}
}
dds_entity_unpin (e);
return rc;
}

View file

@ -57,18 +57,18 @@ dds_entity_t dds_create_guardcondition (dds_entity_t owner)
}
dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, NULL, NULL, 0);
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, false, NULL, NULL, 0);
gcond->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (e, &gcond->m_entity);
dds_entity_init_complete (&gcond->m_entity);
dds_entity_unlock (e);
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return rc;
}

View file

@ -20,11 +20,36 @@
#include "dds__handles.h"
#include "dds__types.h"
#define HDL_REFCOUNT_MASK (0x0ffff000u)
#define HDL_REFCOUNT_MASK (0x07fff000u)
#define HDL_REFCOUNT_UNIT (0x00001000u)
#define HDL_REFCOUNT_SHIFT 12
#define HDL_PINCOUNT_MASK (0x00000fffu)
/*
"regular" entities other than topics:
- create makes it
- delete deletes it and its children immediately
- explicit domain: additional protection for bootstrapping complications need extra care
implicit entities other than topics (pub, sub, domain, cyclonedds):
- created "spontaneously" as a consequence of creating the writer/reader/participant
- delete of last child causes it to disappear
- explicit delete treated like a delete of a "regular" entity
- domain, cyclonedds: bootstrapping complications require additional protection
topics:
- create makes it
- never has children (so the handle's cnt_flags can have a different meaning)
- readers, writers keep it in existence
- delete deferred until no readers/writers exist
- an attempt at deleting it fails if in "deferred delete" state (or should it simply
return ok while doing nothing?), other operations keep going so, e.g., listeners
remain useful
built-in topics:
- implicit variant of a topic
*/
/* Maximum number of handles is INT32_MAX - 1, but as the allocator relies on a
random generator for finding a free one, the time spent in the dds_handle_create
increases with an increasing number of handles. 16M handles seems likely to be
@ -82,7 +107,7 @@ void dds_handle_server_fini (void)
cf & HDL_PINCOUNT_MASK, (cf & HDL_REFCOUNT_MASK) >> HDL_REFCOUNT_SHIFT,
cf & HDL_FLAG_PENDING ? " pending" : "",
cf & HDL_FLAG_CLOSING ? " closing" : "",
cf & HDL_FLAG_CLOSED ? " closed" : "");
cf & HDL_FLAG_DELETE_DEFERRED ? " delete-deferred" : "");
}
assert (ddsrt_hh_iter_first (handles.ht, &it) == NULL);
#endif
@ -94,9 +119,9 @@ void dds_handle_server_fini (void)
}
static bool hhadd (struct ddsrt_hh *ht, void *elem) { return ddsrt_hh_add (ht, elem); }
static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
static dds_handle_t dds_handle_create_int (struct dds_handle_link *link, bool implicit, bool refc_counts_children)
{
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | (implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT) | (refc_counts_children ? HDL_FLAG_ALLOW_CHILDREN : 0) | 1u);
do {
do {
link->hdl = (int32_t) (ddsrt_random () & INT32_MAX);
@ -105,7 +130,7 @@ static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
return link->hdl;
}
dds_handle_t dds_handle_create (struct dds_handle_link *link)
dds_handle_t dds_handle_create (struct dds_handle_link *link, bool implicit, bool allow_children)
{
dds_handle_t ret;
ddsrt_mutex_lock (&handles.lock);
@ -117,14 +142,14 @@ dds_handle_t dds_handle_create (struct dds_handle_link *link)
else
{
handles.count++;
ret = dds_handle_create_int (link);
ret = dds_handle_create_int (link, implicit, allow_children);
ddsrt_mutex_unlock (&handles.lock);
assert (ret > 0);
}
return ret;
}
dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_handle_t handle)
dds_return_t dds_handle_register_special (struct dds_handle_link *link, bool implicit, bool allow_children, dds_handle_t handle)
{
dds_return_t ret;
if (handle <= 0)
@ -138,7 +163,7 @@ dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_hand
else
{
handles.count++;
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | (implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT) | (allow_children ? HDL_FLAG_ALLOW_CHILDREN : 0) | 1u);
link->hdl = handle;
if (hhadd (handles.ht, link))
ret = handle;
@ -155,9 +180,9 @@ void dds_handle_unpend (struct dds_handle_link *link)
#ifndef NDEBUG
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
assert ((cf & HDL_FLAG_PENDING));
assert (!(cf & HDL_FLAG_CLOSED));
assert (!(cf & HDL_FLAG_DELETE_DEFERRED));
assert (!(cf & HDL_FLAG_CLOSING));
assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT);
assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT || (cf & HDL_FLAG_IMPLICIT));
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
#endif
ddsrt_atomic_and32 (&link->cnt_flags, ~HDL_FLAG_PENDING);
@ -171,7 +196,6 @@ int32_t dds_handle_delete (struct dds_handle_link *link)
if (!(cf & HDL_FLAG_PENDING))
{
assert (cf & HDL_FLAG_CLOSING);
assert (cf & HDL_FLAG_CLOSED);
assert ((cf & HDL_REFCOUNT_MASK) == 0u);
}
assert ((cf & HDL_PINCOUNT_MASK) == 1u);
@ -213,7 +237,7 @@ static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, struct dds_
rc = DDS_RETCODE_OK;
do {
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
if (cf & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
{
rc = DDS_RETCODE_BAD_PARAMETER;
break;
@ -229,6 +253,169 @@ int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
return dds_handle_pin_int (hdl, 1u, link);
}
int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_handle_link **link)
{
struct dds_handle_link dummy = { .hdl = hdl };
int32_t rc;
/* it makes sense to check here for initialization: the first thing any operation
(other than create_participant) does is to call dds_handle_pin on the supplied
entity, so checking here whether the library has been initialised helps avoid
crashes if someone forgets to create a participant (or allows a program to
continue after failing to create one).
One could check that the handle is > 0, but that would catch fewer errors
without any advantages. */
if (handles.ht == NULL)
return DDS_RETCODE_PRECONDITION_NOT_MET;
ddsrt_mutex_lock (&handles.lock);
*link = ddsrt_hh_lookup (handles.ht, &dummy);
if (*link == NULL)
rc = DDS_RETCODE_BAD_PARAMETER;
else
{
uint32_t cf, cf1;
/* Assume success; bail out if the object turns out to be in the process of
being deleted */
do {
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
{
/* Only one can succeed (and if closing is already set, the handle's reference has
already been dropped) */
rc = DDS_RETCODE_BAD_PARAMETER;
break;
}
else if (cf & HDL_FLAG_DELETE_DEFERRED)
{
/* Someone already called delete, but the operation was deferred becauses there are still
outstanding references. This implies that there are no children, because then the
entire hierarchy would simply have been deleted. */
assert (!(cf & HDL_FLAG_ALLOW_CHILDREN));
if (cf & HDL_REFCOUNT_MASK)
{
rc = DDS_RETCODE_ALREADY_DELETED;
break;
}
else
{
/* Refcount reached zero. Pin to allow deletion. */
cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
}
}
else if (explicit)
{
/* Explicit call to dds_delete (either by application or by parent deleting its children) */
if (cf & HDL_FLAG_IMPLICIT)
{
/* Entity is implicit, so handle doesn't hold a reference */
cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
}
else
{
assert ((cf & HDL_REFCOUNT_MASK) > 0);
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
{
/* Last reference is closing. Pin entity and indicate that it is closing. */
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
}
else if (!(cf & HDL_FLAG_ALLOW_CHILDREN))
{
/* The refcnt does not contain children.
* Indicate that the closing of the entity is deferred. */
cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
}
else
{
/* Entity is explicit, so handle held a reference, refc only counts children as so is not our concern */
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
}
}
}
else
{
/* Implicit call to dds_delete (child invoking delete on its parent) */
if (cf & HDL_FLAG_IMPLICIT)
{
assert ((cf & HDL_REFCOUNT_MASK) > 0);
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
{
/* Last reference is closing. Pin entity and indicate that it is closing. */
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
}
else if (!(cf & HDL_FLAG_ALLOW_CHILDREN))
{
/* The refcnt does not contain children.
* Indicate that the closing of the entity is deferred. */
cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
}
else
{
/* Just reduce the children refcount by one. */
cf1 = (cf - HDL_REFCOUNT_UNIT);
}
}
else
{
/* Child can't delete an explicit parent */
rc = DDS_RETCODE_ILLEGAL_OPERATION;
break;
}
}
rc = ((cf1 & HDL_REFCOUNT_MASK) == 0 || (cf1 & HDL_FLAG_ALLOW_CHILDREN)) ? DDS_RETCODE_OK : DDS_RETCODE_TRY_AGAIN;
} while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cf, cf1));
}
ddsrt_mutex_unlock (&handles.lock);
return rc;
}
bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_delete_parent)
{
bool del_parent = false;
ddsrt_mutex_lock (&handles.lock);
uint32_t cf, cf1;
do {
cf = ddsrt_atomic_ld32 (&link->cnt_flags);
if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
{
/* Only one can succeed; child ref still to be removed */
assert ((cf & HDL_REFCOUNT_MASK) > 0);
cf1 = (cf - HDL_REFCOUNT_UNIT);
del_parent = false;
}
else
{
if (cf & HDL_FLAG_IMPLICIT)
{
/* Implicit parent: delete if last ref */
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT && may_delete_parent)
{
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u);
del_parent = true;
}
else
{
assert ((cf & HDL_REFCOUNT_MASK) > 0);
cf1 = (cf - HDL_REFCOUNT_UNIT);
del_parent = false;
}
}
else
{
/* Child can't delete an explicit parent; child ref still to be removed */
assert ((cf & HDL_REFCOUNT_MASK) > 0);
cf1 = (cf - HDL_REFCOUNT_UNIT);
del_parent = false;
}
}
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, cf, cf1));
ddsrt_mutex_unlock (&handles.lock);
return del_parent;
}
int32_t dds_handle_pin_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
{
return dds_handle_pin_int (hdl, HDL_REFCOUNT_UNIT + 1u, link);
@ -237,7 +424,6 @@ int32_t dds_handle_pin_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
void dds_handle_repin (struct dds_handle_link *link)
{
uint32_t x = ddsrt_atomic_inc32_nv (&link->cnt_flags);
assert (!(x & HDL_FLAG_CLOSED));
(void) x;
}
@ -245,7 +431,6 @@ void dds_handle_unpin (struct dds_handle_link *link)
{
#ifndef NDEBUG
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
assert (!(cf & HDL_FLAG_CLOSED));
if (cf & HDL_FLAG_CLOSING)
assert ((cf & HDL_PINCOUNT_MASK) > 1u);
else
@ -266,16 +451,43 @@ void dds_handle_add_ref (struct dds_handle_link *link)
bool dds_handle_drop_ref (struct dds_handle_link *link)
{
assert ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_REFCOUNT_MASK) != 0);
uint32_t old, new;
do {
old = ddsrt_atomic_ld32 (&link->cnt_flags);
if ((old & HDL_REFCOUNT_MASK) != HDL_REFCOUNT_UNIT)
assert ((old & HDL_REFCOUNT_MASK) > 0);
new = old - HDL_REFCOUNT_UNIT;
else
new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSING;
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
return (new & HDL_REFCOUNT_MASK) == 0;
ddsrt_mutex_lock (&handles.lock);
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
{
ddsrt_cond_broadcast (&handles.cond);
}
ddsrt_mutex_unlock (&handles.lock);
return ((new & HDL_REFCOUNT_MASK) == 0);
}
bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
{
uint32_t old, new;
do {
old = ddsrt_atomic_ld32 (&link->cnt_flags);
assert ((old & HDL_REFCOUNT_MASK) > 0);
assert ((old & HDL_PINCOUNT_MASK) > 0);
new = old - HDL_REFCOUNT_UNIT - 1u;
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
ddsrt_mutex_lock (&handles.lock);
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
{
ddsrt_cond_broadcast (&handles.cond);
}
ddsrt_mutex_unlock (&handles.lock);
return ((new & HDL_REFCOUNT_MASK) == 0);
}
bool dds_handle_close (struct dds_handle_link *link)
{
uint32_t old = ddsrt_atomic_or32_ov (&link->cnt_flags, HDL_FLAG_CLOSING);
return (old & HDL_REFCOUNT_MASK) == 0;
}
void dds_handle_close_wait (struct dds_handle_link *link)
@ -283,17 +495,18 @@ void dds_handle_close_wait (struct dds_handle_link *link)
#ifndef NDEBUG
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
assert ((cf & HDL_FLAG_CLOSING));
assert (!(cf & HDL_FLAG_CLOSED));
assert ((cf & HDL_REFCOUNT_MASK) == 0u);
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
#endif
ddsrt_mutex_lock (&handles.lock);
while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 1u)
ddsrt_cond_wait (&handles.cond, &handles.lock);
/* only one thread may call close_wait on a given handle */
assert (!(ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED));
ddsrt_atomic_or32 (&link->cnt_flags, HDL_FLAG_CLOSED);
ddsrt_mutex_unlock (&handles.lock);
}
bool dds_handle_is_not_refd (struct dds_handle_link *link)
{
return ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_REFCOUNT_MASK) == 0);
}
extern inline bool dds_handle_is_closed (struct dds_handle_link *link);

View file

@ -119,9 +119,8 @@ dds_return_t dds_init (void)
goto fail_handleserver;
}
dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, NULL, NULL, 0);
dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, true, NULL, NULL, 0);
dds_global.m_entity.m_iid = ddsi_iid_gen ();
dds_global.m_entity.m_flags = DDS_ENTITY_IMPLICIT;
dds_handle_repin (&dds_global.m_entity.m_hdllink);
dds_entity_add_ref_locked (&dds_global.m_entity);
dds_entity_init_complete (&dds_global.m_entity);

View file

@ -113,7 +113,7 @@ dds_return_t dds_unregister_instance_ts (dds_entity_t writer, const void *data,
return ret;
if (wr->m_entity.m_qos)
dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
(void) dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
thread_state_awake (ts1, &wr->m_entity.m_domain->gv);
if (autodispose)
@ -140,7 +140,7 @@ dds_return_t dds_unregister_instance_ih_ts (dds_entity_t writer, dds_instance_ha
return ret;
if (wr->m_entity.m_qos)
dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
(void) dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
thread_state_awake (ts1, &wr->m_entity.m_domain->gv);
if (autodispose)

View file

@ -117,7 +117,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
}
pp = dds_alloc (sizeof (*pp));
if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, false, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
goto err_entity_init;
pp->m_entity.m_guid = guid;
@ -126,14 +126,14 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
pp->m_builtin_subscriber = 0;
/* Add participant to extent */
ddsrt_mutex_lock (&dds_global.m_entity.m_mutex);
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
dds_entity_register_child (&dom->m_entity, &pp->m_entity);
ddsrt_mutex_unlock (&dds_global.m_entity.m_mutex);
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
dds_entity_init_complete (&pp->m_entity);
/* drop temporary extra ref to domain, dds_init */
dds_delete (dom->m_entity.m_hdllink.hdl);
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
dds_entity_unpin_and_drop_ref (&dom->m_entity);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return ret;
err_entity_init:
@ -141,9 +141,9 @@ err_entity_init:
err_new_participant:
err_qos_validation:
dds_delete_qos (new_qos);
dds_delete (dom->m_entity.m_hdllink.hdl);
dds_entity_unpin_and_drop_ref (&dom->m_entity);
err_domain_create:
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
err_dds_init:
return ret;
}
@ -175,6 +175,6 @@ dds_return_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *par
}
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return ret;
}

View file

@ -45,17 +45,13 @@ const struct dds_entity_deriver dds_entity_deriver_publisher = {
.validate_status = dds_publisher_status_validate
};
dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener)
dds_entity_t dds__create_publisher_l (dds_participant *par, bool implicit, const dds_qos_t *qos, const dds_listener_t *listener)
{
dds_participant *par;
dds_publisher *pub;
dds_entity_t hdl;
dds_qos_t *new_qos;
dds_return_t ret;
if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
return ret;
new_qos = dds_create_qos ();
if (qos)
nn_xqos_mergein_missing (new_qos, qos, DDS_PUBLISHER_QOS_MASK);
@ -67,10 +63,21 @@ dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qo
}
pub = dds_alloc (sizeof (*pub));
hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, new_qos, listener, DDS_PUBLISHER_STATUS_MASK);
hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, implicit, new_qos, listener, DDS_PUBLISHER_STATUS_MASK);
pub->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&par->m_entity, &pub->m_entity);
dds_entity_init_complete (&pub->m_entity);
return hdl;
}
dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener)
{
dds_participant *par;
dds_entity_t hdl;
dds_return_t ret;
if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
return ret;
hdl = dds__create_publisher_l (par, false, qos, listener);
dds_participant_unlock (par);
return hdl;
}

View file

@ -41,7 +41,7 @@ dds_readcond *dds_create_readcond (dds_reader *rd, dds_entity_kind_t kind, uint3
{
dds_readcond *cond = dds_alloc (sizeof (*cond));
assert ((kind == DDS_KIND_COND_READ && filter == 0) || (kind == DDS_KIND_COND_QUERY && filter != 0));
(void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, NULL, NULL, 0);
(void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, false, NULL, NULL, 0);
cond->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&rd->m_entity, &cond->m_entity);
cond->m_sample_states = mask & DDS_ANY_SAMPLE_STATE;

View file

@ -62,11 +62,11 @@ static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_reader_delete (dds_entity *e)
{
dds_reader * const rd = (dds_reader *) e;
(void) dds_delete (rd->m_topic->m_entity.m_hdllink.hdl);
dds_free (rd->m_loan);
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
dds_rhc_free (rd->m_rhc);
thread_state_asleep (lookup_thread_state ());
dds_entity_drop_ref (&rd->m_topic->m_entity);
return DDS_RETCODE_OK;
}
@ -150,6 +150,7 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
rd->m_entity.m_cb_count--;
rd->m_entity.m_cb_pending_count--;
ddsrt_cond_broadcast (&rd->m_entity.m_observers_cond);
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
}
@ -232,16 +233,47 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
}
case DDS_LIVELINESS_CHANGED_STATUS_ID: {
struct dds_liveliness_changed_status * const st = vst = &rd->m_liveliness_changed_status;
if (data->add) {
DDSRT_STATIC_ASSERT ((uint32_t) LIVELINESS_CHANGED_ADD_ALIVE == 0 &&
LIVELINESS_CHANGED_ADD_ALIVE < LIVELINESS_CHANGED_ADD_NOT_ALIVE &&
LIVELINESS_CHANGED_ADD_NOT_ALIVE < LIVELINESS_CHANGED_REMOVE_NOT_ALIVE &&
LIVELINESS_CHANGED_REMOVE_NOT_ALIVE < LIVELINESS_CHANGED_REMOVE_ALIVE &&
LIVELINESS_CHANGED_REMOVE_ALIVE < LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE &&
LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE < LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE &&
LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE < LIVELINESS_CHANGED_TWITCH &&
(uint32_t) LIVELINESS_CHANGED_TWITCH < UINT32_MAX);
assert (data->extra <= (uint32_t) LIVELINESS_CHANGED_TWITCH);
switch ((enum liveliness_changed_data_extra) data->extra)
{
case LIVELINESS_CHANGED_ADD_ALIVE:
st->alive_count++;
st->alive_count_change++;
if (st->not_alive_count > 0) {
st->not_alive_count--;
}
} else {
st->alive_count--;
break;
case LIVELINESS_CHANGED_ADD_NOT_ALIVE:
st->not_alive_count++;
st->not_alive_count_change++;
break;
case LIVELINESS_CHANGED_REMOVE_NOT_ALIVE:
st->not_alive_count--;
st->not_alive_count_change--;
break;
case LIVELINESS_CHANGED_REMOVE_ALIVE:
st->alive_count--;
st->alive_count_change--;
break;
case LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE:
st->alive_count--;
st->alive_count_change--;
st->not_alive_count++;
st->not_alive_count_change++;
break;
case LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE:
st->not_alive_count--;
st->not_alive_count_change--;
st->alive_count++;
st->alive_count_change++;
break;
case LIVELINESS_CHANGED_TWITCH:
break;
}
st->last_publication_handle = data->handle;
invoke = (lst->on_liveliness_changed != 0);
@ -332,36 +364,37 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
case DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION:
internal_topic = true;
subscriber = dds__get_builtin_subscriber (participant_or_subscriber);
if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK)
return ret;
t = dds__get_builtin_topic (subscriber, topic);
break;
default: {
dds_entity *p_or_s;
if ((ret = dds_entity_pin (participant_or_subscriber, &p_or_s)) != DDS_RETCODE_OK)
if ((ret = dds_entity_lock (participant_or_subscriber, DDS_KIND_DONTCARE, &p_or_s)) != DDS_RETCODE_OK)
return ret;
if (dds_entity_kind (p_or_s) == DDS_KIND_PARTICIPANT)
subscriber = dds_create_subscriber (participant_or_subscriber, qos, NULL);
else
switch (dds_entity_kind (p_or_s))
{
case DDS_KIND_SUBSCRIBER:
subscriber = participant_or_subscriber;
dds_entity_unpin (p_or_s);
sub = (dds_subscriber *) p_or_s;
break;
case DDS_KIND_PARTICIPANT:
subscriber = dds__create_subscriber_l ((dds_participant *) p_or_s, true, qos, NULL);
dds_entity_unlock (p_or_s);
if ((ret = dds_subscriber_lock (subscriber, &sub)) < 0)
return ret;
break;
default:
dds_entity_unlock (p_or_s);
return DDS_RETCODE_ILLEGAL_OPERATION;
}
internal_topic = false;
t = topic;
break;
}
}
if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK)
{
reader = ret;
goto err_sub_lock;
}
if (subscriber != participant_or_subscriber && !internal_topic)
{
/* Delete implicit subscriber if reader creation fails */
sub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
}
if ((ret = dds_topic_lock (t, &tp)) != DDS_RETCODE_OK)
{
reader = ret;
@ -405,7 +438,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
/* Create reader and associated read cache (if not provided by caller) */
rd = dds_alloc (sizeof (*rd));
reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, rqos, listener, DDS_READER_STATUS_MASK);
reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK);
rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED;
rd->m_topic = tp;
rd->m_rhc = rhc ? rhc : dds_rhc_default_new (rd, tp->m_stopic);
@ -431,12 +464,6 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
dds_topic_unlock (tp);
dds_subscriber_unlock (sub);
if (internal_topic)
{
/* If topic is builtin, then the topic entity is local and should be deleted because the application won't. */
dds_delete (t);
}
return reader;
err_bad_qos:
@ -446,9 +473,6 @@ err_tp_lock:
dds_subscriber_unlock (sub);
if ((sub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0)
(void) dds_delete (subscriber);
err_sub_lock:
if (internal_topic)
dds_delete (t);
return reader;
}

View file

@ -1110,7 +1110,7 @@ static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, cons
if (inst->wrcount == 2 && inst->wr_iid_islive && inst->wr_iid != wr_iid)
{
TRACE (",delreg(remain)");
lwregs_delete (&rhc->registrations, inst->iid, inst->wr_iid);
(void) lwregs_delete (&rhc->registrations, inst->iid, inst->wr_iid);
}
return 1;
}
@ -1627,7 +1627,7 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
}
}
dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
(void) dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
TRACE ("\n");

View file

@ -256,24 +256,25 @@ size_t dds_stream_check_optimize (const dds_topic_descriptor_t * __restrict desc
return dds_stream_check_optimize1 (desc);
}
static char *dds_stream_reuse_string (dds_istream_t * __restrict is, char * __restrict str, const uint32_t bound)
static void dds_stream_reuse_string_bound (dds_istream_t * __restrict is, char * __restrict str, const uint32_t bound)
{
const uint32_t length = dds_is_get4 (is);
const void *src = is->m_buffer + is->m_index;
if (bound)
{
/* FIXME: validation now rejects data containing an oversize bounded string,
so this check is superfluous, but perhaps rejecting such a sample is the
wrong thing to do */
assert (str != NULL);
memcpy (str, src, length > bound ? bound : length);
}
else
{
is->m_index += length;
}
static char *dds_stream_reuse_string (dds_istream_t * __restrict is, char * __restrict str)
{
const uint32_t length = dds_is_get4 (is);
const void *src = is->m_buffer + is->m_index;
if (str == NULL || strlen (str) + 1 < length)
str = dds_realloc (str, length);
memcpy (str, src, length);
}
is->m_index += length;
return str;
}
@ -596,7 +597,7 @@ static const uint32_t *dds_stream_read_seq (dds_istream_t * __restrict is, char
seq->_length = (num <= seq->_maximum) ? num : seq->_maximum;
char **ptr = (char **) seq->_buffer;
for (uint32_t i = 0; i < seq->_length; i++)
ptr[i] = dds_stream_reuse_string (is, ptr[i], 0);
ptr[i] = dds_stream_reuse_string (is, ptr[i]);
for (uint32_t i = seq->_length; i < num; i++)
dds_stream_skip_string (is);
return ops + 2;
@ -607,7 +608,7 @@ static const uint32_t *dds_stream_read_seq (dds_istream_t * __restrict is, char
seq->_length = (num <= seq->_maximum) ? num : seq->_maximum;
char *ptr = (char *) seq->_buffer;
for (uint32_t i = 0; i < seq->_length; i++)
(void) dds_stream_reuse_string (is, ptr + i * elem_size, elem_size);
dds_stream_reuse_string_bound (is, ptr + i * elem_size, elem_size);
for (uint32_t i = seq->_length; i < num; i++)
dds_stream_skip_string (is);
return ops + 3;
@ -641,14 +642,14 @@ static const uint32_t *dds_stream_read_arr (dds_istream_t * __restrict is, char
case DDS_OP_VAL_STR: {
char **ptr = (char **) addr;
for (uint32_t i = 0; i < num; i++)
ptr[i] = dds_stream_reuse_string (is, ptr[i], 0);
ptr[i] = dds_stream_reuse_string (is, ptr[i]);
return ops + 3;
}
case DDS_OP_VAL_BST: {
char *ptr = (char *) addr;
const uint32_t elem_size = ops[4];
for (uint32_t i = 0; i < num; i++)
(void) dds_stream_reuse_string (is, ptr + i * elem_size, elem_size);
dds_stream_reuse_string_bound (is, ptr + i * elem_size, elem_size);
return ops + 5;
}
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
@ -685,7 +686,7 @@ static const uint32_t *dds_stream_read_uni (dds_istream_t * __restrict is, char
case DDS_OP_VAL_2BY: *((uint16_t *) valaddr) = dds_is_get2 (is); break;
case DDS_OP_VAL_4BY: *((uint32_t *) valaddr) = dds_is_get4 (is); break;
case DDS_OP_VAL_8BY: *((uint64_t *) valaddr) = dds_is_get8 (is); break;
case DDS_OP_VAL_STR: *(char **) valaddr = dds_stream_reuse_string (is, *((char **) valaddr), 0); break;
case DDS_OP_VAL_STR: *(char **) valaddr = dds_stream_reuse_string (is, *((char **) valaddr)); break;
case DDS_OP_VAL_BST: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
dds_stream_read (is, valaddr, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]));
break;
@ -709,8 +710,8 @@ static void dds_stream_read (dds_istream_t * __restrict is, char * __restrict da
case DDS_OP_VAL_2BY: *((uint16_t *) addr) = dds_is_get2 (is); ops += 2; break;
case DDS_OP_VAL_4BY: *((uint32_t *) addr) = dds_is_get4 (is); ops += 2; break;
case DDS_OP_VAL_8BY: *((uint64_t *) addr) = dds_is_get8 (is); ops += 2; break;
case DDS_OP_VAL_STR: *((char **) addr) = dds_stream_reuse_string (is, *((char **) addr), 0); ops += 2; break;
case DDS_OP_VAL_BST: dds_stream_reuse_string (is, (char *) addr, ops[2]); ops += 3; break;
case DDS_OP_VAL_STR: *((char **) addr) = dds_stream_reuse_string (is, *((char **) addr)); ops += 2; break;
case DDS_OP_VAL_BST: dds_stream_reuse_string_bound (is, (char *) addr, ops[2]); ops += 3; break;
case DDS_OP_VAL_SEQ: ops = dds_stream_read_seq (is, addr, ops, insn); break;
case DDS_OP_VAL_ARR: ops = dds_stream_read_arr (is, addr, ops, insn); break;
case DDS_OP_VAL_UNI: ops = dds_stream_read_uni (is, addr, data, ops, insn); break;
@ -1126,8 +1127,8 @@ void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sampl
case DDS_OP_VAL_2BY: *((uint16_t *) dst) = dds_is_get2 (is); break;
case DDS_OP_VAL_4BY: *((uint32_t *) dst) = dds_is_get4 (is); break;
case DDS_OP_VAL_8BY: *((uint64_t *) dst) = dds_is_get8 (is); break;
case DDS_OP_VAL_STR: *((char **) dst) = dds_stream_reuse_string (is, *((char **) dst), 0); break;
case DDS_OP_VAL_BST: dds_stream_reuse_string (is, dst, op[2]); break;
case DDS_OP_VAL_STR: *((char **) dst) = dds_stream_reuse_string (is, *((char **) dst)); break;
case DDS_OP_VAL_BST: dds_stream_reuse_string_bound (is, dst, op[2]); break;
case DDS_OP_VAL_ARR:
dds_is_get_bytes (is, dst, op[2], get_type_size (DDS_OP_SUBTYPE (*op)));
break;
@ -1728,16 +1729,16 @@ static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_is
num = dds_is_get4 (is);
if (num == 0)
{
prtf (buf, bufsize, "{}");
(void) prtf (buf, bufsize, "{}");
return skip_sequence_insns (ops, insn);
}
switch (subtype)
{
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
prtf_simple_array (buf, bufsize, is, num, subtype);
(void) prtf_simple_array (buf, bufsize, is, num, subtype);
return ops + 2;
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
prtf_simple_array (buf, bufsize, is, num, subtype);
(void) prtf_simple_array (buf, bufsize, is, num, subtype);
return ops + (subtype == DDS_OP_VAL_STR ? 2 : 3);
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
@ -1745,10 +1746,10 @@ static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_is
bool cont = prtf (buf, bufsize, "{");
for (uint32_t i = 0; cont && i < num; i++)
{
if (i > 0) prtf (buf, bufsize, ",");
if (i > 0) (void) prtf (buf, bufsize, ",");
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
}
prtf (buf, bufsize, "}");
(void) prtf (buf, bufsize, "}");
return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */
}
}
@ -1762,10 +1763,10 @@ static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_is
switch (subtype)
{
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
prtf_simple_array (buf, bufsize, is, num, subtype);
(void) prtf_simple_array (buf, bufsize, is, num, subtype);
return ops + 3;
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
prtf_simple_array (buf, bufsize, is, num, subtype);
(void) prtf_simple_array (buf, bufsize, is, num, subtype);
return ops + (subtype == DDS_OP_VAL_STR ? 3 : 5);
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
@ -1773,10 +1774,10 @@ static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_is
bool cont = prtf (buf, bufsize, "{");
for (uint32_t i = 0; cont && i < num; i++)
{
if (i > 0) prtf (buf, bufsize, ",");
if (i > 0) (void) prtf (buf, bufsize, ",");
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
}
prtf (buf, bufsize, "}");
(void) prtf (buf, bufsize, "}");
return ops + (jmp ? jmp : 5);
}
}
@ -1787,7 +1788,7 @@ static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_is
{
const uint32_t disc = read_union_discriminant (is, DDS_OP_SUBTYPE (insn));
uint32_t const * const jeq_op = find_union_case (ops, disc);
prtf (buf, bufsize, "%"PRIu32":", disc);
(void) prtf (buf, bufsize, "%"PRIu32":", disc);
ops += DDS_OP_ADR_JMP (ops[3]);
if (jeq_op)
{
@ -1796,10 +1797,10 @@ static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_is
{
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
prtf_simple (buf, bufsize, is, valtype);
(void) prtf_simple (buf, bufsize, is, valtype);
break;
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
(void) dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
break;
}
}
@ -1812,11 +1813,11 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric
bool cont = true;
bool needs_comma = false;
if (add_braces)
prtf (buf, bufsize, "{");
(void) prtf (buf, bufsize, "{");
while (cont && (insn = *ops) != DDS_OP_RTS)
{
if (needs_comma)
prtf (buf, bufsize, ",");
(void) prtf (buf, bufsize, ",");
needs_comma = true;
switch (DDS_OP (insn))
{
@ -1859,13 +1860,13 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric
}
}
if (add_braces)
prtf (buf, bufsize, "}");
(void) prtf (buf, bufsize, "}");
return cont;
}
size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize)
{
dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true);
(void) dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true);
return bufsize;
}
@ -1891,7 +1892,7 @@ size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_se
break;
}
}
prtf (&buf, &bufsize, "}");
(void) prtf (&buf, &bufsize, "}");
return bufsize;
}

View file

@ -45,7 +45,7 @@ const struct dds_entity_deriver dds_entity_deriver_subscriber = {
.validate_status = dds_subscriber_status_validate
};
dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_qos_t *qos, const dds_listener_t *listener)
dds_entity_t dds__create_subscriber_l (dds_participant *participant, bool implicit, const dds_qos_t *qos, const dds_listener_t *listener)
{
/* participant entity lock must be held */
dds_subscriber *sub;
@ -64,7 +64,7 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_q
}
sub = dds_alloc (sizeof (*sub));
subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, implicit, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
sub->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&participant->m_entity, &sub->m_entity);
dds_entity_init_complete (&sub->m_entity);
@ -78,7 +78,7 @@ dds_entity_t dds_create_subscriber (dds_entity_t participant, const dds_qos_t *q
dds_return_t ret;
if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
return ret;
hdl = dds__create_subscriber_l (par, qos, listener);
hdl = dds__create_subscriber_l (par, false, qos, listener);
dds_participant_unlock (par);
return hdl;
}

View file

@ -31,6 +31,7 @@
#include "dds/ddsi/ddsi_iid.h"
#include "dds/ddsi/q_plist.h"
#include "dds/ddsi/q_globals.h"
#include "dds__serdata_builtintopic.h"
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic)
@ -135,12 +136,16 @@ static bool dds_find_topic_check_and_add_ref (dds_entity_t participant, dds_enti
ret = false;
else
{
/* FIXME: calling addref is wrong because the Cyclone library has no
knowledge of the reference and hence simply deleting the participant
won't make the ref count drop to 0. On the other hand, the DDS spec
says find_topic (and a second call to create_topic) return a new
proxy that must separately be deleted. */
dds_entity_add_ref_locked (&tp->m_entity);
/* Simply return the same topic, though that is different to the spirit
of the DDS specification, which gives you a unique copy. Giving that
unique copy means there potentially many versions of exactly the same
topic around, and that two entities can be dealing with the same data
even though they have different topics objects (though with the same
name). That I find a confusing model.
As far as I can tell, the only benefit is the ability to set different
listeners on the various copies of the topic. And that seems to be a
really small benefit. */
ret = true;
}
dds_topic_unlock (tp);
@ -259,12 +264,7 @@ static dds_return_t create_topic_topic_arbitrary_check_sertopic (dds_entity_t pa
ret = DDS_RETCODE_INCONSISTENT_POLICY;
else
{
/* FIXME: calling addref is wrong because the Cyclone library has no
knowledge of the reference and hence simply deleting the participant
won't make the ref count drop to 0. On the other hand, the DDS spec
says find_topic (and a second call to create_topic) return a new
proxy that must separately be deleted. */
dds_entity_add_ref_locked (&tp->m_entity);
/* See dds_find_topic_check_and_add_ref */
ret = DDS_RETCODE_OK;
}
dds_topic_unlock (tp);
@ -429,7 +429,8 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
/* Create topic */
top = dds_alloc (sizeof (*top));
hdl = dds_entity_init (&top->m_entity, &par->m_entity, DDS_KIND_TOPIC, new_qos, listener, DDS_TOPIC_STATUS_MASK);
/* FIXME: setting "implicit" based on sertopic->ops is a hack */
hdl = dds_entity_init (&top->m_entity, &par->m_entity, DDS_KIND_TOPIC, (sertopic->ops == &ddsi_sertopic_ops_builtintopic), new_qos, listener, DDS_TOPIC_STATUS_MASK);
top->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&par->m_entity, &top->m_entity);
top->m_stopic = sertopic;

View file

@ -166,7 +166,7 @@ dds_entity_t dds_create_waitset (dds_entity_t owner)
}
dds_waitset *waitset = dds_alloc (sizeof (*waitset));
dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, NULL, NULL, 0);
dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, false, NULL, NULL, 0);
ddsrt_mutex_init (&waitset->wait_lock);
ddsrt_cond_init (&waitset->wait_cond);
waitset->m_entity.m_iid = ddsi_iid_gen ();
@ -176,13 +176,13 @@ dds_entity_t dds_create_waitset (dds_entity_t owner)
waitset->entities = NULL;
dds_entity_init_complete (&waitset->m_entity);
dds_entity_unlock (e);
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return rc;
}

View file

@ -209,13 +209,12 @@ static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_writer_delete (dds_entity *e)
{
dds_writer * const wr = (dds_writer *) e;
dds_return_t ret;
/* FIXME: not freeing WHC here because it is owned by the DDSI entity */
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
nn_xpack_free (wr->m_xp);
thread_state_asleep (lookup_thread_state ());
ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl);
return ret;
dds_entity_drop_ref (&wr->m_topic->m_entity);
return DDS_RETCODE_OK;
}
static dds_return_t dds_writer_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled)
@ -277,21 +276,27 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
{
dds_entity *p_or_p;
if ((rc = dds_entity_pin (participant_or_publisher, &p_or_p)) != DDS_RETCODE_OK)
if ((rc = dds_entity_lock (participant_or_publisher, DDS_KIND_DONTCARE, &p_or_p)) != DDS_RETCODE_OK)
return rc;
if (dds_entity_kind (p_or_p) == DDS_KIND_PARTICIPANT)
publisher = dds_create_publisher (participant_or_publisher, qos, NULL);
else
switch (dds_entity_kind (p_or_p))
{
case DDS_KIND_PUBLISHER:
publisher = participant_or_publisher;
dds_entity_unpin (p_or_p);
pub = (dds_publisher *) p_or_p;
break;
case DDS_KIND_PARTICIPANT:
publisher = dds__create_publisher_l ((dds_participant *) p_or_p, true, qos, NULL);
dds_entity_unlock (p_or_p);
if ((rc = dds_publisher_lock (publisher, &pub)) < 0)
return rc;
break;
default:
dds_entity_unlock (p_or_p);
return DDS_RETCODE_ILLEGAL_OPERATION;
}
}
if ((rc = dds_publisher_lock (publisher, &pub)) != DDS_RETCODE_OK)
return rc;
ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.data_conn_uc;
if (publisher != participant_or_publisher)
pub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
if ((rc = dds_topic_lock (topic, &tp)) != DDS_RETCODE_OK)
goto err_tp_lock;
@ -322,7 +327,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
/* Create writer */
wr = dds_alloc (sizeof (*wr));
writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, wqos, listener, DDS_WRITER_STATUS_MASK);
writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK);
wr->m_topic = tp;
dds_entity_add_ref_locked (&tp->m_entity);

View file

@ -21,12 +21,14 @@ set(ddsc_test_sources
"config.c"
"dispose.c"
"domain.c"
"domain_torture.c"
"entity_api.c"
"entity_hierarchy.c"
"entity_status.c"
"err.c"
"instance_get_key.c"
"listener.c"
"liveliness.c"
"participant.c"
"publisher.c"
"qos.c"
@ -55,7 +57,8 @@ add_cunit_executable(cunit_ddsc ${ddsc_test_sources})
target_include_directories(
cunit_ddsc PRIVATE
"$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src/include/>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsi/include/>")
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsc/src>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../ddsi/include>")
target_link_libraries(cunit_ddsc PRIVATE RoundTrip Space TypesArrayKey ddsc)
# Setup environment for config-tests

View file

@ -27,98 +27,62 @@
#define URI_VARIABLE DDS_PROJECT_NAME_NOSPACE_CAPS"_URI"
#define MAX_PARTICIPANTS_VARIABLE "MAX_PARTICIPANTS"
static void config__check_env(
const char * env_variable,
const char * expected_value)
static void config__check_env (const char *env_variable, const char *expected_value)
{
char * env_uri = NULL;
ddsrt_getenv(env_variable, &env_uri);
#if 0
const char * const env_not_set = "Environment variable '%s' isn't set. This needs to be set to '%s' for this test to run.";
const char * const env_not_as_expected = "Environment variable '%s' has an unexpected value: '%s' (expected: '%s')";
#endif
char *env_uri = NULL;
ddsrt_getenv (env_variable, &env_uri);
#ifdef FORCE_ENV
{
bool env_ok;
if ( env_uri == NULL ) {
if (env_uri == NULL)
env_ok = false;
} else if ( strncmp(env_uri, expected_value, strlen(expected_value)) != 0 ) {
else if (strncmp (env_uri, expected_value, strlen (expected_value)) != 0)
env_ok = false;
} else {
else
env_ok = true;
}
if ( !env_ok ) {
dds_return_t r;
r = ddsrt_setenv(env_variable, expected_value);
CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK);
if (!env_ok)
{
dds_return_t r = ddsrt_setenv (env_variable, expected_value);
CU_ASSERT_EQUAL_FATAL (r, DDS_RETCODE_OK);
}
}
#else
CU_ASSERT_PTR_NOT_NULL_FATAL(env_uri);
CU_ASSERT_STRING_EQUAL_FATAL(env_uri, expected_value);
CU_ASSERT_PTR_NOT_NULL_FATAL (env_uri);
CU_ASSERT_STRING_EQUAL_FATAL (env_uri, expected_value);
#endif /* FORCE_ENV */
}
CU_Test(ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini) {
CU_Test (ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini)
{
dds_entity_t participant;
config__check_env(URI_VARIABLE, CONFIG_ENV_SIMPLE_UDP);
config__check_env(MAX_PARTICIPANTS_VARIABLE, CONFIG_ENV_MAX_PARTICIPANTS);
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(participant> 0);
dds_delete(participant);
config__check_env (URI_VARIABLE, CONFIG_ENV_SIMPLE_UDP);
config__check_env (MAX_PARTICIPANTS_VARIABLE, CONFIG_ENV_MAX_PARTICIPANTS);
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL (participant> 0);
dds_delete (participant);
}
CU_Test(ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini) {
CU_ASSERT_FATAL(dds_create_domain(1,
CU_Test (ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini)
{
dds_entity_t domain;
domain = dds_create_domain (1,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
dds_entity_t participant_1;
dds_entity_t participant_2;
dds_entity_t participant_3;
participant_1 = dds_create_participant(1, NULL, NULL);
"</"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL (domain > 0);
dds_entity_t participant_1 = dds_create_participant (1, NULL, NULL);
CU_ASSERT_FATAL(participant_1 > 0);
participant_2 = dds_create_participant(1, NULL, NULL);
dds_entity_t participant_2 = dds_create_participant (1, NULL, NULL);
CU_ASSERT_FATAL(participant_2 > 0);
participant_3 = dds_create_participant(1, NULL, NULL);
dds_entity_t participant_3 = dds_create_participant (1, NULL, NULL);
CU_ASSERT(participant_3 < 0);
CU_ASSERT(participant_3 <= 0);
dds_delete(participant_3);
dds_delete(participant_2);
dds_delete(participant_1);
}
CU_Test(ddsc_config, incorrect_config, .init = ddsrt_init, .fini = ddsrt_fini) {
CU_ASSERT_FATAL(dds_create_domain(1, NULL) == DDS_RETCODE_BAD_PARAMETER);
CU_ASSERT_FATAL(dds_create_domain(1, "<CycloneDDS incorrect XML") != DDS_RETCODE_OK);
CU_ASSERT_FATAL(dds_create_domain(DDS_DOMAIN_DEFAULT,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_BAD_PARAMETER);
CU_ASSERT_FATAL(dds_create_domain(2,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
CU_ASSERT_FATAL(dds_create_domain(2, "") == DDS_RETCODE_PRECONDITION_NOT_MET);
dds_delete (domain);
}
/*
@ -824,3 +788,4 @@ CU_Test(ddsc_config, security_qos_invalid, .init = ddsrt_init, .fini = ddsrt_fin
dds_set_log_sink(NULL, NULL);
dds_set_trace_sink(NULL, NULL);
}

View file

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-model href="https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/etc/cyclonedds.xsd"
schematypens="http://www.w3.org/2001/XMLSchema" ?>
<!--
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
@ -10,10 +12,10 @@
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
-->
<CycloneDDS>
<CycloneDDS xmlns="https://cdds.io/config">
<!-- Simple config-file for testing whether a config-file can be picked up
correctly. -->
<Domain id="3">
<Domain Id="3">
<General>
<NetworkInterfaceAddress>127.0.0.1</NetworkInterfaceAddress>
<AllowMulticast>true</AllowMulticast>
@ -28,8 +30,8 @@
</Tracing>
<Internal>
<MaxParticipants>${MAX_PARTICIPANTS}</MaxParticipants>
<HeartbeatInterval max="10 s"> 100 ms </HeartbeatInterval>
<RediscoveryBlacklistDuration></RediscoveryBlacklistDuration>
<HeartbeatInterval>100 ms</HeartbeatInterval>
<RediscoveryBlacklistDuration>10s</RediscoveryBlacklistDuration>
</Internal>
</Domain>
</CycloneDDS>

View file

@ -140,3 +140,150 @@ CU_Test(ddsc_domain, delete_cyclonedds)
rc = dds_get_domainid (pp[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
CU_Test(ddsc_domain_create, valid)
{
dds_return_t ret;
dds_domainid_t did;
dds_entity_t domain;
domain = dds_create_domain(1, "<"DDS_PROJECT_NAME"><Domain><Id>1</Id></Domain></"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL(domain > 0);
ret = dds_get_domainid (domain, &did);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
CU_ASSERT_FATAL(did == 1);
ret = dds_delete(domain);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
ret = dds_delete(domain);
CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
}
CU_Test(ddsc_domain_create, mismatch)
{
dds_return_t ret;
dds_domainid_t did;
dds_entity_t domain;
/* The config should have been ignored. */
domain = dds_create_domain(2, "<"DDS_PROJECT_NAME"><Domain><Id>3</Id></Domain></"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL(domain > 0);
ret = dds_get_domainid (domain, &did);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
CU_ASSERT_FATAL(did == 2);
ret = dds_delete(domain);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
}
CU_Test(ddsc_domain_create, empty)
{
dds_return_t ret;
dds_domainid_t did;
dds_entity_t domain;
/* This should create a domain with default settings. */
domain = dds_create_domain(3, "");
CU_ASSERT_FATAL(domain > 0);
ret = dds_get_domainid (domain, &did);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
CU_ASSERT_FATAL(did == 3);
ret = dds_delete(domain);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
}
CU_Test(ddsc_domain_create, null)
{
dds_return_t ret;
dds_domainid_t did;
dds_entity_t domain;
/* This should start create a domain with default settings. */
domain = dds_create_domain(5, NULL);
CU_ASSERT_FATAL(domain > 0);
ret = dds_get_domainid (domain, &did);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
CU_ASSERT_FATAL(did == 5);
ret = dds_delete(domain);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
}
CU_Test(ddsc_domain_create, after_domain)
{
dds_entity_t domain1;
dds_entity_t domain2;
domain1 = dds_create_domain(4, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL(domain1 > 0);
domain2 = dds_create_domain(4, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL(domain2 == DDS_RETCODE_PRECONDITION_NOT_MET);
dds_delete(domain1);
}
CU_Test(ddsc_domain_create, after_participant)
{
dds_entity_t domain;
dds_entity_t participant;
participant = dds_create_participant (5, NULL, NULL);
CU_ASSERT_FATAL(participant > 0);
domain = dds_create_domain(5, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL(domain == DDS_RETCODE_PRECONDITION_NOT_MET);
dds_delete(participant);
}
CU_Test(ddsc_domain_create, diff)
{
dds_return_t ret;
dds_domainid_t did;
dds_entity_t domain1;
dds_entity_t domain2;
domain1 = dds_create_domain(1, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL(domain1 > 0);
domain2 = dds_create_domain(2, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL(domain2 > 0);
ret = dds_get_domainid (domain1, &did);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
CU_ASSERT_FATAL(did == 1);
ret = dds_get_domainid (domain2, &did);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
CU_ASSERT_FATAL(did == 2);
ret = dds_delete(domain1);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
ret = dds_delete(domain2);
CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
ret = dds_delete(domain1);
CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
ret = dds_delete(domain2);
CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
}
CU_Test(ddsc_domain_create, domain_default)
{
dds_entity_t domain;
domain = dds_create_domain(DDS_DOMAIN_DEFAULT, "<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain></"DDS_PROJECT_NAME">");
CU_ASSERT_FATAL(domain == DDS_RETCODE_BAD_PARAMETER);
}
CU_Test(ddsc_domain_create, invalid_xml)
{
dds_entity_t domain;
domain = dds_create_domain(1, "<CycloneDDS incorrect XML");
CU_ASSERT_FATAL(domain == DDS_RETCODE_ERROR);
}

View file

@ -0,0 +1,118 @@
/*
* Copyright(c) 2019 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 <assert.h>
#include <limits.h>
#include "dds/dds.h"
#include "CUnit/Theory.h"
#include "RoundTrip.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/time.h"
#define N_THREADS (10)
static const dds_duration_t TEST_DURATION = DDS_SECS(3);
static ddsrt_atomic_uint32_t terminate;
static uint32_t create_participants_thread (void *varg)
{
(void) varg;
while (!ddsrt_atomic_ld32 (&terminate))
{
dds_entity_t par = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
if (par < 0)
{
fprintf (stderr, "dds_create_participant failed: %s\n", dds_strretcode (par));
ddsrt_atomic_st32 (&terminate, 1);
return 1;
}
dds_return_t ret = dds_delete(par);
if (ret != DDS_RETCODE_OK)
{
fprintf (stderr, "dds_delete failed: %s\n", dds_strretcode (ret));
ddsrt_atomic_st32 (&terminate, 1);
return 1;
}
}
return 0;
}
static void participant_creation_torture()
{
dds_return_t rc;
ddsrt_thread_t tids[N_THREADS];
ddsrt_threadattr_t tattr;
ddsrt_threadattr_init (&tattr);
/* Start threads. */
for (size_t i = 0; i < sizeof(tids) / sizeof(*tids); i++)
{
rc = ddsrt_thread_create (&tids[i], "domain_torture_explicit", &tattr, create_participants_thread, 0);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
}
/* Let the threads do the torturing for a while. */
dds_sleepfor(TEST_DURATION);
/* Stop and check threads results. */
ddsrt_atomic_st32 (&terminate, 1);
for (size_t i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
{
uint32_t retval;
rc = ddsrt_thread_join (tids[i], &retval);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT (retval == 0);
}
}
/*
* There are some issues when completely init/deinit the
* library in a torturing way. We really just want to
* check the domain creation/deletion. So, disable this
* test for now.
*/
CU_Test (ddsc_domain, torture_implicit, .disabled=true)
{
/* No explicit domain creation, just start creating and
* deleting participants (that'll create and delete the
* domain implicitly) in a torturing manner. */
participant_creation_torture();
}
CU_Test (ddsc_domain, torture_explicit)
{
dds_return_t rc;
dds_entity_t domain;
/* Create domain explicitly. */
domain = dds_create_domain(1, "");
CU_ASSERT_FATAL (domain > 0);
/* Start creating and deleting participants on the
* explicit domain in a torturing manner. */
participant_creation_torture();
/* Delete domain. */
rc = dds_delete(domain);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
rc = dds_delete(domain);
CU_ASSERT_FATAL (rc != DDS_RETCODE_OK);
}

View file

@ -192,6 +192,10 @@ CU_Test(ddsc_entity_delete, recursive_with_deleted_topic)
ret = dds_delete(g_topic);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
/* Second call to delete a topic must fail */
ret = dds_delete(g_topic);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ALREADY_DELETED);
/* Third, deleting the participant should delete all children of which
* the writer with the last topic reference is one. */
ret = dds_delete(g_participant);
@ -988,6 +992,70 @@ CU_Test(ddsc_entity_get_parent, implicit_subscriber)
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_Test(ddsc_entity_implicit, delete_publisher)
{
dds_entity_t participant;
dds_entity_t writer;
dds_entity_t parent;
dds_entity_t topic;
dds_return_t ret;
char name[100];
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(participant > 0);
topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_delete_publisher", name, 100), NULL, NULL);
CU_ASSERT_FATAL(topic > 0);
writer = dds_create_writer(participant, topic, NULL, NULL);
CU_ASSERT_FATAL(writer > 0);
parent = dds_get_parent(writer);
CU_ASSERT_FATAL(parent > 0);
ret = dds_delete(parent);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ret = dds_delete(writer);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
dds_delete(participant);
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_Test(ddsc_entity_implicit, delete_subscriber)
{
dds_entity_t participant;
dds_entity_t reader;
dds_entity_t parent;
dds_entity_t topic;
dds_return_t ret;
char name[100];
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(participant > 0);
topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_delete_subscriber", name, 100), NULL, NULL);
CU_ASSERT_FATAL(topic > 0);
reader = dds_create_reader(participant, topic, NULL, NULL);
CU_ASSERT_FATAL(reader > 0);
parent = dds_get_parent(reader);
CU_ASSERT_FATAL(parent > 0);
ret = dds_delete(parent);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ret = dds_delete(reader);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
dds_delete(participant);
}
/*************************************************************************************************/
/*************************************************************************************************/
#endif

View file

@ -360,9 +360,9 @@ CU_Test(ddsc_entity, liveliness_changed, .init=init_entity_status, .fini=fini_en
ret = dds_get_liveliness_changed_status (rea, &liveliness_changed);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,1);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, -1);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl);
/* Second call should reset the changed count. */
@ -370,7 +370,7 @@ CU_Test(ddsc_entity, liveliness_changed, .init=init_entity_status, .fini=fini_en
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl);
}

View file

@ -1196,9 +1196,9 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
CU_ASSERT_EQUAL_FATAL(triggered & DDS_LIVELINESS_CHANGED_STATUS, DDS_LIVELINESS_CHANGED_STATUS);
CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count, 0);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count_change, 0);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 1);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 1);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count_change, -1);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 0);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 0);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.last_publication_handle, writer_hdl);
/* The listener should have reset the count_change. */
@ -1206,7 +1206,7 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl);
}

View file

@ -0,0 +1,815 @@
/*
* 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 <assert.h>
#include <limits.h>
#include "dds/dds.h"
#include "CUnit/Theory.h"
#include "Space.h"
#include "config_env.h"
#include "dds/version.h"
#include "dds__entity.h"
#include "dds/ddsi/q_entity.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/time.h"
#define DDS_DOMAINID_PUB 0
#define DDS_DOMAINID_SUB 1
#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
#define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Tracing><OutputFile>cyclonedds_liveliness_tests.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.log</OutputFile><Verbosity>finest</Verbosity></Tracing><Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
uint32_t g_topic_nr = 0;
static dds_entity_t g_pub_domain = 0;
static dds_entity_t g_pub_participant = 0;
static dds_entity_t g_pub_publisher = 0;
static dds_entity_t g_sub_domain = 0;
static dds_entity_t g_sub_participant = 0;
static dds_entity_t g_sub_subscriber = 0;
static char *create_topic_name(const char *prefix, uint32_t nr, char *name, size_t size)
{
/* Get unique g_topic name. */
ddsrt_pid_t pid = ddsrt_getpid();
ddsrt_tid_t tid = ddsrt_gettid();
(void)snprintf(name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid);
return name;
}
static void liveliness_init(void)
{
/* Domains for pub and sub use a different domain id, but the portgain setting
* in configuration is 0, so that both domains will map to the same port number.
* This allows to create two domains in a single test process. */
char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub);
g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub);
dds_free(conf_pub);
dds_free(conf_sub);
g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL);
CU_ASSERT_FATAL(g_pub_participant > 0);
g_sub_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL);
CU_ASSERT_FATAL(g_sub_participant > 0);
g_pub_publisher = dds_create_publisher(g_pub_participant, NULL, NULL);
CU_ASSERT_FATAL(g_pub_publisher > 0);
g_sub_subscriber = dds_create_subscriber(g_sub_participant, NULL, NULL);
CU_ASSERT_FATAL(g_sub_subscriber > 0);
}
static void liveliness_fini(void)
{
dds_delete(g_sub_subscriber);
dds_delete(g_pub_publisher);
dds_delete(g_sub_participant);
dds_delete(g_pub_participant);
dds_delete(g_sub_domain);
dds_delete(g_pub_domain);
}
/**
* Gets the current PMD sequence number for the participant. This
* can be used to count the number of PMD messages that is sent by
* the participant.
*/
static seqno_t get_pmd_seqno(dds_entity_t participant)
{
seqno_t seqno;
struct dds_entity *pp_entity;
struct participant *pp;
struct writer *wr;
CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
wr = get_builtin_writer(pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
CU_ASSERT_FATAL(wr != NULL);
assert(wr != NULL); /* for Clang's static analyzer */
seqno = wr->seq;
thread_state_asleep(lookup_thread_state());
dds_entity_unpin(pp_entity);
return seqno;
}
/**
* Gets the current PMD interval for the participant
*/
static dds_duration_t get_pmd_interval(dds_entity_t participant)
{
dds_duration_t intv;
struct dds_entity *pp_entity;
struct participant *pp;
CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
intv = pp_get_pmd_interval(pp);
thread_state_asleep(lookup_thread_state());
dds_entity_unpin(pp_entity);
return intv;
}
/**
* Gets the current lease duration for the participant
*/
static dds_duration_t get_ldur_config(dds_entity_t participant)
{
struct dds_entity *pp_entity;
dds_duration_t ldur;
CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
ldur = (dds_duration_t)pp_entity->m_domain->gv.config.lease_duration;
dds_entity_unpin(pp_entity);
return ldur;
}
/**
* Test that the correct number of PMD messages is sent for
* the various liveliness kinds.
*/
#define A DDS_LIVELINESS_AUTOMATIC
#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
#define MT DDS_LIVELINESS_MANUAL_BY_TOPIC
CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = {
CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
CU_DataPoints(uint32_t, 200, 500, 100, 100), /* lease duration */
CU_DataPoints(double, 10, 5, 5, 5), /* delay (n times lease duration) */
};
#undef MT
#undef MP
#undef A
CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t writer;
seqno_t start_seqno, end_seqno;
dds_qos_t *rqos;
dds_qos_t *wqos;
dds_entity_t waitset;
dds_attach_t triggered;
uint32_t status;
char name[100];
dds_time_t t;
t = dds_time();
printf("%d.%06d running test: kind %s, lease duration %d, delay %d\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
kind == 0 ? "A" : "MP", ldur, (int32_t)(mult * ldur));
/* wait for initial PMD to be sent by the participant */
while (get_pmd_seqno(g_pub_participant) < 1)
dds_sleepfor(DDS_MSECS(50));
/* topics */
create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, name, sizeof name);
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
/* reader */
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
dds_delete_qos(rqos);
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* waitset on reader */
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
/* writer */
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
dds_delete_qos(wqos);
/* wait for writer to be alive */
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* check no of PMD messages sent */
start_seqno = get_pmd_seqno(g_pub_participant);
dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
end_seqno = get_pmd_seqno(g_pub_participant);
t = dds_time();
printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
start_seqno, end_seqno);
/* End-start should be mult - 1 under ideal circumstances, but consider the test successful
when at least 50% of the expected PMD's was sent. This checks that the frequency for sending
PMDs was increased when the writer was added. */
CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? (50 * (mult - 1)) / 100 : 0))
if (kind != DDS_LIVELINESS_AUTOMATIC)
CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
/* cleanup */
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
/**
* Test that the expected number of proxy writers expires (set to not-alive)
* after a certain delay for various combinations of writers with different
* liveliness kinds.
*/
CU_TheoryDataPoints(ddsc_liveliness, expire_liveliness_kinds) = {
CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration for initial test run (increased for each retry when test fails) */
CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
CU_DataPoints(uint32_t, 1, 0, 2, 0, 1, 0, 0, 1, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
CU_DataPoints(uint32_t, 1, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
CU_DataPoints(uint32_t, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 5, 0, 10), /* number of writers with manual-by-topic liveliness */
};
CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 120)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t *writers;
dds_qos_t *rqos, *wqos_auto, *wqos_man_pp, *wqos_man_tp;
dds_entity_t waitset;
dds_attach_t triggered;
struct dds_liveliness_changed_status lstatus;
uint32_t status, n, run = 1, wr_cnt = wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp;
char name[100];
dds_time_t tstart, t;
bool test_finished = false;
do
{
tstart = dds_time();
printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n",
(int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000,
ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
/* topics */
create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, name, sizeof name);
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
/* reader */
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
dds_delete_qos(rqos);
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* writers */
CU_ASSERT_FATAL((wqos_auto = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos_auto, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
CU_ASSERT_FATAL((wqos_man_pp = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos_man_pp, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
CU_ASSERT_FATAL((wqos_man_tp = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos_man_tp, DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur));
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
writers = dds_alloc(wr_cnt * sizeof(dds_entity_t));
for (n = 0; n < wr_cnt; n++)
{
dds_qos_t *wqos;
wqos = n < wr_cnt_auto ? wqos_auto : (n < (wr_cnt_auto + wr_cnt_man_pp) ? wqos_man_pp : wqos_man_tp);
CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
}
dds_delete_qos(wqos_auto);
dds_delete_qos(wqos_man_pp);
dds_delete_qos(wqos_man_tp);
t = dds_time();
if (t - tstart > DDS_MSECS(0.5 * ldur))
{
ldur *= 10 / (run + 1);
printf("%d.%06d failed to create writers in time\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
}
else
{
/* check alive count before proxy writers are expired */
dds_get_liveliness_changed_status(reader, &lstatus);
printf("%d.%06d writers alive: %d\n", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, lstatus.alive_count);
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt);
dds_time_t tstop = tstart + DDS_MSECS((dds_duration_t)(mult * ldur));
uint32_t stopped = 0;
do
{
dds_duration_t w = tstop - dds_time();
CU_ASSERT_FATAL((dds_waitset_wait(waitset, &triggered, 1, w > 0 ? w : 0)) >= 0);
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
stopped += (uint32_t)lstatus.not_alive_count_change;
} while (dds_time() < tstop);
t = dds_time();
printf("%d.%06d writers stopped: %u\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, stopped);
size_t exp_stopped = mult < 1 ? 0 : (wr_cnt_man_pp + wr_cnt_man_tp);
if (stopped != exp_stopped)
{
ldur *= 10 / (run + 1);
printf("%d.%06d incorrect number of stopped writers\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
}
else
{
/* check alive count */
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
CU_ASSERT_EQUAL(lstatus.alive_count, mult < 1 ? wr_cnt : wr_cnt_auto);
test_finished = true;
}
}
/* cleanup */
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
for (n = 0; n < wr_cnt; n++)
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
dds_free(writers);
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
if (!test_finished)
{
if (++run > 3)
{
printf("%d.%06d run limit reached, test failed\n", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000);
CU_FAIL_FATAL("Run limit reached");
test_finished = true;
continue;
}
else
{
printf("%d.%06d restarting test with ldur %d\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, ldur);
}
}
} while (!test_finished);
}
static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur, dds_entity_t *writer, dds_entity_t topic, dds_entity_t reader)
{
dds_entity_t waitset;
dds_qos_t *wqos;
dds_attach_t triggered;
uint32_t status;
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos, kind, ldur);
CU_ASSERT_FATAL((*writer = dds_create_writer(g_pub_participant, topic, wqos, NULL)) > 0);
dds_delete_qos(wqos);
/* wait for writer to be alive */
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
}
/**
* Test that the correct PMD interval is set for the participant
* based on the lease duration of the writers.
*/
#define MAX_WRITERS 10
CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveliness_fini)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t writers[MAX_WRITERS];
uint32_t wr_cnt = 0;
char name[100];
dds_qos_t *rqos;
uint32_t n;
/* topics */
create_topic_name("ddsc_liveliness_ldur", 1, name, sizeof name);
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
/* reader and waitset */
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
dds_delete_qos(rqos);
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* check if pmd defaults to configured duration */
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), get_ldur_config(g_pub_participant));
/* create writers and check pmd interval in publishing participant */
add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader);
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader);
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
/* cleanup */
for (n = 0; n < wr_cnt; n++)
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
#undef MAX_WRITERS
/**
* Check that the correct lease duration is set in the matched
* publications in the readers. */
CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = liveliness_fini)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t writer;
char name[100];
dds_qos_t *rqos, *wqos;
dds_entity_t waitset;
dds_attach_t triggered;
uint32_t status;
dds_duration_t ldur;
/* topics */
create_topic_name("ddsc_liveliness_ldurpwr", 1, name, sizeof name);
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
/* reader */
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
dds_delete_qos(rqos);
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* writer */
ldur = 1000;
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
/* wait for writer to be alive */
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* check pwr lease duration in matched publication */
dds_instance_handle_t wrs[1];
CU_ASSERT_EQUAL_FATAL(dds_get_matched_publications(reader, wrs, 1), 1);
dds_builtintopic_endpoint_t *ep;
ep = dds_get_matched_publication_data(reader, wrs[0]);
CU_ASSERT_FATAL(ep != NULL);
assert(ep != NULL); /* for Clang's static analyzer */
CU_ASSERT_EQUAL_FATAL(ep->qos->liveliness.lease_duration, DDS_MSECS(ldur));
dds_delete_qos(ep->qos);
dds_free(ep->topic_name);
dds_free(ep->type_name);
dds_free(ep);
/* cleanup */
dds_delete_qos(wqos);
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
/**
* Create a relative large number of writers with liveliness kinds automatic and
* manual-by-participant and with decreasing lease duration, and check that all
* writers become alive. During the writer creation loop, every third writer
* is deleted immediately after creating.
*/
#define MAX_WRITERS 100
CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini, .timeout = 15)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t writers[MAX_WRITERS];
dds_entity_t waitset;
dds_qos_t *wqos;
struct dds_liveliness_changed_status lstatus;
uint32_t alive_writers_auto = 0, alive_writers_man = 0;
char name[100];
dds_qos_t *rqos;
dds_attach_t triggered;
uint32_t n;
Space_Type1 sample = {0, 0, 0};
int64_t ldur = 1000;
/* topics */
create_topic_name("ddsc_liveliness_wr_stress", 1, name, sizeof name);
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
/* reader and waitset */
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
dds_delete_qos(rqos);
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
/* create 1st writer and wait for it to become alive */
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
alive_writers_man++;
/* create writers */
for (n = 1; n < MAX_WRITERS; n++)
{
dds_qset_liveliness(wqos, n % 2 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(n % 3 ? ldur + n : ldur - n) + ((n % 3) == 2 ? 1 : 0));
CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
dds_write(writers[n], &sample);
if (n % 3 == 2)
dds_delete(writers[n]);
else if (n % 2)
alive_writers_auto++;
else
alive_writers_man++;
}
dds_delete_qos(wqos);
printf("alive_writers_auto: %d, alive_writers_man: %d\n", alive_writers_auto, alive_writers_man);
/* wait for auto liveliness writers to become alive and manual-by-pp writers to become not-alive */
do
{
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
printf("alive: %d, not-alive: %d\n", lstatus.alive_count, lstatus.not_alive_count);
dds_sleepfor(DDS_MSECS(50));
} while (lstatus.alive_count != alive_writers_auto || lstatus.not_alive_count != alive_writers_man);
/* check that counts are stable after a delay */
dds_sleepfor(DDS_MSECS(ldur / 2));
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
CU_ASSERT_FATAL(lstatus.alive_count == alive_writers_auto && lstatus.not_alive_count == alive_writers_man);
/* cleanup remaining writers */
for (n = 0; n < MAX_WRITERS; n++)
{
if (n % 3 != 2)
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
}
/* wait for alive_count and not_alive_count to become 0 */
do
{
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
printf("alive: %d, not: %d\n", lstatus.alive_count, lstatus.not_alive_count);
dds_sleepfor(DDS_MSECS(ldur / 10));
} while (lstatus.alive_count > 0 || lstatus.not_alive_count > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
}
#undef MAX_WRITERS
/**
* Check the counts in liveliness_changed_status result.
*/
CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = liveliness_fini)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t writer;
dds_entity_t waitset;
dds_qos_t *rqos;
dds_qos_t *wqos;
dds_attach_t triggered;
struct dds_liveliness_changed_status lstatus;
struct dds_subscription_matched_status sstatus;
char name[100];
dds_duration_t ldur = DDS_MSECS(500);
Space_Type1 sample = {1, 0, 0};
/* topics */
create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, name, sizeof name);
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
/* reader */
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
dds_delete_qos(rqos);
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
/* writer */
CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur);
CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
dds_delete_qos(wqos);
/* wait for writer to be alive */
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
/* check status counts before proxy writer is expired */
dds_get_liveliness_changed_status(reader, &lstatus);
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
dds_get_subscription_matched_status(reader, &sstatus);
CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
/* sleep for more than lease duration, writer should be set not-alive but subscription still matched */
dds_sleepfor(ldur + DDS_MSECS(100));
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
dds_get_liveliness_changed_status(reader, &lstatus);
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0);
dds_get_subscription_matched_status(reader, &sstatus);
CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
/* write sample and re-check status counts */
dds_write(writer, &sample);
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
dds_get_liveliness_changed_status(reader, &lstatus);
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
dds_get_subscription_matched_status(reader, &sstatus);
CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
/* cleanup */
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
}
/**
* Test that dds_assert_liveliness works as expected for liveliness
* kinds manual-by-participant and manual-by-topic.
*/
#define MAX_WRITERS 100
CU_TheoryDataPoints(ddsc_liveliness, assert_liveliness) = {
CU_DataPoints(uint32_t, 1, 0, 0, 1), /* number of writers with automatic liveliness */
CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */
CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */
};
CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout = 60)
{
dds_entity_t pub_topic, sub_topic, reader, writers[MAX_WRITERS];
dds_qos_t *rqos;
struct dds_liveliness_changed_status lstatus;
char name[100];
uint32_t ldur = 100, wr_cnt, run = 1, stopped;
dds_time_t tstart, tstop, t;
bool test_finished = false;
do
{
wr_cnt = 0;
assert(wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u with ldur %d\n",
wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, ldur);
/* topics */
create_topic_name("ddsc_liveliness_assert", g_topic_nr++, name, sizeof name);
CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0);
/* reader */
CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
dds_delete_qos(rqos);
CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* writers */
for (size_t n = 0; n < wr_cnt_auto; n++)
add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
tstart = dds_time();
for (size_t n = 0; n < wr_cnt_man_pp; n++)
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
for (size_t n = 0; n < wr_cnt_man_tp; n++)
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
t = dds_time();
if (t - tstart > DDS_MSECS(0.5 * ldur))
{
ldur *= 10 / (run + 1);
printf("%d.%06d failed to create writers with non-automatic liveliness kind in time\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
}
else
{
/* check status counts before proxy writer is expired */
dds_get_liveliness_changed_status(reader, &lstatus);
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
/* delay for more than lease duration and assert liveliness on writers:
all writers (including man-by-pp) should be kept alive */
tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
stopped = 0;
do
{
for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
dds_assert_liveliness(writers[n]);
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
stopped += (uint32_t)lstatus.not_alive_count_change;
dds_sleepfor(DDS_MSECS(50));
} while (dds_time() < tstop);
dds_get_liveliness_changed_status(reader, &lstatus);
printf("writers alive with dds_assert_liveliness on all writers: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp || stopped != 0)
{
ldur *= 10 / (run + 1);
printf("incorrect number of writers alive or stopped writers\n");
}
else
{
/* delay for more than lease duration and assert liveliness on participant:
writers with liveliness man-by-pp should be kept alive, man-by-topic writers
should stop */
tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
stopped = 0;
do
{
dds_assert_liveliness(g_pub_participant);
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
stopped += (uint32_t)lstatus.not_alive_count_change;
dds_sleepfor(DDS_MSECS(50));
} while (dds_time() < tstop);
dds_get_liveliness_changed_status(reader, &lstatus);
printf("writers alive with dds_assert_liveliness on participant: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp || stopped != wr_cnt_man_tp)
{
ldur *= 10 / (run + 1);
printf("incorrect number of writers alive or stopped writers\n");
}
else
{
test_finished = true;
}
}
}
/* cleanup */
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
for (size_t n = 0; n < wr_cnt; n++)
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
if (!test_finished)
{
if (++run > 3)
{
CU_FAIL_FATAL("Run limit reached");
test_finished = true;
continue;
}
else
{
printf("restarting test with ldur %d\n", ldur);
}
}
} while (!test_finished);
}
#undef MAX_WRITERS

View file

@ -19,6 +19,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_ipaddr.c
ddsi_mcgroup.c
ddsi_security_omg.c
ddsi_portmapping.c
ddsi_serdata.c
ddsi_serdata_default.c
ddsi_sertopic.c
@ -28,6 +29,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_vendor.c
ddsi_threadmon.c
ddsi_rhc.c
ddsi_pmd.c
q_addrset.c
q_bitset_inlines.c
q_bswap.c
@ -71,6 +73,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_mcgroup.h
ddsi_plist_generic.h
ddsi_security_omg.h
ddsi_portmapping.h
ddsi_serdata.h
ddsi_sertopic.h
ddsi_serdata_default.h

View file

@ -0,0 +1,35 @@
/*
* Copyright(c) 2006 to 2019 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
*/
#ifndef DDSI_PMD_H
#define DDSI_PMD_H
#include "dds/ddsi/q_time.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct q_globals;
struct thread_state1;
struct ddsi_guid;
struct nn_xpack;
struct participant;
struct receiver_state;
void write_pmd_message_guid (struct q_globals * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind);
void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind);
void handle_pmd_message (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len);
#if defined (__cplusplus)
}
#endif
#endif /* DDSI_PMD_H */

View file

@ -0,0 +1,49 @@
/*
* Copyright(c) 2019 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
*/
#ifndef DDSI_PORTMAPPING_H
#define DDSI_PORTMAPPING_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#if defined (__cplusplus)
extern "C" {
#endif
enum ddsi_port {
DDSI_PORT_MULTI_DISC,
DDSI_PORT_MULTI_DATA,
DDSI_PORT_UNI_DISC,
DDSI_PORT_UNI_DATA
};
struct ddsi_portmapping {
uint32_t base;
uint32_t dg;
uint32_t pg;
uint32_t d0;
uint32_t d1;
uint32_t d2;
uint32_t d3;
};
struct config;
bool ddsi_valid_portmapping (const struct config *config, int32_t participant_index, char *msg, size_t msgsize);
uint32_t ddsi_get_port (const struct config *config, enum ddsi_port which, int32_t participant_index);
#if defined (__cplusplus)
}
#endif
#endif /* DDSI_PORTMAPPING_H */

View file

@ -61,7 +61,7 @@ typedef void (*ddsi_tran_peer_locator_fn_t) (ddsi_tran_conn_t, nn_locator_t *);
typedef void (*ddsi_tran_disable_multiplexing_fn_t) (ddsi_tran_conn_t);
typedef ddsi_tran_conn_t (*ddsi_tran_accept_fn_t) (ddsi_tran_listener_t);
typedef ddsi_tran_conn_t (*ddsi_tran_create_conn_fn_t) (ddsi_tran_factory_t fact, uint32_t, ddsi_tran_qos_t);
typedef ddsi_tran_listener_t (*ddsi_tran_create_listener_fn_t) (ddsi_tran_factory_t fact, int port, ddsi_tran_qos_t);
typedef ddsi_tran_listener_t (*ddsi_tran_create_listener_fn_t) (ddsi_tran_factory_t fact, uint32_t port, ddsi_tran_qos_t);
typedef void (*ddsi_tran_release_conn_fn_t) (ddsi_tran_conn_t);
typedef void (*ddsi_tran_close_conn_fn_t) (ddsi_tran_conn_t);
typedef void (*ddsi_tran_unblock_listener_fn_t) (ddsi_tran_listener_t);
@ -70,6 +70,7 @@ typedef int (*ddsi_tran_join_mc_fn_t) (ddsi_tran_conn_t, const nn_locator_t *src
typedef int (*ddsi_tran_leave_mc_fn_t) (ddsi_tran_conn_t, const nn_locator_t *srcip, const nn_locator_t *mcip, const struct nn_interface *interf);
typedef int (*ddsi_is_mcaddr_fn_t) (ddsi_tran_factory_t tran, const nn_locator_t *loc);
typedef int (*ddsi_is_ssm_mcaddr_fn_t) (ddsi_tran_factory_t tran, const nn_locator_t *loc);
typedef int (*ddsi_is_valid_port_fn_t) (ddsi_tran_factory_t tran, uint32_t port);
enum ddsi_nearby_address_result {
DNAR_DISTANT,
@ -172,6 +173,7 @@ struct ddsi_tran_factory
ddsi_locator_from_string_fn_t m_locator_from_string_fn;
ddsi_locator_to_string_fn_t m_locator_to_string_fn;
ddsi_enumerate_interfaces_fn_t m_enumerate_interfaces_fn;
ddsi_is_valid_port_fn_t m_is_valid_port_fn;
/* Data */
@ -205,10 +207,17 @@ void ddsi_factory_conn_init (const struct ddsi_tran_factory *factory, ddsi_tran_
inline bool ddsi_factory_supports (const struct ddsi_tran_factory *factory, int32_t kind) {
return factory->m_supports_fn (factory, kind);
}
inline int ddsi_is_valid_port (ddsi_tran_factory_t factory, uint32_t port) {
return factory->m_is_valid_port_fn (factory, port);
}
inline ddsi_tran_conn_t ddsi_factory_create_conn (ddsi_tran_factory_t factory, uint32_t port, ddsi_tran_qos_t qos) {
if (!ddsi_is_valid_port (factory, port))
return NULL;
return factory->m_create_conn_fn (factory, port, qos);
}
inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, int port, ddsi_tran_qos_t qos) {
inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, uint32_t port, ddsi_tran_qos_t qos) {
if (!ddsi_is_valid_port (factory, port))
return NULL;
return factory->m_create_listener_fn (factory, port, qos);
}

View file

@ -16,17 +16,12 @@
#include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_xqos.h"
#include "dds/ddsi/q_feature_check.h"
#include "dds/ddsi/ddsi_portmapping.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* FIXME: should eventually move to abstraction layer */
typedef enum q__schedPrioClass {
Q__SCHED_PRIO_RELATIVE,
Q__SCHED_PRIO_ABSOLUTE
} q__schedPrioClass;
enum nn_standards_conformance {
NN_SC_PEDANTIC,
NN_SC_STRICT,
@ -54,14 +49,6 @@ enum boolean_default {
BOOLDEF_TRUE
};
enum durability_cdr
{
DUR_CDR_LE,
DUR_CDR_BE,
DUR_CDR_SERVER,
DUR_CDR_CLIENT
};
#define PARTICIPANT_INDEX_AUTO -1
#define PARTICIPANT_INDEX_NONE -2
@ -77,7 +64,6 @@ struct config_networkpartition_listelem {
char *address_string;
struct addrset *as;
int connected;
uint32_t partitionHash;
uint32_t partitionId;
};
@ -245,9 +231,10 @@ struct config
int dontRoute;
int enableMulticastLoopback;
uint32_t domainId;
struct config_maybe_uint32 extDomainId; // domain id advertised in discovery
char *domainTag;
int participantIndex;
int maxAutoParticipantIndex;
uint32_t port_base;
char *spdpMulticastAddressString;
char *defaultMulticastAddressString;
char *assumeMulticastCapable;
@ -370,12 +357,7 @@ struct config
enum many_sockets_mode many_sockets_mode;
int assume_rti_has_pmd_endpoints;
uint32_t port_dg;
uint32_t port_pg;
uint32_t port_d0;
uint32_t port_d1;
uint32_t port_d2;
uint32_t port_d3;
struct ddsi_portmapping ports;
int monitor_port;

View file

@ -20,7 +20,7 @@ struct debug_monitor;
typedef int (*debug_monitor_cpf_t) (ddsi_tran_conn_t conn, const char *fmt, ...);
typedef int (*debug_monitor_plugin_t) (ddsi_tran_conn_t conn, debug_monitor_cpf_t cpf, void *arg);
struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port);
struct debug_monitor *new_debug_monitor (struct q_globals *gv, int32_t port);
void add_debug_monitor_plugin (struct debug_monitor *dm, debug_monitor_plugin_t fn, void *arg);
void free_debug_monitor (struct debug_monitor *dm);

View file

@ -12,8 +12,10 @@
#ifndef Q_ENTITY_H
#define Q_ENTITY_H
#include "dds/export.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/avl.h"
#include "dds/ddsrt/fibheap.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsi/q_rtps.h"
#include "dds/ddsi/q_plist.h"
@ -48,14 +50,25 @@ struct proxy_group;
struct proxy_endpoint_common;
typedef void (*ddsi2direct_directread_cb_t) (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, void *arg);
/* Liveliness changed is more complicated than just add/remove. Encode the event
in status_cb_data_t::extra and ignore status_cb_data_t::add */
enum liveliness_changed_data_extra {
LIVELINESS_CHANGED_ADD_ALIVE,
LIVELINESS_CHANGED_ADD_NOT_ALIVE,
LIVELINESS_CHANGED_REMOVE_NOT_ALIVE,
LIVELINESS_CHANGED_REMOVE_ALIVE,
LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE,
LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE,
LIVELINESS_CHANGED_TWITCH
};
typedef struct status_cb_data
{
int raw_status_id;
uint32_t extra;
uint64_t handle;
bool add;
}
status_cb_data_t;
} status_cb_data_t;
typedef void (*status_cb_t) (void *entity, const status_cb_data_t *data);
@ -67,6 +80,8 @@ struct prd_wr_match {
struct rd_pwr_match {
ddsrt_avl_node_t avlnode;
ddsi_guid_t pwr_guid;
unsigned pwr_alive: 1; /* tracks pwr's alive state */
uint32_t pwr_alive_vclock; /* used to ensure progress */
#ifdef DDSI_INCLUDE_SSM
nn_locator_t ssm_mc_loc;
nn_locator_t ssm_src_loc;
@ -189,6 +204,7 @@ struct participant
int32_t user_refc; /* number of non-built-in endpoints in this participant [refc_lock] */
int32_t builtin_refc; /* number of built-in endpoints in this participant [refc_lock] */
int builtins_deleted; /* whether deletion of built-in endpoints has been initiated [refc_lock] */
ddsrt_fibheap_t ldur_auto_wr; /* Heap that contains lease duration for writers with automatic liveliness in this participant */
};
struct endpoint_common {
@ -210,6 +226,11 @@ enum writer_state {
typedef ddsrt_atomic_uint64_t seq_xmit_t;
struct ldur_fhnode {
ddsrt_fibheap_node_t heapnode;
dds_duration_t ldur;
};
struct writer
{
struct entity_common e;
@ -239,7 +260,7 @@ struct writer
struct addrset *as; /* set of addresses to publish to */
struct addrset *as_group; /* alternate case, used for SPDP, when using Cloud with multiple bootstrap locators */
struct xevent *heartbeat_xevent; /* timed event for "periodically" publishing heartbeats when unack'd data present, NULL <=> unreliable */
dds_duration_t lease_duration;
struct ldur_fhnode *lease_duration; /* fibheap node to keep lease duration for this writer, NULL in case of automatic liveliness with inifite duration */
struct whc *whc; /* WHC tracking history, T-L durability service history + samples by sequence number for retransmit */
uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */
nn_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */
@ -305,7 +326,11 @@ struct proxy_participant
unsigned prismtech_bes; /* prismtech-specific extension of built-in endpoints set */
ddsi_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */
struct nn_plist *plist; /* settings/QoS for this participant */
ddsrt_atomic_voidp_t lease; /* lease object for this participant, for automatic leases */
ddsrt_atomic_voidp_t minl_auto; /* lease object for shortest automatic liveliness pwr's lease (includes this proxypp's lease) */
ddsrt_fibheap_t leaseheap_auto; /* keeps leases for this proxypp and leases for pwrs (with liveliness automatic) */
ddsrt_atomic_voidp_t minl_man; /* lease object for shortest manual-by-participant liveliness pwr's lease */
ddsrt_fibheap_t leaseheap_man; /* keeps leases for this proxypp and leases for pwrs (with liveliness manual-by-participant) */
struct lease *lease; /* lease for this proxypp */
struct addrset *as_default; /* default address set to use for user data traffic */
struct addrset *as_meta; /* default address set to use for discovery traffic */
struct proxy_endpoint_common *endpoints; /* all proxy endpoints can be reached from here */
@ -316,6 +341,7 @@ struct proxy_participant
unsigned is_ddsi2_pp: 1; /* if this is the federation-leader on the remote node */
unsigned minimal_bes_mode: 1;
unsigned lease_expired: 1;
unsigned deleting: 1;
unsigned proxypp_have_spdp: 1;
unsigned proxypp_have_cm: 1;
unsigned owns_lease: 1;
@ -368,10 +394,12 @@ struct proxy_writer {
unsigned deliver_synchronously: 1; /* iff 1, delivery happens straight from receive thread for non-historical data; else through delivery queue "dqueue" */
unsigned have_seen_heartbeat: 1; /* iff 1, we have received at least on heartbeat from this proxy writer */
unsigned local_matching_inprogress: 1; /* iff 1, we are still busy matching local readers; this is so we don't deliver incoming data to some but not all readers initially */
unsigned alive: 1; /* iff 1, the proxy writer is alive (lease for this proxy writer is not expired); field may be modified only when holding both pwr->e.lock and pwr->c.proxypp->e.lock */
unsigned filtered: 1; /* iff 1, builtin proxy writer uses content filter, which affects heartbeats and gaps. */
#ifdef DDSI_INCLUDE_SSM
unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */
#endif
uint32_t alive_vclock; /* virtual clock counting transitions between alive/not-alive */
struct nn_defrag *defrag; /* defragmenter for this proxy writer; FIXME: perhaps shouldn't be for historical data */
struct nn_reorder *reorder; /* message reordering for this proxy writer, out-of-sync readers can have their own, see pwr_rd_match */
struct nn_dqueue *dqueue; /* delivery queue for asynchronous delivery (historical data is always delivered asynchronously) */
@ -379,6 +407,7 @@ struct proxy_writer {
struct local_reader_ary rdary; /* LOCAL readers for fast-pathing; if not fast-pathed, fall back to scanning local_readers */
ddsi2direct_directread_cb_t ddsi2direct_cb;
void *ddsi2direct_cbarg;
struct lease *lease;
};
@ -553,10 +582,14 @@ dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *p
void update_participant_plist (struct participant *pp, const struct nn_plist *plist);
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_guid *guid);
/* Gets the interval for PMD messages, which is the minimal lease duration for writers
with auto liveliness in this participant, or the participants lease duration if shorter */
DDS_EXPORT dds_duration_t pp_get_pmd_interval(struct participant *pp);
/* To obtain the builtin writer to be used for publishing SPDP, SEDP,
PMD stuff for PP and its endpoints, given the entityid. If PP has
its own writer, use it; else use the privileged participant. */
struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid);
DDS_EXPORT struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid);
/* To create a new DDSI writer or reader belonging to participant with
GUID "ppguid". May return NULL if participant unknown or
@ -628,6 +661,7 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct
void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bool delete_from_as_disc);
/* To create a new proxy writer or reader; the proxy participant is
determined from the GUID and must exist. */
int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const struct nn_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq);
@ -648,6 +682,10 @@ int delete_proxy_reader (struct q_globals *gv, const struct ddsi_guid *guid, nn_
void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
void proxy_writer_set_alive_may_unlock (struct proxy_writer *pwr, bool notify);
int proxy_writer_set_notalive (struct proxy_writer *pwr, bool notify);
void proxy_writer_set_notalive_guid (struct q_globals *gv, const struct ddsi_guid *pwrguid, bool notify);
int new_proxy_group (const struct ddsi_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp);
void delete_proxy_group (struct ephash *guid_hash, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);

View file

@ -80,15 +80,15 @@ void ephash_remove_reader_guid (struct ephash *eh, struct reader *rd);
void ephash_remove_proxy_writer_guid (struct ephash *eh, struct proxy_writer *pwr);
void ephash_remove_proxy_reader_guid (struct ephash *eh, struct proxy_reader *prd);
void *ephash_lookup_guid_untyped (const struct ephash *eh, const struct ddsi_guid *guid);
void *ephash_lookup_guid (const struct ephash *eh, const struct ddsi_guid *guid, enum entity_kind kind);
DDS_EXPORT void *ephash_lookup_guid_untyped (const struct ephash *eh, const struct ddsi_guid *guid);
DDS_EXPORT void *ephash_lookup_guid (const struct ephash *eh, const struct ddsi_guid *guid, enum entity_kind kind);
struct participant *ephash_lookup_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
struct writer *ephash_lookup_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
struct reader *ephash_lookup_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
DDS_EXPORT struct participant *ephash_lookup_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
DDS_EXPORT struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
DDS_EXPORT struct writer *ephash_lookup_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
DDS_EXPORT struct reader *ephash_lookup_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
DDS_EXPORT struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
DDS_EXPORT struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
/* Enumeration of entries in the hash table:

View file

@ -12,6 +12,9 @@
#ifndef Q_LEASE_H
#define Q_LEASE_H
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/fibheap.h"
#include "dds/ddsrt/time.h"
#include "dds/ddsi/q_time.h"
#if defined (__cplusplus)
@ -20,21 +23,31 @@ extern "C" {
struct receiver_state;
struct participant;
struct lease;
struct entity_common;
struct q_globals; /* FIXME: make a special for the lease admin */
struct lease {
ddsrt_fibheap_node_t heapnode;
ddsrt_fibheap_node_t pp_heapnode;
nn_etime_t tsched; /* access guarded by leaseheap_lock */
ddsrt_atomic_uint64_t tend; /* really an nn_etime_t */
dds_duration_t tdur; /* constant (renew depends on it) */
struct entity_common *entity; /* constant */
};
int compare_lease_tsched (const void *va, const void *vb);
int compare_lease_tdur (const void *va, const void *vb);
void lease_management_init (struct q_globals *gv);
void lease_management_term (struct q_globals *gv);
struct lease *lease_new (nn_etime_t texpire, int64_t tdur, struct entity_common *e);
struct lease *lease_clone (const struct lease *l);
void lease_register (struct lease *l);
void lease_unregister (struct lease *l);
void lease_free (struct lease *l);
void lease_renew (struct lease *l, nn_etime_t tnow);
void lease_set_expiry (struct lease *l, nn_etime_t when);
int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow);
void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len);
#if defined (__cplusplus)
}
#endif

View file

@ -39,8 +39,6 @@ DDS_EXPORT int guid_prefix_eq (const ddsi_guid_prefix_t *a, const ddsi_guid_pref
DDS_EXPORT int guid_eq (const struct ddsi_guid *a, const struct ddsi_guid *b);
DDS_EXPORT int ddsi2_patmatch (const char *pat, const char *str);
uint32_t crc32_calc (const void *buf, size_t length);
#if defined (__cplusplus)
}
#endif

View file

@ -56,13 +56,15 @@ extern "C" {
#ifdef DDSI_INCLUDE_SSM
#define PP_READER_FAVOURS_SSM ((uint64_t)1 << 39)
#endif
#define PP_DOMAIN_ID ((uint64_t)1 << 40)
#define PP_DOMAIN_TAG ((uint64_t)1 << 41)
/* Security extensions. */
#define PP_IDENTITY_TOKEN ((uint64_t)1 << 41)
#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 42)
#define PP_ENDPOINT_SECURITY_INFO ((uint64_t)1 << 43)
#define PP_PARTICIPANT_SECURITY_INFO ((uint64_t)1 << 44)
#define PP_IDENTITY_STATUS_TOKEN ((uint64_t)1 << 45)
#define PP_DATA_TAGS ((uint64_t)1 << 46)
#define PP_IDENTITY_TOKEN ((uint64_t)1 << 42)
#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 43)
#define PP_ENDPOINT_SECURITY_INFO ((uint64_t)1 << 44)
#define PP_PARTICIPANT_SECURITY_INFO ((uint64_t)1 << 45)
#define PP_IDENTITY_STATUS_TOKEN ((uint64_t)1 << 46)
#define PP_DATA_TAGS ((uint64_t)1 << 47)
/* Set for unrecognized parameters that are in the reserved space or
in our own vendor-specific space that have the
PID_UNRECOGNIZED_INCOMPATIBLE_FLAG set (see DDSI 2.1 9.6.2.2.1) */
@ -241,6 +243,8 @@ typedef struct nn_plist {
#ifdef DDSI_INCLUDE_SSM
nn_reader_favours_ssm_t reader_favours_ssm;
#endif
uint32_t domain_id;
char *domain_tag;
} nn_plist_t;

View file

@ -350,6 +350,8 @@ DDSRT_WARNING_MSVC_ON(4200)
#define PID_PAD 0x0u
#define PID_SENTINEL 0x1u
#define PID_DOMAIN_ID 0xfu
#define PID_DOMAIN_TAG (0x14u | PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)
#define PID_USER_DATA 0x2cu
#define PID_TOPIC_NAME 0x5u
#define PID_TYPE_NAME 0x7u

View file

@ -98,7 +98,8 @@ struct nn_rmsg {
struct nn_rmsg_chunk chunk;
};
#define NN_RMSG_PAYLOAD(m) ((unsigned char *) (&(m)->chunk + 1))
DDSRT_STATIC_ASSERT (sizeof (struct nn_rmsg) == offsetof (struct nn_rmsg, chunk) + sizeof (struct nn_rmsg_chunk));
#define NN_RMSG_PAYLOAD(m) ((unsigned char *) (m + 1))
#define NN_RMSG_PAYLOADOFF(m, o) (NN_RMSG_PAYLOAD (m) + (o))
struct receiver_state {

View file

@ -27,7 +27,7 @@ typedef int64_t seqno_t;
#define PGUIDPREFIX(gp) (gp).u[0], (gp).u[1], (gp).u[2]
#define PGUID(g) PGUIDPREFIX ((g).prefix), (g).entityid.u
#define PGUIDFMT "%"PRIx32":%"PRIx32":%"PRIx32":%"PRIx32
#define PGUIDFMT "%" PRIx32 ":%" PRIx32 ":%" PRIx32 ":%" PRIx32
/* predefined entity ids; here viewed as an unsigned int, on the
network as four bytes corresponding to the integer in network byte

View file

@ -42,7 +42,8 @@ int write_sample_nogc_notk (struct thread_state1 * const ts1, struct nn_xpack *x
/* When calling the following functions, wr->lock must be held */
dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, unsigned fragnum, struct proxy_reader *prd,struct nn_xmsg **msg, int isnew);
int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew);
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, ddsi_entityid_t dst, int issync);
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, int hbliveliness, ddsi_entityid_t dst, int issync);
dds_return_t write_hb_liveliness (struct q_globals * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp);
int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, struct proxy_reader *prd);
#if defined (__cplusplus)

View file

@ -123,7 +123,7 @@ char *ddsi_ipaddr_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_
(void)tran;
assert (sizeof_dst > 1);
if (loc->kind == NN_LOCATOR_KIND_INVALID)
snprintf (dst, sizeof_dst, "(invalid)");
(void) snprintf (dst, sizeof_dst, "(invalid)");
else
{
struct sockaddr_storage src;

View file

@ -148,7 +148,7 @@ static char *make_joinleave_msg (char *buf, size_t bufsz, ddsi_tran_conn_t conn,
(void) snprintf (interfstr, sizeof (interfstr), "(default)");
n = err ? snprintf (buf, bufsz, "error %d in ", err) : 0;
if ((size_t) n < bufsz)
snprintf (buf + n, bufsz - (size_t) n, "%s conn %p for (%s, %s) interface %s", join ? "join" : "leave", (void *) conn, mcstr, srcstr, interfstr);
(void) snprintf (buf + n, bufsz - (size_t) n, "%s conn %p for (%s, %s) interface %s", join ? "join" : "leave", (void *) conn, mcstr, srcstr, interfstr);
return buf;
}

View file

@ -0,0 +1,160 @@
/*
* Copyright(c) 2006 to 2019 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 <stdlib.h>
#include <string.h>
#include "dds/ddsi/ddsi_pmd.h"
#include "dds/ddsi/ddsi_serdata.h"
#include "dds/ddsi/ddsi_serdata_default.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsi/q_bswap.h"
#include "dds/ddsi/q_entity.h"
#include "dds/ddsi/q_globals.h"
#include "dds/ddsi/q_lease.h"
#include "dds/ddsi/q_log.h"
#include "dds/ddsi/q_misc.h"
#include "dds/ddsi/q_protocol.h"
#include "dds/ddsi/q_radmin.h"
#include "dds/ddsi/q_rtps.h"
#include "dds/ddsi/q_time.h"
#include "dds/ddsi/q_transmit.h"
#include "dds/ddsi/q_xmsg.h"
#include "dds/ddsi/sysdeps.h"
static void debug_print_rawdata (const struct q_globals *gv, const char *msg, const void *data, size_t len)
{
const unsigned char *c = data;
size_t i;
GVTRACE ("%s<", msg);
for (i = 0; i < len; i++)
{
if (32 < c[i] && c[i] <= 127)
GVTRACE ("%s%c", (i > 0 && (i%4) == 0) ? " " : "", c[i]);
else
GVTRACE ("%s\\x%02x", (i > 0 && (i%4) == 0) ? " " : "", c[i]);
}
GVTRACE (">");
}
void write_pmd_message_guid (struct q_globals * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind)
{
struct thread_state1 * const ts1 = lookup_thread_state ();
thread_state_awake (ts1, gv);
struct participant *pp = ephash_lookup_participant_guid (gv->guid_hash, pp_guid);
if (pp == NULL)
GVTRACE ("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (*pp_guid));
else
write_pmd_message (ts1, NULL, pp, pmd_kind);
thread_state_asleep (ts1);
}
void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind)
{
#define PMD_DATA_LENGTH 1
struct q_globals * const gv = pp->e.gv;
struct writer *wr;
union {
ParticipantMessageData_t pmd;
char pad[offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH];
} u;
struct ddsi_serdata *serdata;
struct ddsi_tkmap_instance *tk;
if ((wr = get_builtin_writer (pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER)) == NULL)
{
GVTRACE ("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (pp->e.guid));
return;
}
u.pmd.participantGuidPrefix = nn_hton_guid_prefix (pp->e.guid.prefix);
u.pmd.kind = ddsrt_toBE4u (pmd_kind);
u.pmd.length = PMD_DATA_LENGTH;
memset (u.pmd.value, 0, u.pmd.length);
struct ddsi_rawcdr_sample raw = {
.blob = &u,
.size = offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH,
.key = &u.pmd,
.keysize = 16
};
serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw);
serdata->timestamp = now ();
tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata);
write_sample_nogc (ts1, xp, wr, serdata, tk);
ddsi_tkmap_instance_unref (gv->m_tkmap, tk);
#undef PMD_DATA_LENGTH
}
void handle_pmd_message (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
{
const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
const int bswap = (data->identifier == CDR_LE) ^ (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN);
struct proxy_participant *proxypp;
ddsi_guid_t ppguid;
struct lease *l;
RSTTRACE (" PMD ST%x", statusinfo);
if (data->identifier != CDR_LE && data->identifier != CDR_BE)
{
RSTTRACE (" PMD data->identifier %u !?\n", ntohs (data->identifier));
return;
}
switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER))
{
case 0:
if (offsetof (ParticipantMessageData_t, value) > len - sizeof (struct CDRHeader))
debug_print_rawdata (rst->gv, " SHORT1", data, len);
else
{
const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1);
ddsi_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
uint32_t kind = ntohl (pmd->kind);
uint32_t length = bswap ? ddsrt_bswap4u (pmd->length) : pmd->length;
RSTTRACE (" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length);
if (len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value) < length)
debug_print_rawdata (rst->gv, " SHORT2", pmd->value, len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value));
else
debug_print_rawdata (rst->gv, "", pmd->value, length);
ppguid.prefix = p;
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
if ((proxypp = ephash_lookup_proxy_participant_guid (rst->gv->guid_hash, &ppguid)) == NULL)
RSTTRACE (" PPunknown");
else if (kind == PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE &&
(l = ddsrt_atomic_ldvoidp (&proxypp->minl_man)) != NULL)
{
/* Renew lease for entity with shortest manual-by-participant lease */
lease_renew (l, now_et ());
}
}
break;
case NN_STATUSINFO_DISPOSE:
case NN_STATUSINFO_UNREGISTER:
case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER:
/* Serialized key; BE or LE doesn't matter as both fields are
defined as octets. */
if (len < sizeof (struct CDRHeader) + sizeof (ddsi_guid_prefix_t))
debug_print_rawdata (rst->gv, " SHORT3", data, len);
else
{
ppguid.prefix = nn_ntoh_guid_prefix (*((ddsi_guid_prefix_t *) (data + 1)));
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
if (delete_proxy_participant_by_guid (rst->gv, &ppguid, timestamp, 0) < 0)
RSTTRACE (" unknown");
else
RSTTRACE (" delete");
}
break;
}
RSTTRACE ("\n");
}

View file

@ -0,0 +1,126 @@
/*
* Copyright(c) 2019 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 <assert.h>
#include "dds/ddsi/ddsi_portmapping.h"
#include "dds/ddsi/q_config.h"
static bool get_port_int (uint32_t *port, const struct ddsi_portmapping *map, enum ddsi_port which, uint32_t domain_id, int32_t participant_index, char *str_if_overflow, size_t strsize)
{
uint32_t off = UINT32_MAX, ppidx = UINT32_MAX;
assert (domain_id != UINT32_MAX);
assert (participant_index >= 0 || participant_index == PARTICIPANT_INDEX_NONE);
switch (which)
{
case DDSI_PORT_MULTI_DISC:
off = map->d0;
/* multicast port numbers are not affected by participant index */
ppidx = 0;
break;
case DDSI_PORT_MULTI_DATA:
off = map->d2;
/* multicast port numbers are not affected by participant index */
ppidx = 0;
break;
case DDSI_PORT_UNI_DISC:
if (participant_index == PARTICIPANT_INDEX_NONE)
{
/* participant index "none" means unicast ports get chosen by the transport */
*port = 0;
return true;
}
off = map->d1;
ppidx = (uint32_t) participant_index;
break;
case DDSI_PORT_UNI_DATA:
if (participant_index == PARTICIPANT_INDEX_NONE)
{
/* participant index "none" means unicast ports get chosen by the transport */
*port = 0;
return true;
}
off = map->d3;
ppidx = (uint32_t) participant_index;
break;
}
const uint64_t a = (uint64_t) map->dg * domain_id;
const uint64_t b = map->base + (uint64_t) map->pg * ppidx + off;
/* For the mapping to be valid, the port number must be in range of an unsigned 32 bit integer and must
not be 0 (as that is used for indicating a random port should be selected by the transport). The
transports may limit this further, but at least we won't have to worry about overflow anymore. */
*port = (uint32_t) (a + b);
if (a <= UINT32_MAX && b <= UINT32_MAX - a && *port > 0)
return true;
else
{
/* a, b < 2^64 ~ 18e18; 2^32 <= a + b < 2^65 ~ 36e18
2^32 ~ 4e9, so it can easily be split into (a+b) `div` 1e9 and (a+b) `mod` 1e9
and then the most-significant part is guaranteed to be > 0 */
const uint32_t billion = 1000000000;
const uint32_t y = (uint32_t) (a % billion) + (uint32_t) (b % billion);
const uint64_t x = (a / billion) + (b / billion) + (y / billion);
snprintf (str_if_overflow, strsize, "%"PRIu64"%09"PRIu32, x, y % billion);
return false;
}
}
static const char *portname (enum ddsi_port which)
{
const char *n = "?";
switch (which)
{
case DDSI_PORT_MULTI_DISC: n = "multicast discovery"; break;
case DDSI_PORT_MULTI_DATA: n = "multicast data"; break;
case DDSI_PORT_UNI_DISC: n = "unicast discovery"; break;
case DDSI_PORT_UNI_DATA: n = "unicast data"; break;
}
return n;
}
bool ddsi_valid_portmapping (const struct config *config, int32_t participant_index, char *msg, size_t msgsize)
{
DDSRT_STATIC_ASSERT (DDSI_PORT_MULTI_DISC >= 0 &&
DDSI_PORT_MULTI_DISC + 1 == DDSI_PORT_MULTI_DATA &&
DDSI_PORT_MULTI_DATA + 1 == DDSI_PORT_UNI_DISC &&
DDSI_PORT_UNI_DISC + 1 == DDSI_PORT_UNI_DATA &&
DDSI_PORT_UNI_DATA >= 0);
uint32_t dummy_port;
char str[32];
bool ok = true;
enum ddsi_port which = DDSI_PORT_MULTI_DISC;
int n = snprintf (msg, msgsize, "port number(s) of out range:");
size_t pos = (n >= 0 && (size_t) n <= msgsize) ? (size_t) n : msgsize;
do {
if (!get_port_int (&dummy_port, &config->ports, which, config->extDomainId.value, participant_index, str, sizeof (str)))
{
n = snprintf (msg + pos, msgsize - pos, "%s %s %s", ok ? "" : ",", portname (which), str);
if (n >= 0 && (size_t) n <= msgsize - pos)
pos += (size_t) n;
ok = false;
}
} while (which++ != DDSI_PORT_UNI_DATA);
return ok;
}
uint32_t ddsi_get_port (const struct config *config, enum ddsi_port which, int32_t participant_index)
{
/* Not supposed to come here if port mapping is invalid */
uint32_t port;
char str[32];
bool ok = get_port_int (&port, &config->ports, which, config->extDomainId.value, participant_index, str, sizeof (str));
assert (ok);
(void) ok;
return port;
}

View file

@ -42,11 +42,11 @@ static char *ddsi_raweth_to_string (ddsi_tran_factory_t tran, char *dst, size_t
{
(void)tran;
if (with_port)
snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]:%u",
(void) snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]:%u",
loc->address[10], loc->address[11], loc->address[12],
loc->address[13], loc->address[14], loc->address[15], loc->port);
else
snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]",
(void) snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]",
loc->address[10], loc->address[11], loc->address[12],
loc->address[13], loc->address[14], loc->address[15]);
return dst;
@ -94,7 +94,7 @@ static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf
)
{
char addrbuf[DDSI_LOCSTRLEN];
snprintf(addrbuf, sizeof(addrbuf), "[%02x:%02x:%02x:%02x:%02x:%02x]:%u",
(void) snprintf(addrbuf, sizeof(addrbuf), "[%02x:%02x:%02x:%02x:%02x:%02x]:%u",
src.sll_addr[0], src.sll_addr[1], src.sll_addr[2],
src.sll_addr[3], src.sll_addr[4], src.sll_addr[5], ntohs(src.sll_protocol));
DDS_CWARNING(&conn->m_base.gv->logconfig, "%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len);
@ -356,6 +356,12 @@ static int ddsi_raweth_enumerate_interfaces (ddsi_tran_factory_t fact, enum tran
return ddsrt_getifaddrs(ifs, afs);
}
static int ddsi_raweth_is_valid_port (ddsi_tran_factory_t fact, uint32_t port)
{
(void) fact;
return (port >= 1 && port <= 65535);
}
int ddsi_raweth_init (struct q_globals *gv)
{
struct ddsi_tran_factory *fact = ddsrt_malloc (sizeof (*fact));
@ -377,6 +383,7 @@ int ddsi_raweth_init (struct q_globals *gv)
fact->m_locator_from_string_fn = ddsi_raweth_address_from_string;
fact->m_locator_to_string_fn = ddsi_raweth_to_string;
fact->m_enumerate_interfaces_fn = ddsi_raweth_enumerate_interfaces;
fact->m_is_valid_port_fn = ddsi_raweth_is_valid_port;
ddsi_factory_add (gv, fact);
GVLOG (DDS_LC_CONFIG, "raweth initialized\n");
return 0;

View file

@ -856,7 +856,7 @@ static ddsi_tcp_conn_t ddsi_tcp_new_conn (struct ddsi_tran_factory_tcp *fact, dd
return conn;
}
static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, int port, ddsi_tran_qos_t qos)
static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, uint32_t port, ddsi_tran_qos_t qos)
{
char buff[DDSI_LOCSTRLEN];
ddsrt_socket_t sock;
@ -1055,6 +1055,12 @@ static enum ddsi_nearby_address_result ddsi_tcp_is_nearby_address (ddsi_tran_fac
return ddsi_ipaddr_is_nearby_address(tran, loc, ownloc, ninterf, interf);
}
static int ddsi_tcp_is_valid_port (ddsi_tran_factory_t fact, uint32_t port)
{
(void) fact;
return (port <= 65535);
}
int ddsi_tcp_init (struct q_globals *gv)
{
struct ddsi_tran_factory_tcp *fact = ddsrt_malloc (sizeof (*fact));
@ -1079,6 +1085,7 @@ int ddsi_tcp_init (struct q_globals *gv)
fact->fact.m_is_mcaddr_fn = ddsi_tcp_is_mcaddr;
fact->fact.m_is_ssm_mcaddr_fn = ddsi_tcp_is_ssm_mcaddr;
fact->fact.m_is_nearby_address_fn = ddsi_tcp_is_nearby_address;
fact->fact.m_is_valid_port_fn = ddsi_tcp_is_valid_port;
ddsi_factory_add (gv, &fact->fact);
#if DDSRT_HAVE_IPV6

View file

@ -23,8 +23,9 @@
extern inline uint32_t ddsi_conn_type (ddsi_tran_conn_t conn);
extern inline uint32_t ddsi_conn_port (ddsi_tran_conn_t conn);
extern inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, int port, ddsi_tran_qos_t qos);
extern inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, uint32_t port, ddsi_tran_qos_t qos);
extern inline bool ddsi_factory_supports (const struct ddsi_tran_factory *factory, int32_t kind);
extern inline int ddsi_is_valid_port (ddsi_tran_factory_t factory, uint32_t port);
extern inline ddsrt_socket_t ddsi_conn_handle (ddsi_tran_conn_t conn);
extern inline int ddsi_conn_locator (ddsi_tran_conn_t conn, nn_locator_t * loc);
extern inline ddsrt_socket_t ddsi_tran_handle (ddsi_tran_base_t base);
@ -285,7 +286,7 @@ char *ddsi_locator_to_string (const struct q_globals *gv, char *dst, size_t size
if (0 < pos && (size_t)pos < sizeof_dst)
(void) tran->m_locator_to_string_fn (tran, dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 1);
} else {
snprintf (dst, sizeof_dst, "invalid/0:0");
(void) snprintf (dst, sizeof_dst, "invalid/0:0");
}
return dst;
}
@ -298,7 +299,7 @@ char *ddsi_locator_to_string_no_port (const struct q_globals *gv, char *dst, siz
if (0 < pos && (size_t)pos < sizeof_dst)
(void) tran->m_locator_to_string_fn (tran, dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 0);
} else {
snprintf (dst, sizeof_dst, "invalid/0");
(void) snprintf (dst, sizeof_dst, "invalid/0");
}
return dst;
}

View file

@ -454,7 +454,7 @@ static char *ddsi_udp_locator_to_string (ddsi_tran_factory_t tran, char *dst, si
pos += (size_t)cnt;
}
if (with_port && pos < sizeof_dst) {
snprintf (dst + pos, sizeof_dst - pos, ":%"PRIu32, loc->port);
(void) snprintf (dst + pos, sizeof_dst - pos, ":%"PRIu32, loc->port);
}
return dst;
}
@ -466,6 +466,12 @@ static void ddsi_udp_fini (ddsi_tran_factory_t fact)
ddsrt_free (fact);
}
static int ddsi_udp_is_valid_port (ddsi_tran_factory_t fact, uint32_t port)
{
(void) fact;
return (port <= 65535);
}
int ddsi_udp_init (struct q_globals *gv)
{
struct ddsi_tran_factory *fact = ddsrt_malloc (sizeof (*fact));
@ -489,6 +495,7 @@ int ddsi_udp_init (struct q_globals *gv)
fact->m_locator_from_string_fn = ddsi_udp_address_from_string;
fact->m_locator_to_string_fn = ddsi_udp_locator_to_string;
fact->m_enumerate_interfaces_fn = ddsi_eth_enumerate_interfaces;
fact->m_is_valid_port_fn = ddsi_udp_is_valid_port;
#if DDSRT_HAVE_IPV6
if (gv->config.transport_selector == TRANS_UDP6)
{

View file

@ -103,25 +103,22 @@ static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrse
if (!ddsi_is_mcaddr (gv, &loc))
{
assert (gv->config.maxAutoParticipantIndex >= 0);
for (uint32_t i = 0; i <= (uint32_t) gv->config.maxAutoParticipantIndex; i++)
for (int32_t i = 0; i <= gv->config.maxAutoParticipantIndex; i++)
{
uint32_t port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + i * gv->config.port_pg + gv->config.port_d1;
loc.port = (unsigned) port;
loc.port = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DISC, i);
if (i == 0)
GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc));
else
GVLOG (DDS_LC_CONFIG, ", :%"PRIu32, port);
GVLOG (DDS_LC_CONFIG, ", :%"PRIu32, loc.port);
add_to_addrset (gv, as, &loc);
}
}
else
{
uint32_t port;
if (port_mode == -1)
port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0;
loc.port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0);
else
port = (uint32_t) port_mode;
loc.port = (unsigned) port;
loc.port = (uint32_t) port_mode;
GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc));
add_to_addrset (gv, as, &loc);
}

View file

@ -166,7 +166,6 @@ DUPF(uint32);
DU(natint);
DU(natint_255);
DUPF(participantIndex);
DU(port);
DU(dyn_port);
DUPF(memsize);
DU(duration_inf);
@ -756,20 +755,20 @@ static const struct cfgelem sizing_cfgelems[] = {
};
static const struct cfgelem discovery_ports_cfgelems[] = {
{ LEAF("Base"), 1, "7400", ABSOFF(port_base), 0, uf_port, 0, pf_uint,
{ LEAF("Base"), 1, "7400", ABSOFF(ports.base), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the base port number (refer to the DDSI 2.1 specification, section 9.6.1, constant PB).</p>") },
{ LEAF("DomainGain"), 1, "250", ABSOFF(port_dg), 0, uf_uint, 0, pf_uint,
{ LEAF("DomainGain"), 1, "250", ABSOFF(ports.dg), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the domain gain, relating domain ids to sets of port numbers (refer to the DDSI 2.1 specification, section 9.6.1, constant DG).</p>") },
{ LEAF("ParticipantGain"), 1, "2", ABSOFF(port_pg), 0, uf_uint, 0, pf_uint,
{ LEAF("ParticipantGain"), 1, "2", ABSOFF(ports.pg), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the participant gain, relating p0, articipant index to sets of port numbers (refer to the DDSI 2.1 specification, section 9.6.1, constant PG).</p>") },
{ LEAF("MulticastMetaOffset"), 1, "0", ABSOFF(port_d0), 0, uf_uint, 0, pf_uint,
{ LEAF("MulticastMetaOffset"), 1, "0", ABSOFF(ports.d0), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the port number for multicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d0).</p>") },
{ LEAF("UnicastMetaOffset"), 1, "10", ABSOFF(port_d1), 0, uf_uint, 0, pf_uint,
{ LEAF("UnicastMetaOffset"), 1, "10", ABSOFF(ports.d1), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the port number for unicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d1).</p>") },
{ LEAF("MulticastDataOffset"), 1, "1", ABSOFF(port_d2), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the port number for multicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d2).</p>") },
{ LEAF("UnicastDataOffset"), 1, "11", ABSOFF(port_d3), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the port number for unicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d3).</p>") },
{ LEAF("MulticastDataOffset"), 1, "1", ABSOFF(ports.d2), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the port number for multicast data traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d2).</p>") },
{ LEAF("UnicastDataOffset"), 1, "11", ABSOFF(ports.d3), 0, uf_uint, 0, pf_uint,
BLURB("<p>This element specifies the port number for unicast data traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d3).</p>") },
END_MARKER
};
@ -844,6 +843,10 @@ static const struct cfgelem discovery_peers_cfgelems[] = {
};
static const struct cfgelem discovery_cfgelems[] = {
{ LEAF("Tag"), 0, "", ABSOFF(domainTag), 0, uf_string, ff_free, pf_string,
BLURB("<p>String extension for domain id that remote participants must match to be discovered.</p>") },
{ LEAF ("ExternalDomainId"), 1, "default", ABSOFF (extDomainId), 0, uf_maybe_int32, 0, pf_maybe_int32,
BLURB("<p>An override for the domain id, to be used in discovery and for determining the port number mapping. This allows creating multiple domains in a single process while making them appear as a single domain on the network. The value \"default\" disables the override.</p>") },
{ LEAF("DSGracePeriod"), 1, "30 s", ABSOFF(ds_grace_period), 0, uf_duration_inf, 0, pf_duration,
BLURB("<p>This setting controls for how long endpoints discovered via a Cloud discovery service will survive after the discovery service disappeared, allowing reconnect without loss of data when the discovery service restarts (or another instance takes over).</p>") },
{ GROUP("Peers", discovery_peers_cfgelems),
@ -983,7 +986,9 @@ static const struct cfgelem root_cfgelems[] = {
};
static const struct cfgelem root_cfgattrs[] = {
{ ATTR("xmlns"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
{ ATTR("xmlns:xsi"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
{ ATTR("xsi:schemaLocation"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
{ ATTR("xsi:noNamespaceSchemaLocation"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
END_MARKER
};
@ -1314,7 +1319,7 @@ static int64_t lookup_multiplier (struct cfgst *cfgst, const struct unit *unitta
always allow 0 to be specified without a unit */
return 1;
} else if (def_mult == 0 && err_on_unrecognised) {
cfg_error (cfgst, "%s: unit is required", value);
(void) cfg_error (cfgst, "%s: unit is required", value);
return 0;
} else {
cfg_warning (cfgst, "%s: use of default unit is deprecated", value);
@ -1327,7 +1332,7 @@ static int64_t lookup_multiplier (struct cfgst *cfgst, const struct unit *unitta
if (strcmp(unittab[i].name, value + unit_pos) == 0)
return unittab[i].multiplier;
if (err_on_unrecognised)
cfg_error(cfgst, "%s: unrecognised unit", value + unit_pos);
(void) cfg_error(cfgst, "%s: unrecognised unit", value + unit_pos);
return 0;
}
}
@ -2045,34 +2050,23 @@ static enum update_result uf_natint_255(struct cfgst *cfgst, void *parent, struc
static enum update_result uf_uint (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value)
{
unsigned * const elem = cfg_address (cfgst, parent, cfgelem);
uint32_t * const elem = cfg_address (cfgst, parent, cfgelem);
char *endptr;
unsigned long v = strtoul (value, &endptr, 10);
if (*value == 0 || *endptr != 0)
return cfg_error (cfgst, "%s: not a decimal integer", value);
if (v != (unsigned) v)
if (v != (uint32_t) v)
return cfg_error (cfgst, "%s: value out of range", value);
*elem = (unsigned) v;
*elem = (uint32_t) v;
return URES_SUCCESS;
}
static void pf_uint (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources)
{
unsigned const * const p = cfg_address (cfgst, parent, cfgelem);
uint32_t const * const p = cfg_address (cfgst, parent, cfgelem);
cfg_logelem (cfgst, sources, "%u", *p);
}
static enum update_result uf_port(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value)
{
int *elem = cfg_address (cfgst, parent, cfgelem);
if (uf_uint (cfgst, parent, cfgelem, first, value) != URES_SUCCESS)
return URES_ERROR;
else if (*elem < 1 || *elem > 65535)
return cfg_error (cfgst, "%s: out of range", value);
else
return URES_SUCCESS;
}
static enum update_result uf_duration_gen (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, const char *value, int64_t def_mult, int64_t min_ns, int64_t max_ns)
{
return uf_natint64_unit (cfgst, cfg_address (cfgst, parent, cfgelem), value, unittab_duration, def_mult, min_ns, max_ns);
@ -2242,7 +2236,7 @@ static int set_default (struct cfgst *cfgst, void *parent, struct cfgelem const
enum update_result res;
if (cfgelem->defvalue == NULL)
{
cfg_error (cfgst, "element missing in configuration");
(void) cfg_error (cfgst, "element missing in configuration");
return 0;
}
res = do_update (cfgst, cfgelem->update, parent, cfgelem, cfgelem->defvalue, 0);
@ -2572,7 +2566,7 @@ static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED
cfg_subelem = partial_match;
else
{
cfg_error (cfgst, "%s: unknown element", name);
(void) cfg_error (cfgst, "%s: unknown element", name);
cfgst_push (cfgst, 0, NULL, NULL);
return 0;
}
@ -2686,7 +2680,7 @@ static int proc_attr (void *varg, UNUSED_ARG (uintptr_t eleminfo), const char *n
return proc_update_cfgelem (cfgst, cfg_attr, value, true);
else
{
cfg_error (cfgst, "%s: unknown attribute", name);
(void) cfg_error (cfgst, "%s: unknown attribute", name);
return 0;
}
}
@ -2703,7 +2697,7 @@ static int proc_elem_data (void *varg, UNUSED_ARG (uintptr_t eleminfo), const ch
return proc_update_cfgelem (cfgst, cfgelem, value, isattr);
else
{
cfg_error (cfgst, "%s: no data expected", value);
(void) cfg_error (cfgst, "%s: no data expected", value);
return 0;
}
}
@ -2730,7 +2724,7 @@ static int proc_elem_close (void *varg, UNUSED_ARG (uintptr_t eleminfo), int lin
static void proc_error (void *varg, const char *msg, int line)
{
struct cfgst * const cfgst = varg;
cfg_error (cfgst, "parser error %s at line %d", msg, line);
(void) cfg_error (cfgst, "parser error %s at line %d", msg, line);
}
static int cfgst_node_cmp (const void *va, const void *vb)
@ -2892,7 +2886,7 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi
qx = ddsrt_xmlp_new_string (tok, cfgst, &cb);
ddsrt_xmlp_set_options (qx, DDSRT_XMLP_ANONYMOUS_CLOSE_TAG | DDSRT_XMLP_MISSING_CLOSE_AS_EOF);
fp = NULL;
snprintf (env_input, sizeof (env_input), "CYCLONEDDS_URI+%u", (unsigned) (tok - copy));
(void) snprintf (env_input, sizeof (env_input), "CYCLONEDDS_URI+%u", (unsigned) (tok - copy));
cfgst->input = env_input;
cfgst->line = 1;
}
@ -2996,12 +2990,7 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi
while (p)
{
cfgst->cfg->nof_networkPartitions++;
/* also use crc32 just like native nw and ordinary ddsi2e, only
for interoperability because it is asking for trouble &
forces us to include a crc32 routine when we have md5
available anyway */
p->partitionId = cfgst->cfg->nof_networkPartitions; /* starting at 1 */
p->partitionHash = crc32_calc(p->name, strlen(p->name));
p = p->next;
}
}
@ -3077,7 +3066,7 @@ static char *get_partition_search_pattern (const char *partition, const char *to
{
size_t sz = strlen (partition) + strlen (topic) + 2;
char *pt = ddsrt_malloc (sz);
snprintf (pt, sz, "%s.%s", partition, topic);
(void) snprintf (pt, sz, "%s.%s", partition, topic);
return pt;
}

View file

@ -44,6 +44,7 @@
#include "dds/ddsi/ddsi_serdata_default.h"
#include "dds/ddsi/q_feature_check.h"
#include "dds/ddsi/ddsi_security_omg.h"
#include "dds/ddsi/ddsi_pmd.h"
static int get_locator (const struct q_globals *gv, nn_locator_t *loc, const nn_locators_t *locs, int uc_same_subnet)
{
@ -217,12 +218,25 @@ int spdp_write (struct participant *pp)
nn_plist_init_empty (&ps);
ps.present |= PP_PARTICIPANT_GUID | PP_BUILTIN_ENDPOINT_SET |
PP_PROTOCOL_VERSION | PP_VENDORID | PP_PARTICIPANT_LEASE_DURATION;
PP_PROTOCOL_VERSION | PP_VENDORID | PP_PARTICIPANT_LEASE_DURATION |
PP_DOMAIN_ID;
ps.participant_guid = pp->e.guid;
ps.builtin_endpoint_set = pp->bes;
ps.protocol_version.major = RTPS_MAJOR;
ps.protocol_version.minor = RTPS_MINOR;
ps.vendorid = NN_VENDORID_ECLIPSE;
ps.domain_id = pp->e.gv->config.extDomainId.value;
/* Be sure not to send a DOMAIN_TAG when it is the default (an empty)
string: it is an "incompatible-if-unrecognized" parameter, and so
implementations that don't understand the parameter will refuse to
discover us, and so sending the default would break backwards
compatibility. */
if (strcmp (pp->e.gv->config.domainTag, "") != 0)
{
ps.present |= PP_DOMAIN_TAG;
ps.aliased |= PP_DOMAIN_TAG;
ps.domain_tag = pp->e.gv->config.domainTag;
}
if (pp->prismtech_bes)
{
ps.present |= PP_PRISMTECH_BUILTIN_ENDPOINT_SET;
@ -305,7 +319,7 @@ int spdp_write (struct participant *pp)
ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock);
if (ddsrt_gethostname(node, sizeof(node)-1) < 0)
ddsrt_strlcpy (node, "unknown", sizeof (node));
(void) ddsrt_strlcpy (node, "unknown", sizeof (node));
size = strlen(node) + strlen(DDS_VERSION) + strlen(DDS_HOST_NAME) + strlen(DDS_TARGET_NAME) + 4; /* + ///'\0' */
ps.prismtech_participant_version_info.internals = ddsrt_malloc(size);
(void) snprintf(ps.prismtech_participant_version_info.internals, size, "%s/%s/%s/%s", node, DDS_VERSION, DDS_HOST_NAME, DDS_TARGET_NAME);
@ -418,7 +432,7 @@ static void respond_to_spdp (const struct q_globals *gv, const ddsi_guid_t *dest
GVTRACE (" %"PRId64, delay);
if (!pp->e.gv->config.unicast_response_to_spdp_messages)
/* pp can't reach gc_delete_participant => can safely reschedule */
resched_xevent_if_earlier (pp->spdp_xevent, tsched);
(void) resched_xevent_if_earlier (pp->spdp_xevent, tsched);
else
qxev_spdp (gv->xevents, tsched, &pp->e.guid, dest_proxypp_guid);
}
@ -498,10 +512,8 @@ static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const dd
{
struct ephash_enum_proxy_participant it;
struct proxy_participant *pp, *d2pp;
struct lease *d2pp_lease;
if ((d2pp = ephash_lookup_proxy_participant_guid (gv->guid_hash, ddsi2guid)) == NULL)
return;
d2pp_lease = ddsrt_atomic_ldvoidp (&d2pp->lease);
ephash_enum_proxy_participant_init (&it, gv->guid_hash);
while ((pp = ephash_enum_proxy_participant_next (&it)) != NULL)
{
@ -511,7 +523,7 @@ static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const dd
ddsrt_mutex_lock (&pp->e.lock);
pp->privileged_pp_guid = *ddsi2guid;
ddsrt_mutex_unlock (&pp->e.lock);
proxy_participant_reassign_lease (pp, d2pp_lease);
proxy_participant_reassign_lease (pp, d2pp->lease);
GVTRACE ("\n");
if (ephash_lookup_proxy_participant_guid (gv->guid_hash, ddsi2guid) == NULL)
@ -545,6 +557,18 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
dds_duration_t lease_duration;
unsigned custom_flags = 0;
/* If advertised domain id or domain tag doesn't match, ignore the message. Do this first to
minimize the impact such messages have. */
{
const uint32_t domain_id = (datap->present & PP_DOMAIN_ID) ? datap->domain_id : gv->config.extDomainId.value;
const char *domain_tag = (datap->present & PP_DOMAIN_TAG) ? datap->domain_tag : "";
if (domain_id != gv->config.extDomainId.value || strcmp (domain_tag, gv->config.domainTag) != 0)
{
GVTRACE ("ignore remote participant in mismatching domain %"PRIu32" tag \"%s\"\n", domain_id, domain_tag);
return 0;
}
}
if (!(datap->present & PP_PARTICIPANT_GUID) || !(datap->present & PP_BUILTIN_ENDPOINT_SET))
{
GVWARNING ("data (SPDP, vendor %u.%u): no/invalid payload\n", rst->vendor.id[0], rst->vendor.id[1]);
@ -611,12 +635,15 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
else if (existing_entity->kind == EK_PROXY_PARTICIPANT)
{
struct proxy_participant *proxypp = (struct proxy_participant *) existing_entity;
struct lease *lease;
int interesting = 0;
RSTTRACE ("SPDP ST0 "PGUIDFMT" (known)", PGUID (datap->participant_guid));
/* SPDP processing is so different from normal processing that we are
even skipping the automatic lease renewal. Therefore do it regardless
of gv.config.arrival_of_data_asserts_pp_and_ep_liveliness. */
lease_renew (ddsrt_atomic_ldvoidp (&proxypp->lease), now_et ());
even skipping the automatic lease renewal. Note that proxy writers
that are not alive are not set alive here. This is done only when
data is received from a particular pwr (in handle_regular) */
if ((lease = ddsrt_atomic_ldvoidp (&proxypp->minl_auto)) != NULL)
lease_renew (lease, now_et ());
ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->implicitly_created || seq > proxypp->seq)
{
@ -1278,7 +1305,7 @@ static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn
GVLOGDISC (" "PGUIDFMT" attach-to-DS "PGUIDFMT, PGUID(pp->e.guid), PGUIDPREFIX(*src_guid_prefix), pp->privileged_pp_guid.entityid.u);
ddsrt_mutex_lock (&pp->e.lock);
pp->privileged_pp_guid.prefix = *src_guid_prefix;
lease_set_expiry(ddsrt_atomic_ldvoidp(&pp->lease), never);
lease_set_expiry(pp->lease, never);
ddsrt_mutex_unlock (&pp->e.lock);
}
GVLOGDISC ("\n");
@ -1388,13 +1415,9 @@ static void handle_SEDP_dead (const struct receiver_state *rst, nn_plist_t *data
}
GVLOGDISC (" "PGUIDFMT, PGUID (datap->endpoint_guid));
if (is_writer_entityid (datap->endpoint_guid.entityid))
{
res = delete_proxy_writer (gv, &datap->endpoint_guid, timestamp, 0);
}
else
{
res = delete_proxy_reader (gv, &datap->endpoint_guid, timestamp, 0);
}
GVLOGDISC (" %s\n", (res < 0) ? " unknown" : " delete");
}
@ -1812,7 +1835,7 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
break;
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER:
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER:
handle_PMD (sampleinfo->rst, timestamp, statusinfo, datap, datasz);
handle_pmd_message (sampleinfo->rst, timestamp, statusinfo, datap, datasz);
break;
case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER:
handle_SEDP_CM (sampleinfo->rst, srcguid.entityid, timestamp, statusinfo, datap, datasz);

View file

@ -346,10 +346,11 @@ static uint32_t debmon_main (void *vdm)
return 0;
}
struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port)
struct debug_monitor *new_debug_monitor (struct q_globals *gv, int32_t port)
{
struct debug_monitor *dm;
/* negative port number means the feature is disabled */
if (gv->config.monitor_port < 0)
return NULL;
@ -362,7 +363,14 @@ struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port)
dm->plugins = NULL;
if ((dm->tran_factory = ddsi_factory_find (gv, "tcp")) == NULL)
dm->tran_factory = ddsi_factory_find (gv, "tcp6");
dm->servsock = ddsi_factory_create_listener (dm->tran_factory, port, NULL);
if (!ddsi_is_valid_port (dm->tran_factory, (uint32_t) port))
{
GVERROR ("debug monitor port number %"PRId32" is invalid\n", port);
goto err_invalid_port;
}
dm->servsock = ddsi_factory_create_listener (dm->tran_factory, (uint32_t) port, NULL);
if (dm->servsock == NULL)
{
GVWARNING ("debmon: can't create socket\n");
@ -381,7 +389,8 @@ struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port)
if (ddsi_listener_listen (dm->servsock) < 0)
goto err_listen;
dm->stop = 0;
create_thread (&dm->servts, gv, "debmon", debmon_main, dm);
if (create_thread (&dm->servts, gv, "debmon", debmon_main, dm) != DDS_RETCODE_OK)
goto err_listen;
return dm;
err_listen:
@ -389,6 +398,7 @@ err_listen:
ddsrt_mutex_destroy(&dm->lock);
ddsi_listener_free(dm->servsock);
err_servsock:
err_invalid_port:
ddsrt_free(dm);
return NULL;
}

View file

@ -13,6 +13,7 @@
#include <string.h>
#include <stddef.h>
#include "dds/ddsrt/fibheap.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/sockets.h"
@ -69,6 +70,11 @@ struct deleted_participants_admin {
int64_t delay;
};
struct proxy_writer_alive_state {
bool alive;
uint32_t vclock;
};
static int compare_guid (const void *va, const void *vb);
static void augment_wr_prd_match (void *vnode, const void *vleft, const void *vright);
@ -409,6 +415,16 @@ static void remove_deleted_participant_guid (struct deleted_participants_admin *
/* PARTICIPANT ------------------------------------------------------ */
static int compare_ldur (const void *va, const void *vb)
{
const struct ldur_fhnode *a = va;
const struct ldur_fhnode *b = vb;
return (a->ldur == b->ldur) ? 0 : (a->ldur < b->ldur) ? -1 : 1;
}
/* used in participant for keeping writer liveliness renewal */
const ddsrt_fibheap_def_t ldur_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct ldur_fhnode, heapnode), compare_ldur);
static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, const dds_qos_t *xqos, nn_wctime_t timestamp)
{
uint64_t mask;
@ -601,6 +617,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
ddsrt_mutex_init (&pp->refc_lock);
inverse_uint32_set_init(&pp->avail_entityids.x, 1, UINT32_MAX / NN_ENTITYID_ALLOCSTEP);
pp->lease_duration = gv->config.lease_duration;
ddsrt_fibheap_init (&ldur_fhdef, &pp->ldur_auto_wr);
pp->plist = ddsrt_malloc (sizeof (*pp->plist));
nn_plist_copy (pp->plist, plist);
nn_plist_mergein_missing (pp->plist, &gv->default_local_plist_pp, ~(uint64_t)0, ~(uint64_t)0);
@ -1165,6 +1182,19 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity
return ephash_lookup_writer_guid (pp->e.gv->guid_hash, &bwr_guid);
}
dds_duration_t pp_get_pmd_interval (struct participant *pp)
{
struct ldur_fhnode *ldur_node;
dds_duration_t intv;
ddsrt_mutex_lock (&pp->e.lock);
ldur_node = ddsrt_fibheap_min (&ldur_fhdef, &pp->ldur_auto_wr);
intv = (ldur_node != NULL) ? ldur_node->ldur : T_NEVER;
if (pp->lease_duration < intv)
intv = pp->lease_duration;
ddsrt_mutex_unlock (&pp->e.lock);
return intv;
}
/* WRITER/READER/PROXY-WRITER/PROXY-READER CONNECTION ---------------
These are all located in a separate section because they are so
@ -1568,6 +1598,19 @@ static void free_wr_rd_match (struct wr_rd_match *m)
if (m) ddsrt_free (m);
}
static void proxy_writer_get_alive_state_locked (struct proxy_writer *pwr, struct proxy_writer_alive_state *st)
{
st->alive = pwr->alive;
st->vclock = pwr->alive_vclock;
}
static void proxy_writer_get_alive_state (struct proxy_writer *pwr, struct proxy_writer_alive_state *st)
{
ddsrt_mutex_lock (&pwr->e.lock);
proxy_writer_get_alive_state_locked (pwr, st);
ddsrt_mutex_unlock (&pwr->e.lock);
}
static void writer_drop_connection (const struct ddsi_guid *wr_guid, const struct proxy_reader *prd)
{
struct writer *wr;
@ -1625,6 +1668,55 @@ static void writer_drop_local_connection (const struct ddsi_guid *wr_guid, struc
}
}
static void reader_update_notify_pwr_alive_state (struct reader *rd, const struct proxy_writer *pwr, const struct proxy_writer_alive_state *alive_state)
{
struct rd_pwr_match *m;
bool notify = false;
int delta = 0; /* -1: alive -> not_alive; 0: unchanged; 1: not_alive -> alive */
ddsrt_mutex_lock (&rd->e.lock);
if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL)
{
if ((int32_t) (alive_state->vclock - m->pwr_alive_vclock) > 0)
{
delta = (int) alive_state->alive - (int) m->pwr_alive;
notify = true;
m->pwr_alive = alive_state->alive;
m->pwr_alive_vclock = alive_state->vclock;
}
}
ddsrt_mutex_unlock (&rd->e.lock);
if (delta < 0 && rd->rhc)
{
struct ddsi_writer_info wrinfo;
ddsi_make_writer_info (&wrinfo, &pwr->e, pwr->c.xqos);
ddsi_rhc_unregister_wr (rd->rhc, &wrinfo);
}
/* Liveliness changed events can race each other and can, potentially, be delivered
in a different order. */
if (notify && rd->status_cb)
{
status_cb_data_t data;
data.handle = pwr->e.iid;
if (delta == 0)
data.extra = (uint32_t) LIVELINESS_CHANGED_TWITCH;
else if (delta < 0)
data.extra = (uint32_t) LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE;
else
data.extra = (uint32_t) LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE;
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
}
}
static void reader_update_notify_pwr_alive_state_guid (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, const struct proxy_writer_alive_state *alive_state)
{
struct reader *rd;
if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rd_guid)) != NULL)
reader_update_notify_pwr_alive_state (rd, pwr, alive_state);
}
static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr)
{
struct reader *rd;
@ -1646,9 +1738,9 @@ static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struc
if (rd->status_cb)
{
status_cb_data_t data;
data.add = false;
data.handle = pwr->e.iid;
data.add = false;
data.extra = (uint32_t) (m->pwr_alive ? LIVELINESS_CHANGED_REMOVE_ALIVE : LIVELINESS_CHANGED_REMOVE_NOT_ALIVE);
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
@ -1683,9 +1775,9 @@ static void reader_drop_local_connection (const struct ddsi_guid *rd_guid, const
if (rd->status_cb)
{
status_cb_data_t data;
data.add = false;
data.handle = wr->e.iid;
data.add = false;
data.extra = (uint32_t) LIVELINESS_CHANGED_REMOVE_ALIVE;
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
@ -1864,7 +1956,7 @@ static void writer_add_connection (struct writer *wr, struct proxy_reader *prd)
if (tnext.v < wr->hbcontrol.tsched.v)
{
wr->hbcontrol.tsched = tnext;
resched_xevent_if_earlier (wr->heartbeat_xevent, tnext);
(void) resched_xevent_if_earlier (wr->heartbeat_xevent, tnext);
}
ddsrt_mutex_unlock (&wr->e.lock);
}
@ -1928,12 +2020,14 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd)
}
}
static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, nn_count_t *init_count)
static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, nn_count_t *init_count, const struct proxy_writer_alive_state *alive_state)
{
struct rd_pwr_match *m = ddsrt_malloc (sizeof (*m));
ddsrt_avl_ipath_t path;
m->pwr_guid = pwr->e.guid;
m->pwr_alive = alive_state->alive;
m->pwr_alive_vclock = alive_state->vclock;
ddsrt_mutex_lock (&rd->e.lock);
@ -1973,7 +2067,9 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr,
/* FIXME: for now, assume that the ports match for datasock_mc --
't would be better to dynamically create and destroy sockets on
an as needed basis. */
ddsi_join_mc (rd->e.gv, rd->e.gv->mship, rd->e.gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc);
int ret = ddsi_join_mc (rd->e.gv, rd->e.gv->mship, rd->e.gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc);
if (ret < 0)
ELOGDISC (rd, " unable to join\n");
}
else
{
@ -1985,9 +2081,14 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr,
if (rd->status_cb)
{
status_cb_data_t data;
data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
data.add = true;
data.handle = pwr->e.iid;
data.add = true;
data.extra = (uint32_t) (alive_state->alive ? LIVELINESS_CHANGED_ADD_ALIVE : LIVELINESS_CHANGED_ADD_NOT_ALIVE);
data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
}
}
@ -2019,14 +2120,15 @@ static void reader_add_local_connection (struct reader *rd, struct writer *wr)
if (rd->status_cb)
{
status_cb_data_t data;
data.add = true;
data.handle = wr->e.iid;
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
data.add = true;
data.extra = (uint32_t) LIVELINESS_CHANGED_ADD_ALIVE;
data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
}
}
}
@ -2153,16 +2255,6 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
qxev_pwr_entityid (pwr, &rd->e.guid);
ELOGDISC (pwr, "\n");
if (rd->status_cb)
{
status_cb_data_t data;
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
data.add = true;
data.handle = pwr->e.iid;
(rd->status_cb) (rd->status_cb_entity, &data);
}
return;
already_matched:
@ -2374,6 +2466,7 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r
const int isb1 = (is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0);
dds_qos_policy_id_t reason;
nn_count_t init_count;
struct proxy_writer_alive_state alive_state;
if (isb0 != isb1)
return;
if (rd->e.onlylocal)
@ -2383,8 +2476,18 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r
reader_qos_mismatch (rd, reason);
return;
}
reader_add_connection (rd, pwr, &init_count);
/* Initialze the reader's tracking information for the writer liveliness state to something
sensible, but that may be outdated by the time the reader gets added to the writer's list
of matching readers. */
proxy_writer_get_alive_state (pwr, &alive_state);
reader_add_connection (rd, pwr, &init_count, &alive_state);
proxy_writer_add_connection (pwr, rd, tnow, init_count);
/* Once everything is set up: update with the latest state, any updates to the alive state
happening in parallel will cause this to become a no-op. */
proxy_writer_get_alive_state (pwr, &alive_state);
reader_update_notify_pwr_alive_state (rd, pwr, &alive_state);
}
static bool ignore_local_p (const ddsi_guid_t *guid1, const ddsi_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2)
@ -3072,13 +3175,17 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se
{
wr->heartbeat_xevent = NULL;
}
assert (wr->xqos->present & QP_LIVELINESS);
if (wr->xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC || wr->xqos->liveliness.lease_duration != T_NEVER)
if (wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC && wr->xqos->liveliness.lease_duration != T_NEVER)
{
ELOGDISC (wr, "writer "PGUIDFMT": incorrectly treating it as of automatic liveliness kind with lease duration = inf (%d, %"PRId64")\n",
PGUID (wr->e.guid), (int) wr->xqos->liveliness.kind, wr->xqos->liveliness.lease_duration);
wr->lease_duration = ddsrt_malloc (sizeof(*wr->lease_duration));
wr->lease_duration->ldur = wr->xqos->liveliness.lease_duration;
}
else
{
wr->lease_duration = NULL;
}
wr->lease_duration = T_NEVER; /* FIXME */
wr->whc = whc;
if (wr->xqos->history.kind == DDS_HISTORY_KEEP_LAST)
@ -3147,10 +3254,19 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g
match_writer_with_local_readers (wr, tnow);
sedp_write_writer (wr);
if (wr->lease_duration != T_NEVER)
if (wr->lease_duration != NULL)
{
nn_mtime_t tsched = { 0 };
resched_xevent_if_earlier (pp->pmd_update_xevent, tsched);
assert (wr->lease_duration->ldur != T_NEVER);
assert (wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC);
assert (!is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE));
/* Store writer lease duration in participant's heap in case of automatic liveliness */
ddsrt_mutex_lock (&pp->e.lock);
ddsrt_fibheap_insert (&ldur_fhdef, &pp->ldur_auto_wr, wr->lease_duration);
ddsrt_mutex_unlock (&pp->e.lock);
/* Trigger pmd update */
(void) resched_xevent_if_earlier (pp->pmd_update_xevent, now_mt ());
}
return 0;
@ -3243,6 +3359,11 @@ static void gc_delete_writer (struct gcreq *gcreq)
reader_drop_local_connection (&m->rd_guid, wr);
free_wr_rd_match (m);
}
if (wr->lease_duration != NULL)
{
assert (wr->lease_duration->ldur == DDS_DURATION_INVALID);
ddsrt_free (wr->lease_duration);
}
/* Do last gasp on SEDP and free writer. */
if (!is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE))
@ -3323,6 +3444,13 @@ dds_return_t delete_writer_nolinger_locked (struct writer *wr)
local_reader_ary_setinvalid (&wr->rdary);
ephash_remove_writer_guid (wr->e.gv->guid_hash, wr);
writer_set_state (wr, WRST_DELETING);
if (wr->lease_duration != NULL) {
ddsrt_mutex_lock (&wr->c.pp->e.lock);
ddsrt_fibheap_delete (&ldur_fhdef, &wr->c.pp->ldur_auto_wr, wr->lease_duration);
ddsrt_mutex_unlock (&wr->c.pp->e.lock);
wr->lease_duration->ldur = DDS_DURATION_INVALID;
resched_xevent_if_earlier (wr->c.pp->pmd_update_xevent, now_mt ());
}
gcreq_writer (wr);
return 0;
}
@ -3577,11 +3705,6 @@ static dds_return_t new_reader_guid
ddsi_rhc_set_qos (rd->rhc, rd->xqos);
}
assert (rd->xqos->present & QP_LIVELINESS);
if (rd->xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC || rd->xqos->liveliness.lease_duration != T_NEVER)
{
ELOGDISC (rd, "reader "PGUIDFMT": incorrectly treating it as of automatic liveliness kind with lease duration = inf (%d, %"PRId64")\n",
PGUID (rd->e.guid), (int) rd->xqos->liveliness.kind, rd->xqos->liveliness.lease_duration);
}
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
rd->as = new_addrset ();
@ -3758,14 +3881,52 @@ void update_reader_qos (struct reader *rd, const dds_qos_t *xqos)
}
/* PROXY-PARTICIPANT ------------------------------------------------ */
const ddsrt_fibheap_def_t lease_fhdef_proxypp = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, pp_heapnode), compare_lease_tdur);
static void gc_proxy_participant_lease (struct gcreq *gcreq)
{
lease_free (gcreq->arg);
gcreq_free (gcreq);
}
static void proxy_participant_replace_minl (struct proxy_participant *proxypp, bool manbypp, struct lease *lnew)
{
/* By loading/storing the pointer atomically, we ensure we always
read a valid (or once valid) lease. By delaying freeing the lease
through the garbage collector, we ensure whatever lease update
occurs in parallel completes before the memory is released. */
struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease);
struct lease *lease_old = ddsrt_atomic_ldvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto);
lease_unregister (lease_old); /* ensures lease will not expire while it is replaced */
gcreq->arg = lease_old;
gcreq_enqueue (gcreq);
ddsrt_atomic_stvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto, lnew);
}
void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct lease *newlease)
{
ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->owns_lease)
{
struct lease *minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto);
ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
if (minl == proxypp->lease)
{
if ((minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto)) != NULL)
{
dds_duration_t trem = minl->tdur - proxypp->lease->tdur;
assert (trem >= 0);
nn_etime_t texp = add_duration_to_etime (now_et(), trem);
struct lease *lnew = lease_new (texp, minl->tdur, minl->entity);
proxy_participant_replace_minl (proxypp, false, lnew);
lease_register (lnew);
}
else
{
proxy_participant_replace_minl (proxypp, false, NULL);
}
}
/* Lease renewal is done by the receive thread without locking the
proxy participant (and I'd like to keep it that way), but that
means we must guarantee that the lease pointer remains valid once
@ -3776,20 +3937,16 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct
through the garbage collector, we ensure whatever lease update
occurs in parallel completes before the memory is released.
The lease_renew(never) call ensures the lease will never expire
The lease_unregister call ensures the lease will never expire
while we are messing with it. */
ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->owns_lease)
{
const nn_etime_t never = { T_NEVER };
struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease);
struct lease *oldlease = ddsrt_atomic_ldvoidp (&proxypp->lease);
lease_renew (oldlease, never);
gcreq->arg = oldlease;
lease_unregister (proxypp->lease);
gcreq->arg = proxypp->lease;
gcreq_enqueue (gcreq);
proxypp->owns_lease = 0;
}
ddsrt_atomic_stvoidp (&proxypp->lease, newlease);
proxypp->lease = newlease;
ddsrt_mutex_unlock (&proxypp->e.lock);
}
@ -3942,14 +4099,13 @@ static void add_proxy_builtin_endpoints(
&gv->builtin_stateless_xqos_rd);
#endif
/* Register lease, but be careful not to accidentally re-register
DDSI2's lease, as we may have become dependent on DDSI2 any time
after ephash_insert_proxy_participant_guid even if
privileged_pp_guid was NULL originally */
/* Register lease for auto liveliness, but be careful not to accidentally re-register
DDSI2's lease, as we may have become dependent on DDSI2 any time after
ephash_insert_proxy_participant_guid even if privileged_pp_guid was NULL originally */
ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->owns_lease)
lease_register (ddsrt_atomic_ldvoidp (&proxypp->lease));
lease_register (ddsrt_atomic_ldvoidp (&proxypp->minl_auto));
builtintopic_write (gv->builtin_topic_interface, &proxypp->e, timestamp, true);
ddsrt_mutex_unlock (&proxypp->e.lock);
@ -3959,6 +4115,68 @@ static void add_proxy_builtin_endpoints(
#undef LTE
}
static void proxy_participant_add_pwr_lease_locked (struct proxy_participant * proxypp, const struct proxy_writer * pwr)
{
struct lease *minl_prev;
struct lease *minl_new;
ddsrt_fibheap_t *lh;
bool manbypp;
assert (pwr->lease != NULL);
manbypp = (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT);
lh = manbypp ? &proxypp->leaseheap_man : &proxypp->leaseheap_auto;
minl_prev = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh);
ddsrt_fibheap_insert (&lease_fhdef_proxypp, lh, pwr->lease);
minl_new = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh);
/* if inserted lease is new shortest lease */
if (proxypp->owns_lease && minl_prev != minl_new)
{
nn_etime_t texp = add_duration_to_etime (now_et (), minl_new->tdur);
struct lease *lnew = lease_new (texp, minl_new->tdur, minl_new->entity);
if (minl_prev == NULL)
{
assert (manbypp);
assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL);
ddsrt_atomic_stvoidp (&proxypp->minl_man, lnew);
}
else
{
proxy_participant_replace_minl (proxypp, manbypp, lnew);
}
lease_register (lnew);
}
}
static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant * proxypp, struct proxy_writer * pwr)
{
struct lease *minl;
bool manbypp;
ddsrt_fibheap_t *lh;
assert (pwr->lease != NULL);
manbypp = (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT);
lh = manbypp ? &proxypp->leaseheap_man : &proxypp->leaseheap_auto;
minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh);
ddsrt_fibheap_delete (&lease_fhdef_proxypp, lh, pwr->lease);
/* if pwr with min lease is removed: update proxypp lease to use new minimal duration */
if (proxypp->owns_lease && pwr->lease == minl)
{
if ((minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh)) != NULL)
{
dds_duration_t trem = minl->tdur - pwr->lease->tdur;
assert (trem >= 0);
nn_etime_t texp = add_duration_to_etime (now_et(), trem);
struct lease *lnew = lease_new (texp, minl->tdur, minl->entity);
proxy_participant_replace_minl (proxypp, manbypp, lnew);
lease_register (lnew);
}
else
{
proxy_participant_replace_minl (proxypp, manbypp, NULL);
}
}
}
void new_proxy_participant
(
struct q_globals *gv,
@ -3992,6 +4210,7 @@ void new_proxy_participant
entity_common_init (&proxypp->e, gv, ppguid, "", EK_PROXY_PARTICIPANT, timestamp, vendor, false);
proxypp->refc = 1;
proxypp->lease_expired = 0;
proxypp->deleting = 0;
proxypp->vendor = vendor;
proxypp->bes = bes;
proxypp->prismtech_bes = prismtech_bes;
@ -4017,18 +4236,42 @@ void new_proxy_participant
{
struct proxy_participant *privpp;
privpp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &proxypp->privileged_pp_guid);
ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_auto);
ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_man);
ddsrt_atomic_stvoidp (&proxypp->minl_man, NULL);
if (privpp != NULL && privpp->is_ddsi2_pp)
{
ddsrt_atomic_stvoidp (&proxypp->lease, ddsrt_atomic_ldvoidp (&privpp->lease));
proxypp->lease = privpp->lease;
proxypp->owns_lease = 0;
ddsrt_atomic_stvoidp (&proxypp->minl_auto, NULL);
}
else
{
/* Lease duration is meaningless when the lease never expires, but when proxy participants are created implicitly because of endpoint discovery from a cloud service, we do want the lease to expire eventually when the cloud discovery service disappears and never reappears. The normal data path renews the lease, so if the lease expiry is changed after the DS disappears but data continues to flow (even if it is only a single sample) the proxy participant would immediately go back to a non-expiring lease with no further triggers for deleting it. Instead, we take tlease_dur == NEVER as a special value meaning a lease that doesn't expire now and that has a "reasonable" lease duration. That way the lease renewal in the data path is fine, and we only need to do something special in SEDP handling. */
/* Lease duration is meaningless when the lease never expires, but when proxy participants are
created implicitly because of endpoint discovery from a cloud service, we do want the lease to expire
eventually when the cloud discovery service disappears and never reappears. The normal data path renews
the lease, so if the lease expiry is changed after the DS disappears but data continues to flow (even if
it is only a single sample) the proxy participant would immediately go back to a non-expiring lease with
no further triggers for deleting it. Instead, we take tlease_dur == NEVER as a special value meaning a
lease that doesn't expire now and that has a "reasonable" lease duration. That way the lease renewal in
the data path is fine, and we only need to do something special in SEDP handling. */
nn_etime_t texp = add_duration_to_etime (now_et(), tlease_dur);
dds_duration_t dur = (tlease_dur == T_NEVER) ? gv->config.lease_duration : tlease_dur;
ddsrt_atomic_stvoidp (&proxypp->lease, lease_new (texp, dur, &proxypp->e));
proxypp->lease = lease_new (texp, dur, &proxypp->e);
proxypp->owns_lease = 1;
/* Add the proxypp lease to heap so that monitoring liveliness will include this lease
and uses the shortest duration for proxypp and all its pwr's (with automatic liveliness) */
ddsrt_fibheap_insert (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
/* Set the shortest lease for auto liveliness: clone proxypp's lease and store the clone in
proxypp->minl_auto. As there are no pwr's at this point, the proxy pp's lease is the
shortest lease. When a pwr with a shorter is added, the lease in minl_auto is replaced
by the lease from the proxy writer in proxy_participant_add_pwr_lease_locked. This old shortest
lease is freed, so that's why we need a clone and not the proxypp's lease in the heap. */
ddsrt_atomic_stvoidp (&proxypp->minl_auto, (void *) lease_clone (proxypp->lease));
}
}
@ -4084,7 +4327,7 @@ int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, se
switch (source)
{
case UPD_PROXYPP_SPDP:
update_qos_locked (&proxypp->e, &proxypp->plist->qos, &new_plist->qos, timestamp);
(void) update_qos_locked (&proxypp->e, &proxypp->plist->qos, &new_plist->qos, timestamp);
nn_plist_fini (new_plist);
ddsrt_free (new_plist);
proxypp->proxypp_have_spdp = 1;
@ -4108,9 +4351,14 @@ int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t s
return 0;
}
static void ref_proxy_participant (struct proxy_participant *proxypp, struct proxy_endpoint_common *c)
static int ref_proxy_participant (struct proxy_participant *proxypp, struct proxy_endpoint_common *c)
{
ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->deleting)
{
ddsrt_mutex_unlock (&proxypp->e.lock);
return DDS_RETCODE_PRECONDITION_NOT_MET;
}
c->proxypp = proxypp;
proxypp->refc++;
@ -4122,6 +4370,8 @@ static void ref_proxy_participant (struct proxy_participant *proxypp, struct pro
}
proxypp->endpoints = c;
ddsrt_mutex_unlock (&proxypp->e.lock);
return DDS_RETCODE_OK;
}
static void unref_proxy_participant (struct proxy_participant *proxypp, struct proxy_endpoint_common *c)
@ -4145,14 +4395,24 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p
if (refc == 0)
{
assert (proxypp->endpoints == NULL);
if (proxypp->owns_lease)
{
struct lease * minl_auto = ddsrt_atomic_ldvoidp (&proxypp->minl_auto);
ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto) == NULL);
assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_man) == NULL);
assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL);
assert (!compare_guid (&minl_auto->entity->guid, &proxypp->e.guid));
lease_unregister (minl_auto);
lease_free (minl_auto);
lease_free (proxypp->lease);
}
ddsrt_mutex_unlock (&proxypp->e.lock);
ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=0, freeing\n", PGUID (proxypp->e.guid));
unref_addrset (proxypp->as_default);
unref_addrset (proxypp->as_meta);
nn_plist_fini (proxypp->plist);
ddsrt_free (proxypp->plist);
if (proxypp->owns_lease)
lease_free (ddsrt_atomic_ldvoidp (&proxypp->lease));
entity_common_fini (&proxypp->e);
remove_deleted_participant_guid (proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE);
ddsrt_free (proxypp);
@ -4213,15 +4473,17 @@ static void delete_or_detach_dependent_pp (struct proxy_participant *p, struct p
/* Clear dependency (but don't touch entity id, which must be 0x1c1) and set the lease ticking */
ELOGDISC (p, PGUIDFMT" detach-from-DS "PGUIDFMT"\n", PGUID(p->e.guid), PGUID(proxypp->e.guid));
memset (&p->privileged_pp_guid.prefix, 0, sizeof (p->privileged_pp_guid.prefix));
lease_set_expiry (ddsrt_atomic_ldvoidp (&p->lease), texp);
lease_set_expiry (p->lease, texp);
/* FIXME: replace in p->leaseheap_auto and get new minl_auto */
ddsrt_mutex_unlock (&p->e.lock);
}
}
static void delete_ppt (struct proxy_participant *proxypp, nn_wctime_t timestamp, int isimplicit)
{
struct proxy_endpoint_common * c;
int ret;
ddsi_entityid_t *eps;
ddsi_guid_t ep_guid;
uint32_t ep_count = 0;
/* if any proxy participants depend on this participant, delete them */
ELOGDISC (proxypp, "delete_ppt("PGUIDFMT") - deleting dependent proxy participants\n", PGUID (proxypp->e.guid));
@ -4234,31 +4496,38 @@ static void delete_ppt (struct proxy_participant *proxypp, nn_wctime_t timestamp
ephash_enum_proxy_participant_fini (&est);
}
/* delete_proxy_{reader,writer} merely schedules the actual delete
operation, so we can hold the lock -- at least, for now. */
ddsrt_mutex_lock (&proxypp->e.lock);
proxypp->deleting = 1;
if (isimplicit)
proxypp->lease_expired = 1;
ELOGDISC (proxypp, "delete_ppt("PGUIDFMT") - deleting endpoints\n", PGUID (proxypp->e.guid));
c = proxypp->endpoints;
while (c)
/* Get snapshot of endpoints list so that we can release proxypp->e.lock
Pwrs/prds may be deleted during the iteration over the entities,
but resolving the guid will fail for these entities and the our
call to delete_proxy_writer/reader returns. */
{
struct entity_common *e = entity_common_from_proxy_endpoint_common (c);
if (is_writer_entityid (e->guid.entityid))
eps = ddsrt_malloc (proxypp->refc * sizeof(ddsi_entityid_t));
struct proxy_endpoint_common *cep = proxypp->endpoints;
while (cep)
{
ret = delete_proxy_writer (proxypp->e.gv, &e->guid, timestamp, isimplicit);
const struct entity_common *entc = entity_common_from_proxy_endpoint_common (cep);
eps[ep_count++] = entc->guid.entityid;
cep = cep->next_ep;
}
else
{
ret = delete_proxy_reader (proxypp->e.gv, &e->guid, timestamp, isimplicit);
}
(void) ret;
c = c->next_ep;
}
ddsrt_mutex_unlock (&proxypp->e.lock);
ELOGDISC (proxypp, "delete_ppt("PGUIDFMT") - deleting endpoints\n", PGUID (proxypp->e.guid));
ep_guid.prefix = proxypp->e.guid.prefix;
for (uint32_t n = 0; n < ep_count; n++)
{
ep_guid.entityid = eps[n];
if (is_writer_entityid (ep_guid.entityid))
delete_proxy_writer (proxypp->e.gv, &ep_guid, timestamp, isimplicit);
else
delete_proxy_reader (proxypp->e.gv, &ep_guid, timestamp, isimplicit);
}
ddsrt_free (eps);
gcreq_proxy_participant (proxypp);
}
@ -4335,9 +4604,10 @@ uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_g
/* PROXY-ENDPOINT --------------------------------------------------- */
static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct ddsi_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist)
static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct ddsi_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist)
{
const char *name;
int ret;
if (is_builtin_entityid (guid->entityid, proxypp->vendor))
assert ((plist->qos.present & (QP_TOPIC_NAME | QP_TYPE_NAME)) == 0);
@ -4361,7 +4631,16 @@ static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_en
c->security_info.plugin_security_attributes = 0;
#endif
ref_proxy_participant (proxypp, c);
if ((ret = ref_proxy_participant (proxypp, c)) != DDS_RETCODE_OK)
{
nn_xqos_fini (c->xqos);
ddsrt_free (c->xqos);
unref_addrset (c->as);
entity_common_fini (e);
return ret;
}
return DDS_RETCODE_OK;
}
static void proxy_endpoint_common_fini (struct entity_common *e, struct proxy_endpoint_common *c)
@ -4396,6 +4675,7 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
int isreliable;
nn_mtime_t tnow = now_mt ();
enum nn_reorder_mode reorder_mode;
int ret;
assert (is_writer_entityid (guid->entityid));
assert (ephash_lookup_proxy_writer_guid (gv->guid_hash, guid) == NULL);
@ -4407,7 +4687,11 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
}
pwr = ddsrt_malloc (sizeof (*pwr));
proxy_endpoint_common_init (&pwr->e, &pwr->c, EK_PROXY_WRITER, guid, timestamp, seq, proxypp, as, plist);
if ((ret = proxy_endpoint_common_init (&pwr->e, &pwr->c, EK_PROXY_WRITER, guid, timestamp, seq, proxypp, as, plist)) != DDS_RETCODE_OK)
{
ddsrt_free (pwr);
return ret;
}
ddsrt_avl_init (&pwr_readers_treedef, &pwr->readers);
pwr->n_reliable_readers = 0;
@ -4416,6 +4700,8 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
pwr->last_fragnum = ~0u;
pwr->nackfragcount = 0;
pwr->last_fragnum_reset = 0;
pwr->alive = 1;
pwr->alive_vclock = 0;
pwr->filtered = 0;
ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, 1);
if (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor)) {
@ -4440,17 +4726,25 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
#endif
assert (pwr->c.xqos->present & QP_LIVELINESS);
if (pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC)
GVLOGDISC (" FIXME: only AUTOMATIC liveliness supported");
#if 0
pwr->tlease_dur = nn_from_ddsi_duration (pwr->c.xqos->liveliness.lease_duration);
if (pwr->tlease_dur == 0)
if (pwr->c.xqos->liveliness.lease_duration != T_NEVER)
{
GVLOGDISC (" FIXME: treating lease_duration=0 as inf");
pwr->tlease_dur = T_NEVER;
nn_etime_t texpire = add_duration_to_etime (now_et (), pwr->c.xqos->liveliness.lease_duration);
pwr->lease = lease_new (texpire, pwr->c.xqos->liveliness.lease_duration, &pwr->e);
if (pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
{
ddsrt_mutex_lock (&proxypp->e.lock);
proxy_participant_add_pwr_lease_locked (proxypp, pwr);
ddsrt_mutex_unlock (&proxypp->e.lock);
}
else
{
lease_register (pwr->lease);
}
}
else
{
pwr->lease = NULL;
}
pwr->tlease_end = add_duration_to_wctime (tnow, pwr->tlease_dur);
#endif
if (isreliable)
{
@ -4531,7 +4825,7 @@ void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset
}
}
update_qos_locked (&pwr->e, pwr->c.xqos, xqos, timestamp);
(void) update_qos_locked (&pwr->e, pwr->c.xqos, xqos, timestamp);
}
ddsrt_mutex_unlock (&pwr->e.lock);
}
@ -4589,7 +4883,7 @@ void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset
}
}
update_qos_locked (&prd->e, prd->c.xqos, xqos, timestamp);
(void) update_qos_locked (&prd->e, prd->c.xqos, xqos, timestamp);
}
ddsrt_mutex_unlock (&prd->e.lock);
}
@ -4599,7 +4893,6 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq)
struct proxy_writer *pwr = gcreq->arg;
ELOGDISC (pwr, "gc_delete_proxy_writer(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pwr->e.guid));
gcreq_free (gcreq);
while (!ddsrt_avl_is_empty (&pwr->readers))
{
struct pwr_rd_match *m = ddsrt_avl_root_non_empty (&pwr_readers_treedef, &pwr->readers);
@ -4609,17 +4902,22 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq)
free_pwr_rd_match (m);
}
local_reader_ary_fini (&pwr->rdary);
if (pwr->c.xqos->liveliness.lease_duration != T_NEVER)
lease_free (pwr->lease);
proxy_endpoint_common_fini (&pwr->e, &pwr->c);
nn_defrag_free (pwr->defrag);
nn_reorder_free (pwr->reorder);
ddsrt_free (pwr);
}
/* First stage in deleting the proxy writer. In this function the pwr and its member pointers
will remain valid. The real cleaning-up is done async in gc_delete_proxy_writer. */
int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit)
{
struct proxy_writer *pwr;
(void)isimplicit;
DDSRT_UNUSED_ARG (isimplicit);
GVLOGDISC ("delete_proxy_writer ("PGUIDFMT") ", PGUID (*guid));
ddsrt_mutex_lock (&gv->lock);
if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, guid)) == NULL)
{
@ -4627,6 +4925,7 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_
GVLOGDISC ("- unknown\n");
return DDS_RETCODE_BAD_PARAMETER;
}
/* Set "deleting" flag in particular for Lite, to signal to the receive path it can't
trust rdary[] anymore, which is because removing the proxy writer from the hash
table will prevent the readers from looking up the proxy writer, and consequently
@ -4636,8 +4935,96 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_
builtintopic_write (gv->builtin_topic_interface, &pwr->e, timestamp, false);
ephash_remove_proxy_writer_guid (gv->guid_hash, pwr);
ddsrt_mutex_unlock (&gv->lock);
if (pwr->c.xqos->liveliness.lease_duration != T_NEVER &&
pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC)
lease_unregister (pwr->lease);
if (proxy_writer_set_notalive (pwr, false) != DDS_RETCODE_OK)
GVLOGDISC ("proxy_writer_set_notalive failed for "PGUIDFMT"\n", PGUID(*guid));
gcreq_proxy_writer (pwr);
return 0;
return DDS_RETCODE_OK;
}
static void proxy_writer_notify_liveliness_change_may_unlock (struct proxy_writer *pwr)
{
struct proxy_writer_alive_state alive_state;
proxy_writer_get_alive_state_locked (pwr, &alive_state);
struct ddsi_guid rdguid;
struct pwr_rd_match *m;
memset (&rdguid, 0, sizeof (rdguid));
while (pwr->alive_vclock == alive_state.vclock &&
(m = ddsrt_avl_lookup_succ (&pwr_readers_treedef, &pwr->readers, &rdguid)) != NULL)
{
rdguid = m->rd_guid;
ddsrt_mutex_unlock (&pwr->e.lock);
/* unlocking pwr means alive state may have changed already; we break out of the loop once we
detect this but there for the reader in the current iteration, anything is possible */
reader_update_notify_pwr_alive_state_guid (&rdguid, pwr, &alive_state);
ddsrt_mutex_lock (&pwr->e.lock);
}
}
void proxy_writer_set_alive_may_unlock (struct proxy_writer *pwr, bool notify)
{
/* Caller has pwr->e.lock, so we can safely read pwr->alive. Updating pwr->alive requires
also taking pwr->c.proxypp->e.lock because pwr->alive <=> (pwr->lease in proxypp's lease
heap). */
assert (!pwr->alive);
/* check that proxy writer still exists (when deleting it is removed from guid hash) */
if (ephash_lookup_proxy_writer_guid (pwr->e.gv->guid_hash, &pwr->e.guid) == NULL)
{
ELOGDISC (pwr, "proxy_writer_set_alive_may_unlock("PGUIDFMT") - not in guid_hash, pwr deleting\n", PGUID (pwr->e.guid));
return;
}
ddsrt_mutex_lock (&pwr->c.proxypp->e.lock);
pwr->alive = true;
pwr->alive_vclock++;
if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
proxy_participant_add_pwr_lease_locked (pwr->c.proxypp, pwr);
ddsrt_mutex_unlock (&pwr->c.proxypp->e.lock);
if (notify)
proxy_writer_notify_liveliness_change_may_unlock (pwr);
}
int proxy_writer_set_notalive (struct proxy_writer *pwr, bool notify)
{
/* Caller should not have taken pwr->e.lock and pwr->c.proxypp->e.lock;
* this function takes both locks to update pwr->alive value */
ddsrt_mutex_lock (&pwr->e.lock);
if (!pwr->alive)
{
ddsrt_mutex_unlock (&pwr->e.lock);
return DDS_RETCODE_PRECONDITION_NOT_MET;
}
ddsrt_mutex_lock (&pwr->c.proxypp->e.lock);
pwr->alive = false;
pwr->alive_vclock++;
if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
proxy_participant_remove_pwr_lease_locked (pwr->c.proxypp, pwr);
ddsrt_mutex_unlock (&pwr->c.proxypp->e.lock);
if (notify)
proxy_writer_notify_liveliness_change_may_unlock (pwr);
ddsrt_mutex_unlock (&pwr->e.lock);
return DDS_RETCODE_OK;
}
void proxy_writer_set_notalive_guid (struct q_globals *gv, const struct ddsi_guid *pwrguid, bool notify)
{
struct proxy_writer *pwr;
if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, pwrguid)) == NULL)
GVLOGDISC (" "PGUIDFMT"?\n", PGUID (*pwrguid));
else
{
GVLOGDISC ("proxy_writer_set_notalive_guid ("PGUIDFMT")", PGUID (*pwrguid));
if (proxy_writer_set_notalive (pwr, notify) == DDS_RETCODE_PRECONDITION_NOT_MET)
GVLOGDISC (" pwr was not alive");
GVLOGDISC ("\n");
}
}
/* PROXY-READER ----------------------------------------------------- */
@ -4651,6 +5038,7 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
struct proxy_participant *proxypp;
struct proxy_reader *prd;
nn_mtime_t tnow = now_mt ();
int ret;
assert (!is_writer_entityid (guid->entityid));
assert (ephash_lookup_proxy_reader_guid (gv->guid_hash, guid) == NULL);
@ -4662,7 +5050,11 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
}
prd = ddsrt_malloc (sizeof (*prd));
proxy_endpoint_common_init (&prd->e, &prd->c, EK_PROXY_READER, guid, timestamp, seq, proxypp, as, plist);
if ((ret = proxy_endpoint_common_init (&prd->e, &prd->c, EK_PROXY_READER, guid, timestamp, seq, proxypp, as, plist)) != DDS_RETCODE_OK)
{
ddsrt_free (prd);
return ret;
}
prd->deleting = 0;
#ifdef DDSI_INCLUDE_SSM
@ -4690,7 +5082,7 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
ddsrt_mutex_unlock (&prd->e.lock);
match_proxy_reader_with_writers (prd, tnow);
return 0;
return DDS_RETCODE_OK;
}
static void proxy_reader_set_delete_and_ack_all_messages (struct proxy_reader *prd)

View file

@ -133,7 +133,7 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q)
} else {
to = delay;
}
ddsrt_cond_waitfor (&q->cond, &q->lock, to);
(void) ddsrt_cond_waitfor (&q->cond, &q->lock, to);
}
if (q->first)
{

View file

@ -71,36 +71,30 @@ static void add_peer_addresses (const struct q_globals *gv, struct addrset *as,
}
}
static int make_uc_sockets (struct q_globals *gv, uint32_t * pdisc, uint32_t * pdata, int ppid)
enum make_uc_sockets_ret {
MUSRET_SUCCESS,
MUSRET_INVALID_PORTS,
MUSRET_NOSOCKET
};
static enum make_uc_sockets_ret make_uc_sockets (struct q_globals *gv, uint32_t * pdisc, uint32_t * pdata, int ppid)
{
if (gv->config.many_sockets_mode == MSM_NO_UNICAST)
{
assert (ppid == PARTICIPANT_INDEX_NONE);
*pdata = *pdisc = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId);
*pdata = *pdisc = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, ppid);
if (gv->config.allowMulticast)
{
/* FIXME: ugly hack - but we'll fix up after creating the multicast sockets */
return 0;
return MUSRET_SUCCESS;
}
}
if (ppid >= 0)
{
/* FIXME: verify port numbers are in range instead of truncating them like this */
uint32_t base = gv->config.port_base + (gv->config.port_dg * gv->config.domainId) + ((uint32_t) ppid * gv->config.port_pg);
*pdisc = base + gv->config.port_d1;
*pdata = base + gv->config.port_d3;
}
else if (ppid == PARTICIPANT_INDEX_NONE)
{
*pdata = 0;
*pdisc = 0;
}
else
{
DDS_FATAL ("make_uc_sockets: invalid participant index %d\n", ppid);
return -1;
}
*pdisc = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DISC, ppid);
*pdata = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DATA, ppid);
if (!ddsi_is_valid_port (gv->m_factory, *pdisc) || !ddsi_is_valid_port (gv->m_factory, *pdata))
return MUSRET_INVALID_PORTS;
gv->disc_conn_uc = ddsi_factory_create_conn (gv->m_factory, *pdisc, NULL);
if (gv->disc_conn_uc)
@ -123,13 +117,12 @@ static int make_uc_sockets (struct q_globals *gv, uint32_t * pdisc, uint32_t * p
else
{
/* Set unicast locators */
ddsi_conn_locator (gv->disc_conn_uc, &gv->loc_meta_uc);
ddsi_conn_locator (gv->data_conn_uc, &gv->loc_default_uc);
}
}
return gv->data_conn_uc ? 0 : -1;
return gv->data_conn_uc ? MUSRET_SUCCESS : MUSRET_NOSOCKET;
}
static void make_builtin_endpoint_xqos (dds_qos_t *q, const dds_qos_t *template)
@ -309,7 +302,7 @@ static int string_to_default_locator (const struct q_globals *gv, nn_locator_t *
static int set_spdp_address (struct q_globals *gv)
{
const uint32_t port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0);
const uint32_t port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0);
int rc = 0;
/* FIXME: FIXME: FIXME: */
gv->loc_spdp_mc.kind = NN_LOCATOR_KIND_INVALID;
@ -341,7 +334,7 @@ static int set_spdp_address (struct q_globals *gv)
static int set_default_mc_address (struct q_globals *gv)
{
const uint32_t port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2);
const uint32_t port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DATA, 0);
int rc;
if (!gv->config.defaultMulticastAddressString)
gv->loc_default_mc = gv->loc_spdp_mc;
@ -482,6 +475,33 @@ int rtps_config_prep (struct q_globals *gv, struct cfgst *cfgst)
unsigned num_channel_threads = 0;
#endif
/* advertised domain id defaults to the real domain id; clear "isdefault" so the config
dump includes the actually used value rather than "default" */
if (gv->config.extDomainId.isdefault)
{
gv->config.extDomainId.value = gv->config.domainId;
gv->config.extDomainId.isdefault = 0;
}
{
char message[256];
int32_t ppidx;
if (gv->config.participantIndex >= 0 || gv->config.participantIndex == PARTICIPANT_INDEX_NONE)
ppidx = gv->config.participantIndex;
else if (gv->config.participantIndex == PARTICIPANT_INDEX_AUTO)
ppidx = gv->config.maxAutoParticipantIndex;
else
{
assert (0);
ppidx = 0;
}
if (!ddsi_valid_portmapping (&gv->config, ppidx, message, sizeof (message)))
{
DDS_ILOG (DDS_LC_ERROR, gv->config.domainId, "Invalid port mapping: %s\n", message);
goto err_config_late_error;
}
}
/* retry_on_reject_duration default is dependent on late_ack_mode and responsiveness timeout, so fix up */
if (gv->config.whc_init_highwater_mark.isdefault)
gv->config.whc_init_highwater_mark.value = gv->config.whc_lowwater_mark;
@ -669,8 +689,13 @@ int create_multicast_sockets (struct q_globals *gv)
uint32_t port;
qos->m_multicast = 1;
/* FIXME: should check for overflow */
port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0);
port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0);
if (!ddsi_is_valid_port (gv->m_factory, port))
{
GVERROR ("Failed to create discovery multicast socket for domain %"PRIu32": resulting port number (%"PRIu32") is out of range\n",
gv->config.extDomainId.value, port);
goto err_disc;
}
if ((disc = ddsi_factory_create_conn (gv->m_factory, port, qos)) == NULL)
goto err_disc;
if (gv->config.many_sockets_mode == MSM_NO_UNICAST)
@ -680,15 +705,23 @@ int create_multicast_sockets (struct q_globals *gv)
}
else
{
port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2);
port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DATA, 0);
if (!ddsi_is_valid_port (gv->m_factory, port))
{
GVERROR ("Failed to create data multicast socket for domain %"PRIu32": resulting port number (%"PRIu32") is out of range\n",
gv->config.extDomainId.value, port);
goto err_disc;
}
if ((data = ddsi_factory_create_conn (gv->m_factory, port, qos)) == NULL)
{
goto err_data;
}
}
ddsi_tran_free_qos (qos);
gv->disc_conn_mc = disc;
gv->data_conn_mc = data;
GVTRACE ("Multicast Ports: discovery %"PRIu32" data %"PRIu32" \n",
GVLOG (DDS_LC_CONFIG, "Multicast Ports: discovery %"PRIu32" data %"PRIu32" \n",
ddsi_conn_port (gv->disc_conn_mc), ddsi_conn_port (gv->data_conn_mc));
return 1;
@ -724,7 +757,7 @@ static void wait_for_receive_threads_helper (struct xevent *xev, void *varg, nn_
if (arg->count++ == arg->gv->config.recv_thread_stop_maxretries)
abort ();
trigger_recv_threads (arg->gv);
resched_xevent_if_earlier (xev, add_duration_to_mtime (tnow, T_SECOND));
(void) resched_xevent_if_earlier (xev, add_duration_to_mtime (tnow, T_SECOND));
}
static void wait_for_receive_threads (struct q_globals *gv)
@ -1003,7 +1036,7 @@ int rtps_init (struct q_globals *gv)
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
/* Convert address sets in partition mappings from string to address sets */
{
const uint32_t port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2;
const uint32_t port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DATA, 0);
struct config_networkpartition_listelem *np;
for (np = gv->config.networkPartitions; np; np = np->next)
{
@ -1106,33 +1139,44 @@ int rtps_init (struct q_globals *gv)
{
if (gv->config.participantIndex >= 0 || gv->config.participantIndex == PARTICIPANT_INDEX_NONE)
{
if (make_uc_sockets (gv, &port_disc_uc, &port_data_uc, gv->config.participantIndex) < 0)
enum make_uc_sockets_ret musret = make_uc_sockets (gv, &port_disc_uc, &port_data_uc, gv->config.participantIndex);
switch (musret)
{
GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant %d\n", gv->config.domainId, gv->config.participantIndex);
case MUSRET_SUCCESS:
break;
case MUSRET_INVALID_PORTS:
GVERROR ("Failed to create unicast sockets for domain %"PRIu32" participant index %d: resulting port numbers (%"PRIu32", %"PRIu32") are out of range\n",
gv->config.extDomainId.value, gv->config.participantIndex, port_disc_uc, port_data_uc);
goto err_unicast_sockets;
case MUSRET_NOSOCKET:
GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant index %d (ports %"PRIu32", %"PRIu32")\n", gv->config.extDomainId.value, gv->config.participantIndex, port_disc_uc, port_data_uc);
goto err_unicast_sockets;
}
}
else if (gv->config.participantIndex == PARTICIPANT_INDEX_AUTO)
{
/* try to find a free one, and update gv->config.participantIndex */
enum make_uc_sockets_ret musret = MUSRET_NOSOCKET;
int ppid;
GVLOG (DDS_LC_CONFIG, "rtps_init: trying to find a free participant index\n");
for (ppid = 0; ppid <= gv->config.maxAutoParticipantIndex; ppid++)
for (ppid = 0; ppid <= gv->config.maxAutoParticipantIndex && musret == MUSRET_NOSOCKET; ppid++)
{
int r = make_uc_sockets (gv, &port_disc_uc, &port_data_uc, ppid);
if (r == 0) /* Success! */
musret = make_uc_sockets (gv, &port_disc_uc, &port_data_uc, ppid);
switch (musret)
{
case MUSRET_SUCCESS:
break;
else if (r == -1) /* Try next one */
continue;
else /* Oops! */
{
GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant %d\n", gv->config.domainId, ppid);
case MUSRET_INVALID_PORTS:
GVERROR ("Failed to create unicast sockets for domain %"PRIu32" participant index %d: resulting port numbers (%"PRIu32", %"PRIu32") are out of range\n",
gv->config.extDomainId.value, ppid, port_disc_uc, port_data_uc);
goto err_unicast_sockets;
case MUSRET_NOSOCKET: /* Try next one */
break;
}
}
if (ppid > gv->config.maxAutoParticipantIndex)
{
GVERROR ("rtps_init: failed to find a free participant index for domain %"PRId32"\n", gv->config.domainId);
GVERROR ("Failed to find a free participant index for domain %"PRIu32"\n", gv->config.extDomainId.value);
goto err_unicast_sockets;
}
gv->config.participantIndex = ppid;
@ -1143,7 +1187,7 @@ int rtps_init (struct q_globals *gv)
}
GVLOG (DDS_LC_CONFIG, "rtps_init: uc ports: disc %"PRIu32" data %"PRIu32"\n", port_disc_uc, port_data_uc);
}
GVLOG (DDS_LC_CONFIG, "rtps_init: domainid %"PRId32" participantid %d\n", gv->config.domainId, gv->config.participantIndex);
GVLOG (DDS_LC_CONFIG, "rtps_init: domainid %"PRIu32" participantid %d\n", gv->config.domainId, gv->config.participantIndex);
if (gv->config.pcap_file && *gv->config.pcap_file)
{
@ -1193,9 +1237,15 @@ int rtps_init (struct q_globals *gv)
/* Must have a data_conn_uc/tev_conn/transmit_conn */
gv->data_conn_uc = ddsi_factory_create_conn (gv->m_factory, 0, NULL);
if (gv->config.tcp_port != -1)
if (gv->config.tcp_port == -1)
; /* nop */
else if (!ddsi_is_valid_port (gv->m_factory, (uint32_t) gv->config.tcp_port))
{
gv->listener = ddsi_factory_create_listener (gv->m_factory, gv->config.tcp_port, NULL);
GVERROR ("Listener port %d is out of range for transport %s\n", gv->config.tcp_port, gv->m_factory->m_typename);
}
else
{
gv->listener = ddsi_factory_create_listener (gv->m_factory, (uint32_t) gv->config.tcp_port, NULL);
if (gv->listener == NULL || ddsi_listener_listen (gv->listener) != 0)
{
GVERROR ("Failed to create %s listener\n", gv->m_factory->m_typename);
@ -1445,13 +1495,23 @@ int rtps_start (struct q_globals *gv)
}
if (gv->listener)
{
create_thread (&gv->listen_ts, gv, "listen", (uint32_t (*) (void *)) listen_thread, gv->listener);
/* FIXME: error handling */
if (create_thread (&gv->listen_ts, gv, "listen", (uint32_t (*) (void *)) listen_thread, gv->listener) != DDS_RETCODE_OK)
{
GVERROR ("failed to create TCP listener thread\n");
ddsi_listener_free (gv->listener);
gv->listener = NULL;
rtps_stop (gv);
return -1;
}
}
if (gv->config.monitor_port >= 0)
{
gv->debmon = new_debug_monitor (gv, gv->config.monitor_port);
/* FIXME: clean up */
if ((gv->debmon = new_debug_monitor (gv, gv->config.monitor_port)) == NULL)
{
GVERROR ("failed to create debug monitor thread\n");
rtps_stop (gv);
return -1;
}
}
return 0;

View file

@ -43,30 +43,27 @@
!= 0 -- and note that it had better be 2's complement machine! */
#define TSCHED_NOT_ON_HEAP INT64_MIN
struct lease {
ddsrt_fibheap_node_t heapnode;
nn_etime_t tsched; /* access guarded by leaseheap_lock */
ddsrt_atomic_uint64_t tend; /* really an nn_etime_t */
dds_duration_t tdur; /* constant (renew depends on it) */
struct entity_common *entity; /* constant */
};
static int compare_lease_tsched (const void *va, const void *vb);
static const ddsrt_fibheap_def_t lease_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, heapnode), compare_lease_tsched);
const ddsrt_fibheap_def_t lease_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER (offsetof (struct lease, heapnode), compare_lease_tsched);
static void force_lease_check (struct gcreq_queue *gcreq_queue)
{
gcreq_enqueue (gcreq_new (gcreq_queue, gcreq_free));
}
static int compare_lease_tsched (const void *va, const void *vb)
int compare_lease_tsched (const void *va, const void *vb)
{
const struct lease *a = va;
const struct lease *b = vb;
return (a->tsched.v == b->tsched.v) ? 0 : (a->tsched.v < b->tsched.v) ? -1 : 1;
}
int compare_lease_tdur (const void *va, const void *vb)
{
const struct lease *a = va;
const struct lease *b = vb;
return (a->tdur == b->tdur) ? 0 : (a->tdur < b->tdur) ? -1 : 1;
}
void lease_management_init (struct q_globals *gv)
{
ddsrt_mutex_init (&gv->leaseheap_lock);
@ -92,6 +89,20 @@ struct lease *lease_new (nn_etime_t texpire, dds_duration_t tdur, struct entity_
return l;
}
/**
* Returns a clone of the provided lease. Note that this function does not use
* locking and should therefore only be called from a context where lease 'l'
* cannot be changed by another thread during the function call.
*/
struct lease *lease_clone (const struct lease *l)
{
nn_etime_t texp;
dds_duration_t tdur;
texp.v = (int64_t) ddsrt_atomic_ld64 (&l->tend);
tdur = l->tdur;
return lease_new (texp, tdur, l->entity);
}
void lease_register (struct lease *l) /* FIXME: make lease admin struct */
{
struct q_globals * const gv = l->entity->gv;
@ -110,23 +121,31 @@ void lease_register (struct lease *l) /* FIXME: make lease admin struct */
force_lease_check (gv->gcreq_queue);
}
void lease_free (struct lease *l)
void lease_unregister (struct lease *l)
{
struct q_globals * const gv = l->entity->gv;
GVTRACE ("lease_free(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid));
GVTRACE ("lease_unregister(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid));
ddsrt_mutex_lock (&gv->leaseheap_lock);
if (l->tsched.v != TSCHED_NOT_ON_HEAP)
{
ddsrt_fibheap_delete (&lease_fhdef, &gv->leaseheap, l);
l->tsched.v = TSCHED_NOT_ON_HEAP;
}
ddsrt_mutex_unlock (&gv->leaseheap_lock);
ddsrt_free (l);
/* see lease_register() */
force_lease_check (gv->gcreq_queue);
}
void lease_free (struct lease *l)
{
struct q_globals * const gv = l->entity->gv;
GVTRACE ("lease_free(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid));
ddsrt_free (l);
}
void lease_renew (struct lease *l, nn_etime_t tnowE)
{
struct q_globals const * const gv = l->entity->gv;
nn_etime_t tend_new = add_duration_to_etime (tnowE, l->tdur);
/* do not touch tend if moving forward or if already expired */
@ -137,6 +156,11 @@ void lease_renew (struct lease *l, nn_etime_t tnowE)
return;
} while (!ddsrt_atomic_cas64 (&l->tend, (uint64_t) tend, (uint64_t) tend_new.v));
/* Only at this point we can assume that gv can be recovered from the entity in the
* lease (i.e. the entity still exists). In cases where dereferencing l->entity->gv
* is not safe (e.g. the deletion of entities), the early out in the loop above
* will be the case because tend is set to T_NEVER. */
struct q_globals const * gv = l->entity->gv;
if (gv->logconfig.c.mask & DDS_LC_TRACE)
{
int32_t tsec, tusec;
@ -253,26 +277,19 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
switch (k)
{
case EK_PARTICIPANT:
delete_participant (gv, &g);
break;
case EK_PROXY_PARTICIPANT:
delete_proxy_participant_by_guid (gv, &g, now(), 1);
break;
case EK_WRITER:
delete_writer_nolinger (gv, &g);
break;
case EK_PROXY_WRITER:
delete_proxy_writer (gv, &g, now(), 1);
proxy_writer_set_notalive_guid (gv, &g, true);
break;
case EK_PARTICIPANT:
case EK_READER:
delete_reader (gv, &g);
break;
case EK_WRITER:
case EK_PROXY_READER:
delete_proxy_reader (gv, &g, now(), 1);
assert (false);
break;
}
ddsrt_mutex_lock (&gv->leaseheap_lock);
}
@ -281,83 +298,3 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
return delay;
}
/******/
static void debug_print_rawdata (const struct q_globals *gv, const char *msg, const void *data, size_t len)
{
const unsigned char *c = data;
size_t i;
GVTRACE ("%s<", msg);
for (i = 0; i < len; i++)
{
if (32 < c[i] && c[i] <= 127)
GVTRACE ("%s%c", (i > 0 && (i%4) == 0) ? " " : "", c[i]);
else
GVTRACE ("%s\\x%02x", (i > 0 && (i%4) == 0) ? " " : "", c[i]);
}
GVTRACE (">");
}
void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
{
const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
const int bswap = (data->identifier == CDR_LE) ^ (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN);
struct proxy_participant *pp;
ddsi_guid_t ppguid;
RSTTRACE (" PMD ST%x", statusinfo);
if (data->identifier != CDR_LE && data->identifier != CDR_BE)
{
RSTTRACE (" PMD data->identifier %u !?\n", ntohs (data->identifier));
return;
}
switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER))
{
case 0:
if (offsetof (ParticipantMessageData_t, value) > len - sizeof (struct CDRHeader))
debug_print_rawdata (rst->gv, " SHORT1", data, len);
else
{
const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1);
ddsi_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
uint32_t kind = ntohl (pmd->kind);
uint32_t length = bswap ? ddsrt_bswap4u (pmd->length) : pmd->length;
RSTTRACE (" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length);
if (len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value) < length)
debug_print_rawdata (rst->gv, " SHORT2", pmd->value, len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value));
else
debug_print_rawdata (rst->gv, "", pmd->value, length);
ppguid.prefix = p;
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
if ((pp = ephash_lookup_proxy_participant_guid (rst->gv->guid_hash, &ppguid)) == NULL)
RSTTRACE (" PPunknown");
else
{
/* Renew lease if arrival of this message didn't already do so, also renew the lease
of the virtual participant used for DS-discovered endpoints */
#if 0 // FIXME: superfluous ... receipt of the message already did it */
lease_renew (ddsrt_atomic_ldvoidp (&pp->lease), now_et ());
#endif
}
}
break;
case NN_STATUSINFO_DISPOSE:
case NN_STATUSINFO_UNREGISTER:
case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER:
/* Serialized key; BE or LE doesn't matter as both fields are
defined as octets. */
if (len < sizeof (struct CDRHeader) + sizeof (ddsi_guid_prefix_t))
debug_print_rawdata (rst->gv, " SHORT3", data, len);
else
{
ppguid.prefix = nn_ntoh_guid_prefix (*((ddsi_guid_prefix_t *) (data + 1)));
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
if (delete_proxy_participant_by_guid (rst->gv, &ppguid, timestamp, 0) < 0)
RSTTRACE (" unknown");
else
RSTTRACE (" delete");
}
break;
}
RSTTRACE ("\n");
}

View file

@ -99,66 +99,3 @@ int ddsi2_patmatch (const char *pat, const char *str)
}
return *str == 0;
}
static const uint32_t crc32_table[] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
uint32_t crc32_calc (const void *buf, size_t length)
{
const uint8_t *vptr = buf;
uint32_t reg = 0;
uint8_t top;
size_t i;
for (i = 0; i < length; i++)
{
top = (uint8_t) (reg >> 24);
top ^= *vptr;
reg = (reg << 8) ^ crc32_table[top];
vptr++;
}
return reg;
}

View file

@ -464,11 +464,11 @@ int find_own_ip (struct q_globals *gv, const char *requested_address)
char if_name[sizeof (last_if_name)];
int q = 0;
ddsrt_strlcpy(if_name, ifa->name, sizeof(if_name));
(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);
ddsrt_strlcpy(last_if_name, if_name, sizeof(last_if_name));
(void) ddsrt_strlcpy(last_if_name, if_name, sizeof(last_if_name));
/* interface must be up */
if ((ifa->flags & IFF_UP) == 0) {

View file

@ -96,7 +96,7 @@ FILE *new_pcap_file (const struct ddsrt_log_cfg *logcfg, const char *name)
hdr.sigfigs = 0;
hdr.snaplen = 65535;
hdr.network = LINKTYPE_RAW;
fwrite (&hdr, sizeof (hdr), 1, fp);
(void) fwrite (&hdr, sizeof (hdr), 1, fp);
return fp;
DDSRT_WARNING_MSVC_ON(4996);
@ -109,7 +109,7 @@ static void write_data (FILE *fp, const ddsrt_msghdr_t *msghdr, size_t sz)
{
size_t m1 = msghdr->msg_iov[i].iov_len;
size_t m = (n + m1 <= sz) ? m1 : sz - n;
fwrite (msghdr->msg_iov[i].iov_base, m, 1, fp);
(void) fwrite (msghdr->msg_iov[i].iov_base, m, 1, fp);
n += m;
}
assert (n == sz);
@ -142,20 +142,20 @@ void write_pcap_received (struct q_globals *gv, nn_wctime_t tstamp, const struct
ddsrt_mutex_lock (&gv->pcap_lock);
wctime_to_sec_usec (&pcap_hdr.ts_sec, &pcap_hdr.ts_usec, tstamp);
pcap_hdr.incl_len = pcap_hdr.orig_len = (uint32_t) sz_iud;
fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp);
(void) fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp);
u.ipv4_hdr = ipv4_hdr_template;
u.ipv4_hdr.totallength = ddsrt_toBE2u ((unsigned short) sz_iud);
u.ipv4_hdr.ttl = 128;
u.ipv4_hdr.srcip = ((struct sockaddr_in*) src)->sin_addr.s_addr;
u.ipv4_hdr.dstip = ((struct sockaddr_in*) dst)->sin_addr.s_addr;
u.ipv4_hdr.checksum = calc_ipv4_checksum (u.x);
fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp);
(void) fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp);
udp_hdr.srcport = ((struct sockaddr_in*) src)->sin_port;
udp_hdr.dstport = ((struct sockaddr_in*) dst)->sin_port;
udp_hdr.length = ddsrt_toBE2u ((unsigned short) sz_ud);
udp_hdr.checksum = 0; /* don't have to compute a checksum for UDPv4 */
fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp);
fwrite (buf, sz, 1, gv->pcap_fp);
(void) fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp);
(void) fwrite (buf, sz, 1, gv->pcap_fp);
ddsrt_mutex_unlock (&gv->pcap_lock);
}
}
@ -175,19 +175,19 @@ void write_pcap_sent (struct q_globals *gv, nn_wctime_t tstamp, const struct soc
ddsrt_mutex_lock (&gv->pcap_lock);
wctime_to_sec_usec (&pcap_hdr.ts_sec, &pcap_hdr.ts_usec, tstamp);
pcap_hdr.incl_len = pcap_hdr.orig_len = (uint32_t) sz_iud;
fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp);
(void) fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp);
u.ipv4_hdr = ipv4_hdr_template;
u.ipv4_hdr.totallength = ddsrt_toBE2u ((unsigned short) sz_iud);
u.ipv4_hdr.ttl = 255;
u.ipv4_hdr.srcip = ((struct sockaddr_in*) src)->sin_addr.s_addr;
u.ipv4_hdr.dstip = ((struct sockaddr_in*) hdr->msg_name)->sin_addr.s_addr;
u.ipv4_hdr.checksum = calc_ipv4_checksum (u.x);
fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp);
(void) fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp);
udp_hdr.srcport = ((struct sockaddr_in*) src)->sin_port;
udp_hdr.dstport = ((struct sockaddr_in*) hdr->msg_name)->sin_port;
udp_hdr.length = ddsrt_toBE2u ((unsigned short) sz_ud);
udp_hdr.checksum = 0; /* don't have to compute a checksum for UDPv4 */
fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp);
(void) fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp);
write_data (gv->pcap_fp, hdr, sz);
ddsrt_mutex_unlock (&gv->pcap_lock);
}

View file

@ -1309,6 +1309,8 @@ static const struct piddesc piddesc_omg[] = {
PP (IDENTITY_STATUS_TOKEN, identity_status_token, XS, XQ, XbPROP, XS, XS, XSTOP, XQ, XbPROP, XS, XO, XSTOP),
PP (DATA_TAGS, data_tags, XQ, XS, XS, XSTOP),
#endif
PP (DOMAIN_ID, domain_id, Xu),
PP (DOMAIN_TAG, domain_tag, XS),
{ PID_STATUSINFO, PDF_FUNCTION, PP_STATUSINFO, "STATUSINFO",
offsetof (struct nn_plist, statusinfo), membersize (struct nn_plist, statusinfo),
{ .f = { .deser = deser_statusinfo, .ser = ser_statusinfo } }, 0 },
@ -1424,7 +1426,7 @@ struct piddesc_index {
nn_plist_init_tables.
FIXME: should compute them at build-time */
#define DEFAULT_PROC_ARRAY_SIZE 19
#define DEFAULT_PROC_ARRAY_SIZE 20
#ifdef DDSI_INCLUDE_SSM
#define DEFAULT_OMG_PIDS_ARRAY_SIZE (PID_READER_FAVOURS_SSM + 1)
#else
@ -2255,13 +2257,7 @@ static dds_return_t init_one_parameter (nn_plist_t *plist, nn_ipaddress_params_t
return return_unrecognized_pid (plist, pid);
assert (pid_to_index (pid) == pid_to_index (entry->pid));
if (pid != entry->pid)
{
DDS_CERROR (logcfg, "error processing parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" mapped to pid %"PRIx16"\n",
dd->vendorid.id[0], dd->vendorid.id[1],
dd->protocol_version.major, dd->protocol_version.minor,
pid, entry->pid);
return return_unrecognized_pid (plist, pid);
}
assert (pid != PID_PAD);
struct flagset flagset;

View file

@ -2562,7 +2562,7 @@ struct nn_dqueue *nn_dqueue_new (const char *name, const struct q_globals *gv, u
thrnamesz = 3 + strlen (name) + 1;
if ((thrname = ddsrt_malloc (thrnamesz)) == NULL)
goto fail_thrname;
snprintf (thrname, thrnamesz, "dq.%s", name);
(void) snprintf (thrname, thrnamesz, "dq.%s", name);
if (create_thread (&q->ts, gv, thrname, (uint32_t (*) (void *)) dqueue_thread, q) != DDS_RETCODE_OK)
goto fail_thread;
ddsrt_free (thrname);
@ -2675,7 +2675,7 @@ void nn_dqueue_enqueue1 (struct nn_dqueue *q, const ddsi_guid_t *rdguid, struct
ddsrt_atomic_add32 (&q->nof_samples, 1 + (uint32_t) rres);
if (nn_dqueue_enqueue_bubble_locked (q, b))
ddsrt_cond_broadcast (&q->cond);
nn_dqueue_enqueue_locked (q, sc);
(void) nn_dqueue_enqueue_locked (q, sc);
ddsrt_mutex_unlock (&q->lock);
}

View file

@ -136,9 +136,11 @@ static int valid_AckNack (const struct receiver_state *rst, AckNack_t *msg, size
/* Validation following 8.3.7.1.3 + 8.3.5.5 */
if (!valid_sequence_number_set (&msg->readerSNState))
{
/* FastRTPS sends invalid pre-emptive ACKs -- patch the message so we can process it */
if (! NN_STRICT_P (rst->gv->config) && vendor_is_eprosima (rst->vendor) &&
fromSN (msg->readerSNState.bitmap_base) == 0 && msg->readerSNState.numbits == 0)
/* FastRTPS, Connext send invalid pre-emptive ACKs -- patch the message to
make it well-formed and process it as normal */
if (! NN_STRICT_P (rst->gv->config) &&
(fromSN (msg->readerSNState.bitmap_base) == 0 && msg->readerSNState.numbits == 0) &&
(vendor_is_eprosima (rst->vendor) || vendor_is_rti (rst->vendor)))
msg->readerSNState.bitmap_base = toSN (1);
else
return 0;
@ -544,7 +546,7 @@ static void force_heartbeat_to_peer (struct writer *wr, const struct whc_state *
}
/* Send a Heartbeat just to this peer */
add_Heartbeat (m, wr, whcst, hbansreq, prd->e.guid.entityid, 0);
add_Heartbeat (m, wr, whcst, hbansreq, 0, prd->e.guid.entityid, 0);
ETRACE (wr, "force_heartbeat_to_peer: "PGUIDFMT" -> "PGUIDFMT" - queue for transmit\n",
PGUID (wr->e.guid), PGUID (prd->e.guid));
qxev_msg (wr->evq, m);
@ -689,6 +691,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac
struct proxy_reader *prd;
struct wr_prd_match *rn;
struct writer *wr;
struct lease *lease;
ddsi_guid_t src, dst;
seqno_t seqbase;
seqno_t seq_xmit;
@ -744,8 +747,8 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac
return 1;
}
/* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->lease), tnow);
if ((lease = ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto)) != NULL)
lease_renew (lease, tnow);
if (!wr->reliable) /* note: reliability can't be changed */
{
@ -1173,6 +1176,7 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct
const seqno_t lastseq = fromSN (msg->lastSN);
struct handle_Heartbeat_helper_arg arg;
struct proxy_writer *pwr;
struct lease *lease;
ddsi_guid_t src, dst;
src.prefix = rst->src_guid_prefix;
@ -1200,14 +1204,19 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct
return 1;
}
/* liveliness is still only implemented partially (with all set to AUTOMATIC,
BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow);
if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL)
lease_renew (lease, tnow);
RSTTRACE (PGUIDFMT" -> "PGUIDFMT":", PGUID (src), PGUID (dst));
ddsrt_mutex_lock (&pwr->e.lock);
if (msg->smhdr.flags & HEARTBEAT_FLAG_LIVELINESS &&
pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC &&
pwr->c.xqos->liveliness.lease_duration != T_NEVER)
{
if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man)) != NULL)
lease_renew (lease, tnow);
lease_renew (pwr->lease, tnow);
}
if (pwr->n_reliable_readers == 0)
{
RSTTRACE (PGUIDFMT" -> "PGUIDFMT" no-reliable-readers)", PGUID (src), PGUID (dst));
@ -1347,6 +1356,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
const nn_fragment_number_t fragnum = msg->lastFragmentNum - 1; /* we do 0-based */
ddsi_guid_t src, dst;
struct proxy_writer *pwr;
struct lease *lease;
src.prefix = rst->src_guid_prefix;
src.entityid = msg->writerId;
@ -1372,8 +1382,8 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
return 1;
}
/* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow);
if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL)
lease_renew (lease, tnow);
RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst));
ddsrt_mutex_lock (&pwr->e.lock);
@ -1449,7 +1459,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
samples we no longer care about) */
int64_t delay = rst->gv->config.nack_delay;
RSTTRACE ("/nackfrag");
resched_xevent_if_earlier (m->acknack_xevent, add_duration_to_mtime (now_mt(), delay));
(void) resched_xevent_if_earlier (m->acknack_xevent, add_duration_to_mtime (now_mt(), delay));
}
}
}
@ -1463,6 +1473,7 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
struct proxy_reader *prd;
struct wr_prd_match *rn;
struct writer *wr;
struct lease *lease;
struct whc_borrowed_sample sample;
ddsi_guid_t src, dst;
nn_count_t *countp;
@ -1505,8 +1516,8 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
return 1;
}
/* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->lease), tnow);
if ((lease = ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto)) != NULL)
lease_renew (lease, tnow);
if (!wr->reliable) /* note: reliability can't be changed */
{
@ -1720,6 +1731,7 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm
struct proxy_writer *pwr;
struct pwr_rd_match *wn;
struct lease *lease;
ddsi_guid_t src, dst;
seqno_t gapstart, listbase;
int32_t last_included_rel;
@ -1759,8 +1771,8 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm
return 1;
}
/* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow);
if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL)
lease_renew (lease, tnow);
ddsrt_mutex_lock (&pwr->e.lock);
if ((wn = ddsrt_avl_lookup (&pwr_readers_treedef, &pwr->readers, &dst)) == NULL)
@ -2220,11 +2232,13 @@ static void clean_defrag (struct proxy_writer *pwr)
nn_defrag_notegap (pwr->defrag, 1, seq);
}
static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Data_DataFrag_common_t *msg, const struct nn_rsample_info *sampleinfo, uint32_t fragnum, struct nn_rdata *rdata, struct nn_dqueue **deferred_wakeup)
static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Data_DataFrag_common_t *msg, const struct nn_rsample_info *sampleinfo,
uint32_t fragnum, struct nn_rdata *rdata, struct nn_dqueue **deferred_wakeup, bool renew_manbypp_lease)
{
struct proxy_writer *pwr;
struct nn_rsample *rsample;
ddsi_guid_t dst;
struct lease *lease;
dst.prefix = rst->dst_guid_prefix;
dst.entityid = msg->readerId;
@ -2239,14 +2253,28 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
return;
}
/* liveliness is still only implemented partially (with all set to
AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy
participant's lease. */
lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow);
/* Proxy participant's "automatic" lease has to be renewed always, manual-by-participant one only
for data published by the application. If pwr->lease exists, it is in some manual lease mode,
so check whether it is actually in manual-by-topic mode before renewing it. As pwr->lease is
set once (during entity creation) we can read it outside the lock, keeping all the lease
renewals together. */
if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL)
lease_renew (lease, tnow);
if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man)) != NULL && renew_manbypp_lease)
lease_renew (lease, tnow);
if (pwr->lease && pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC)
lease_renew (pwr->lease, tnow);
/* Shouldn't lock the full writer, but will do so for now */
ddsrt_mutex_lock (&pwr->e.lock);
/* A change in transition from not-alive to alive is relatively complicated
and may involve temporarily unlocking the proxy writer during the process
(to avoid unnecessarily holding pwr->e.lock while invoking listeners on
the reader) */
if (!pwr->alive)
proxy_writer_set_alive_may_unlock (pwr, true);
/* Don't accept data when reliable readers exist and we haven't yet seen
a heartbeat telling us what the "current" sequence number of the writer
is. If no reliable readers are present, we can't request a heartbeat and
@ -2347,7 +2375,10 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
/* Enqueue or deliver with pwr->e.lock held: to ensure no other
receive thread's data gets interleaved -- arguably delivery
needn't be exactly in-order, which would allow us to do this
without pwr->e.lock held. */
without pwr->e.lock held.
Note that PMD is also handled here, but the pwr for PMD does not
use no synchronous delivery, so deliver_user_data_synchronously
(which asserts pwr is not built-in) is not used for PMD handling. */
if (pwr->deliver_synchronously)
{
/* FIXME: just in case the synchronous delivery runs into a delay caused
@ -2529,25 +2560,36 @@ static int handle_Data (struct receiver_state *rst, nn_etime_t tnow, struct nn_r
unsigned submsg_offset, payload_offset;
submsg_offset = (unsigned) ((unsigned char *) msg - NN_RMSG_PAYLOAD (rmsg));
if (datap)
{
payload_offset = (unsigned) ((unsigned char *) datap - NN_RMSG_PAYLOAD (rmsg));
}
else
{
payload_offset = submsg_offset + (unsigned) size;
}
rdata = nn_rdata_new (rmsg, 0, sampleinfo->size, submsg_offset, payload_offset);
if ((msg->x.writerId.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) ||
(msg->x.writerId.u == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER))
/* SPDP needs special treatment: there are no proxy writers for it
and we accept data from unknown sources */
if ((msg->x.writerId.u & NN_ENTITYID_SOURCE_MASK) == NN_ENTITYID_SOURCE_BUILTIN)
{
bool renew_manbypp_lease = true;
switch (msg->x.writerId.u)
{
case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER:
/* fall through */
case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER:
/* SPDP needs special treatment: there are no proxy writers for it and we accept data from unknown sources */
handle_SPDP (sampleinfo, rdata);
break;
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER:
/* fall through */
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER:
/* Handle PMD as a regular message, but without renewing the leases on proxypp */
renew_manbypp_lease = false;
/* fall through */
default:
handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, ~0u, rdata, deferred_wakeup, renew_manbypp_lease);
}
}
else
{
handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, ~0u, rdata, deferred_wakeup);
handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, ~0u, rdata, deferred_wakeup, true);
}
}
RSTTRACE (")");
@ -2583,13 +2625,23 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct
struct nn_rdata *rdata;
unsigned submsg_offset, payload_offset;
uint32_t begin, endp1;
if ((msg->x.writerId.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) ||
(msg->x.writerId.u == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER))
bool renew_manbypp_lease = true;
if ((msg->x.writerId.u & NN_ENTITYID_SOURCE_MASK) == NN_ENTITYID_SOURCE_BUILTIN)
{
switch (msg->x.writerId.u)
{
case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER:
/* fall through */
case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER:
DDS_CWARNING (&rst->gv->logconfig, "DATAFRAG("PGUIDFMT" #%"PRId64" -> "PGUIDFMT") - fragmented builtin data not yet supported\n",
PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, fromSN (msg->x.writerSN),
PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u);
return 1;
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER:
/* fall through */
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER:
renew_manbypp_lease = false;
}
}
submsg_offset = (unsigned) ((unsigned char *) msg - NN_RMSG_PAYLOAD (rmsg));
@ -2630,7 +2682,7 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct
wrong, it'll simply generate a request for retransmitting a
non-existent fragment. The other side SHOULD be capable of
dealing with that. */
handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, msg->fragmentStartingNum + msg->fragmentsInSubmessage - 2, rdata, deferred_wakeup);
handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, msg->fragmentStartingNum + msg->fragmentsInSubmessage - 2, rdata, deferred_wakeup, renew_manbypp_lease);
}
RSTTRACE (")");
return 1;
@ -3120,12 +3172,14 @@ static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, d
{
return false;
}
DDSRT_STATIC_ASSERT (sizeof (struct nn_rmsg) == offsetof (struct nn_rmsg, chunk) + sizeof (struct nn_rmsg_chunk));
buff = (unsigned char *) NN_RMSG_PAYLOAD (rmsg);
hdr = (Header_t*) buff;
if (conn->m_stream)
{
MsgLen_t * ml = (MsgLen_t*) (buff + RTPS_MESSAGE_HEADER_SIZE);
MsgLen_t * ml = (MsgLen_t*) (hdr + 1);
/*
Read in packet header to get size of packet in MsgLen_t, then read in

View file

@ -704,8 +704,8 @@ void os_sockWaitsetFree (os_sockWaitset ws)
closesocket (ws->pipe[0]);
closesocket (ws->pipe[1]);
#elif !defined(LWIP_SOCKET)
close (ws->pipe[0]);
close (ws->pipe[1]);
(void) close (ws->pipe[0]);
(void) close (ws->pipe[1]);
#endif
#if defined(__VXWORKS__) && defined(__RTP__)
pipeDevDelete ((char*) &nameBuf, 0);

View file

@ -251,7 +251,7 @@ static struct thread_state1 *init_thread_state (const char *tname, const struct
ts = &thread_states.ts[cand];
ddsrt_atomic_stvoidp (&ts->gv, (struct q_globals *) gv);
assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts->vtime)));
ddsrt_strlcpy (ts->name, tname, sizeof (ts->name));
(void) ddsrt_strlcpy (ts->name, tname, sizeof (ts->name));
ts->state = state;
return ts;

View file

@ -123,7 +123,7 @@ void writer_hbcontrol_note_asyncwrite (struct writer *wr, nn_mtime_t tnow)
least one unacked msg if there are reliable readers, so must
have a heartbeat scheduled. Do so now */
hbc->tsched = tnext;
resched_xevent_if_earlier (wr->heartbeat_xevent, tnext);
(void) resched_xevent_if_earlier (wr->heartbeat_xevent, tnext);
}
}
@ -197,7 +197,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
nn_xmsg_setencoderid (msg, wr->partition_id);
#endif
add_Heartbeat (msg, wr, whcst, hbansreq, to_entityid (NN_ENTITYID_UNKNOWN), issync);
add_Heartbeat (msg, wr, whcst, hbansreq, 0, to_entityid (NN_ENTITYID_UNKNOWN), issync);
}
else
{
@ -218,7 +218,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
nn_xmsg_setencoderid (msg, wr->partition_id);
#endif
add_Heartbeat (msg, wr, whcst, hbansreq, prd_guid->entityid, issync);
add_Heartbeat (msg, wr, whcst, hbansreq, 0, prd_guid->entityid, issync);
}
/* It is possible that the encoding removed the submessage(s). */
@ -352,7 +352,7 @@ struct nn_xmsg *writer_hbcontrol_p2p(struct writer *wr, const struct whc_state *
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
nn_xmsg_setencoderid (msg, wr->partition_id);
#endif
add_Heartbeat (msg, wr, whcst, hbansreq, prd->e.guid.entityid, 1);
add_Heartbeat (msg, wr, whcst, hbansreq, 0, prd->e.guid.entityid, 1);
if (nn_xmsg_size(msg) == 0)
{
@ -364,7 +364,7 @@ struct nn_xmsg *writer_hbcontrol_p2p(struct writer *wr, const struct whc_state *
}
#endif
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, ddsi_entityid_t dst, int issync)
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, int hbliveliness, ddsi_entityid_t dst, int issync)
{
struct q_globals const * const gv = wr->e.gv;
struct nn_xmsg_marker sm_marker;
@ -375,6 +375,7 @@ void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_sta
assert (wr->reliable);
assert (hbansreq >= 0);
assert (hbliveliness >= 0);
if (gv->config.meas_hb_to_ack_latency)
{
@ -388,6 +389,8 @@ void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_sta
if (!hbansreq)
hb->smhdr.flags |= HEARTBEAT_FLAG_FINAL;
if (hbliveliness)
hb->smhdr.flags |= HEARTBEAT_FLAG_LIVELINESS;
hb->readerId = nn_hton_entityid (dst);
hb->writerId = nn_hton_entityid (wr->e.guid.entityid);
@ -736,6 +739,34 @@ static void create_HeartbeatFrag (struct writer *wr, seqno_t seq, unsigned fragn
}
}
dds_return_t write_hb_liveliness (struct q_globals * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp)
{
struct nn_xmsg *msg = NULL;
struct whc_state whcst;
struct thread_state1 * const ts1 = lookup_thread_state ();
thread_state_awake (ts1, gv);
struct writer *wr = ephash_lookup_writer_guid (gv->guid_hash, wr_guid);
if (wr == NULL)
{
GVTRACE ("write_hb_liveliness("PGUIDFMT") - writer not found\n", PGUID (*wr_guid));
return DDS_RETCODE_PRECONDITION_NOT_MET;
}
if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL)
return DDS_RETCODE_OUT_OF_RESOURCES;
ddsrt_mutex_lock (&wr->e.lock);
nn_xmsg_setdstN (msg, wr->as, wr->as_group);
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
nn_xmsg_setencoderid (msg, wr->partition_id);
#endif
whc_get_state (wr->whc, &whcst);
add_Heartbeat (msg, wr, &whcst, 0, 1, to_entityid (NN_ENTITYID_UNKNOWN), 1);
ddsrt_mutex_unlock (&wr->e.lock);
nn_xpack_addmsg (xp, msg, 0);
nn_xpack_send (xp, true);
thread_state_asleep (ts1);
return DDS_RETCODE_OK;
}
#if 0
static int must_skip_frag (const char *frags_to_skip, unsigned frag)
{

View file

@ -37,10 +37,12 @@
#include "dds/ddsi/q_bitset.h"
#include "dds/ddsi/q_lease.h"
#include "dds/ddsi/q_xmsg.h"
#include "dds/ddsi/q_entity.h"
#include "dds/ddsi/ddsi_serdata.h"
#include "dds/ddsi/ddsi_serdata_default.h"
#include "dds/ddsi/ddsi_security_omg.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsi/ddsi_pmd.h"
#include "dds__whc.h"
#include "dds/ddsi/sysdeps.h"
@ -715,7 +717,7 @@ static void handle_xevk_heartbeat (struct nn_xpack *xp, struct xevent *ev, nn_mt
ddsrt_avl_is_empty (&wr->readers) ? (seqno_t) -1 : ((struct wr_prd_match *) ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers))->min_seq,
ddsrt_avl_is_empty (&wr->readers) || ((struct wr_prd_match *) ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers))->all_have_replied_to_hb ? "" : "!",
whcst.max_seq, writer_read_seq_xmit (wr));
resched_xevent_if_earlier (ev, t_next);
(void) resched_xevent_if_earlier (ev, t_next);
wr->hbcontrol.tsched = t_next;
ddsrt_mutex_unlock (&wr->e.lock);
@ -1013,7 +1015,7 @@ static void handle_xevk_acknack (struct nn_xpack *xp, struct xevent *ev, nn_mtim
HEARTBEAT, I've seen too many cases of not sending an NACK
because the writing side got confused ... Better to recover
eventually. */
resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, gv->config.auto_resched_nack_delay));
(void) resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, gv->config.auto_resched_nack_delay));
}
GVTRACE ("send acknack(rd "PGUIDFMT" -> pwr "PGUIDFMT")\n",
PGUID (ev->u.acknack.rd_guid), PGUID (ev->u.acknack.pwr_guid));
@ -1039,7 +1041,7 @@ static void handle_xevk_acknack (struct nn_xpack *xp, struct xevent *ev, nn_mtim
intv = 5;
else
intv = 10;
resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, intv * T_SECOND));
(void) resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, intv * T_SECOND));
}
ddsrt_mutex_unlock (&pwr->e.lock);
@ -1052,7 +1054,7 @@ static void handle_xevk_acknack (struct nn_xpack *xp, struct xevent *ev, nn_mtim
outofmem:
/* What to do if out of memory? Crash or burn? */
ddsrt_mutex_unlock (&pwr->e.lock);
resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, 100 * T_MILLISECOND));
(void) resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, 100 * T_MILLISECOND));
}
static bool resend_spdp_sample_by_guid_key (struct writer *wr, const ddsi_guid_t *guid, struct proxy_reader *prd)
@ -1177,7 +1179,7 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e
PGUID (pp->e.guid),
PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER,
(double)(tnext.v - tnow.v) / 1e9);
resched_xevent_if_earlier (ev, tnext);
(void) resched_xevent_if_earlier (ev, tnext);
}
}
else
@ -1204,48 +1206,10 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e
PGUID (pp->e.guid),
PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER,
(double)(tnext.v - tnow.v) / 1e9);
resched_xevent_if_earlier (ev, tnext);
(void) resched_xevent_if_earlier (ev, tnext);
}
}
static void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind)
{
#define PMD_DATA_LENGTH 1
struct q_globals * const gv = pp->e.gv;
struct writer *wr;
union {
ParticipantMessageData_t pmd;
char pad[offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH];
} u;
struct ddsi_serdata *serdata;
struct ddsi_tkmap_instance *tk;
if ((wr = get_builtin_writer (pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER)) == NULL)
{
GVTRACE ("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (pp->e.guid));
return;
}
u.pmd.participantGuidPrefix = nn_hton_guid_prefix (pp->e.guid.prefix);
u.pmd.kind = ddsrt_toBE4u (pmd_kind);
u.pmd.length = PMD_DATA_LENGTH;
memset (u.pmd.value, 0, u.pmd.length);
struct ddsi_rawcdr_sample raw = {
.blob = &u,
.size = offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH,
.key = &u.pmd,
.keysize = 16
};
serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw);
serdata->timestamp = now ();
tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata);
write_sample_nogc (ts1, xp, wr, serdata, tk);
ddsi_tkmap_instance_unref (gv->m_tkmap, tk);
#undef PMD_DATA_LENGTH
}
static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_xpack *xp, struct xevent *ev, nn_mtime_t tnow)
{
struct q_globals * const gv = ev->evq->gv;
@ -1260,16 +1224,7 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_
write_pmd_message (ts1, xp, pp, PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE);
/* QoS changes can't change lease durations. So the only thing that
could cause trouble here is that the addition or removal of a
writer cause the interval to change for this participant. If we
lock pp for reading out the lease duration we are guaranteed a
consistent value (can't assume 64-bit atomic reads on all support
platforms!) */
ddsrt_mutex_lock (&pp->e.lock);
intv = pp->lease_duration;
/* FIXME: need to use smallest liveliness duration of all automatic-liveliness writers */
intv = pp_get_pmd_interval (pp);
if (intv == T_NEVER)
{
tnext.v = T_NEVER;
@ -1286,8 +1241,7 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_
GVTRACE ("resched pmd("PGUIDFMT"): %gs\n", PGUID (pp->e.guid), (double)(tnext.v - tnow.v) / 1e9);
}
resched_xevent_if_earlier (ev, tnext);
ddsrt_mutex_unlock (&pp->e.lock);
(void) resched_xevent_if_earlier (ev, tnext);
}
static void handle_xevk_delete_writer (UNUSED_ARG (struct nn_xpack *xp), struct xevent *ev, UNUSED_ARG (nn_mtime_t tnow))

View file

@ -1387,7 +1387,7 @@ static uint32_t nn_xpack_sendq_thread (void *vgv)
struct nn_xpack *xp;
if ((xp = gv->sendq_head) == NULL)
{
ddsrt_cond_waitfor (&gv->sendq_cond, &gv->sendq_lock, 1000000);
(void) ddsrt_cond_waitfor (&gv->sendq_cond, &gv->sendq_lock, 1000000);
}
else
{
@ -1416,7 +1416,8 @@ void nn_xpack_sendq_init (struct q_globals *gv)
void nn_xpack_sendq_start (struct q_globals *gv)
{
create_thread (&gv->sendq_ts, gv, "sendq", nn_xpack_sendq_thread, NULL);
if (create_thread (&gv->sendq_ts, gv, "sendq", nn_xpack_sendq_thread, NULL) != DDS_RETCODE_OK)
GVERROR ("nn_xpack_sendq_start: can't create nn_xpack_sendq_thread\n");
}
void nn_xpack_sendq_stop (struct q_globals *gv)

View file

@ -70,7 +70,7 @@ static char *print_tstamp (char *buf, size_t sz, dds_time_t t)
if (d / 1000000000 != 0)
pos += (size_t) snprintf (buf + pos, sz - pos, "%+ds", (int) (d / 1000000000));
if (d % 1000000000 != 0)
snprintf (buf + pos, sz - pos, "%+dns", (int) (d % 1000000000));
(void) snprintf (buf + pos, sz - pos, "%+dns", (int) (d % 1000000000));
return buf;
}
@ -439,7 +439,7 @@ static void print_condmask (char *buf, size_t bufsz, const dds_readcond *cond)
pos += (size_t) snprintf (buf + pos, bufsz - pos, "%sALIVE | DISPOSED", sep);
break;
}
snprintf (buf + pos, bufsz - pos, "]");
(void) snprintf (buf + pos, bufsz - pos, "]");
}
static void rdcond (struct dds_rhc *rhc, dds_readcond *cond, const struct check *chk, int max, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2])

View file

@ -184,14 +184,6 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage
endif()
set(system_exists FALSE)
# Allow custom implementations for a feature. e.g. lwip as opposed to
# windows or posix.
set(_system_name "${system_name}")
if(NOT HAVE_${feature_uc} MATCHES "[tT][rR][uU][eE]")
set(_system_name "${HAVE_${feature_uc}}")
endif()
foreach(system ${_system_name} posix)
# Headers that must remain private but are required by other runtime
# source files must be located in src/<feature>/dds/ddsrt.
if(IS_DIRECTORY "${source_path}/${feature}/include")
@ -204,6 +196,15 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage
ddsrt INTERFACE
"$<BUILD_INTERFACE:${source_path}/${feature}/include/>")
endif()
# Allow custom implementations for a feature. e.g. lwip as opposed to
# windows or posix.
set(_system_name "${system_name}")
if(NOT HAVE_${feature_uc} MATCHES "[tT][rR][uU][eE]")
set(_system_name "${HAVE_${feature_uc}}")
endif()
foreach(system ${_system_name} posix)
if(IS_DIRECTORY "${source_path}/${feature}/${system}")
file(GLOB_RECURSE
files

Some files were not shown because too many files have changed in this diff Show more