Merge pull request #527 from eclipse-cyclonedds/security

Merge security into master
This commit is contained in:
eboasson 2020-06-04 17:47:28 +02:00 committed by GitHub
commit 3030a81528
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
454 changed files with 101361 additions and 3771 deletions

View file

@ -143,33 +143,37 @@ windows_vs2017: &windows_vs2017
jobs: jobs:
include: include:
- <<: *linux_gcc8 - <<: *linux_gcc8
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", COVERITY_SCAN=true ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", COVERITY_SCAN=true ]
if: type = cron if: type = cron
- <<: *linux_gcc8 - <<: *linux_gcc8
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ]
- <<: *linux_gcc8 - <<: *linux_gcc8
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", CONANFILE=conanfile102.txt ]
- <<: *linux_gcc8 - <<: *linux_gcc8
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=NO, LIFESPAN=NO, DEADLINE=NO, GENERATOR="Unix Makefiles" ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ]
- <<: *linux_gcc8
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=NO, SECURITY=YES, LIFESPAN=NO, DEADLINE=NO, GENERATOR="Unix Makefiles" ]
- <<: *linux_clang - <<: *linux_clang
env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ]
- <<: *linux_clang - <<: *linux_clang
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=NO, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ]
- <<: *linux_clang
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode9 - <<: *osx_xcode9
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ]
if: type = cron if: type = cron
- <<: *osx_xcode - <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", MACOSX_DEPLOYMENT_TARGET=10.12 ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", MACOSX_DEPLOYMENT_TARGET=10.12 ]
- <<: *osx_xcode - <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode - <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ]
- <<: *windows_vs2017 - <<: *windows_vs2017
env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017" ] env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017", CONANFILE=conanfile102.txt ]
- <<: *windows_vs2017 - <<: *windows_vs2017
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ]
- <<: *windows_vs2017 - <<: *windows_vs2017
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ] env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ]
before_script: before_script:
- conan profile new default --detect - conan profile new default --detect
@ -195,12 +199,13 @@ script:
- INSTALLPREFIX="$(pwd)/install" - INSTALLPREFIX="$(pwd)/install"
- mkdir build - mkdir build
- cd build - cd build
- conan install -b missing -s arch=${ARCH} -s build_type=${BUILD_TYPE} .. - conan install -b missing -s arch=${ARCH} -s build_type=${BUILD_TYPE} ../${CONANFILE:-conanfile.txt}
- which trang && BUILD_SCHEMA=1 || BUILD_SCHEMA=0 - which trang && BUILD_SCHEMA=1 || BUILD_SCHEMA=0
- cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} - cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX=${INSTALLPREFIX} -DCMAKE_INSTALL_PREFIX=${INSTALLPREFIX}
-DUSE_SANITIZER=${ASAN} -DUSE_SANITIZER=${ASAN}
-DENABLE_SSL=${SSL} -DENABLE_SSL=${SSL}
-DENABLE_SECURITY=${SECURITY}
-DENABLE_LIFESPAN=${LIFESPAN} -DENABLE_LIFESPAN=${LIFESPAN}
-DENABLE_DEADLINE_MISSED=${DEADLINE} -DENABLE_DEADLINE_MISSED=${DEADLINE}
-DBUILD_TESTING=on -DBUILD_TESTING=on

View file

@ -10,7 +10,7 @@
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
# #
cmake_minimum_required(VERSION 3.7) cmake_minimum_required(VERSION 3.7)
project(CycloneDDS VERSION 0.6.0) project(CycloneDDS VERSION 0.7.0)
# Set a default build type if none was specified # Set a default build type if none was specified
set(default_build_type "RelWithDebInfo") set(default_build_type "RelWithDebInfo")

View file

@ -281,12 +281,17 @@ function(add_cunit_executable TARGET)
set_property( set_property(
TEST ${ctest} TEST ${ctest}
PROPERTY ENVIRONMENT PROPERTY ENVIRONMENT
"DYLD_LIBRARY_PATH=${CUNIT_LIBRARY_DIR}:$ENV{DYLD_LIBRARY_PATH}") "DYLD_LIBRARY_PATH=${CUNIT_LIBRARY_DIR}:${CMAKE_LIBRARY_OUTPUT_DIRECTORY}:$ENV{DYLD_LIBRARY_PATH}")
elseif(WIN32 AND ${CUNIT_LIBRARY_TYPE} STREQUAL "SHARED_LIBRARY") elseif(WIN32 AND ${CUNIT_LIBRARY_TYPE} STREQUAL "SHARED_LIBRARY")
set_property( set_property(
TEST ${ctest} TEST ${ctest}
PROPERTY ENVIRONMENT PROPERTY ENVIRONMENT
"PATH=${CUNIT_LIBRARY_DIR};$ENV{PATH}") "PATH=${CUNIT_LIBRARY_DIR};$ENV{PATH}")
else()
set_property(
TEST ${ctest}
PROPERTY ENVIRONMENT
"LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}:$ENV{LD_LIBRARY_PATH}")
endif() endif()
endforeach() endforeach()

6
conanfile102.txt Normal file
View file

@ -0,0 +1,6 @@
[requires]
cunit/2.1-3@bincrafters/stable
OpenSSL/1.0.2@conan/stable
[generators]
cmake

View file

@ -0,0 +1,406 @@
# DDS Security effort
ADLink has decided to donate their Vortex OpenSplice DDS Security
implementation to the Cyclone DDS project. However, that will not be a simple
code drop.
This document catches all the work that is foreseen to port Vortex OpenSplice
DDS Security to Cyclone DDS.
This document can be removed when DDS Security has been implemented.
**Table of contents**
- [Definition of done](#done)
- [Footprint](#footprint)
- [Multi process testing (done)](#testing)
- [Runtime library loading (done)](#loading)
- [Hopscotch utility (done)](#hopscotch)
- [FSM utility (in progress)](#fsm)
- [Port DDS Security plugin API (done)](#port-api)
- [De-Serializing messages in DDSI (done)](#deserializing)
- [De-Serializing security message parameters in DDSI (done)](#deserializing_plist)
- [Port DDS Security builtin plugins (in progress)](#port-plugins)
- [Port DDSI DDS Security (in progress)](#port-ddsi)
- [Move configuration (in progress)](#Move-configuration)
- [Failure handling](#failures)
- [Multiple configurations](#multiple-configurations)
- [Example](#example)
- [QosProvider](#qosprovider)
- [Data Tags (optional)](#datatags)
## Definition of done<a name="done" />
When this document tells that a certain aspect is 'done', it means that it
has been accepted into the security branch of the cyclonedds repository
(https://github.com/eclipse-cyclonedds/cyclonedds/tree/security).
However, it is possible that various parts need some rework before the security
branch can be merged into the cyclonedds master branch.
## Footprint<a name="footprint" />
A non-functional requirement is that cyclonedds should be buildable without
the DDS Security support in it. That will reduce the footprint (and possibly
improve performance) for applications that don't need security.
For that, the ENABLE_SECURITY build option is introduced that translates into
the DDSI_INCLUDE_SECURITY compile switch. However, the usage of that switch
should not explode. That'll reduce the maintainability.
For instance, the usage of the switch can be minimized by using functions that
will reduce to an inline function that just returns a hardcode value when
security is not included (otherwise they'll do some certain task).
The compiler can use these inline functions to do clever stuff regarding
footprint and performance.
There can be other solutions to decrease security footprint without impeding
on the maintainability of the code by inserting the switch too much.
## Multi process testing (done)<a name="testing" />
To properly test DDS Security, multi process testing will be necessary.
This is not yet available in Cyclone DDS.
See the [Multi Process Testing](multi_process_testing.md) document for
more information.
## Runtime library loading (done)<a name="loading" />
The ddsi component needs to be able to load DDS Security plugins at runtime.
These plugins are provided as libraries.<br>
Loading libraries at runtime is currently not possible in Cyclone DDS.
## Hopscotch utility (done)<a name="hopscotch" />
This hash table is used by the Security plugins.<br>
Both versions on OpenSplice and Cyclone are equivalent.<br>
No additional effort is expected.
## FSM utility (in progress)<a name="fsm" />
The Finite State Machine utility has been introduced in OpenSplice to support
the handshake of DDS Security.<br>
This has to be ported to Cyclone.
However, it already has some technical dept, which should be removed before
adding it to Cyclone. This means that a refactor should happen as part of the
porting.
The related DBTs should also be ported to Cyclone unit tests.
It was decided to just port the FSM at the moment. The refactor will take place
when trying to get the security branch into master.
## Port DDS Security plugin API (done)<a name="port-api" />
The DDS Security plugin API are just a few header files. The ddsi component
uses that to link against. The implementation of the API is done in the
individual plugins. The plugins are [loaded at runtime](#loading) (when
configured).
This means that ddsi can be DDS Security prepared (after building against this
API) without there being actual DDS Security plugins.
It seems to be just a code drop of a number of header files.<br>
Maybe add some CMake module for both ddsi and the plugins to easily link
against?
## De-Serializing messages in DDSI (done)<a name="deserializing" />
DDSI needs to be able to (de)serialize a few Security messages. In OpenSplice,
some functionality of the database is used. This is unavailable in Cyclone.
What is available is a serializer that uses marshaling operations (see, for
for instance, m_ops in the dds_topic_descriptor struct).
The (de)serializing of the Security messages should be supported by supplying
the m_ops sequences, message structs (if not yet available) and some
convenience functions using both.
## De-Serializing security message parameters in DDSI (done)<a name="deserializing_plist" />
DDSI needs to be able to (de)serialize a few message parameters that have
been introduced by the DDS Security spec.
## Port DDS Security builtin plugins (in progress)<a name="port-plugins" />
No major changes between the DDS Security plugins in OpenSplice and Cyclone
are expected.
The DDS Security plugins require OpenSSL. Cyclone DDS already uses OpenSSL.
However, it expects (or at least it's preferred to have) version 1.1 or newer,
while the OpenSplice Security plugins are build against 1.0.2. There are some
API changes between the two versions. This will take some porting effort.
The build system should be ported from makefiles to cmake files.
There are security_plugin DBTs in OpenSplice. These tests are base on cunit,
which is also used in Cyclone. However, it is used slightly different. A small
porting effort is expected (i.e. let it work with cmake and runner generation).
This means some additional effort, compared to just a code drop. But it is not
expected to be major.
- Authentication plugin (done).
- Access Control plugin (in progress).
- Cryptography plugin (done).
There are a few sub-features that can be implemented separately.
- Check/handle expiry dates (in progress).
- Trusted directory support.
- etc?
## Port DDSI DDS Security (in progress)<a name="port-ddsi" />
There is already quite a bit of difference between the DDSI codebases in
OpenSplice and Cyclone. So, the copy/merge of the DDSI Security code from
OpenSplice to Cyclone will not be trivial.
Most parts of the merging will not be trivial, but should be quite
straightforward nonetheless. Things that are noticed to be somewhat different
between the DDSI code bases that could impact the merging work:
- Entity matching is slightly different.
- The q_entity.c has a lot of differences that can obfuscate the differences
related to DDS Security.
- Unacked messages logic has changed a bit. Does that impact gaps?
- (De)serializing, of course
(see also [De-Serializing in DDSI](#deserializing)).
- Writer history cache is different, which can impact the builtin volatile
Security endpoints.
- Unknown unknowns.
The buildsystem has to be upgraded.<br>
- A few files are added which are easy to add to cmake.<br>
- There's a new dependency on the [DDS Security API](#port-api), which is done.
Then, of course, there are the tests<br>
First of all, [Multi Process Testing](#testing) should be available, which now
it is.<br>
When that's the case, then the OpenSplice tests business
logic have to be ported from scripts and applications to that new framework.
That porting shouldn't be that hard. However, it will probably take a while.
The DDSI Port doesn't have to be a big bang. It can be split up into various
different pull requests. Examples are
- Extend configuration XML parsing with the security configuration (done).
- Extend nn_qos with security related policies. Fill them with values from the
configuration when applicable (done).
- Add DDS Security endpoints that are non-volatile (done).
- Add DDS Security endpoint that is volatile. This change has more impact than
all the non-volatile endpoints combined (done).
- Handshake (in progress).
- Payload (en)(de)coding (DDSI support: done. Wrapper: todo).
- Submsg (en)(de)coding (DDSI support: done. Wrapper: todo).
- RTPSmsg (en)(de)coding (DDSI support: done. Wrapper: todo).
- Etc
## Move configuration (in progress)<a name="Move-configuration" />
After the port, the DDS Security configuration is still (partly) done through
the overall configuration XML file (rest is coming from the permissions and
governance files).<br>
However, according to the specification, the configuration should happen by
means of the Participant QoS.
The ddsc dds_qos_t is mapped on the ddsi xqos. The ddsi xqos already has the
necessary policy (after the [port](#port-ddsi)), namely the property_policy.
This means that the ddsc qos itself is automatically prepared.<br>
However, getting and setting policies are done through getter and setter
functions in ddsc.<br>
This means we have to add these functions for the security configuration values.
The ddsc policy getter and setter functions use (arrays of) primitive types as
arguments. The configuration of Security is given by means of the property
policy, which isn't a primitive. To keep in line with the QoS API, we could add
something like:
```cpp
typedef struct dds_properties_t; /* opaque type in API, but mapped to
nn_property_qospolicy_t internally */
dds_properties_t *dds_properties_create();
void dds_properties_delete(dds_properties_t *);
void dds_properties_merge(dds_properties_t *, dds_properties_t *);
void dds_properties_add_property(dds_properties_t *, char *name, char *value);
void dds_properties_add_binaryproperty(dds_properties_t *, char *name,
uchar *value, int valuelength);
void dds_qset_properties(dds_qos_t*, dds_properties_t *);
void dds_qget_properties(dds_qos_t*, dds_properties_t **);
```
But this is very preliminary and is still up for debate.
After moving the Security configuration to the participant QoS, it's possible
to have different configurations within a single application if you have
multiple participants. However, ddsi only supports one Security configuration
for now. That doesn't change by changing where that configuration comes
from.<br>
To solve this, it is expected that creation of a participant with a different
configuration will force a failure for now.
Until [Multiple Configurations](#multiple-configurations) is implemented.
After the ddsc API has been extended, we can decide on what to do with the
configuration through XML.
- Keep it. It seems usable: no need to change applications when changing (or
adding) Security settings. However, conflicts between XML and QoS
configuration could cause problems. Simplest seems to be to only allow QoS
security configuration when it's not configured in XML already.
- Remove it. No conflict resolving needed.
All the Security tests depend on providing (different) configurations through
XML. Depending on if we keep or remove the XML configuration option, a lot of
tests have to be updated, or a few added (that test security configuration
through QoS).
For the loading of the plugin libraries, properties with specific names have to
be added to the property policy to know the location and names of the plugins.
As inspiration, fastrtps can be used:
https://github.com/ros2/rmw_fastrtps/blob/master/rmw_fastrtps_shared_cpp/src/rmw_node.cpp#L296
## Failure handling<a name="failures" />
Currently, when an local action is tried that isn't allowed by DDS Security
(like creating a participant when it's not permitted), DDSI is shut down.<br>
Mainly because in OpenSplice it's quite hard to get a failure state from DDSI
to the application.
In Cyclone, however, ddsc::dds_create_participant() results in a direct call to
ddsi::new_participant(). This means that if creation of an entity (or
participant in this example) fails due to security issues in ddsi, we can fail
the actual ddsc API call with a proper error result (there's already the
DDS_RETCODE_NOT_ALLOWED_BY_SECURITY in the ddsc API (not used)).
Maybe we have to do some additional cleanup when a failure is encountered.
Some tests probably have to be adjusted for the new behaviour.
## Multiple configurations<a name="multiple-configurations" />
Currently (because it's done through the overall XML configuration), only one
DDS Security configuration could be supported. Because of this fact, at various
locations, shortcuts could be made in both DDSI and plugins.<br>
However, because the configuration is coming from participants now (see
[Move Configuration](#Move-configuration), we should be able to support
multiple different DDS Security configurations.
Until now, the creation of a second participant with a different configuration
would force a failure (again, see [Move Configuration](#Move-configuration)).
It is expected that the plugin loading still happens through the configuration
XML (see [Move Configuration](#Move-configuration)). This means that DDSI doesn't have to support
multiple sets of plugins. Just the one set, provided at initialization. This
means that DDSI shouldn't have to be changed to support this.
So, it's the plugins need to be able to support multiple configurations.
The Cryptography plugin doesn't seem to care about global DDS Security
configurations. It has basically configurations per participant/topic/
endpoints, which already works. So, this plugin doesn't have to be upgraded.
The Authentication plugin does have global DDS Security configurations. Main
function related to that is validate_local_identity(). This function already
creates a new local identity every time it is called. So, this plugin doesn't
have to be upgraded either.
That leaves the Access Control plugin.<br>
The main function related to configuration is validate_local_permissions().
This function creates access rights depending on Permissions and Governance
files. Currently, there's only one local 'rights' structure that is linked
directly to the plugin (see also the ACCESS_CONTROL_USE_ONE_PERMISSION compile
switch).<br>
This has to change.<br>
The local rights structure needs to be coupled to a participant. This also
means that we have to search for it instead of having direct access when
entering the plugin.<br>
The remote rights can be used as example. That is basically a list of rights/
permissions with the remote identity handle as key.
Tests have to be added to make sure that a setup with different Security
configurations works.
## Example<a name="example" />
A Security example has to be added.
## QosProvider<a name="qosprovider" />
The Participant QoS now contains Security related information. This means that
the QosProvider has to be upgraded to support that.
## Data Tags (optional)<a name="datatags" />
The specification is somewhat fuzzy about the data tags.
The following is a summary (still elaborate) of how it seems to work:
The permissions document can contain the <data_tags> tag on publish and
subscribe level. It's related to the data samples, but don't have to be related
to the keys of those samples.<br>
The QoS of a writer/reader can also have data tags by means of the
DataTagQosPolicy. A writer/reader can only be created when the data_tags in the
QoS matches those in the permissions document. This check should happen on both
the local and remote level.
This creation check is the only thing that DDS Security actually does with the
data tags. They are only authenticated by DDS Security, but not interpreted
further.<br>
This is only a minor security addition, because the publisher can still publish
data that doesn't match the data tags because DDS doesn't interpret the data
nor compares it with the data tags.
What it can be used for is a kind of custom access control scheme on the
application level.<br>
An application that consumes data can see if a publisher is allowed to publish
that sample by comparing the data within the sample with the data tag(s)
associated with that publisher. As said, this comparison is not done on the DDS
level, but has to be done within the application itself.
That leaves the question, how does the application get the tags associated with
the related writer?<br>
In other words; the application gets a sample. It has to know from which writer
it originated and it has to have access to the data tag(s) of that writer.
The dds_sample_info_t contains the dds_instance_handle_t publication_handle,
which is unique to the writer (locally).<br>
That dds_instance_handle_t can be used to get the right
DDS_Security_PublicationBuiltinTopicDataSecure sample for the related secure
builtin reader [**note1**].<br>
DDS_Security_PublicationBuiltinTopicDataSecure contains QoS information
regarding that writer, including the DataTagQosPolicy. The remote
DDS_Security_PublicationBuiltinTopicDataSecure contents have been authenticated
by DDS Security and the data tags can be trusted.<br>
The application can check the sample data against the data_tags within that
QoS.
Things to do:
- Add DataTagQosPolicy to the ddsc API and the related QoSses.
- Add DDS_Security_PublicationBuiltinTopicDataSecure data type to the ddsc API
(better yet, all secure builtin types).
- Add the related builtin reader to the ddsc99 API (better yet, all secure
builtin readers).
- Add test regarding the secure builtin readers and data.
- Add data tag comparisons between QoS and permission documents during local
and remote entity creation.
- Add data tag remote/local (mis)match tests.
Especially because of the lack of access to builtin secure readers, supporting
data tags doesn't seem feasible in the near future. Also, it's optional in the
specification.
**note1**
That DDS_Security_PublicationBuiltinTopicDataSecure reader is not yet available
within the ddsc API, nor is the related data type. Don't know how much work it
would be to add them to that API.

View file

@ -195,3 +195,94 @@ automatic if the target supports it. Finalization is primarily used to release
thread-specific memory and call routines registered by thread-specific memory and call routines registered by
`ddsrt_thread_cleanup_push`. `ddsrt_thread_cleanup_push`.
## DDS Security
### Specification
DDS Security is an [OMG specification](https://www.omg.org/spec/DDS-SECURITY/1.1/PDF) which adds several “DDS Security Support”
compliance points to the DDS Specification.
The specification defines the Security Model and Service Plugin Interface (SPI)
architecture for compliant DDS implementations. The DDS Security Model is enforced
by the invocation of these SPIs by the DDS implementation.
Security Model for DDS defines the security principals (users of the system),
the objects that are being secured, and the operations on the objects that are
to be restricted.
SPIs are defined that when combined together provide Information Assurance to
DDS systems:
* Authentication Service Plugin. Provides the means to verify the identity of the
application and/or user that invokes operations on DDS. Includes facilities to
perform mutual authentication between participants and establish a shared secret.
* AccessControl Service Plugin. Provides the means to enforce policy decisions on
what DDS related operations an authenticated user can perform. For example, which
domains it can join, which Topics it can publish or subscribe to, etc.
* Cryptographic Service Plugin. Implements (or interfaces with libraries that
implement) all cryptographic operations including encryption, decryption,
* Logging Service Plugin. Supports auditing of all DDS security-relevant events
* Data Tagging Service Plugin. Provides a way to add tags to data samples.
<img src="pictures/dds_security_plugin_components.png" alt="DDS Security Plugin Components">
### Cyclone DDS Security
Cyclone DDS Security implementation is composed of the following components/modifications:
* DDS Security plugin API
* DDS Security built-in plugins that implement the API
* DDS Security Core Library that is used by the plugins and DDSI.
* Changes in the DDSI that moderate the specified security model.
The dependency diagram:
DDSI ----> DDS Security API (headers only) <----- DDS Security Plugins
| ^ |
| | |
| | |
-------> DDS Security Core <------------------------
| | |
| | |
| | |
| v |
-------> DDS_RT <------------------------
All security specific contents are under src/security.
##### DDS Security API
The DDS Security plugin API consists of just a few header files. There are separate
header files for each plugin: dds_security_api_authentication.h dds_security_api_cryptography.h
and dds_security_api_access_control.c
The API functions and types are prepared from the IDL by adding DDS_Security_ namespace
prefix to functions and data types. Instead of extending DDS builtin topic data types,
separate DDS_Security_ data type is defined for the current type and the new secure data type.
##### Built-in Plugins
Cyclone DDS Security comes with three mandatory plugins: authentication, cryptography and access control.
###### Authentication Plugin
This plugin implements authentication using a trusted Certificate Authority (CA). It performs
mutual authentication between discovered participants using the RSA or ECDSA Digital Signature
Algorithms and establishes a shared secret using Diffie-Hellman (DH) or Elliptic Curve Diffie-Hellman
(ECDH) Key Agreement Methods.
<img src="pictures/dds_security_authentication_plugin.png" alt="DDS Security Plugin Components">
###### Cryptography Plugin
This plugin provides authenticated encryption using Advanced Encryption Standard (AES) in
Galois Counter Mode (AES-GCM). It supports two AES key sizes: 128 bits and 256 bits. It may
also provide additional reader-specific message authentication codes (MACs) using Galois MAC (AES-GMAC).
<img src="pictures/dds_security_crypto_plugin.png" alt="DDS Security Plugin Components">
###### Access Control Plugin
<img src="pictures/dds_security_access_control_plugin.png" alt="DDS Security Plugin Components">

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

32
docs/dev/todo_list.md Normal file
View file

@ -0,0 +1,32 @@
# TODO LIST
## Security
* Reassess Jeroen's comment:
https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-494040238
> 5. If the security_api just becomes part of ddsc, and it should in my opinion, then I'd prefer you propagate the naming scheme as introduced in ddsrt etc and name the header files e.g. dds/ddssec/auth.h or something instead of dds/security/dds_security_api_authentication.h.
* Reassess Jeroen's comment:
https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-494040238
> I've spent a great deal of time stripping out all the various different error codes and make it so that we simply use DDS_RETCODE_ constants everywhere. This pull request reintroduces separate error codes and that's something I really don't approve of. The security error codes start at an offset of 100 and should nicely integrate with the other codes in dds/ddsrt/retcode.h. The messages should be retrievable using dds_strretcode if you ask me.
* reassess Erik's comment
https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-490718462
> GuidPrefix & BuiltinTopicKey change
* reassess erik's comment
https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-490718462
> ddsrt_strchrs
* Reassess Jeroen's comment:
https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-494040238
> If the security_api just becomes part of ddsc, and it should in my opinion, then I'd prefer you propagate the naming scheme as introduced in ddsrt etc and name the header files e.g. dds/ddssec/auth.h or something instead of dds/security/dds_security_api_authentication.h.
* Reassess Jeroen's comment:
https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-494040238
> If the security_api just becomes part of ddsc, and it should in my opinion, then I'd prefer you propagate the naming scheme as introduced in ddsrt etc and name the header files e.g. dds/ddssec/auth.h or something instead of dds/security/dds_security_api_authentication.h.

View file

@ -0,0 +1,131 @@
# ParticipantVolatileMessageSecure Handling
## Short Introduction
It is expected to have some knowledge of DDSI builtin (security) endpoints.
```cpp
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER 0xff0202c3
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER 0xff0202c4
```
These builtin endpoints have caused about the biggest code change in ddsi, regarding security.
Chapters 7.4.4.3 and 7.4.4.4 in the DDS Security specification indicates the main issue why these builtin endpoints are different from all the others and somewhat more complex.
> 7.4.4.3 Contents of the ParticipantVolatileMessageSecure
> The ParticipantVolatileMessageSecure is intended as a holder of secure information that
> is sent point-to-point from a DomainParticipant to another.
>
> [...]
>
> 7.4.4.4 Destination of the ParticipantVolatileMessageSecure
>
> If the destination_participant_guid member is not set to GUID_UNKNOWN, the message written is
> intended only for the BuiltinParticipantVolatileMessageSecureReader belonging to the
> DomainParticipant with a matching Participant Key.
>
> This is equivalent to saying that the BuiltinParticipantVolatileMessageSecureReader has an implied
> content filter with the logical expression:
>
> “destination_participant_guid == GUID_UNKNOWN
> || destination_participant_guid==BuiltinParticipantVolatileMessageSecureReader.participant.guid”
>
> Implementations of the specification can use this content filter or some other mechanism as long as the
> resulting behavior is equivalent to having this filter.
>
> [...]
The "point-to-point" and "content filter" remarks makes everything more elaborate.
## Complexity
It would be nice to be able to use the ```dds_set_topic_filter()``` functionality for these endpoints. However, that only works on the reader history cache (rhc), which is only available for ddsc entities and not for ddsi builtin entities. And it's the builtin entities that are being used.
The ```dds_set_topic_filter()``` basically simulates that the sample was inserted into the rhc (but didn't insert it), which causes the rest of ddsi (regarding heartbeat, acknacks, gaps, etc) to work as normal while the sample just isn't provided to the reader.
Unfortunately, the builtin volatile endpoints can not use that same simple sequence (just handle the sample but ignore it right at the end). Problem is, the sample is encoded. It can only decode samples that are intended for that reader. This would mean that it is best for the reader to only receive 'owned' samples that it can actually decode.
This has all kinds of affects regarding the heartbeat, acknacks, gaps, etc. Basically, every writer/reader combination should have information regarding gaps and sequence numbers between them, while normally such information about proxies are combined.
## Implementation Overview
This only depicts an overview. Some details will have been omitted.
### Writing
The function ```write_crypto_exchange_message()``` takes care of generating the right sample information and pass it on to ```write_sample_p2p_wrlock_held()```.
A proxy reader can now have a filter callback function (```proxy_reader::filter```). This indicates (on the writer side) if a sample will be accepted by the actual reader or not. This could be made more generic for proper 'writer side' content filter implementation. However, now it'll only be used by ParticipantVolatileMessageSecure and the filter is hardcoded to ```volatile_secure_data_filter()```.
So, if ```write_sample_p2p_wrlock_held()``` is called with a proxy reader with a filter, it will get 'send/acked sequences' information between the writer and proxy reader. This is used to determine if gap information has to be send alongside the sample.
Then, ```write_sample_p2p_wrlock_held()``` will enqueue the sample.
Just before the submessage is added to the rtps message and send, it is encoded (todo).
### Reading
First things first, the submessage is decoded when the rtps message is received (todo).
It is received on a builtin reader, so the builtin queue is used and ```builtins_dqueue_handler()``` is called. That will forward the sample to the token exchange functionality, ignoring every sample that isn't related to the related participant (todo).
### Gaps on reader side
The reader remembers the last_seq it knows from every connected proxy writer (```pwr_rd_match::last_seq```).
This is updated when handling heartbeats, gaps and regular messages and used to check if there are gaps.
Normally, the ```last_seq``` of a specific writer is used here. But when the reader knows that the writer uses a 'writer side content filter' (```proxy_writer::uses_filter```), it'll use the the ```last_seq``` that is related to the actual reader/writer match.
It is used to generate the AckNack (which contains gap information) response to the writer.
### Gaps on writer side
The writer remembers which sample sequence it send the last to a specific reader through ```wr_prd_match::lst_seq```.
This is used to determine if a reader has received all relevant samples (through handling of acknack).
It is also used to determine the gap information that is added to samples to a specific reader when necessary.
### Heartbeats
A writer is triggered to send heartbeats once in a while. Normally, that is broadcasted. But, for the volatile secure writer, it has to be send to each reader specifically. The heartbeat submessage that is send to each reader individually is encoded with a reader specific key. This key is generated from the shared secret which was determined during the authentication phase.
When a writer should send heartbeats, ```handle_xevk_heartbeat()``` is called. For the volatile secure writer, the control is immediately submitted to ```send_heartbeat_to_all_readers()```. This will add heartbeat submessages to an rtps message for every reader it deems necessary.
### Reorder
Normally received samples are placed in the reorder administration of the proxy_writer. However in this case the writer applies a content filter which is specific for each destinated reader. In that case the common reorder administration in the proxy_writer can not be used and the reader specific reorder administration must be used to handle the gap's which will be reader specific.
</br>
</br>
</br>
=================================================</br>
Notes</br>
=================================================</br>
### Trying to put the security participant volatile endpoint implementation into context.
The following elements are added to the data structures:
* struct wr_prd_match::lst_seq : Highest seq send to this reader used when filter is applied
* struct pwr_rd_match::last_seq : Reader specific last received sequence number from the writer.
* struct proxy_writer::uses_filter : Indicates that a content-filter is active
* struct proxy_reader::filter : The filter to apply for this specific reader
Functions added:
* writer_hbcontrol_p2p : This function creates a heartbeat destined for a specific reader. The volatile secure writer will use an submessage encoding which uses a distinct key for each reader. Therefor a reader specific heartbeat is needed.
* nn_defrag_prune : When a volatile secure reader is deleted then the defragmentation administration could still contain messages destined for this reader. This function removes these messages from the defragmentation administration.
* volatile_secure_data_filter : The filter applied to the secure volatile messages which filters on the destination participant guid.
* write_sample_p2p_wrlock_held : This function writes a message to a particular reader.
The use of the content-filter for the volatile secure writer implies that for each destination reader which message from the writer history cache is valid and had to be sent.
For messages that do not match this filter a GAP message should be sent to the reader. Each time a message is sent to a specific reader a possible gap message is added.
For the volatile secure writer the sequence number of the last message send to a particular reader is maintained in ```wr_prd_match::lst_seq'''. It is used to determine if a
HEARTBEAT has to send to this particular reader or that the reader has acknowledged all messages. At the reader side the sequence number of the last received message is
maintained in ```pwr_rd_match::last_seq'''. It is used to determine the contents of the ACKNACK message as response to a received HEARTBEAT.
When an ACKNACK (handle_AckNack) is received it is determined which samples should be resent related to the applied filter and for which sequence numbers a GAP message should be sent.

View file

@ -486,6 +486,7 @@ sub read_config {
'DDSI_INCLUDE_SSL' => 1, 'DDSI_INCLUDE_SSL' => 1,
'DDSI_INCLUDE_NETWORK_PARTITIONS' => 1, 'DDSI_INCLUDE_NETWORK_PARTITIONS' => 1,
'DDSI_INCLUDE_SSM' => 1, 'DDSI_INCLUDE_SSM' => 1,
'DDSI_INCLUDE_SECURITY' => 1,
# excluded options # excluded options
'DDSI_INCLUDE_NETWORK_CHANNELS' => 0, 'DDSI_INCLUDE_NETWORK_CHANNELS' => 0,
'DDSI_INCLUDE_BANDWIDTH_LIMITING' => 0); 'DDSI_INCLUDE_BANDWIDTH_LIMITING' => 0);
@ -625,7 +626,7 @@ sub read_config {
# skip reference to internal name (either ABSOFF(field), # skip reference to internal name (either ABSOFF(field),
# RELOFF(field,field) or <int>,<int> (the latter being used by # RELOFF(field,field) or <int>,<int> (the latter being used by
# "verbosity") # "verbosity")
$rest =~ s/(ABSOFF *\( *[A-Za-z_0-9.]+ *\)|RELOFF *\( *[A-Za-z_0-9.]+ *, *[A-Za-z_0-9]+ *\)|[0-9]+ *, *[0-9]+) *, *//; $rest =~ s/(ABSOFF *\( *[A-Za-z_0-9.]+ *\)|RELOFF *\( *[A-Za-z_0-9.]+ *, *[A-Za-z_0-9. ]+\)|[0-9]+ *, *[0-9]+) *, *//;
# skip init function # skip init function
$rest =~ s/([A-Za-z_0-9]+|0) *, *//; $rest =~ s/([A-Za-z_0-9]+|0) *, *//;
# type hint from conversion function # type hint from conversion function

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding=\"utf-8\"?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://www.omg.org/spec/DDS-SECURITY/20170901/omg_shared_ca_governance.xsd">
<domain_access_rules>
<domain_rule>
<domains>
<id_range>
<min>0</min>
<max>230</max>
</id_range>
</domains>
<allow_unauthenticated_participants>false</allow_unauthenticated_participants>
<enable_join_access_control>true</enable_join_access_control>
<discovery_protection_kind>NONE</discovery_protection_kind>
<liveliness_protection_kind>NONE</liveliness_protection_kind>
<rtps_protection_kind>NONE</rtps_protection_kind>
<topic_access_rules>
<topic_rule>
<topic_expression>*</topic_expression>
<enable_discovery_protection>true</enable_discovery_protection>
<enable_liveliness_protection>true</enable_liveliness_protection>
<enable_read_access_control>true</enable_read_access_control>
<enable_write_access_control>true</enable_write_access_control>
<metadata_protection_kind>SIGN</metadata_protection_kind>
<data_protection_kind>ENCRYPT</data_protection_kind>
</topic_rule>
</topic_access_rules>
</domain_rule>
</domain_access_rules>
</dds>

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://www.omg.org/spec/DDS-SECURITY/20170901/omg_shared_ca_permissions.xsd">
<permissions>
<grant name="default_permissions">
<subject_name>emailAddress=alice@cycloneddssecurity.adlinktech.com,CN=Alice Example,O=Example Organization,OU=Organizational Unit Name,L=Locality Name,ST=OV,C=NL</subject_name>
<validity>
<!-- Format is CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] in GMT -->
<not_before>2020-01-01T01:00:00</not_before>
<not_after>2120-01-01T01:00:00</not_after>
</validity>
<allow_rule>
<domains>
<id_range>
<min>0</min>
<max>230</max>
</id_range>
</domains>
<publish>
<topics>
<topic>*</topic>
</topics>
<partitions>
<partition>*</partition>
</partitions>
</publish>
<subscribe>
<topics>
<topic>*</topic>
</topics>
<partitions>
<partition>*</partition>
</partitions>
</subscribe>
</allow_rule>
<default>DENY</default>
</grant>
</permissions>
</dds>

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,19 @@
<Domain id="any">
<DDSSecurity>
<Authentication>
<Library initFunction="init_authentication" finalizeFunction="finalize_authentication" path="dds_security_auth"/>
<IdentityCA>file:/path/to/example_id_ca_cert.pem</IdentityCA>
<IdentityCertificate>file:/path/to/example_alice_cert.pem</IdentityCertificate>
<PrivateKey>file:/path/to/example_alice_priv_key.pem</PrivateKey>
</Authentication>
<Cryptographic>
<Library initFunction="init_crypto" finalizeFunction="finalize_crypto" path="dds_security_crypto"/>
</Cryptographic>
<AccessControl>
<Library initFunction="init_access_control" finalizeFunction="finalize_access_control" path="dds_security_ac"/>
<PermissionsCA>file:/path/to/example_perm_ca_cert.pem</PermissionsCA>
<Governance>file:/path/to/example_governance.p7s</Governance>
<Permissions>file:/path/to/example_permissions.p7s</Permissions>
</AccessControl>
</DDSSecurity>
</Domain>

View file

@ -0,0 +1,21 @@
dds_qos_t * qos = dds_create_qos();
dds_qset_prop(qos, "dds.sec.auth.library.path", "dds_security_auth");
dds_qset_prop(qos, "dds.sec.auth.library.init", "init_authentication");
dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_authentication");
dds_qset_prop(qos, "dds.sec.auth.identity_ca", "file:/path/to/example_id_ca_cert.pem");
dds_qset_prop(qos, "dds.sec.auth.private_key", "file:/path/to/example_alice_priv_key.pem");
dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "file:/path/to/example_alice_cert.pem");
dds_qset_prop(qos, "dds.sec.crypto.library.path", "dds_security_crypto");
dds_qset_prop(qos, "dds.sec.crypto.library.init", "init_crypto");
dds_qset_prop(qos, "dds.sec.crypto.library.finalize", "finalize_crypto");
dds_qset_prop(qos, "dds.sec.access.library.path", "dds_security_ac");
dds_qset_prop(qos, "dds.sec.access.library.init", "init_access_control");
dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_access_control");
dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:/path/to/example_perm_ca_cert.pem");
dds_qset_prop(qos, "dds.sec.access.governance", "file:/path/to/example_governance.p7s");
dds_qset_prop(qos, "dds.sec.access.permissions", "file:/path/to/example_permissions.p7s");
dds_entity_t participant = dds_create_participant(0, qos, NULL);

View file

@ -21,6 +21,7 @@ Welcome to Eclipse Cyclone DDS's documentation!
GettingStartedGuide/index GettingStartedGuide/index
ddsc ddsc
config config
security
Indices and tables Indices and tables
================== ==================

View file

@ -8,7 +8,7 @@ CycloneDDS configuration
## //CycloneDDS/Domain ## //CycloneDDS/Domain
Attributes: [Id](#cycloneddsdomainid) 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. The General element specifying Domain related settings.
@ -100,8 +100,370 @@ The default setting is "lax".
The default value 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
Text
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>
The default value is: "".
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library
Attributes: [finalizeFunction](#cycloneddsdomainddssecurityaccesscontrollibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecurityaccesscontrollibraryinitfunction), [path](#cycloneddsdomainddssecurityaccesscontrollibrarypath)
This element specifies the library to be loaded as the DDS Security
Access Control plugin.
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library[@finalizeFunction]
Text
This element names the finalization function of Access Control plugin.
This function is called to let the plugin release its resources.
The default value is: "finalize_access_control".
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library[@initFunction]
Text
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.
The default value is: "init_access_control".
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library[@path]
Text
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.
The default value is: "dds_security_ac".
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Permissions
Text
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>
The default value is: "".
##### //CycloneDDS/Domain/DDSSecurity/AccessControl/PermissionsCA
Text
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>
The default value is: "".
#### //CycloneDDS/Domain/DDSSecurity/Authentication
Children: [IdentityCA](#cycloneddsdomainddssecurityauthenticationidentityca), [IdentityCertificate](#cycloneddsdomainddssecurityauthenticationidentitycertificate), [IncludeOptionalFields](#cycloneddsdomainddssecurityauthenticationincludeoptionalfields), [Library](#cycloneddsdomainddssecurityauthenticationlibrary), [Password](#cycloneddsdomainddssecurityauthenticationpassword), [PrivateKey](#cycloneddsdomainddssecurityauthenticationprivatekey), [TrustedCADirectory](#cycloneddsdomainddssecurityauthenticationtrustedcadirectory)
This element configures the Authentication plugin of the DDS Security
specification.
##### //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCA
Text
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
Text
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/IncludeOptionalFields
Boolean
The authentication handshake tokens may contain optional fields to be
included for finding interoperability problems.
If this parameter is set to true the optional fields are included in the
handshake token exchange.
The default value is: "false".
##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library
Attributes: [finalizeFunction](#cycloneddsdomainddssecurityauthenticationlibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecurityauthenticationlibraryinitfunction), [path](#cycloneddsdomainddssecurityauthenticationlibrarypath)
This element specifies the library to be loaded as the DDS Security
Access Control plugin.
##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library[@finalizeFunction]
Text
This element names the finalization function of Authentication plugin.
This function is called to let the plugin release its resources.
The default value is: "finalize_authentication".
##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library[@initFunction]
Text
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.
The default value is: "init_authentication".
##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library[@path]
Text
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.
The default value is: "dds_security_auth".
##### //CycloneDDS/Domain/DDSSecurity/Authentication/Password
Text
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.
The default value is: "".
##### //CycloneDDS/Domain/DDSSecurity/Authentication/PrivateKey
Text
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
Text
Trusted CA Directory which contains trusted CA certificates as separated
files.
The default value is: "".
#### //CycloneDDS/Domain/DDSSecurity/Cryptographic
Children: [Library](#cycloneddsdomainddssecuritycryptographiclibrary)
This element configures the Cryptographic plugin of the DDS Security
specification.
##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library
Attributes: [finalizeFunction](#cycloneddsdomainddssecuritycryptographiclibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecuritycryptographiclibraryinitfunction), [path](#cycloneddsdomainddssecuritycryptographiclibrarypath)
This element specifies the library to be loaded as the DDS Security
Cryptographic plugin.
##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library[@finalizeFunction]
Text
This element names the finalization function of Cryptographic plugin.
This function is called to let the plugin release its resources.
The default value is: "finalize_crypto".
##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library[@initFunction]
Text
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.
The default value is: "init_crypto".
##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library[@path]
Text
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.
The default value is: "dds_security_crypto".
### //CycloneDDS/Domain/Discovery ### //CycloneDDS/Domain/Discovery
Children: [DSGracePeriod](#cycloneddsdomaindiscoverydsgraceperiod), [DefaultMulticastAddress](#cycloneddsdomaindiscoverydefaultmulticastaddress), [EnableTopicDiscovery](#cycloneddsdomaindiscoveryenabletopicdiscovery), [ExternalDomainId](#cycloneddsdomaindiscoveryexternaldomainid), [MaxAutoParticipantIndex](#cycloneddsdomaindiscoverymaxautoparticipantindex), [ParticipantIndex](#cycloneddsdomaindiscoveryparticipantindex), [Peers](#cycloneddsdomaindiscoverypeers), [Ports](#cycloneddsdomaindiscoveryports), [SPDPInterval](#cycloneddsdomaindiscoveryspdpinterval), [SPDPMulticastAddress](#cycloneddsdomaindiscoveryspdpmulticastaddress), [Tag](#cycloneddsdomaindiscoverytag) Children: [DSGracePeriod](#cycloneddsdomaindiscoverydsgraceperiod), [DefaultMulticastAddress](#cycloneddsdomaindiscoverydefaultmulticastaddress), [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 The Discovery element allows specifying various parameters related to the
@ -132,14 +494,6 @@ Discovery/SPDPMulticastAddress.
The default value is: "auto". The default value is: "auto".
#### //CycloneDDS/Domain/Discovery/EnableTopicDiscovery
Boolean
Do not use.
The default value is: "true".
#### //CycloneDDS/Domain/Discovery/ExternalDomainId #### //CycloneDDS/Domain/Discovery/ExternalDomainId
Text Text
@ -995,7 +1349,7 @@ is therefore recommended to set it to at least several seconds.
Valid values are finite durations with an explicit unit or the keyword Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day. 'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.
The default value is: "10s". The default value is: "0s".
#### //CycloneDDS/Domain/Internal/RediscoveryBlacklistDuration[@enforce] #### //CycloneDDS/Domain/Internal/RediscoveryBlacklistDuration[@enforce]
@ -1646,6 +2000,8 @@ threads exist:
* tev: general timed-event handling, retransmits and discovery; * tev: general timed-event handling, retransmits and discovery;
* fsm: finite state machine thread for handling security handshake;
* xmit.CHAN: transmit thread for channel CHAN; * xmit.CHAN: transmit thread for channel CHAN;
* dq.CHAN: delivery thread for channel CHAN; * dq.CHAN: delivery thread for channel CHAN;

801
docs/manual/security.rst Normal file
View file

@ -0,0 +1,801 @@
.. _`DDS Security`:
############
DDS Security
############
CycloneDDS is compliant with The Object Management Group (OMG) DDS Security specification.
This specification defines the Security Model and Service Plugin Interface (SPI) architecture for
compliant DDS implementations. The DDS Security Model is enforced by the invocation of these SPIs
by the DDS implementation.
.. image:: ./_static/pictures/dds_security_overview.png
:width: 1000
The three plugins that comprise the DDS Security Model in CycloneDDS are:
**Authentication Service Plugin**
Provides the means to verify the identity of the application and/or user that invokes operations
on DDS. Includes facilities to perform mutual authentication between participants and establish
a shared secret.
**AccessControl Service Plugin**
Provides the means to enforce policy decisions on what DDS related operations an authenticated
user can perform. For example, which domains it can join, which Topics it can publish or
subscribe to, etc.
**Cryptographic Service Plugin**
Implements (or interfaces with libraries that implement) all cryptographic operations including
encryption, decryption, hashing, digital signatures, etc. This includes the means to derive keys
from a shared secret.
----
CycloneDDS provides built-in implementations of these plugins. Authentication uses PKI
(Public Key Infrastructure) with a pre-configured shared Certificate Authority, RSA is used for
authentication and Diffie-Hellman is used for key exchange. AccessControl use Permissions document
signed by shared Certificate Authority. Cryptography uses AES-GCM (AES using Galois Counter Mode)
for encryption and AES-GMAC for message authentication.
Security plugins are dynamically loaded where the locations are defined in CycloneDDS
configuration or Participant QoS settings.
*******************************************************
Brief information about PKI (public key infrastructure)
*******************************************************
The comprehensive system required to provide public-key encryption and digital signature services
is known as a public-key infrastructure (PKI). The purpose of a PKI is to manage keys and
certificates. By managing keys and certificates through a PKI, an organization establishes and
maintains a trustworthy networking environment.
Public Key Cryptography: Each user has a key pair, generated during the initial certificate
deployment process, that is comprised of a public key, which is shared, and a private key, which
is not shared. Data is encrypted with the users public key and decrypted with their private key.
Digital signatures, used for non-repudiation, authentication and data integrity, are also generated
using public key cryptography.
**Identity Certificate**
This is an electronic document used to prove the ownership of a public key. The certificate
includes information about the key, information about the identity of its owner (called the
subject), and the digital signature of an entity that has verified the certificate's contents
(called the issuer). If the signature is valid, and the software examining the certificate
trusts the issuer, then it can use that key to communicate securely with the certificate's
subject.
**Certificate Authority**
This issues user certificates and acts as the chief agent of trust. When issuing a certificate
to a user, the CA signs the certificate with its private key in order to validate it. During
electronic transactions the CA also confirms that certificates are still valid. Certificates
may be revoked for various reasons. For example, a user may leave the organization or they may
forget their secret passphrase, the certificate may expire or become corrupt. This process is
usually accomplished through the use of a Certificate Revocation List (CRL) which is a list of
the certificates that have been revoked. Only the certificates that have been revoked appear on
this list.
**Subject of Identity Certificate**
This is the identity to be secured. It contains information such as common name (CN),
organization (OU), state (ST) and country (C).
**Subject Name**
This is aka distinguished name and is the string representation of certificate subject.
ie: emailAddress=alice\@adlink.ist,CN=Alice,OU=IST,O=ADLink,ST=OV,C=NL
*************************
PKI Usage in DDS Security
*************************
.. image:: ./_static/pictures/pki_overview.png
:width: 1000
Alice and Bob are the DDS participants who have their private and public keys. Identitity
Certificate Authority (ID CA) has its own self-signed certificate (IdentityCA in the diagram).
ID CA gets Alice's subject information and public key and generates an IdentityCertificate for her.
Alice's certificate includes her public key and certificate of ID CA; so that her certificate can
be verified if it is really issued by ID CA.
Access Control is configured with governance and permissions files. Governance file defines the
security behavior of domains and topics. Permissions file contains the permissions of the domain
participant, topics, readers and writers, binds them to identity certificate by subject name
(distinguished name).
Governance files and Permissions files are signed by Permission CA. Signed documents also
contains Permissions CA certificate; so that they can be verified if they are really issued
by Permissions CA.
Authenticated participants perform a handshake with each other and generate a shared key by
Diffie-Hellman key exchange. This shared key is used for encrypting/decrypting data with AES.
During the handshake Alice checks Bob's certificate and Bob's Permissions file if they are really
issued by the ID CA certificate and Permissions CA Certificate that **she** has. Also Bob checks
Alice's certificate and Alice's Permissions file if they are really issued by the ID CA certificate
and Permissions CA that **he** has.
Permissions files can contain permissions for several identities; so subject name of identity
certificate exist in permissions file to establish a binding between identity and its permissions.
There are several ways to set up the certificates and signed configuration files to be used with
Cyclone DDS Security. One of them is using OpenSSL, which is described in section
`Creating certificates using OpenSSL`_.
*************
Configuration
*************
.. image:: ./_static/pictures/dds_security_configuration_overview.png
:width: 1000
The configuration of DDS Security is split up into two parts.
- `Plugins Configuration`_
- `Access Control Configuration`_
Plugins Configuration
*********************
CycloneDDS gets the security configuration from XML configuration elements or from
the participant QoS policies as stated in the DDS Security specification.
This behavior allows applications to use DDS Security without recompiling the binaries.
Only supplying a new configuration with DDS Security enabled is enough to switch from a
non-secure to a secure deployment. The configuration is at domain level, which means
that all participants created for that domain receive the same DDS security settings.
The configuration options for a domain are bundled in the ``DDSSecurity`` configuration
section in the CycloneDDS configuration. Every DDS Security plugin has its own configuration
sub-section.
.. _`Authentication Properties`:
=========================
Authentication Properties
=========================
To enable authentication for a node, it has to be configured with an identity certificate
(``DDSSecurity/Authentication/IdentityCertificate``). This identity certificate is used to
authenticate all participants of that particular CycloneDDS domain. Associated with the
identity certificate is the corresponding private key
(``DDSSecurity/Authentication/PrivateKey``). The private key may either be a 2048-bit RSA
or a 256-bit Elliptic Curve Key with a prime256v1 curve.
The certificate of identity CA, which is the issuer of the node's identity certificate,
is configured in ``DDSSecurity/Authentication/IdentityCA``. The public key of the
identity CA (as part of its certificate) shall either be a 2048-bit RSA key or a 256-bit
Elliptic Curve Key for the prime256v1 curve. The identity CA certificate can be a
self-signed certificate.
The identity certificate, private key and the identity CA should be a X509 document in PEM
format. It may either be specified directly in the configuration file (as CDATA, prefixed
with ``data:,``) or the configuration file should contain a reference to a corresponding
file (prefixed with ``file:``).
Optionally the private key could be protected by a password
(``DDSSecurity/Authentication/Password``).
Furthermore the CycloneDDS configuration allows configuring a directory containing additional
identity CA's which are used to verify the identity certificates that are received from remote instances
(``DDSSecurity/Authentication/TrustedCADirectory``). This option allows multiple identity
CAs throughout the system.
.. _`Access Control Properties`:
=========================
Access Control Properties
=========================
A governance document (``DDSSecurity/AccessControl/Governance``), a permissions document
(``DDSSecurity/AccessControl/Permissions``) and the permissions CA certificate
(``DDSSecurity/AccessControl/PermissionsCA``) are required for the access control plugin.
Similar to the authentication plugin properties, these values can be provided as CDATA or
by using a path to a file.
.. _`Cryptography Properties`:
=======================
Cryptography Properties
=======================
The cryptography plugin has no properties in the configuration.
.. _`Access Control Configuration`:
Access Control Configuration
****************************
Access Control configuration consists of Governance document and Permissions document.
Both governance and permissions files must be signed by the Permissions CA in S/MIME format.
Participants use their own permissions CA to validate remote permissions. So, all permissions CA
Certificates must be the same for all participants.
The signed document should use S/MIME version 3.2 format as defined in IETF RFC 5761 using
SignedData Content Type (section 2.4.2 of IETF RFC 5761) formatted as multipart/signed (section
3.4.3 of IETF RFC 5761). This corresponds to the mime-type application/pkcs7-signature.
Additionally the signer certificate should be be included within the signature.
===================
Governance Document
===================
The Governance document defines the security behavior of domains and topics. It is an XML document
and its format is specified in OMG DDS Security Version 1.1 Section 9.4.1.2.3.
This section describes the properties that can be specified in a permissions document. An example
of a governance document is provided in `Create a signed governance document`_. The options
that are specified in Governance document must match with the remote node to establishing
communication.
Protection Kinds
================
The domain governance document provides a means for the application to configure the kinds of
cryptographic transformation applied to the complete RTPS Message, certain RTPS SubMessages, and
the SerializedPayload RTPS submessage element that appears within the Data.
.. image:: ./_static/pictures/rtps_message_structure.png
:width: 300
The configuration allows specification of five protection levels: NONE, SIGN, ENCRYPT,
SIGN_WITH_ORIGIN_AUTHENTICATION and ENCRYPT_WITH_ORIGIN_AUTHENTICATION.
**NONE**
indicates no cryptographic transformation is applied.
**SIGN**
indicates the cryptographic transformation shall be purely a message authentication code (MAC),
that is, no encryption is performed.
**ENCRYPT**
indicates the cryptographic transformation shall be an encryption followed by a message
authentication code (MAC) computed on the ciphertext, also known as Encrypt-then-MAC.
**SIGN_WITH_ORIGIN_AUTHENTICATION**
indicates the cryptographic transformation shall be purely a set of message authentication codes
(MAC), that is, no encryption is performed. This cryptographic transformation shall create a
first “common authenticationcode” similar to the case where Protection Kind is SIGN. In addition
the cryptographic transformation shall create additional authentication codes, each produced with
a different secret key. The additional MACs prove to the receiver that the sender originated the
message, preventing other receivers from impersonating the sender.
**ENCRYPT_WITH_ORIGIN_AUTHENTICATION**
indicates the cryptographic transformation shall be an encryption followed by a message
authentication code (MAC) computed on the ciphertext, followed by additional authentication
codes, Each of the additional authentication codes shall use a different secret key. The
encryption and first (common) authentication code is similar to ones produced when the Protection
Kind is ENCRYPT. The additional authentication codes are similar to the ones produced when the
Protection Kind is SIGN_WITH_ORIGIN_AUTHENTICATION.
Participant attributes
======================
**Allow Unauthenticated Participants**
This is used for allowing communication with non-secure participants. If this option is enabled,
secure participant can communicate with non-secure participant by only non-protected topics.
**Enable Join Access Control**
If this option is enabled, remote participant permissions are checked if its subject name is
allowed to create a topic anyhow.
**Discovery Protection Kind**
Protection attribute for discovery communication when it is enabled for topic. Please see the
DDS Security specification document for available options.
**Liveliness Protection Kind**
Protection attribute for liveliness communication when it is enabled for topic. Please see the
DDS Security specification document for available options.
**RTPS Protection Kind**
Protection attribute for all messages on the wire. Please see the DDS Security specification
document for available options. If encryption is selected for RTPS, there is no need to encrypt
submessages (metadata_protection_kind) and payloads (data_protection_kind) which are defined in
topic settings.
Topic Attributes
================
**Enable Discovery protection:**
If enabled, discovery is protected according to Discovery Protection Kind attribute of
corresponding participant.
**Enable Liveliness protection:**
If enabled, liveliness is protected according to Liveliness Protection Kind attribute of
corresponding participant.
**Enable Read Access Control:**
If enabled, the permissions document is checked if the participant is allowed to create
a datareader for the related topic.
**Enable Write Access Control:**
If enabled, the permissions document is checked if the participant is allowed to create
a datawriter for the related topic.
**Metadata protection Kind:**
Protection attribute for submessages.
**Data protection Kind:**
Protection attribute for data payload.
There are different settings for different domain ranges. The domain rules are evaluated in the
same order as they appear in the document. A rule only applies to a particular DomainParticipant
if the domain Section matches the DDS domain_id to which the participant belongs. If multiple
rules match, the first rule that matches is the only one that applies.
The topic access rules are evaluated in the same order as they appear within the
<topic_access_rules> Section. If multiple rules match the first rule that matches is the only one
that applies.
fnmatch pattern matching can be used for topic expressions including the following patterns
.. _`fnmatch pattern matching`:
+----------+----------------------------------+
|Pattern |Meaning |
+==========+==================================+
| \* | matches everything |
+----------+----------------------------------+
| \? | matches any single character |
+----------+----------------------------------+
| [seq] | matches any character in seq |
+----------+----------------------------------+
| [!seq] | matches any character not in seq |
+----------+----------------------------------+
====================
Permissions Document
====================
The permissions document is an XML document containing the permissions of the domain participant
and binding them to the subject name of the DomainParticipant as defined in the identity
certificate. Its format is specified in OMG DDS Security Version 1.1 Section 9.4.1.3.
This section describes the properties that can be specified in a permissions document. An example
of a permissions document is provided in `Creating a signed permissions document`_.
Validity period
===============
It is checked before creating participant. Validity period is also checked during handshake with
remote participant; expired remote permissions document prevents communications to be established.
Subject Name
============
The subject name must match with Identity Certificate subject. It is checked during create
participant and during handshake with remote participant. Use the following openssl command to get
subject name from identity certificate:
``openssl x509 -noout -subject -nameopt RFC2253 -in <identity_certificate_file.pem>``
Rules
=====
Participant permissions are defined by set of rules. The rules are applied in the same order
that appear in the document. If the criteria for the rule matches the domain_id join and/or publish
or subscribe operation that is being attempted, then the allow or deny decision is applied.
If the criteria for a rule does not match the operation being attempted, the evaluation
shall proceed to the next rule. If all rules have been examined without a match, then the
decision specified by the “default” rule is applied. The default rule, if present, must
appear after all allow and deny rules. If the default rule is not present, the
implied default decision is DENY. The matching criteria for each rule specify the domain_id,
topics (published and subscribed), the partitions (published and subscribed), and the data-tags
associated with the DataWriter and DataReader.
For the grant to match there shall be a match of the topics, partitions, and data-tags criteria.
This is interpreted as an AND of each of the criteria. For a specific criterion to match
(e.g., <topics>) it is enough that one of the topic expressions listed matches (i.e., an OR of
the expressions with the <topics> section).
`fnmatch pattern matching`_ can be used for topic expressions and partition expressions.
Logging and tracing
*******************
The security implementation uses the standard logging and tracing mechanism in CycloneDDS.
The following is written to log and trace:
- Configuration errors such as plugin library files, certificate files, governance and permissions
files that can not be found on filesystem.
- Permission errors such as denied permission for creating writer of a topic.
- Attribute mismatch errors such as mismatches of security attributes between participants, topics,
readers and writers.
- Integrity errors such as Permissions file-Permissions CA and Identity Cert-Identity CA integrity.
Local subscription, publication and topic permission errors are written as errors.
Remote participation, subscription and publication permission errors are written to log as
warning messages.
Data Communication And Handshake Process
****************************************
Authentication handshake between participants starts after participant discovery. If a reader and
a writer created during that period, their match will be delayed until after the handshake succeeds.
This means, during the handshake process, volatile data will be lost, just like there is no reader.
After publication match, the encryption / decryption keys are exchanged between reader and writer.
Best-effort data that are sent during this exchange will be lost, however reliable data will be
resent.
DDS Secure Discovery
********************
Just like normal operation, Cyclone DDS discovers remote participants, topics, readers and writers.
However, when DDS Security is enabled, it is more complex and will take a longer time (due to the
handshaking that is required). The effort to perform discovery grows quadratically in the number of
nodes. This can become a problem if the system contains a number of slow platforms or is large.
Proprietary builtin endpoints
*****************************
The DDS standard contains some builtin endpoints. A few are added by the DDS Security
specification. The behaviour of all these builtin endpoints are specified (and thus are be
handled by the plugins that implement the DDS Security specification), meaning that they
don't have to be present in the Governance or Permissions documents and the users don't
have to be bothered with them.
A few of these builtin endpoints slave according to the <discovery_protection_kind> within
the Governance document. In short, related submessages are protected according to the value
of <discovery_protection_kind>. This protects meta information that is send during the
discovery phase.
*******************
DataTag Permissions
*******************
Data Tags provide an extra (optional) level of identification. This can mean f.i. that
a certain reader is not allowed to read data from writer A but it is allowed to read from
writer B (all the same topic).
This optional feature is not yet supported.
.. _`Example configuration`:
*********************
Example configuration
*********************
This sections show an example configuration for DDS Security in Cyclone DDS. First step is
creating the required CA and identity certificates. Then a governance and permissions document
is created to configure access control. Next an example configuration (XML) that
is using these assets is shown, and a code fragment that shows how to set the security
properties by using the participant QoS.
.. _`Creating certificates using OpenSSL`:
Creating certificates using OpenSSL
***********************************
This section describes how to generate a set of CA and identity certificates using OpenSSL,
and how to use OpenSSL to sign the governance and access control configuration files.
First step is generation of the CA for identity management (authentication). First we create the
private key for the CA by:
.. code-block:: bash
openssl genrsa -out example_id_ca_priv_key.pem 2048
Next we can generate the certificate for the identity CA (which is in this case a self-signed
certificate):
.. code-block:: bash
openssl req -x509 -key example_id_ca_priv_key.pem -out example_id_ca_cert.pem -days 3650 -subj "/C=NL/ST=OV/L=Locality Name/OU=Example OU/O=Example ID CA Organization/CN=Example ID CA/emailAddress=authority@cycloneddssecurity.adlinktech.com"
We repeat these steps for generating the private key of the permissions CA (used for
signing the AccessControl configiguration files):
.. code-block:: bash
openssl genrsa -out example_perm_ca_priv_key.pem 2048
And the self-signed certificate for the permissions CA:
.. code-block:: bash
openssl req -x509 -key example_perm_ca_priv_key.pem -out example_perm_ca_cert.pem -days 3650 -subj "/C=NL/ST=OV/L=Locality Name/OU=Example OU/O=Example CA Organization/CN=Example Permissions CA/emailAddress=authority@cycloneddssecurity.adlinktech.com"
==============================
Create an Identity Certificate
==============================
Now that we have set up the CA for identity management, we can create an identity certificate
signed by this CA and the private key corresponding to this identity. Here we are creating
a private key and certificate for identity named Alice. These steps need to be repeated for each
identity in the system.
Generating the private key for Alice's identity:
.. code-block:: bash
openssl genrsa -out example_alice_priv_key.pem 2048
Now we create a 'certificate signing request' (CSR) to request the identity CA to generate a certificate:
.. code-block:: bash
openssl req -new -key example_alice_priv_key.pem -out example_alice.csr -subj "/C=NL/ST=OV/L=Locality Name/OU=Organizational Unit Name/O=Example Organization/CN=Alice Example/emailAddress=alice@cycloneddssecurity.adlinktech.com"
Next Alice's identity certificate is created:
.. code-block:: bash
openssl x509 -req -CA example_id_ca_cert.pem -CAkey example_id_ca_priv_key.pem -CAcreateserial -days 3650 -in example_alice.csr -out example_alice_cert.pem
Now the file 'example_alice_cert.pem' can be used as ``IdentityCertificate`` in the DDS Security
authentication configuration and 'example_alice_priv_key.pem' for the ``PrivateKey`` setting. The
certificate of the CA used for signing this identity, 'example_id_ca_cert.pem' in this example,
should be used for the ``IdentityCA`` configuration setting.
.. _`Create a signed governance document`:
===================================
Create a signed governance document
===================================
An example of a governance document that is using signing for submessage and encrypted payload:
.. literalinclude:: _static/example_governance.xml
:linenos:
:language: xml
As mentioned before, the governance document needs to be signed by the permissions CA
that was created above. This can be done by using this openssl command:
.. code-block:: bash
openssl smime -sign -in example_governance.xml -text -out example_governance.p7s -signer example_perm_ca_cert.pem -inkey example_perm_ca_priv_key.pem
.. _`Creating a signed permissions document`:
======================================
Creating a signed permissions document
======================================
The permissions document is an XML document that contains the permissions of the participant and
binds them to the subject name of the identity certificate (distinguished name) for the participant
as defined in the DDS:Auth:PKI-DH authentication plugin.
An example of a permissions document:
.. literalinclude:: _static/example_permissions.xml
:linenos:
:language: xml
This document also needs to be signed by the permissions CA:
.. code-block:: bash
openssl smime -sign -in example_permissions.xml -text -out example_permissions.p7s -signer example_perm_ca_cert.pem -inkey example_perm_ca_priv_key.pem
Example DDS Security configuration
**********************************
With the above steps we have all certificates and documents that are required when configuring
security. In the next two sections, both configuring security by properties and configuring
security by DDS configuration are covered.
======================================
Security properties in participant QoS
======================================
This code fragment shows how to set the security properties to a QoS object and use this QoS
when creating a participant:
.. literalinclude:: _static/security_by_qos.c
:linenos:
:language: c
===========================================
Configure security in Cyclone configuration
===========================================
As an alternative for using the QoS, security settings can also be applied using the CycloneDDS
configuration XML. In case both QoS and the configuration XML contain security settings, the values
from the QoS will be used and the security settings in the configuration XML are ignored.
The following XML fragment shows how to set security settings through configuration:
.. literalinclude:: _static/security_by_config.xml
:linenos:
:language: xml
To use this configuration file for an application, set the CYCLONEDDS_URI environment
variable to this config file:
.. code-block:: bash
export CYCLONEDDS_URI=/path/to/secure_config.xml
Bacause this example configuration uses the attribute ``id=any`` for the ``domain`` element, any participant
that is created (which implicitly creates a domain) in an application using this configuration gets
these security settings.
***************************
External Plugin Development
***************************
DDS Security consists of three plugins (authentication, cryptography and access control).
CycloneDDS comes with built-in security plugins that comply with OMG DDS Security specification.
The plugins are loaded in the run-time. However, you can also implement your own custom plugin by
implementing the given API according to OMG DDS Security specification.
You can implement all of the plugins or just one of them.
The followings are the key points for implementing you own plugin:
Interface
*********
Implement all plugin specific functions with exactly same prototype. Plugin specific function
interfaces are in dds_security_api_access_control.h, dds_security_api_authentication.h and
dds_security_api_cryptography.h header files accordingly.
Init and Finalize
*****************
A plugin should have an init and a finalize functions. plugin_init and plugin_finalize
interfaces are given in dds_security_api.h header file and function should be same as in
configuration file.
Init function is called once, just after the plugin is loaded. Finalize function is
called once, just before the plugin is unloaded.
Inter Plugin Communication
**************************
There is a shared object (*DDS_Security_SharedSecretHandle*) within authentication and
cryptography plugins. If you want to implement only one of them and use the builtin for the
other one, you have to get or provide the shared object properly.
*DDS_Security_SharedSecretHandle* is the integer representation of
*DDS_Security_SharedSecretHandleImpl* struct object. Cryptography plugin gets the
*DDS_Security_SharedSecretHandle* from authentication plugin and casts to
*DDS_Security_SharedSecretHandleImpl* struct. Then all needed information can be retieved
through *DDS_Security_SharedSecretHandleImpl* struct:
::
typedef struct DDS_Security_SharedSecretHandleImpl {
DDS_Security_octet* shared_secret;
DDS_Security_long shared_secret_size;
DDS_Security_octet challenge1[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE];
DDS_Security_octet challenge2[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE];
} DDS_Security_SharedSecretHandleImpl;
Error Codes
***********
Most of the plugin functions have parameter for reporting exception. The following exception
codes should be used in the reported exception data according to the situation.
dds_security_api_err.h header file contains the code and message constants.
+-------+----------------------------------------------------------------+
| Code | Message |
+=======+================================================================+
| 0 | (OK) |
+-------+----------------------------------------------------------------+
| 100 | Can not generate random data |
+-------+----------------------------------------------------------------+
| 110 | Identity empty |
+-------+----------------------------------------------------------------+
| 111 | Participant Crypto Handle empty |
+-------+----------------------------------------------------------------+
| 112 | Permission Handle empty |
+-------+----------------------------------------------------------------+
| 113 | Invalid Crypto Handle |
+-------+----------------------------------------------------------------+
| 114 | Invalid argument |
+-------+----------------------------------------------------------------+
| 115 | Invalid Crypto token |
+-------+----------------------------------------------------------------+
| 116 | Invalid parameter |
+-------+----------------------------------------------------------------+
| 117 | File could not be found, opened or is empty, path: %s |
+-------+----------------------------------------------------------------+
| 118 | Unknown or unexpected transformation kind |
+-------+----------------------------------------------------------------+
| 119 | Message cannot be authenticated, incorrect signature |
+-------+----------------------------------------------------------------+
| 120 | Can not open trusted CA directory |
+-------+----------------------------------------------------------------+
| 121 | Identity CA is not trusted |
+-------+----------------------------------------------------------------+
| 122 | Certificate start date is in the future |
+-------+----------------------------------------------------------------+
| 123 | Certificate expired |
+-------+----------------------------------------------------------------+
| 125 | Certificate authentication algorithm unknown |
+-------+----------------------------------------------------------------+
| 126 | Failed to allocate internal structure |
+-------+----------------------------------------------------------------+
| 127 | Failed to parse PKCS7 SMIME document |
+-------+----------------------------------------------------------------+
| 128 | Property is missing: (%s) |
+-------+----------------------------------------------------------------+
| 129 | Permissions document is invalid |
+-------+----------------------------------------------------------------+
| 130 | Governance document is invalid |
+-------+----------------------------------------------------------------+
| 131 | Operation is not permitted in this state |
+-------+----------------------------------------------------------------+
| 132 | Remote permissions document is not available |
+-------+----------------------------------------------------------------+
| 133 | Certificate is invalid |
+-------+----------------------------------------------------------------+
| 134 | Certificate type is not supported |
+-------+----------------------------------------------------------------+
| 135 | Governance property is required |
+-------+----------------------------------------------------------------+
| 136 | Permissions CA property is required |
+-------+----------------------------------------------------------------+
| 137 | Can not parse governance file |
+-------+----------------------------------------------------------------+
| 138 | Can not parse permissions file |
+-------+----------------------------------------------------------------+
| 139 | Could not find permissions for topic |
+-------+----------------------------------------------------------------+
| 140 | Could not find domain %d in permissions |
+-------+----------------------------------------------------------------+
| 141 | Could not find domain %d in governance |
+-------+----------------------------------------------------------------+
| 142 | Could not find %s topic attributes for domain(%d) in governance|
+-------+----------------------------------------------------------------+
| 143 | PluginClass in remote token is incompatible |
+-------+----------------------------------------------------------------+
| 144 | MajorVersion in remote token is incompatible |
+-------+----------------------------------------------------------------+
| 145 | Access denied by access control |
+-------+----------------------------------------------------------------+
| 146 | Subject name is invalid |
+-------+----------------------------------------------------------------+
| 147 | Permissions validity period expired for %s |
+-------+----------------------------------------------------------------+
| 148 | Permissions validity period has not started yet for %s |
+-------+----------------------------------------------------------------+
| 149 | Could not find valid grant in permissions |
+-------+----------------------------------------------------------------+
| 150 | Unsupported URI type: %s |
+-------+----------------------------------------------------------------+
| 151 | The payload is not aligned at 4 bytes |
+-------+----------------------------------------------------------------+
| 152 | Cannot open trusted CA directory: maximum number exceeded |
+-------+----------------------------------------------------------------+
| 200 | Undefined Error Message |
+-------+----------------------------------------------------------------+
.. EoF

View file

@ -80,7 +80,318 @@ though there is no good reason not to.</li></ul>
element StandardsConformance { element StandardsConformance {
("lax"|"strict"|"pedantic") ("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" """
<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><p>The
default value is: &quot;&quot;.</p>""" ] ]
element Governance {
text
}?
& [ a:documentation [ xml:lang="en" """
<p>This element specifies the library to be loaded as the DDS Security
Access Control plugin.</p>""" ] ]
element Library {
[ a:documentation [ xml:lang="en" """
<p>This element names the finalization function of Access Control plugin.
This function is called to let the plugin release its
resources.</p><p>The default value is:
&quot;finalize_access_control&quot;.</p>""" ] ]
attribute finalizeFunction {
text
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The default value
is: &quot;init_access_control&quot;.</p>""" ] ]
attribute initFunction {
text
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The default value is:
&quot;dds_security_ac&quot;.</p>""" ] ]
attribute path {
text
}?
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The
default value is: &quot;&quot;.</p>""" ] ]
element Permissions {
text
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The default value is:
&quot;&quot;.</p>""" ] ]
element PermissionsCA {
text
}?
}?
& [ 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" """
<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 {
text
}
& [ a:documentation [ xml:lang="en" """
<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 {
text
}
& [ a:documentation [ xml:lang="en" """
<p>The authentication handshake tokens may contain optional fields to be
included for finding interoperability problems.
If this parameter is set to true the optional fields are included in the
handshake token exchange.</p><p>The default value is:
&quot;false&quot;.</p>""" ] ]
element IncludeOptionalFields {
xsd:boolean
}?
& [ a:documentation [ xml:lang="en" """
<p>This element specifies the library to be loaded as the DDS Security
Access Control plugin.</p>""" ] ]
element Library {
[ a:documentation [ xml:lang="en" """
<p>This element names the finalization function of Authentication plugin.
This function is called to let the plugin release its
resources.</p><p>The default value is:
&quot;finalize_authentication&quot;.</p>""" ] ]
attribute finalizeFunction {
text
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The default value
is: &quot;init_authentication&quot;.</p>""" ] ]
attribute initFunction {
text
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The default value is:
&quot;dds_security_auth&quot;.</p>""" ] ]
attribute path {
text
}?
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The
default value is: &quot;&quot;.</p>""" ] ]
element Password {
text
}?
& [ a:documentation [ xml:lang="en" """
<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 {
text
}
& [ a:documentation [ xml:lang="en" """
<p>Trusted CA Directory which contains trusted CA certificates as
separated files.</p><p>The default value is: &quot;&quot;.</p>""" ] ]
element TrustedCADirectory {
text
}?
}?
& [ 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" """
<p>This element specifies the library to be loaded as the DDS Security
Cryptographic plugin.</p>""" ] ]
element Library {
[ a:documentation [ xml:lang="en" """
<p>This element names the finalization function of Cryptographic plugin.
This function is called to let the plugin release its
resources.</p><p>The default value is: &quot;finalize_crypto&quot;.</p>""" ] ]
attribute finalizeFunction {
text
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The default value
is: &quot;init_crypto&quot;.</p>""" ] ]
attribute initFunction {
text
}?
& [ a:documentation [ xml:lang="en" """
<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><p>The default value is:
&quot;dds_security_crypto&quot;.</p>""" ] ]
attribute path {
text
}?
}?
}?
}*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>The Discovery element allows specifying various parameters related to <p>The Discovery element allows specifying various parameters related to
the discovery of peers.</p>""" ] ] the discovery of peers.</p>""" ] ]
@ -106,11 +417,6 @@ Discovery/SPDPMulticastAddress.</p><p>The default value is:
text text
}? }?
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>Do not use.</p><p>The default value is: &quot;true&quot;.</p>""" ] ]
element EnableTopicDiscovery {
xsd:boolean
}?
& [ a:documentation [ xml:lang="en" """
<p>An override for the domain id, to be used in discovery and for <p>An override for the domain id, to be used in discovery and for
determining the port number mapping. This allows creating multiple determining the port number mapping. This allows creating multiple
domains in a single process while making them appear as a single domain domains in a single process while making them appear as a single domain
@ -272,7 +578,7 @@ be discovered.</p><p>The default value is: &quot;&quot;.</p>""" ] ]
element Tag { element Tag {
text text
}? }?
}? }*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>The General element specifies overall Cyclone DDS service <p>The General element specifies overall Cyclone DDS service
settings.</p>""" ] ] settings.</p>""" ] ]
@ -807,7 +1113,7 @@ is therefore recommended to set it to at least several seconds.</p>
<p>Valid values are finite durations with an explicit unit or the keyword <p>Valid values are finite durations with an explicit unit or the keyword
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, 'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.</p><p>The default value is: &quot;10s&quot;.</p>""" ] ] day.</p><p>The default value is: &quot;0s&quot;.</p>""" ] ]
element RediscoveryBlacklistDuration { element RediscoveryBlacklistDuration {
[ a:documentation [ xml:lang="en" """ [ a:documentation [ xml:lang="en" """
<p>This attribute controls whether the configured time during which <p>This attribute controls whether the configured time during which
@ -1024,7 +1330,7 @@ s, min, hr, day.</p><p>The default value is: &quot;1 s&quot;.</p>""" ] ]
element WriterLingerDuration { element WriterLingerDuration {
duration duration
}? }?
}? }*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>The Partitioning element specifies Cyclone DDS network partitions and <p>The Partitioning element specifies Cyclone DDS network partitions and
how DCPS partition/topic combinations are mapped onto the network how DCPS partition/topic combinations are mapped onto the network
@ -1114,7 +1420,7 @@ DCPSPartitionTopic attribute within this PartitionMapping element.</p>""" ] ]
} }
}* }*
}* }*
}? }*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>The SSL element allows specifying various parameters related to using <p>The SSL element allows specifying various parameters related to using
SSL/TLS for DDSI over TCP.</p>""" ] ] SSL/TLS for DDSI over TCP.</p>""" ] ]
@ -1174,7 +1480,7 @@ connecting client.</p><p>The default value is: &quot;true&quot;.</p>""" ] ]
element VerifyClient { element VerifyClient {
xsd:boolean xsd:boolean
}? }?
}? }*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>The Sizing element specifies a variety of configuration settings <p>The Sizing element specifies a variety of configuration settings
dealing with expected system sizes, buffer sizes, &c.</p>""" ] ] dealing with expected system sizes, buffer sizes, &c.</p>""" ] ]
@ -1205,7 +1511,7 @@ MiB&quot;.</p>""" ] ]
element ReceiveBufferSize { element ReceiveBufferSize {
memsize memsize
}? }?
}? }*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>The TCP element allows specifying various parameters related to <p>The TCP element allows specifying various parameters related to
running DDSI over TCP.</p>""" ] ] running DDSI over TCP.</p>""" ] ]
@ -1262,7 +1568,7 @@ s, min, hr, day.</p><p>The default value is: &quot;2 s&quot;.</p>""" ] ]
element WriteTimeout { element WriteTimeout {
duration duration
}? }?
}? }*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>The ThreadPool element allows specifying various parameters related to <p>The ThreadPool element allows specifying various parameters related to
using a thread pool to send DDSI messages to multiple unicast addresses using a thread pool to send DDSI messages to multiple unicast addresses
@ -1286,7 +1592,7 @@ pool.</p><p>The default value is: &quot;4&quot;.</p>""" ] ]
element Threads { element Threads {
xsd:integer xsd:integer
}? }?
}? }*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>This element is used to set thread properties.</p>""" ] ] <p>This element is used to set thread properties.</p>""" ] ]
element Threads { element Threads {
@ -1311,6 +1617,9 @@ for discovery;</li>
<li><i>tev</i>: general timed-event handling, retransmits and <li><i>tev</i>: general timed-event handling, retransmits and
discovery;</li> discovery;</li>
<li><i>fsm</i>: finite state machine thread for handling security
handshake;</li>
<li><i>xmit.CHAN</i>: transmit thread for channel CHAN;</li> <li><i>xmit.CHAN</i>: transmit thread for channel CHAN;</li>
<li><i>dq.CHAN</i>: delivery thread for channel CHAN;</li> <li><i>dq.CHAN</i>: delivery thread for channel CHAN;</li>
@ -1355,7 +1664,7 @@ default.</p>
memsize memsize
}? }?
}* }*
}? }*
& [ a:documentation [ xml:lang="en" """ & [ a:documentation [ xml:lang="en" """
<p>The Tracing element controls the amount and type of information that <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 is written into the tracing log by the DDSI service. This is useful to
@ -1472,8 +1781,8 @@ verbosity levels are <i>config</i>, <i>fine</i> and
element Verbosity { element Verbosity {
("finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none") ("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" } 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)" } duration = xsd:token { pattern = "0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([num]?s|min|hr|day)" }

View file

@ -7,7 +7,7 @@ CycloneDDS configuration</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element minOccurs="0" ref="config:Domain"/> <xs:element minOccurs="0" maxOccurs="unbounded" ref="config:Domain"/>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
@ -17,17 +17,18 @@ CycloneDDS configuration</xs:documentation>
&lt;p&gt;The General element specifying Domain related settings.&lt;/p&gt;</xs:documentation> &lt;p&gt;The General element specifying Domain related settings.&lt;/p&gt;</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:all> <xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element minOccurs="0" ref="config:Compatibility"/> <xs:element ref="config:Compatibility"/>
<xs:element minOccurs="0" ref="config:Discovery"/> <xs:element ref="config:DDSSecurity"/>
<xs:element minOccurs="0" ref="config:General"/> <xs:element ref="config:Discovery"/>
<xs:element minOccurs="0" ref="config:Internal"/> <xs:element ref="config:General"/>
<xs:element minOccurs="0" ref="config:Partitioning"/> <xs:element ref="config:Internal"/>
<xs:element minOccurs="0" ref="config:SSL"/> <xs:element ref="config:Partitioning"/>
<xs:element minOccurs="0" ref="config:Sizing"/> <xs:element ref="config:SSL"/>
<xs:element minOccurs="0" ref="config:TCP"/> <xs:element ref="config:Sizing"/>
<xs:element minOccurs="0" ref="config:ThreadPool"/> <xs:element ref="config:TCP"/>
<xs:element minOccurs="0" name="Threads"> <xs:element ref="config:ThreadPool"/>
<xs:element name="Threads">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
&lt;p&gt;This element is used to set thread properties.&lt;/p&gt;</xs:documentation> &lt;p&gt;This element is used to set thread properties.&lt;/p&gt;</xs:documentation>
@ -38,8 +39,8 @@ CycloneDDS configuration</xs:documentation>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element minOccurs="0" ref="config:Tracing"/> <xs:element ref="config:Tracing"/>
</xs:all> </xs:choice>
<xs:attribute name="Id"> <xs:attribute name="Id">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
@ -146,6 +147,383 @@ though there is no good reason not to.&lt;/li&gt;&lt;/ul&gt;
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:element> </xs:element>
<xs:element name="DDSSecurity">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element is used to configure Cyclone DDS with the DDS Security
specification plugins and settings.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="config:AccessControl"/>
<xs:element minOccurs="0" ref="config:Authentication"/>
<xs:element minOccurs="0" ref="config:Cryptographic"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="AccessControl">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element configures the Access Control plugin of the DDS Security
specification.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" ref="config:Governance"/>
<xs:element minOccurs="0" name="Library">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the library to be loaded as the DDS Security
Access Control plugin.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="finalizeFunction">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element names the finalization function of Access Control plugin.
This function is called to let the plugin release its
resources.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;finalize_access_control&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="initFunction">
<xs:annotation>
<xs:documentation>
&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;The default value
is: &amp;quot;init_access_control&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="path">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element points to the path of Access Control plugin library.&lt;/p&gt;
&lt;p&gt;It can be either absolute path excluding file extension (
/usr/lib/dds_security_ac ) or single file without extension (
dds_security_ac ).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;dds_security_ac&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" ref="config:Permissions"/>
<xs:element minOccurs="0" ref="config:PermissionsCA"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="Governance" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;URI to the shared Governance Document signed by the Permissions CA in
S/MIME format&lt;/p&gt;
&lt;p&gt;URI schemes: file, data&lt;/p&gt;&lt;br&gt;
&lt;p&gt;Examples file URIs:&lt;/p&gt;
&lt;p&gt;&lt;Governance&gt;file:governance.smime&lt;/Governance&gt;&lt;/p&gt;
&lt;p&gt;&lt;Governance&gt;file:/home/myuser/governance.smime&lt;/Governance&gt;&lt;/p&gt;&lt;br&gt;
&lt;p&gt;&lt;Governance&gt;&lt;![CDATA[data:,MIME-Version: 1.0&lt;/p&gt;
&lt;p&gt;Content-Type: multipart/signed;
protocol="application/x-pkcs7-signature"; micalg="sha-256";
boundary="----F9A8A198D6F08E1285A292ADF14DD04F"&lt;/p&gt;
&lt;p&gt;This is an S/MIME signed message &lt;/p&gt;
&lt;p&gt;------F9A8A198D6F08E1285A292ADF14DD04F&lt;/p&gt;
&lt;p&gt;&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;/p&gt;
&lt;p&gt;&lt;dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;/p&gt;
&lt;p&gt;xsi:noNamespaceSchemaLocation="omg_shared_ca_governance.xsd"&gt;&lt;/p&gt;
&lt;p&gt;&lt;domain_access_rules&gt;&lt;/p&gt;
&lt;p&gt; . . . &lt;/p&gt;
&lt;p&gt;&lt;/domain_access_rules&gt;&lt;/p&gt;
&lt;p&gt;&lt;/dds&gt;&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;------F9A8A198D6F08E1285A292ADF14DD04F&lt;/p&gt;
&lt;p&gt;Content-Type: application/x-pkcs7-signature; name="smime.p7s"&lt;/p&gt;
&lt;p&gt;Content-Transfer-Encoding: base64&lt;/p&gt;
&lt;p&gt;Content-Disposition: attachment; filename="smime.p7s"&lt;/p&gt;
&lt;p&gt;MIIDuAYJKoZIhv ...al5s=&lt;/p&gt;
&lt;p&gt;------F9A8A198D6F08E1285A292ADF14DD04F-]]&lt;/Governance&gt;&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="Permissions" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;URI to the DomainParticipant permissions document signed by the
Permissions CA in S/MIME format&lt;/p&gt;
&lt;p&gt;The permissions document specifies the permissions to be applied to a
domain.&lt;/p&gt;&lt;br&gt;
&lt;p&gt;Example file URIs:&lt;/p&gt;
&lt;p&gt;&lt;Permissions&gt;file:permissions_document.p7s&lt;/Permissions&gt;&lt;/p&gt;
&lt;p&gt;&lt;Permissions&gt;file:/path_to/permissions_document.p7s&lt;/Permissions&gt;&lt;/p&gt;
&lt;p&gt;Example data URI:&lt;/p&gt;
&lt;p&gt;&lt;Permissions&gt;&lt;![CDATA[data:,.........]]&lt;/Permissions&gt;&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="PermissionsCA" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;URI to a X509 certificate for the PermissionsCA in PEM format.&lt;/p&gt;
&lt;p&gt;Supported URI schemes: file, data&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;&lt;br&gt;
&lt;p&gt;Examples:&lt;/p&gt;&lt;br&gt;
&lt;p&gt;&lt;PermissionsCA&gt;file:permissions_ca.pem&lt;/PermissionsCA&gt;&lt;/p&gt;
&lt;p&gt;&lt;PermissionsCA&gt;file:/home/myuser/permissions_ca.pem&lt;/PermissionsCA&gt;&lt;/p&gt;&lt;br&gt;
&lt;p&gt;&lt;PermissionsCA&gt;data:&lt;strong&gt;,&lt;/strong&gt;-----BEGIN CERTIFICATE-----&lt;/p&gt;
&lt;p&gt;MIIC3DCCAcQCCQCWE5x+Z ... PhovK0mp2ohhRLYI0ZiyYQ==&lt;/p&gt;
&lt;p&gt;-----END CERTIFICATE-----&lt;/PermissionsCA&gt;&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="Authentication">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element configures the Authentication plugin of the DDS Security
specification.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element ref="config:IdentityCA"/>
<xs:element ref="config:IdentityCertificate"/>
<xs:element minOccurs="0" ref="config:IncludeOptionalFields"/>
<xs:element minOccurs="0" name="Library">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the library to be loaded as the DDS Security
Access Control plugin.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="finalizeFunction">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element names the finalization function of Authentication plugin.
This function is called to let the plugin release its
resources.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;finalize_authentication&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="initFunction">
<xs:annotation>
<xs:documentation>
&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;The default value
is: &amp;quot;init_authentication&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="path">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element points to the path of Authentication plugin library.&lt;/p&gt;
&lt;p&gt;It can be either absolute path excluding file extension (
/usr/lib/dds_security_auth ) or single file without extension (
dds_security_auth ).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;dds_security_auth&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" ref="config:Password"/>
<xs:element ref="config:PrivateKey"/>
<xs:element minOccurs="0" ref="config:TrustedCADirectory"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="IdentityCA" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;URI to the X509 certificate [39] of the Identity CA that is the signer
of Identity Certificate.&lt;/p&gt;
&lt;p&gt;Supported URI schemes: file, data&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;p&gt;&lt;IdentityCA&gt;file:identity_ca.pem&lt;/IdentityCA&gt;&lt;/p&gt;
&lt;p&gt;&lt;IdentityCA&gt;data:,-----BEGIN CERTIFICATE-----&lt;br&gt;
MIIC3DCCAcQCCQCWE5x+Z...PhovK0mp2ohhRLYI0ZiyYQ==&lt;br&gt;
-----END CERTIFICATE-----&lt;/IdentityCA&gt;&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="IdentityCertificate" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;Identity certificate that will be used for identifying all
participants in the OSPL instance.&lt;br&gt;The content is URI to a X509
certificate signed by the IdentityCA in PEM format containing the signed
public key.&lt;/p&gt;
&lt;p&gt;Supported URI schemes: file, data&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;p&gt;&lt;IdentityCertificate&gt;file:participant1_identity_cert.pem&lt;/IdentityCertificate&gt;&lt;/p&gt;
&lt;p&gt;&lt;IdentityCertificate&gt;data:,-----BEGIN CERTIFICATE-----&lt;br&gt;
MIIDjjCCAnYCCQDCEu9...6rmT87dhTo=&lt;br&gt;
-----END CERTIFICATE-----&lt;/IdentityCertificate&gt;&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="IncludeOptionalFields" type="xs:boolean">
<xs:annotation>
<xs:documentation>
&lt;p&gt;The authentication handshake tokens may contain optional fields to be
included for finding interoperability problems.
If this parameter is set to true the optional fields are included in the
handshake token exchange.&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="Password" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;A password used to decrypt the private_key.&lt;/p&gt;
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.&lt;/p&gt;
If the password property is not present, then the value supplied in the
private_key property must contain the unencrypted private key. &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="PrivateKey" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;URI to access the private Private Key for all of the participants in
the OSPL federation.&lt;/p&gt;
&lt;p&gt;Supported URI schemes: file, data&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;p&gt;&lt;PrivateKey&gt;file:identity_ca_private_key.pem&lt;/PrivateKey&gt;&lt;/p&gt;
&lt;p&gt;&lt;PrivateKey&gt;data:,-----BEGIN RSA PRIVATE KEY-----&lt;br&gt;
MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==&lt;br&gt;
-----END RSA PRIVATE KEY-----&lt;/PrivateKey&gt;&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="TrustedCADirectory" type="xs:string">
<xs:annotation>
<xs:documentation>
&lt;p&gt;Trusted CA Directory which contains trusted CA certificates as
separated files.&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="Cryptographic">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element configures the Cryptographic plugin of the DDS Security
specification.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="Library">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element specifies the library to be loaded as the DDS Security
Cryptographic plugin.&lt;/p&gt;</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="finalizeFunction">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element names the finalization function of Cryptographic plugin.
This function is called to let the plugin release its
resources.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;finalize_crypto&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="initFunction">
<xs:annotation>
<xs:documentation>
&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;The default value
is: &amp;quot;init_crypto&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="path">
<xs:annotation>
<xs:documentation>
&lt;p&gt;This element points to the path of Cryptographic plugin library.&lt;/p&gt;
&lt;p&gt;It can be either absolute path excluding file extension (
/usr/lib/dds_security_crypto ) or single file without extension (
dds_security_crypto ).&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;dds_security_crypto&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Discovery"> <xs:element name="Discovery">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
@ -156,7 +534,6 @@ the discovery of peers.&lt;/p&gt;</xs:documentation>
<xs:all> <xs:all>
<xs:element minOccurs="0" ref="config:DSGracePeriod"/> <xs:element minOccurs="0" ref="config:DSGracePeriod"/>
<xs:element minOccurs="0" ref="config:DefaultMulticastAddress"/> <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:ExternalDomainId"/>
<xs:element minOccurs="0" ref="config:MaxAutoParticipantIndex"/> <xs:element minOccurs="0" ref="config:MaxAutoParticipantIndex"/>
<xs:element minOccurs="0" ref="config:ParticipantIndex"/> <xs:element minOccurs="0" ref="config:ParticipantIndex"/>
@ -190,12 +567,6 @@ Discovery/SPDPMulticastAddress.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;auto&amp;quot;.&lt;/p&gt;</xs:documentation> &amp;quot;auto&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="EnableTopicDiscovery" type="xs:boolean">
<xs:annotation>
<xs:documentation>
&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:element name="ExternalDomainId" type="xs:string">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
@ -1104,7 +1475,7 @@ is therefore recommended to set it to at least several seconds.&lt;/p&gt;
&lt;p&gt;Valid values are finite durations with an explicit unit or the keyword &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, '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> day.&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;0s&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:simpleContent> <xs:simpleContent>
@ -1777,6 +2148,9 @@ for discovery;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;tev&lt;/i&gt;: general timed-event handling, retransmits and &lt;li&gt;&lt;i&gt;tev&lt;/i&gt;: general timed-event handling, retransmits and
discovery;&lt;/li&gt; discovery;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;fsm&lt;/i&gt;: finite state machine thread for handling security
handshake;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;xmit.CHAN&lt;/i&gt;: transmit thread for channel CHAN;&lt;/li&gt; &lt;li&gt;&lt;i&gt;xmit.CHAN&lt;/i&gt;: transmit thread for channel CHAN;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;dq.CHAN&lt;/i&gt;: delivery thread for channel CHAN;&lt;/li&gt; &lt;li&gt;&lt;i&gt;dq.CHAN&lt;/i&gt;: delivery thread for channel CHAN;&lt;/li&gt;

View file

@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"> <package format="3">
<name>cyclonedds</name> <name>cyclonedds</name>
<version>0.6.0</version> <version>0.7.0</version>
<description>Eclipse Cyclone DDS is a very performant and robust open-source DDS implementation. Cyclone DDS is developed completely in the open as an Eclipse IoT project.</description> <description>Eclipse Cyclone DDS is a very performant and robust open-source DDS implementation. Cyclone DDS is developed completely in the open as an Eclipse IoT project.</description>
<maintainer email="cyclonedds-dev@eclipse.org">Eclipse Foundation, Inc.</maintainer> <maintainer email="cyclonedds-dev@eclipse.org">Eclipse Foundation, Inc.</maintainer>
<license>Eclipse Public License 2.0</license> <license>Eclipse Public License 2.0</license>

View file

@ -16,6 +16,69 @@ if(NOT ${PROJECT_NAME} STREQUAL "CycloneDDS")
message(FATAL_ERROR "Top-level CMakeLists.txt was moved to the top-level directory. Please run cmake on ${dir} instead of ${CMAKE_CURRENT_LIST_DIR}") message(FATAL_ERROR "Top-level CMakeLists.txt was moved to the top-level directory. Please run cmake on ${dir} instead of ${CMAKE_CURRENT_LIST_DIR}")
endif() endif()
# Generate a header file listing compile-time options relevant to the API. Define to
# "1" if enabled so that the generated features.h ends up having either
#
# - #define DDS_HAS_SECURITY 1
# or
# - /* #undef DDS_HAS_SECURITY */
#
# which caters both for those who prefer #ifdef DDS_HAS_SECURITY and for those who prefer
# #if DDS_HAS_SECURITY.
if(ENABLE_SECURITY)
set(DDS_HAS_SECURITY "1")
endif()
if(ENABLE_LIFESPAN)
set(DDS_HAS_LIFESPAN "1")
endif()
if(ENABLE_DEADLINE_MISSED)
set(DDS_HAS_DEADLINE_MISSED "1")
endif()
configure_file(features.h.in "${CMAKE_CURRENT_BINARY_DIR}/core/include/dds/features.h")
add_definitions(-DDDSI_INCLUDE_NETWORK_PARTITIONS -DDDSI_INCLUDE_SSM)
# OpenSSL is huge, raising the RSS by 1MB or so, and moreover find_package(OpenSSL) causes
# trouble on some older CMake versions that otherwise work fine, so provide an option to avoid
# all OpenSSL related things.
#
# Historically the option was DDSC_ENABLE_OPENSSL so make some allowance for those who are
# currently relying on it.
option(ENABLE_SSL "Enable openssl support" ON)
option(DDSC_ENABLE_OPENSSL "Deprecated: please use ENABLE_SSL instead" ON)
if(NOT DDSC_ENABLE_OPENSSL)
message(ERROR "DDSC_ENABLE_OPENSSL is deprecated, please use ENABLE_SSL instead")
set(ENABLE_SSL OFF)
endif()
if(ENABLE_SSL)
find_package(OpenSSL)
if(OPENSSL_FOUND)
add_definitions(-DDDSI_INCLUDE_SSL)
message(STATUS "Building with OpenSSL support")
else()
message(STATUS "Building without OpenSSL support")
endif()
endif()
# Support the OMG DDS Security within ddsc adds quite a bit of code.
option(ENABLE_SECURITY "Enable OMG DDS Security support" ON)
if(NOT ENABLE_SECURITY)
message(STATUS "Building without OMG DDS Security support")
else()
add_definitions(-DDDSI_INCLUDE_SECURITY)
endif()
option(ENABLE_LIFESPAN "Enable Lifespan QoS support" ON)
if(ENABLE_LIFESPAN)
add_definitions(-DDDSI_INCLUDE_LIFESPAN)
endif()
option(ENABLE_DEADLINE_MISSED "Enable Deadline Missed QoS support" ON)
if(ENABLE_DEADLINE_MISSED)
add_definitions(-DDDSI_INCLUDE_DEADLINE_MISSED)
endif()
add_subdirectory(ddsrt) add_subdirectory(ddsrt)
# some of the tests in the core rely on preprocessing IDL, so idlc has to # some of the tests in the core rely on preprocessing IDL, so idlc has to
@ -23,6 +86,7 @@ add_subdirectory(ddsrt)
if(BUILD_IDLC) if(BUILD_IDLC)
add_subdirectory(idlc) add_subdirectory(idlc)
endif() endif()
add_subdirectory(security)
add_subdirectory(core) add_subdirectory(core)
add_subdirectory(tools) add_subdirectory(tools)
if(BUILD_TESTING AND HAVE_MULTI_PROCESS AND BUILD_IDLC) if(BUILD_TESTING AND HAVE_MULTI_PROCESS AND BUILD_IDLC)

View file

@ -25,44 +25,21 @@ else()
add_library(ddsc) add_library(ddsc)
endif() endif()
add_definitions(-DDDSI_INCLUDE_NETWORK_PARTITIONS -DDDSI_INCLUDE_SSM) if(ENABLE_SSL AND OPENSSL_FOUND)
target_link_libraries(ddsc PRIVATE OpenSSL::SSL)
option(ENABLE_LIFESPAN "Enable Lifespan QoS support" ON) if(CMAKE_GENERATOR MATCHES "Visual Studio")
if(ENABLE_LIFESPAN) set_target_properties(ddsc PROPERTIES LINK_FLAGS "/ignore:4099")
add_definitions(-DDDSI_INCLUDE_LIFESPAN)
endif()
option(ENABLE_DEADLINE_MISSED "Enable Deadline Missed QoS support" ON)
if(ENABLE_DEADLINE_MISSED)
add_definitions(-DDDSI_INCLUDE_DEADLINE_MISSED)
endif()
# OpenSSL is huge, raising the RSS by 1MB or so, and moreover find_package(OpenSSL) causes
# trouble on some older CMake versions that otherwise work fine, so provide an option to avoid
# all OpenSSL related things.
#
# Historically the option was DDSC_ENABLE_OPENSSL so make some allowance for those who are
# currently relying on it.
option(ENABLE_SSL "Enable openssl support" ON)
option(DDSC_ENABLE_OPENSSL "Deprecated: please use ENABLE_SSL instead" ON)
if(NOT DDSC_ENABLE_OPENSSL)
message(ERROR "DDSC_ENABLE_OPENSSL is deprecated, please use ENABLE_SSL instead")
set(ENABLE_SSL OFF)
endif()
if(ENABLE_SSL)
find_package(OpenSSL)
if(OPENSSL_FOUND)
add_definitions(-DDDSI_INCLUDE_SSL)
target_link_libraries(ddsc PRIVATE OpenSSL::SSL)
if(CMAKE_GENERATOR MATCHES "Visual Studio")
set_target_properties(ddsc PROPERTIES LINK_FLAGS "/ignore:4099")
endif()
message(STATUS "Building with OpenSSL support")
else()
message(STATUS "Building without OpenSSL support")
endif() endif()
endif() endif()
# Support the OMG DDS Security within ddsc adds quite a bit of code.
if(ENABLE_SECURITY)
target_link_libraries(ddsc PRIVATE security_core)
target_include_directories(
ddsc PUBLIC
$<BUILD_INTERFACE:$<TARGET_PROPERTY:security_api,INTERFACE_INCLUDE_DIRECTORIES>>)
endif()
include(ddsi/CMakeLists.txt) include(ddsi/CMakeLists.txt)
include(ddsc/CMakeLists.txt) include(ddsc/CMakeLists.txt)

View file

@ -25,6 +25,7 @@
#endif #endif
#include "dds/export.h" #include "dds/export.h"
#include "dds/features.h"
/** /**
* Handle to an entity. A valid entity handle will always have a positive * Handle to an entity. A valid entity handle will always have a positive
@ -89,6 +90,7 @@ typedef enum dds_status_id {
DDS_PUBLICATION_MATCHED_STATUS_ID, DDS_PUBLICATION_MATCHED_STATUS_ID,
DDS_SUBSCRIPTION_MATCHED_STATUS_ID DDS_SUBSCRIPTION_MATCHED_STATUS_ID
} dds_status_id_t; } dds_status_id_t;
#define DDS_STATUS_ID_MAX (DDS_SUBSCRIPTION_MATCHED_STATUS_ID)
/** Another topic exists with the same name but with different characteristics. */ /** Another topic exists with the same name but with different characteristics. */
#define DDS_INCONSISTENT_TOPIC_STATUS (1u << DDS_INCONSISTENT_TOPIC_STATUS_ID) #define DDS_INCONSISTENT_TOPIC_STATUS (1u << DDS_INCONSISTENT_TOPIC_STATUS_ID)
@ -762,8 +764,22 @@ dds_set_listener(dds_entity_t entity, const dds_listener_t * listener);
* *
* @retval >0 * @retval >0
* A valid participant handle. * A valid participant handle.
* @retval DDS_RETCODE_NOT_ALLOWED_BY_SECURITY
* An invalid DDS Security configuration was specified (whether
* that be missing or incorrect entries, expired certificates,
* or anything else related to the security settings and
* implementation).
* @retval DDS_RETCODE_PRECONDITION_NOT_MET
* Some security properties specified in the QoS, but the Cyclone
* build does not include support for DDS Security.
* @retval DDS_RETCODE_OUT_OF_RESOURCES
* Some resource limit (maximum participants, memory, handles,
* &c.) prevented creation of the participant.
* @retval DDS_RETCODE_ERROR * @retval DDS_RETCODE_ERROR
* An internal error has occurred. * The "CYCLONEDDS_URI" environment variable lists non-existent
* or invalid configuration files, or contains invalid embedded
* configuration items; or an unspecified internal error has
* occurred.
*/ */
DDS_EXPORT dds_entity_t DDS_EXPORT dds_entity_t
dds_create_participant( dds_create_participant(
@ -2741,6 +2757,53 @@ dds_take_mask_wl(
uint32_t maxs, uint32_t maxs,
uint32_t mask); uint32_t mask);
#define DDS_HAS_READCDR 1
/**
* @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. Returned samples are
* marked as READ.
*
* 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_readcdr(
dds_entity_t reader_or_condition,
struct ddsi_serdata **buf,
uint32_t maxs,
dds_sample_info_t *si,
uint32_t mask);
/** /**
* @brief Access the collection of serialized data values (of same type) and * @brief Access the collection of serialized data values (of same type) and
* sample info from the data reader, readcondition or querycondition. * sample info from the data reader, readcondition or querycondition.

View file

@ -225,6 +225,13 @@ enum dds_stream_typecode_subtype {
#define DDS_OP_FLAG_KEY 0x01 /* key field: applicable to {1,2,4,8}BY, STR, BST, ARR-of-{1,2,4,8}BY */ #define DDS_OP_FLAG_KEY 0x01 /* key field: applicable to {1,2,4,8}BY, STR, BST, ARR-of-{1,2,4,8}BY */
#define DDS_OP_FLAG_DEF 0x02 /* union has a default case (for DDS_OP_ADR | DDS_OP_TYPE_UNI) */ #define DDS_OP_FLAG_DEF 0x02 /* union has a default case (for DDS_OP_ADR | DDS_OP_TYPE_UNI) */
/* For a union: (1) the discriminator may be a key field; (2) there may be a default value;
and (3) the discriminator can be an integral type (or enumerated - here treated as equivalent).
What it can't be is a floating-point type. So DEF and FP need never be set at the same time.
There are only a few flag bits, so saving one is not such a bad idea. */
#define DDS_OP_FLAG_FP 0x02 /* floating-point: applicable to {4,8}BY and arrays, sequences of them */
#define DDS_OP_FLAG_SGN 0x04 /* signed: applicable to {1,2,4,8}BY and arrays, sequences of them */
/** /**
* Description : Enable or disable write batching. Overrides default configuration * Description : Enable or disable write batching. Overrides default configuration
* setting for write batching (Internal/WriteBatch). * setting for write batching (Internal/WriteBatch).

View file

@ -23,6 +23,11 @@
#include "dds/export.h" #include "dds/export.h"
#include "dds/ddsc/dds_public_qosdefs.h" #include "dds/ddsc/dds_public_qosdefs.h"
/* Whether or not the "property list" QoS setting is supported in this version. If it is,
the "dds.sec." properties are treated specially, preventing the accidental creation of
an non-secure participant by an implementation built without support for DDS Security. */
#define DDS_HAS_PROPERTY_LIST_QOS 1
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
#endif #endif
@ -381,6 +386,72 @@ dds_qset_ignorelocal (
dds_qos_t * __restrict qos, dds_qos_t * __restrict qos,
dds_ignorelocal_kind_t ignore); dds_ignorelocal_kind_t ignore);
/**
* @brief Stores a property with the provided name and string value in a qos structure.
*
* In the case a property with the provided name already exists in the qos structure,
* the value for this entry is overwritten with the provided string value. If more than
* one property with the provided name exists, only the value of the first of these
* properties is updated.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that will store the property
* @param[in] name - Pointer to name of the property
* @param[in] value - Pointer to a (null-terminated) string that will be stored
*/
DDS_EXPORT void
dds_qset_prop (
dds_qos_t * __restrict qos,
const char * name,
const char * value);
/**
* @brief Removes the property with the provided name from a qos structure.
*
* In case more than one property exists with this name, only the first property
* is removed.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property
* @param[in] name - Pointer to name of the property
*/
DDS_EXPORT void
dds_qunset_prop (
dds_qos_t * __restrict qos,
const char * name);
/**
* @brief Stores the provided binary data as a property in a qos structure
*
* In the case a property with the provided name already exists in the qos structure,
* the value for this entry is overwritten with the provided data. If more than one
* property with the provided name exists, only the value of the first of these
* properties is updated.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that will store the property
* @param[in] name - Pointer to name of the property
* @param[in] value - Pointer to data to be stored in the property
* @param[in] sz - Size of the data
*/
DDS_EXPORT void
dds_qset_bprop (
dds_qos_t * __restrict qos,
const char * name,
const void * value,
const size_t sz);
/**
* @brief Removes the binary property with the provided name from a qos structure.
*
* In case more than one binary property exists with this name, only the first binary
* property is removed.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains the binary property
* @param[in] name - Pointer to name of the property
*/
DDS_EXPORT void
dds_qunset_bprop (
dds_qos_t * __restrict qos,
const char * name);
/** /**
* @brief Get the userdata from a qos structure * @brief Get the userdata from a qos structure
* *
@ -682,6 +753,74 @@ dds_qget_ignorelocal (
const dds_qos_t * __restrict qos, const dds_qos_t * __restrict qos,
dds_ignorelocal_kind_t *ignore); dds_ignorelocal_kind_t *ignore);
/**
* @brief Gets the names of the properties from a qos structure.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains properties
* @param[in,out] n - Pointer to number of property names that are returned (optional)
* @param[in,out] names - Pointer that will store the string(s) containing property name(s) (optional). This function will allocate the memory for the list of names and for the strings containing the names; the caller gets ownership of the allocated memory
*
* @returns - false iff any of the arguments is invalid or the qos is not present in the qos object
*/
DDS_EXPORT bool
dds_qget_propnames (
const dds_qos_t * __restrict qos,
uint32_t * n,
char *** names);
/**
* @brief Get the value of the property with the provided name from a qos structure.
*
* In case more than one property exists with this name, the value for the first
* property with this name will be returned.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property
* @param[in] name - Pointer to name of the property
* @param[in,out] value - Pointer to a string that will store the value of the property. The memory for storing the string value will be allocated by this function and the caller gets ownership of the allocated memory
*
* @returns - false iff any of the arguments is invalid, the qos is not present in the qos object or there was no property found with the provided name
*/
DDS_EXPORT bool
dds_qget_prop (
const dds_qos_t * __restrict qos,
const char * name,
char ** value);
/**
* @brief Gets the names of the binary properties from a qos structure.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains binary properties
* @param[in,out] n - Pointer to number of binary property names that are returned (optional)
* @param[in,out] names - Pointer that will store the string(s) containing binary property name(s) (optional). This function will allocate the memory for the list of names and for the strings containing the names; the caller gets ownership of the allocated memory
*
* @returns - false iff any of the arguments is invalid or the qos is not present in the qos object
*/
DDS_EXPORT bool
dds_qget_bpropnames (
const dds_qos_t * __restrict qos,
uint32_t * n,
char *** names);
/**
* @brief Get the value of the binary property with the provided name from a qos structure.
*
* In case more than one binary property exists with this name, the value for the first
* binary property with this name will be returned.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property
* @param[in] name - Pointer to name of the binary property
* @param[in,out] value - Pointer to a buffer that will store the value of the property. If sz = 0 then a NULL pointer. The memory for storing the value will be allocated by this function and the caller gets ownership of the allocated memory
* @param[in,out] sz - Pointer that will store the size of the returned buffer.
*
* @returns - false iff any of the arguments is invalid, the qos is not present in the qos object or there was no binary property found with the provided name
*/
DDS_EXPORT bool
dds_qget_bprop (
const dds_qos_t * __restrict qos,
const char * name,
void ** value,
size_t * sz);
#if defined (__cplusplus) #if defined (__cplusplus)
} }
#endif #endif

View file

@ -50,7 +50,8 @@ typedef enum dds_qos_policy_id {
DDS_GROUPDATA_QOS_POLICY_ID, DDS_GROUPDATA_QOS_POLICY_ID,
DDS_TRANSPORTPRIORITY_QOS_POLICY_ID, DDS_TRANSPORTPRIORITY_QOS_POLICY_ID,
DDS_LIFESPAN_QOS_POLICY_ID, DDS_LIFESPAN_QOS_POLICY_ID,
DDS_DURABILITYSERVICE_QOS_POLICY_ID DDS_DURABILITYSERVICE_QOS_POLICY_ID,
DDS_PROPERTY_QOS_POLICY_ID,
} dds_qos_policy_id_t; } dds_qos_policy_id_t;
/* QoS structure is opaque */ /* QoS structure is opaque */

View file

@ -27,9 +27,8 @@ struct dds_reader;
struct ddsi_tkmap; struct ddsi_tkmap;
typedef dds_return_t (*dds_rhc_associate_t) (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap); typedef dds_return_t (*dds_rhc_associate_t) (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap);
typedef int (*dds_rhc_read_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); typedef int32_t (*dds_rhc_read_take_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
typedef int (*dds_rhc_take_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); typedef int32_t (*dds_rhc_read_take_cdr_t) (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
typedef int (*dds_rhc_takecdr_t) (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
typedef bool (*dds_rhc_add_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond); typedef bool (*dds_rhc_add_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond);
typedef void (*dds_rhc_remove_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond); typedef void (*dds_rhc_remove_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond);
@ -40,9 +39,10 @@ struct dds_rhc_ops {
/* A copy of DDSI rhc ops comes first so we can use either interface without /* A copy of DDSI rhc ops comes first so we can use either interface without
additional indirections */ additional indirections */
struct ddsi_rhc_ops rhc_ops; struct ddsi_rhc_ops rhc_ops;
dds_rhc_read_t read; dds_rhc_read_take_t read;
dds_rhc_take_t take; dds_rhc_read_take_t take;
dds_rhc_takecdr_t takecdr; dds_rhc_read_take_cdr_t readcdr;
dds_rhc_read_take_cdr_t takecdr;
dds_rhc_add_readcondition_t add_readcondition; dds_rhc_add_readcondition_t add_readcondition;
dds_rhc_remove_readcondition_t remove_readcondition; dds_rhc_remove_readcondition_t remove_readcondition;
dds_rhc_lock_samples_t lock_samples; dds_rhc_lock_samples_t lock_samples;
@ -76,13 +76,16 @@ DDS_EXPORT inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qo
DDS_EXPORT inline void dds_rhc_free (struct dds_rhc *rhc) { DDS_EXPORT inline void dds_rhc_free (struct dds_rhc *rhc) {
rhc->common.ops->rhc_ops.free (&rhc->common.rhc); rhc->common.ops->rhc_ops.free (&rhc->common.rhc);
} }
DDS_EXPORT inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) { DDS_EXPORT inline int32_t dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) {
return (rhc->common.ops->read) (rhc, lock, values, info_seq, max_samples, mask, handle, cond); return (rhc->common.ops->read) (rhc, lock, values, info_seq, max_samples, mask, handle, cond);
} }
DDS_EXPORT inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) { DDS_EXPORT inline int32_t dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) {
return rhc->common.ops->take (rhc, lock, values, info_seq, max_samples, mask, handle, cond); return rhc->common.ops->take (rhc, lock, values, info_seq, max_samples, mask, handle, cond);
} }
DDS_EXPORT inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) { DDS_EXPORT inline int32_t dds_rhc_readcdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) {
return rhc->common.ops->readcdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle);
}
DDS_EXPORT inline int32_t dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) {
return rhc->common.ops->takecdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle); return rhc->common.ops->takecdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle);
} }
DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) { DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) {

View file

@ -25,7 +25,7 @@ extern "C" {
QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS) QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS)
#define DDS_PARTICIPANT_QOS_MASK \ #define DDS_PARTICIPANT_QOS_MASK \
(QP_USER_DATA | QP_ADLINK_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) (QP_USER_DATA | QP_ADLINK_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST)
#define DDS_PUBLISHER_QOS_MASK \ #define DDS_PUBLISHER_QOS_MASK \
(QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \ (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \
@ -36,7 +36,7 @@ extern "C" {
QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | \ QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | \
QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY | \ QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY | \
QP_RESOURCE_LIMITS | QP_ADLINK_READER_DATA_LIFECYCLE | \ QP_RESOURCE_LIMITS | QP_ADLINK_READER_DATA_LIFECYCLE | \
QP_CYCLONE_IGNORELOCAL) QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST)
#define DDS_SUBSCRIBER_QOS_MASK \ #define DDS_SUBSCRIBER_QOS_MASK \
(QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \ (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \
@ -48,7 +48,7 @@ extern "C" {
QP_LIVELINESS | QP_RELIABILITY | QP_TRANSPORT_PRIORITY | \ QP_LIVELINESS | QP_RELIABILITY | QP_TRANSPORT_PRIORITY | \
QP_LIFESPAN | QP_DESTINATION_ORDER | QP_HISTORY | \ QP_LIFESPAN | QP_DESTINATION_ORDER | QP_HISTORY | \
QP_RESOURCE_LIMITS | QP_ADLINK_WRITER_DATA_LIFECYCLE | \ QP_RESOURCE_LIMITS | QP_ADLINK_WRITER_DATA_LIFECYCLE | \
QP_CYCLONE_IGNORELOCAL) QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST)
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -39,6 +39,8 @@ DDS_EXPORT void dds_topic_set_filter_with_ctx
DDS_EXPORT dds_topic_intern_filter_fn dds_topic_get_filter_with_ctx DDS_EXPORT dds_topic_intern_filter_fn dds_topic_get_filter_with_ctx
(dds_entity_t topic); (dds_entity_t topic);
DDS_EXPORT dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist);
#if defined (__cplusplus) #if defined (__cplusplus)
} }
#endif #endif

View file

@ -23,7 +23,7 @@ DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_writer, DDS_KIND_WRITER)
struct status_cb_data; struct status_cb_data;
void dds_writer_status_cb (void *entity, const struct status_cb_data * data); void dds_writer_status_cb (void *entity, const struct status_cb_data * data);
dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, dds_time_t abstimeout); DDS_EXPORT dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, ddsi_guid_t *rdguid, dds_time_t abstimeout);
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -15,6 +15,7 @@
#include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_entity.h"
#include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_config.h" #include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_bswap.h"
#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_domaingv.h"
#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/ddsi_plist.h"
#include "dds__init.h" #include "dds__init.h"
@ -24,6 +25,7 @@
#include "dds__builtin.h" #include "dds__builtin.h"
#include "dds__entity.h" #include "dds__entity.h"
#include "dds__subscriber.h" #include "dds__subscriber.h"
#include "dds__topic.h"
#include "dds__write.h" #include "dds__write.h"
#include "dds__writer.h" #include "dds__writer.h"
#include "dds__whc_builtintopic.h" #include "dds__whc_builtintopic.h"
@ -76,7 +78,7 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic)
} }
dds_qos_t *qos = dds__create_builtin_qos (); dds_qos_t *qos = dds__create_builtin_qos ();
if ((tp = dds_create_topic_generic (par->m_entity.m_hdllink.hdl, &sertopic, qos, NULL, NULL)) > 0) if ((tp = dds_create_topic_impl (par->m_entity.m_hdllink.hdl, &sertopic, qos, NULL, NULL)) > 0)
{ {
/* keep ownership for built-in sertopics because there are re-used, lifetime for these /* keep ownership for built-in sertopics because there are re-used, lifetime for these
sertopics is bound to domain */ sertopics is bound to domain */
@ -180,10 +182,13 @@ static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct dd
struct dds_domain *domain = vdomain; struct dds_domain *domain = vdomain;
struct ddsi_tkmap_instance *tk; struct ddsi_tkmap_instance *tk;
struct ddsi_serdata *sd; struct ddsi_serdata *sd;
struct nn_keyhash kh; union { ddsi_guid_t guid; struct ddsi_keyhash keyhash; } x;
memcpy (&kh, guid, sizeof (kh)); x.guid = nn_hton_guid (*guid);
/* any random builtin topic will do (provided it has a GUID for a key), because what matters is the "class" of the topic, not the actual topic; also, this is called early in the initialisation of the entity with this GUID, which simply causes serdata_from_keyhash to create a key-only serdata because the key lookup fails. */ /* any random builtin topic will do (provided it has a GUID for a key), because what matters is the "class"
sd = ddsi_serdata_from_keyhash (domain->builtin_participant_topic, &kh); of the topic, not the actual topic; also, this is called early in the initialisation of the entity with
this GUID, which simply causes serdata_from_keyhash to create a key-only serdata because the key lookup
fails. */
sd = ddsi_serdata_from_keyhash (domain->builtin_participant_topic, &x.keyhash);
tk = ddsi_tkmap_find (domain->gv.m_tkmap, sd, true); tk = ddsi_tkmap_find (domain->gv.m_tkmap, sd, true);
ddsi_serdata_unref (sd); ddsi_serdata_unref (sd);
return tk; return tk;
@ -195,7 +200,7 @@ struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, dd
struct dds_domain *dom = e->gv->builtin_topic_interface->arg; struct dds_domain *dom = e->gv->builtin_topic_interface->arg;
struct ddsi_sertopic *topic = NULL; struct ddsi_sertopic *topic = NULL;
struct ddsi_serdata *serdata; struct ddsi_serdata *serdata;
struct nn_keyhash keyhash; union { ddsi_guid_t guid; struct ddsi_keyhash keyhash; } x;
switch (e->kind) switch (e->kind)
{ {
case EK_PARTICIPANT: case EK_PARTICIPANT:
@ -212,8 +217,8 @@ struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, dd
break; break;
} }
assert (topic != NULL); assert (topic != NULL);
memcpy (&keyhash, &e->guid, sizeof (keyhash)); x.guid = nn_hton_guid (e->guid);
serdata = ddsi_serdata_from_keyhash (topic, &keyhash); serdata = ddsi_serdata_from_keyhash (topic, &x.keyhash);
serdata->timestamp = timestamp; serdata->timestamp = timestamp;
serdata->statusinfo = alive ? 0 : NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER; serdata->statusinfo = alive ? 0 : NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER;
return serdata; return serdata;

View file

@ -90,8 +90,7 @@ void dds_listener_copy(dds_listener_t * __restrict dst, const dds_listener_t * _
static bool dds_combine_listener_merge (uint32_t inherited, void (*dst)(void), void (*src)(void)) static bool dds_combine_listener_merge (uint32_t inherited, void (*dst)(void), void (*src)(void))
{ {
(void)inherited; (void)inherited;
(void)src; return dst == 0 && src != 0;
return dst == 0;
} }
static bool dds_combine_listener_override_inherited (uint32_t inherited, void (*dst)(void), void (*src)(void)) static bool dds_combine_listener_override_inherited (uint32_t inherited, void (*dst)(void), void (*src)(void))

View file

@ -144,8 +144,7 @@ static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const ddsi_guid_
dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t writer, dds_instance_handle_t ih) dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t writer, dds_instance_handle_t ih)
{ {
dds_writer *wr; dds_writer *wr;
dds_return_t rc; if (dds_writer_lock (writer, &wr))
if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK)
return NULL; return NULL;
else else
{ {
@ -187,8 +186,7 @@ dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t wri
dds_builtintopic_endpoint_t *dds_get_matched_publication_data (dds_entity_t reader, dds_instance_handle_t ih) dds_builtintopic_endpoint_t *dds_get_matched_publication_data (dds_entity_t reader, dds_instance_handle_t ih)
{ {
dds_reader *rd; dds_reader *rd;
dds_return_t rc; if (dds_reader_lock (reader, &rd))
if ((rc = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK)
return NULL; return NULL;
else else
{ {

View file

@ -96,7 +96,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
dds_participant * pp; dds_participant * pp;
ddsi_plist_t plist; ddsi_plist_t plist;
dds_qos_t *new_qos = NULL; dds_qos_t *new_qos = NULL;
char *config = ""; const char *config = "";
/* Make sure DDS instance is initialized. */ /* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0) if ((ret = dds_init ()) < 0)

View file

@ -114,7 +114,7 @@ dds_return_t dds_wait_for_acks (dds_entity_t publisher_or_writer, dds_duration_t
return DDS_RETCODE_UNSUPPORTED; return DDS_RETCODE_UNSUPPORTED;
case DDS_KIND_WRITER: case DDS_KIND_WRITER:
ret = dds__writer_wait_for_acks ((struct dds_writer *) p_or_w_ent, abstimeout); ret = dds__writer_wait_for_acks ((struct dds_writer *) p_or_w_ent, NULL, abstimeout);
dds_entity_unpin (p_or_w_ent); dds_entity_unpin (p_or_w_ent);
return ret; return ret;

View file

@ -335,6 +335,112 @@ void dds_qset_ignorelocal (dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ig
qos->present |= QP_CYCLONE_IGNORELOCAL; qos->present |= QP_CYCLONE_IGNORELOCAL;
} }
static void dds_qprop_init (dds_qos_t * qos)
{
if (!(qos->present & QP_PROPERTY_LIST))
{
qos->property.value.n = 0;
qos->property.value.props = NULL;
qos->property.binary_value.n = 0;
qos->property.binary_value.props = NULL;
qos->present |= QP_PROPERTY_LIST;
}
}
#define DDS_QPROP_GET_INDEX(prop_type_, prop_field_) \
static bool dds_q##prop_type_##_get_index (const dds_qos_t * qos, const char * name, uint32_t * index) \
{ \
if (qos == NULL || name == NULL || index == NULL || !(qos->present & QP_PROPERTY_LIST)) \
return false; \
for (uint32_t i = 0; i < qos->property.prop_field_.n; i++) \
{ \
if (strcmp (qos->property.prop_field_.props[i].name, name) == 0) \
{ \
*index = i; \
return true; \
} \
} \
return false; \
}
DDS_QPROP_GET_INDEX (prop, value)
DDS_QPROP_GET_INDEX (bprop, binary_value)
#define DDS_QUNSET_PROP(prop_type_, prop_field_, value_field_) \
void dds_qunset_##prop_type_ (dds_qos_t * __restrict qos, const char * name) \
{ \
uint32_t i; \
if (qos == NULL || !(qos->present & QP_PROPERTY_LIST) || qos->property.prop_field_.n == 0 || name == NULL) \
return; \
if (dds_q##prop_type_##_get_index (qos, name, &i)) \
{ \
dds_free (qos->property.prop_field_.props[i].name); \
dds_free (qos->property.prop_field_.props[i].value_field_); \
if (qos->property.prop_field_.n > 1) \
{ \
if (i < (qos->property.prop_field_.n - 1)) \
memmove (qos->property.prop_field_.props + i, qos->property.prop_field_.props + i + 1, \
(qos->property.prop_field_.n - i - 1) * sizeof (*qos->property.prop_field_.props)); \
qos->property.prop_field_.props = dds_realloc (qos->property.prop_field_.props, \
(qos->property.prop_field_.n - 1) * sizeof (*qos->property.prop_field_.props)); \
} \
else \
{ \
dds_free (qos->property.prop_field_.props); \
qos->property.prop_field_.props = NULL; \
} \
qos->property.prop_field_.n--; \
} \
}
DDS_QUNSET_PROP (prop, value, value)
DDS_QUNSET_PROP (bprop, binary_value, value.value)
void dds_qset_prop (dds_qos_t * __restrict qos, const char * name, const char * value)
{
uint32_t i;
if (qos == NULL || name == NULL || value == NULL)
return;
dds_qprop_init (qos);
if (dds_qprop_get_index (qos, name, &i))
{
assert (&qos->property.value.props[i] != NULL); /* for Clang static analyzer */
dds_free (qos->property.value.props[i].value);
qos->property.value.props[i].value = dds_string_dup (value);
}
else
{
qos->property.value.props = dds_realloc (qos->property.value.props,
(qos->property.value.n + 1) * sizeof (*qos->property.value.props));
qos->property.value.props[qos->property.value.n].propagate = 0;
qos->property.value.props[qos->property.value.n].name = dds_string_dup (name);
qos->property.value.props[qos->property.value.n].value = dds_string_dup (value);
qos->property.value.n++;
}
}
void dds_qset_bprop (dds_qos_t * __restrict qos, const char * name, const void * value, const size_t sz)
{
uint32_t i;
if (qos == NULL || name == NULL || (value == NULL && sz > 0))
return;
dds_qprop_init (qos);
if (dds_qbprop_get_index (qos, name, &i))
{
assert (&qos->property.binary_value.props[i].value != NULL); /* for Clang static analyzer */
dds_qos_data_copy_in (&qos->property.binary_value.props[i].value, value, sz, true);
}
else
{
qos->property.binary_value.props = dds_realloc (qos->property.binary_value.props,
(qos->property.binary_value.n + 1) * sizeof (*qos->property.binary_value.props));
qos->property.binary_value.props[qos->property.binary_value.n].propagate = 0;
qos->property.binary_value.props[qos->property.binary_value.n].name = dds_string_dup (name);
dds_qos_data_copy_in (&qos->property.binary_value.props[qos->property.binary_value.n].value, value, sz, false);
qos->property.binary_value.n++;
}
}
bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz) bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz)
{ {
if (qos == NULL || !(qos->present & QP_USER_DATA)) if (qos == NULL || !(qos->present & QP_USER_DATA))
@ -565,3 +671,66 @@ bool dds_qget_ignorelocal (const dds_qos_t * __restrict qos, dds_ignorelocal_kin
*ignore = qos->ignorelocal.value; *ignore = qos->ignorelocal.value;
return true; return true;
} }
#define DDS_QGET_PROPNAMES(prop_type_, prop_field_) \
bool dds_qget_##prop_type_##names (const dds_qos_t * __restrict qos, uint32_t * n, char *** names) \
{ \
bool props; \
if (qos == NULL || (n == NULL && names == NULL)) \
return false; \
props = (qos->present & QP_PROPERTY_LIST) && qos->property.prop_field_.n > 0; \
if (n != NULL) \
*n = props ? qos->property.prop_field_.n : 0; \
if (names != NULL) \
{ \
if (!props) \
*names = NULL; \
else \
{ \
*names = dds_alloc (sizeof (char *) * qos->property.prop_field_.n); \
for (uint32_t i = 0; i < qos->property.prop_field_.n; i++) \
(*names)[i] = dds_string_dup (qos->property.prop_field_.props[i].name); \
} \
} \
return props; \
}
DDS_QGET_PROPNAMES (prop, value)
DDS_QGET_PROPNAMES (bprop, binary_value)
bool dds_qget_prop (const dds_qos_t * __restrict qos, const char * name, char ** value)
{
uint32_t i;
bool found;
if (qos == NULL || name == NULL)
return false;
found = dds_qprop_get_index (qos, name, &i);
if (value != NULL)
*value = found ? dds_string_dup (qos->property.value.props[i].value) : NULL;
return found;
}
bool dds_qget_bprop (const dds_qos_t * __restrict qos, const char * name, void ** value, size_t * sz)
{
uint32_t i;
bool found;
if (qos == NULL || name == NULL || (sz == NULL && value != NULL))
return false;
found = dds_qbprop_get_index (qos, name, &i);
if (found)
{
if (value != NULL || sz != NULL)
dds_qos_data_copy_out (&qos->property.binary_value.props[i].value, value, sz);
}
else
{
if (value != NULL)
*value = NULL;
if (sz != NULL)
*sz = 0;
}
return found;
}

View file

@ -40,7 +40,7 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition,
#define NC_FREE_BUF 2u #define NC_FREE_BUF 2u
#define NC_RESET_BUF 4u #define NC_RESET_BUF 4u
if (buf == NULL || si == NULL || maxs == 0 || bufsz == 0 || bufsz < maxs) if (buf == NULL || si == NULL || maxs == 0 || bufsz == 0 || bufsz < maxs || maxs > INT32_MAX)
return DDS_RETCODE_BAD_PARAMETER; return DDS_RETCODE_BAD_PARAMETER;
if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) { if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) {
@ -61,14 +61,6 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition,
thread_state_awake (ts1, &entity->m_domain->gv); thread_state_awake (ts1, &entity->m_domain->gv);
if (hand != DDS_HANDLE_NIL)
{
if (ddsi_tkmap_find_by_id (entity->m_domain->gv.m_tkmap, hand) == NULL) {
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
goto fail_awake_pinned;
}
}
/* Allocate samples if not provided (assuming all or none provided) */ /* Allocate samples if not provided (assuming all or none provided) */
if (buf[0] == NULL) if (buf[0] == NULL)
{ {
@ -142,8 +134,6 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition,
#undef NC_FREE_BUF #undef NC_FREE_BUF
#undef NC_RESET_BUF #undef NC_RESET_BUF
fail_awake_pinned:
thread_state_asleep (ts1);
fail_pinned: fail_pinned:
dds_entity_unpin (entity); dds_entity_unpin (entity);
fail: fail:
@ -157,12 +147,8 @@ static dds_return_t dds_readcdr_impl (bool take, dds_entity_t reader_or_conditio
struct dds_reader *rd; struct dds_reader *rd;
struct dds_entity *entity; struct dds_entity *entity;
assert (take); if (buf == NULL || si == NULL || maxs == 0 || maxs > INT32_MAX)
assert (buf); return DDS_RETCODE_BAD_PARAMETER;
assert (si);
assert (hand == DDS_HANDLE_NIL);
assert (maxs > 0);
(void)take;
if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) { if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) {
return ret; return ret;
@ -185,7 +171,11 @@ static dds_return_t dds_readcdr_impl (bool take, dds_entity_t reader_or_conditio
assert (dds_entity_kind (rd->m_entity.m_parent) == DDS_KIND_SUBSCRIBER); assert (dds_entity_kind (rd->m_entity.m_parent) == DDS_KIND_SUBSCRIBER);
dds_entity_status_reset (rd->m_entity.m_parent, DDS_DATA_ON_READERS_STATUS); dds_entity_status_reset (rd->m_entity.m_parent, DDS_DATA_ON_READERS_STATUS);
ret = dds_rhc_takecdr (rd->m_rhc, lock, buf, si, maxs, mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE, hand); if (take)
ret = dds_rhc_takecdr (rd->m_rhc, lock, buf, si, maxs, mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE, hand);
else
ret = dds_rhc_readcdr (rd->m_rhc, lock, buf, si, maxs, mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE, hand);
dds_entity_unpin (entity); dds_entity_unpin (entity);
thread_state_asleep (ts1); thread_state_asleep (ts1);
return ret; return ret;
@ -239,6 +229,18 @@ dds_return_t dds_read_mask_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_in
return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, mask, DDS_HANDLE_NIL, lock, false); return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, mask, DDS_HANDLE_NIL, lock, false);
} }
dds_return_t dds_readcdr (dds_entity_t rd_or_cnd, struct ddsi_serdata **buf, uint32_t maxs, dds_sample_info_t *si, uint32_t mask)
{
bool lock = true;
if (maxs == DDS_READ_WITHOUT_LOCK)
{
lock = false;
/* FIXME: Fix the interface. */
maxs = 100;
}
return dds_readcdr_impl (false, rd_or_cnd, buf, maxs, si, mask, DDS_HANDLE_NIL, lock);
}
dds_return_t dds_read_instance (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, dds_instance_handle_t handle) dds_return_t dds_read_instance (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, dds_instance_handle_t handle)
{ {
bool lock = true; bool lock = true;

View file

@ -30,6 +30,7 @@
#include "dds__builtin.h" #include "dds__builtin.h"
#include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_sertopic.h"
#include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/ddsi_entity_index.h"
#include "dds/ddsi/ddsi_security_omg.h"
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader) DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader)
@ -430,6 +431,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
/* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null /* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null
argument, but that isn't the case here */ argument, but that isn't the case here */
struct ddsi_domaingv *gv = &sub->m_entity.m_domain->gv;
rqos = dds_create_qos (); rqos = dds_create_qos ();
if (qos) if (qos)
ddsi_xqos_mergein_missing (rqos, qos, DDS_READER_QOS_MASK); ddsi_xqos_mergein_missing (rqos, qos, DDS_READER_QOS_MASK);
@ -437,25 +439,42 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
ddsi_xqos_mergein_missing (rqos, sub->m_entity.m_qos, ~(uint64_t)0); ddsi_xqos_mergein_missing (rqos, sub->m_entity.m_qos, ~(uint64_t)0);
if (tp->m_ktopic->qos) if (tp->m_ktopic->qos)
ddsi_xqos_mergein_missing (rqos, tp->m_ktopic->qos, ~(uint64_t)0); ddsi_xqos_mergein_missing (rqos, tp->m_ktopic->qos, ~(uint64_t)0);
ddsi_xqos_mergein_missing (rqos, &sub->m_entity.m_domain->gv.default_xqos_rd, ~(uint64_t)0); ddsi_xqos_mergein_missing (rqos, &gv->default_xqos_rd, ~(uint64_t)0);
if ((rc = ddsi_xqos_valid (&sub->m_entity.m_domain->gv.logconfig, rqos)) < 0 || if ((rc = ddsi_xqos_valid (&gv->logconfig, rqos)) < 0 || (rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK)
(rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK)
{
dds_delete_qos (rqos);
goto err_bad_qos; goto err_bad_qos;
}
/* Additional checks required for built-in topics: we don't want to /* Additional checks required for built-in topics: we don't want to
run into a resource limit on a built-in topic, it is a needless run into a resource limit on a built-in topic, it is a needless
complication */ complication */
if (pseudo_topic && !dds__validate_builtin_reader_qos (tp->m_entity.m_domain, pseudo_topic, rqos)) if (pseudo_topic && !dds__validate_builtin_reader_qos (tp->m_entity.m_domain, pseudo_topic, rqos))
{ {
dds_delete_qos (rqos);
rc = DDS_RETCODE_INCONSISTENT_POLICY; rc = DDS_RETCODE_INCONSISTENT_POLICY;
goto err_bad_qos; goto err_bad_qos;
} }
thread_state_awake (lookup_thread_state (), gv);
const struct ddsi_guid * ppguid = dds_entity_participant_guid (&sub->m_entity);
struct participant * pp = entidx_lookup_participant_guid (gv->entity_index, ppguid);
/* When deleting a participant, the child handles (that include the subscriber)
are removed before removing the DDSI participant. So at this point, within
the subscriber lock, we can assert that the participant exists. */
assert (pp != NULL);
#ifdef DDSI_INCLUDE_SECURITY
/* Check if DDS Security is enabled */
if (q_omg_participant_is_secure (pp))
{
/* ask to access control security plugin for create reader permissions */
if (!q_omg_security_check_create_reader (pp, gv->config.domainId, tp->m_stopic->name, rqos))
{
rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY;
goto err_not_allowed;
}
}
#endif
/* Create reader and associated read cache (if not provided by caller) */ /* Create reader and associated read cache (if not provided by caller) */
struct dds_reader * const rd = dds_alloc (sizeof (*rd)); struct dds_reader * const rd = dds_alloc (sizeof (*rd));
const dds_entity_t reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK); const dds_entity_t reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK);
@ -474,8 +493,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
it; and then invoke those listeners that are in the pending set */ it; and then invoke those listeners that are in the pending set */
dds_entity_init_complete (&rd->m_entity); dds_entity_init_complete (&rd->m_entity);
thread_state_awake (lookup_thread_state (), &sub->m_entity.m_domain->gv); rc = new_reader (&rd->m_rd, &rd->m_entity.m_guid, NULL, pp, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
rc = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, dds_entity_participant_guid (&sub->m_entity), tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
assert (rc == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */ assert (rc == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */
thread_state_asleep (lookup_thread_state ()); thread_state_asleep (lookup_thread_state ());
@ -487,7 +505,12 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
dds_subscriber_unlock (sub); dds_subscriber_unlock (sub);
return reader; return reader;
#ifdef DDSI_INCLUDE_SECURITY
err_not_allowed:
thread_state_asleep (lookup_thread_state ());
#endif
err_bad_qos: err_bad_qos:
dds_delete_qos (rqos);
dds_topic_allow_set_qos (tp); dds_topic_allow_set_qos (tp);
err_pp_mismatch: err_pp_mismatch:
dds_topic_unpin (tp); dds_topic_unpin (tp);
@ -632,3 +655,4 @@ DDS_GET_STATUS (reader, sample_rejected, SAMPLE_REJECTED,
DDS_GET_STATUS (reader, sample_lost, SAMPLE_LOST, total_count_change) DDS_GET_STATUS (reader, sample_lost, SAMPLE_LOST, total_count_change)
DDS_GET_STATUS (reader, requested_deadline_missed, REQUESTED_DEADLINE_MISSED, total_count_change) DDS_GET_STATUS (reader, requested_deadline_missed, REQUESTED_DEADLINE_MISSED, total_count_change)
DDS_GET_STATUS (reader, requested_incompatible_qos, REQUESTED_INCOMPATIBLE_QOS, total_count_change) DDS_GET_STATUS (reader, requested_incompatible_qos, REQUESTED_INCOMPATIBLE_QOS, total_count_change)

View file

@ -22,6 +22,7 @@ extern inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qos *q
extern inline void dds_rhc_free (struct dds_rhc *rhc); extern inline void dds_rhc_free (struct dds_rhc *rhc);
extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
extern inline int dds_rhc_readcdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
extern inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); extern inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
extern inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond); extern inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond);
extern inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond); extern inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond);

File diff suppressed because it is too large Load diff

View file

@ -126,14 +126,16 @@ static void from_entity_pwr (struct ddsi_serdata_builtintopic *d, const struct p
assert (d->xqos.present & QP_TYPE_NAME); assert (d->xqos.present & QP_TYPE_NAME);
} }
static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi_sertopic *tpcmn, const ddsi_keyhash_t *keyhash)
{ {
/* FIXME: not quite elegant to manage the creation of a serdata for a built-in topic via this function, but I also find it quite unelegant to let from_sample read straight from the underlying internal entity, and to_sample convert to the external format ... I could claim the internal entity is the "serialised form", but that forces wrapping it in a fragchain in one way or another, which, though possible, is also a bit lacking in elegance. */ /* FIXME: not quite elegant to manage the creation of a serdata for a built-in topic via this function, but I also find it quite unelegant to let from_sample read straight from the underlying internal entity, and to_sample convert to the external format ... I could claim the internal entity is the "serialised form", but that forces wrapping it in a fragchain in one way or another, which, though possible, is also a bit lacking in elegance. */
const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn; const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn;
/* keyhash must in host format (which the GUIDs always are internally) */ union { ddsi_guid_t guid; ddsi_keyhash_t keyhash; } x;
struct entity_common *entity = entidx_lookup_guid_untyped (tp->c.gv->entity_index, (const ddsi_guid_t *) keyhash->value); x.keyhash = *keyhash;
struct ddsi_serdata_builtintopic *d = serdata_builtin_new(tp, entity ? SDK_DATA : SDK_KEY); x.guid = nn_ntoh_guid (x.guid);
memcpy (&d->key, keyhash->value, sizeof (d->key)); struct entity_common *entity = entidx_lookup_guid_untyped (tp->c.gv->entity_index, &x.guid);
struct ddsi_serdata_builtintopic *d = serdata_builtin_new (tp, entity ? SDK_DATA : SDK_KEY);
d->key = x.guid;
if (entity) if (entity)
{ {
ddsrt_mutex_lock (&entity->qos_lock); ddsrt_mutex_lock (&entity->qos_lock);
@ -169,6 +171,41 @@ static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi
return fix_serdata_builtin(d, tp->c.serdata_basehash); return fix_serdata_builtin(d, tp->c.serdata_basehash);
} }
static struct ddsi_serdata *ddsi_serdata_builtin_from_sample (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *sample)
{
const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn;
union {
dds_guid_t extguid;
ddsi_keyhash_t keyhash;
} x;
/* no-one should be trying to convert user-provided data into a built-in topic sample, but converting
a key is something that can be necessary, e.g., dds_lookup_instance depends on it */
if (kind != SDK_KEY)
return NULL;
/* memset x (even though it is entirely superfluous) so we can leave out a default case from the
switch (ensuring at least some compilers will warn when more types are added) without getting
warnings from any compiler */
memset (&x, 0, sizeof (x));
switch (tp->type)
{
case DSBT_PARTICIPANT: {
const dds_builtintopic_participant_t *s = sample;
x.extguid = s->key;
break;
}
case DSBT_READER:
case DSBT_WRITER: {
const dds_builtintopic_endpoint_t *s = sample;
x.extguid = s->key;
break;
}
}
return ddsi_serdata_from_keyhash (tpcmn, &x.keyhash);
}
static struct ddsi_serdata *serdata_builtin_to_topicless (const struct ddsi_serdata *serdata_common) static struct ddsi_serdata *serdata_builtin_to_topicless (const struct ddsi_serdata *serdata_common)
{ {
/* All built-in ones are currently topicless */ /* All built-in ones are currently topicless */
@ -289,12 +326,13 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = {
.from_ser = 0, .from_ser = 0,
.from_ser_iov = 0, .from_ser_iov = 0,
.from_keyhash = ddsi_serdata_builtin_from_keyhash, .from_keyhash = ddsi_serdata_builtin_from_keyhash,
.from_sample = 0, .from_sample = ddsi_serdata_builtin_from_sample,
.to_ser = serdata_builtin_to_ser, .to_ser = serdata_builtin_to_ser,
.to_sample = serdata_builtin_to_sample, .to_sample = serdata_builtin_to_sample,
.to_ser_ref = serdata_builtin_to_ser_ref, .to_ser_ref = serdata_builtin_to_ser_ref,
.to_ser_unref = serdata_builtin_to_ser_unref, .to_ser_unref = serdata_builtin_to_ser_unref,
.to_topicless = serdata_builtin_to_topicless, .to_topicless = serdata_builtin_to_topicless,
.topicless_to_sample = serdata_builtin_topicless_to_sample, .topicless_to_sample = serdata_builtin_topicless_to_sample,
.print = serdata_builtin_topic_print .print = serdata_builtin_topic_print,
.get_keyhash = 0
}; };

View file

@ -32,6 +32,7 @@
#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/ddsi_plist.h"
#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_domaingv.h"
#include "dds/ddsi/ddsi_cdrstream.h" #include "dds/ddsi/ddsi_cdrstream.h"
#include "dds/ddsi/ddsi_security_omg.h"
#include "dds__serdata_builtintopic.h" #include "dds__serdata_builtintopic.h"
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic) DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic)
@ -246,6 +247,7 @@ static dds_return_t lookup_and_check_ktopic (struct dds_ktopic **ktp_out, dds_pa
static dds_entity_t create_topic_pp_locked (struct dds_participant *pp, struct dds_ktopic *ktp, bool implicit, struct ddsi_sertopic *sertopic_registered, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) static dds_entity_t create_topic_pp_locked (struct dds_participant *pp, struct dds_ktopic *ktp, bool implicit, struct ddsi_sertopic *sertopic_registered, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist)
{ {
(void) sedp_plist;
dds_entity_t hdl; dds_entity_t hdl;
dds_topic *tp = dds_alloc (sizeof (*tp)); dds_topic *tp = dds_alloc (sizeof (*tp));
hdl = dds_entity_init (&tp->m_entity, &pp->m_entity, DDS_KIND_TOPIC, implicit, NULL, listener, DDS_TOPIC_STATUS_MASK); hdl = dds_entity_init (&tp->m_entity, &pp->m_entity, DDS_KIND_TOPIC, implicit, NULL, listener, DDS_TOPIC_STATUS_MASK);
@ -253,30 +255,11 @@ static dds_entity_t create_topic_pp_locked (struct dds_participant *pp, struct d
dds_entity_register_child (&pp->m_entity, &tp->m_entity); dds_entity_register_child (&pp->m_entity, &tp->m_entity);
tp->m_ktopic = ktp; tp->m_ktopic = ktp;
tp->m_stopic = sertopic_registered; tp->m_stopic = sertopic_registered;
/* Publish Topic */
if (sedp_plist)
{
struct participant *ddsi_pp;
ddsi_plist_t plist;
thread_state_awake (lookup_thread_state (), &pp->m_entity.m_domain->gv);
ddsi_pp = entidx_lookup_participant_guid (pp->m_entity.m_domain->gv.entity_index, &pp->m_entity.m_guid);
assert (ddsi_pp);
ddsi_plist_init_empty (&plist);
ddsi_plist_mergein_missing (&plist, sedp_plist, ~(uint64_t)0, ~(uint64_t)0);
ddsi_xqos_mergein_missing (&plist.qos, ktp->qos, ~(uint64_t)0);
sedp_write_topic (ddsi_pp, &plist);
ddsi_plist_fini (&plist);
thread_state_asleep (lookup_thread_state ());
}
dds_entity_init_complete (&tp->m_entity); dds_entity_init_complete (&tp->m_entity);
return hdl; return hdl;
} }
dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist)
{ {
dds_return_t rc; dds_return_t rc;
dds_participant *pp; dds_participant *pp;
@ -315,10 +298,12 @@ dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_ser
* reliable ... (and keep behaviour unchanged) */ * reliable ... (and keep behaviour unchanged) */
struct ddsi_domaingv * const gv = &pp->m_entity.m_domain->gv; struct ddsi_domaingv * const gv = &pp->m_entity.m_domain->gv;
if ((rc = ddsi_xqos_valid (&gv->logconfig, new_qos)) != DDS_RETCODE_OK) if ((rc = ddsi_xqos_valid (&gv->logconfig, new_qos)) != DDS_RETCODE_OK)
goto error;
if (!q_omg_security_check_create_topic (&pp->m_entity.m_domain->gv, &pp->m_entity.m_guid, (*sertopic)->name, new_qos))
{ {
dds_delete_qos (new_qos); rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY;
dds_entity_unpin (&pp->m_entity); goto error;
return rc;
} }
/* See if we're allowed to create the topic; ktp is returned pinned & locked /* See if we're allowed to create the topic; ktp is returned pinned & locked
@ -331,9 +316,8 @@ dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_ser
if ((rc = lookup_and_check_ktopic (&ktp, pp, (*sertopic)->name, (*sertopic)->type_name, new_qos)) != DDS_RETCODE_OK) if ((rc = lookup_and_check_ktopic (&ktp, pp, (*sertopic)->name, (*sertopic)->type_name, new_qos)) != DDS_RETCODE_OK)
{ {
GVTRACE ("dds_create_topic_generic: failed after compatibility check: %s\n", dds_strretcode (rc)); GVTRACE ("dds_create_topic_generic: failed after compatibility check: %s\n", dds_strretcode (rc));
dds_participant_unlock (pp); ddsrt_mutex_unlock (&pp->m_entity.m_mutex);
dds_delete_qos (new_qos); goto error;
return rc;
} }
/* Create a ktopic if it doesn't exist yet, else reference existing one and delete the /* Create a ktopic if it doesn't exist yet, else reference existing one and delete the
@ -375,13 +359,31 @@ dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_ser
hdl = create_topic_pp_locked (pp, ktp, (sertopic_registered->ops == &ddsi_sertopic_ops_builtintopic), sertopic_registered, listener, sedp_plist); hdl = create_topic_pp_locked (pp, ktp, (sertopic_registered->ops == &ddsi_sertopic_ops_builtintopic), sertopic_registered, listener, sedp_plist);
ddsi_sertopic_unref (*sertopic); ddsi_sertopic_unref (*sertopic);
*sertopic = sertopic_registered; *sertopic = sertopic_registered;
dds_participant_unlock (pp); ddsrt_mutex_unlock (&pp->m_entity.m_mutex);
dds_entity_unpin (&pp->m_entity);
GVTRACE ("dds_create_topic_generic: new topic %"PRId32"\n", hdl); GVTRACE ("dds_create_topic_generic: new topic %"PRId32"\n", hdl);
return hdl; return hdl;
error:
dds_entity_unpin (&pp->m_entity);
dds_delete_qos (new_qos);
return rc;
}
dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist)
{
if (sertopic == NULL || *sertopic == NULL || (*sertopic)->name == NULL)
return DDS_RETCODE_BAD_PARAMETER;
if (!strncmp((*sertopic)->name, "DCPS", 4))
return DDS_RETCODE_BAD_PARAMETER;
return dds_create_topic_impl (participant, sertopic, qos, listener, sedp_plist);
} }
dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_sertopic *sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_sertopic *sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist)
{ {
if (sertopic == NULL)
return DDS_RETCODE_BAD_PARAMETER;
dds_entity_t ret; dds_entity_t ret;
struct ddsi_sertopic *st = sertopic; struct ddsi_sertopic *st = sertopic;
ddsi_sertopic_ref (st); ddsi_sertopic_ref (st);

View file

@ -849,7 +849,7 @@ static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_i
assert (new_intv->min < new_intv->maxp1); assert (new_intv->min < new_intv->maxp1);
/* insert new node & continue the loop with intv set to the /* insert new node & continue the loop with intv set to the
new interval */ new interval */
if (ddsrt_avl_lookup_ipath (&whc_seq_treedef, &whc->seq, &new_intv->min, &path) != NULL) if (ddsrt_avl_lookup_ipath (&whc_seq_treedef, &whc->seq, &new_intv->min, &path) != NULL)
assert (0); assert (0);
ddsrt_avl_insert_ipath (&whc_seq_treedef, &whc->seq, new_intv, &path); ddsrt_avl_insert_ipath (&whc_seq_treedef, &whc->seq, new_intv, &path);

View file

@ -267,8 +267,7 @@ void dds_write_flush (dds_entity_t writer)
{ {
struct thread_state1 * const ts1 = lookup_thread_state (); struct thread_state1 * const ts1 = lookup_thread_state ();
dds_writer *wr; dds_writer *wr;
dds_return_t rc; if (dds_writer_lock (writer, &wr) == DDS_RETCODE_OK)
if ((rc = dds_writer_lock (writer, &wr)) == DDS_RETCODE_OK)
{ {
thread_state_awake (ts1, &wr->m_entity.m_domain->gv); thread_state_awake (ts1, &wr->m_entity.m_domain->gv);
nn_xpack_send (wr->m_xp, true); nn_xpack_send (wr->m_xp, true);

View file

@ -20,6 +20,7 @@
#include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_xmsg.h"
#include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/ddsi_entity_index.h"
#include "dds/ddsi/ddsi_security_omg.h"
#include "dds__writer.h" #include "dds__writer.h"
#include "dds__listener.h" #include "dds__listener.h"
#include "dds__init.h" #include "dds__init.h"
@ -312,6 +313,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
dds_topic_defer_set_qos (tp); dds_topic_defer_set_qos (tp);
/* Merge Topic & Publisher qos */ /* Merge Topic & Publisher qos */
struct ddsi_domaingv *gv = &pub->m_entity.m_domain->gv;
wqos = dds_create_qos (); wqos = dds_create_qos ();
if (qos) if (qos)
ddsi_xqos_mergein_missing (wqos, qos, DDS_WRITER_QOS_MASK); ddsi_xqos_mergein_missing (wqos, qos, DDS_WRITER_QOS_MASK);
@ -319,29 +321,45 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
ddsi_xqos_mergein_missing (wqos, pub->m_entity.m_qos, ~(uint64_t)0); ddsi_xqos_mergein_missing (wqos, pub->m_entity.m_qos, ~(uint64_t)0);
if (tp->m_ktopic->qos) if (tp->m_ktopic->qos)
ddsi_xqos_mergein_missing (wqos, tp->m_ktopic->qos, ~(uint64_t)0); ddsi_xqos_mergein_missing (wqos, tp->m_ktopic->qos, ~(uint64_t)0);
ddsi_xqos_mergein_missing (wqos, &pub->m_entity.m_domain->gv.default_xqos_wr, ~(uint64_t)0); ddsi_xqos_mergein_missing (wqos, &gv->default_xqos_wr, ~(uint64_t)0);
if ((rc = ddsi_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0 || if ((rc = ddsi_xqos_valid (&gv->logconfig, wqos)) < 0 || (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK)
(rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK)
{
dds_delete_qos(wqos);
goto err_bad_qos; goto err_bad_qos;
thread_state_awake (lookup_thread_state (), gv);
const struct ddsi_guid *ppguid = dds_entity_participant_guid (&pub->m_entity);
struct participant *pp = entidx_lookup_participant_guid (gv->entity_index, ppguid);
/* When deleting a participant, the child handles (that include the publisher)
are removed before removing the DDSI participant. So at this point, within
the publisher lock, we can assert that the participant exists. */
assert (pp != NULL);
#ifdef DDSI_INCLUDE_SECURITY
/* Check if DDS Security is enabled */
if (q_omg_participant_is_secure (pp))
{
/* ask to access control security plugin for create writer permissions */
if (!q_omg_security_check_create_writer (pp, gv->config.domainId, tp->m_stopic->name, wqos))
{
rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY;
goto err_not_allowed;
}
} }
#endif
/* Create writer */ /* Create writer */
ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.xmit_conn; ddsi_tran_conn_t conn = gv->xmit_conn;
struct dds_writer * const wr = dds_alloc (sizeof (*wr)); struct dds_writer * const wr = dds_alloc (sizeof (*wr));
const dds_entity_t writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK); const dds_entity_t writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK);
wr->m_topic = tp; wr->m_topic = tp;
dds_entity_add_ref_locked (&tp->m_entity); dds_entity_add_ref_locked (&tp->m_entity);
wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), pub->m_entity.m_domain->gv.config.xpack_send_async); wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), gv->config.xpack_send_async);
wrinfo = whc_make_wrinfo (wr, wqos); wrinfo = whc_make_wrinfo (wr, wqos);
wr->m_whc = whc_new (&pub->m_entity.m_domain->gv, wrinfo); wr->m_whc = whc_new (gv, wrinfo);
whc_free_wrinfo (wrinfo); whc_free_wrinfo (wrinfo);
wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch; wr->whc_batch = gv->config.whc_batch;
thread_state_awake (lookup_thread_state (), &pub->m_entity.m_domain->gv); rc = new_writer (&wr->m_wr, &wr->m_entity.m_guid, NULL, pp, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, dds_entity_participant_guid (&pub->m_entity), tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
assert(rc == DDS_RETCODE_OK); assert(rc == DDS_RETCODE_OK);
thread_state_asleep (lookup_thread_state ()); thread_state_asleep (lookup_thread_state ());
@ -355,7 +373,12 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
dds_publisher_unlock (pub); dds_publisher_unlock (pub);
return writer; return writer;
#ifdef DDSI_INCLUDE_SECURITY
err_not_allowed:
thread_state_asleep (lookup_thread_state ());
#endif
err_bad_qos: err_bad_qos:
dds_delete_qos(wqos);
dds_topic_allow_set_qos (tp); dds_topic_allow_set_qos (tp);
err_pp_mismatch: err_pp_mismatch:
dds_topic_unpin (tp); dds_topic_unpin (tp);
@ -387,14 +410,14 @@ dds_entity_t dds_get_publisher (dds_entity_t writer)
} }
} }
dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, dds_time_t abstimeout) dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, ddsi_guid_t *rdguid, dds_time_t abstimeout)
{ {
/* during lifetime of the writer m_wr is constant, it is only during deletion that it /* during lifetime of the writer m_wr is constant, it is only during deletion that it
gets erased at some point */ gets erased at some point */
if (wr->m_wr == NULL) if (wr->m_wr == NULL)
return DDS_RETCODE_OK; return DDS_RETCODE_OK;
else else
return writer_wait_for_acks (wr->m_wr, abstimeout); return writer_wait_for_acks (wr->m_wr, rdguid, abstimeout);
} }
DDS_GET_STATUS(writer, publication_matched, PUBLICATION_MATCHED, total_count_change, current_count_change) DDS_GET_STATUS(writer, publication_matched, PUBLICATION_MATCHED, total_count_change, current_count_change)

View file

@ -59,7 +59,9 @@ set(ddsc_test_sources
"write_various_types.c" "write_various_types.c"
"writer.c" "writer.c"
"test_common.c" "test_common.c"
"test_common.h") "test_common.h"
"test_oneliner.c"
"test_oneliner.h")
if(ENABLE_LIFESPAN) if(ENABLE_LIFESPAN)
list(APPEND ddsc_test_sources "lifespan.c") list(APPEND ddsc_test_sources "lifespan.c")
@ -83,11 +85,10 @@ set(CUnit_ddsc_config_simple_udp_file "${CMAKE_CURRENT_LIST_DIR}/config_simple_u
set(CUnit_ddsc_config_simple_udp_uri "file://${CUnit_ddsc_config_simple_udp_file}") set(CUnit_ddsc_config_simple_udp_uri "file://${CUnit_ddsc_config_simple_udp_file}")
set(CUnit_ddsc_config_simple_udp_max_participants "0") set(CUnit_ddsc_config_simple_udp_max_participants "0")
set(CUnit_ddsc_config_simple_udp_env "${PROJECT_NAME_CAPS}_URI=${CUnit_ddsc_config_simple_udp_uri};MAX_PARTICIPANTS=${CUnit_ddsc_config_simple_udp_max_participants};${CUnit_ddsc_config_simple_udp_env}") set(CUnit_ddsc_config_simple_udp_env "${PROJECT_NAME_CAPS}_URI=${CUnit_ddsc_config_simple_udp_uri};MAX_PARTICIPANTS=${CUnit_ddsc_config_simple_udp_max_participants};${CUnit_ddsc_config_simple_udp_env}")
set_tests_properties( set_tests_properties(
CUnit_ddsc_config_simple_udp CUnit_ddsc_config_simple_udp
PROPERTIES PROPERTIES
REQUIRED_FILES ${CUnit_ddsc_config_simple_udp_file} REQUIRED_FILES ${CUnit_ddsc_config_simple_udp_file}
ENVIRONMENT "${CUnit_ddsc_config_simple_udp_env}") ENVIRONMENT "${CUnit_ddsc_config_simple_udp_env}")
configure_file("config_env.h.in" "config_env.h") configure_file("config_env.h.in" "config_env.h" @ONLY)

View file

@ -18,6 +18,8 @@
#include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/environ.h" #include "dds/ddsrt/environ.h"
#include "dds/ddsrt/heap.h" #include "dds/ddsrt/heap.h"
#include "dds/ddsi/q_misc.h"
#include "dds/ddsi/ddsi_xqos.h"
#include "test_common.h" #include "test_common.h"
@ -28,7 +30,7 @@
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; const char *env_uri = NULL;
ddsrt_getenv (env_variable, &env_uri); ddsrt_getenv (env_variable, &env_uri);
#ifdef FORCE_ENV #ifdef FORCE_ENV
{ {
@ -84,3 +86,99 @@ CU_Test (ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini)
dds_delete (domain); dds_delete (domain);
} }
/*
* The 'found' variable will contain flags related to the expected log
* messages that were received.
* Using flags will allow to show that when message isn't received,
* which one it was.
*/
static uint32_t found;
static void logger(void *ptr, const dds_log_data_t *data)
{
char **expected = (char**)ptr;
for (uint32_t i = 0; expected[i] != NULL; i++) {
if (ddsi2_patmatch(expected[i], data->message)) {
found |= (uint32_t)(1 << i);
}
}
}
CU_Test(ddsc_security_config, empty, .init = ddsrt_init, .fini = ddsrt_fini)
{
/* Expected traces when creating participant with an empty security element. We need to
test this one here to be sure that it refuses to start when security is configured
but the implementation doesn't include support for it. */
const char *log_expected[] = {
#ifndef DDSI_INCLUDE_SECURITY
"config: //CycloneDDS/Domain: DDSSecurity: unknown element*",
#else
"config: //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCertificate/#text: element missing in configuration*",
"config: //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCA/#text: element missing in configuration*",
"config: //CycloneDDS/Domain/DDSSecurity/Authentication/PrivateKey/#text: element missing in configuration*",
#endif
NULL
};
dds_entity_t participant;
/* Set up the trace sinks to detect the config parsing. */
dds_set_log_mask(DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG);
dds_set_log_sink(&logger, (void*)log_expected);
dds_set_trace_sink(&logger, (void*)log_expected);
/* Create participant with an empty security element. */
found = 0;
ddsrt_setenv(URI_VARIABLE, "<DDSSecurity/>");
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
ddsrt_setenv(URI_VARIABLE, "");
CU_ASSERT_FATAL(participant < 0);
dds_set_log_sink(NULL, NULL);
dds_set_trace_sink(NULL, NULL);
/* All traces should have been provided. */
#ifndef DDSI_INCLUDE_SECURITY
CU_ASSERT_FATAL(found == 0x1);
#else
CU_ASSERT_FATAL(found == 0x7);
#endif
}
CU_Test(ddsc_security_qos, empty, .init = ddsrt_init, .fini = ddsrt_fini)
{
/* Expected traces when creating participant with some (not all) security QoS
settings. We need to test this one here to be sure that it also refuses to
start when security is configured but the implementation doesn't include
support for it. */
const char *log_expected[] = {
#ifdef DDSI_INCLUDE_SECURITY
"new_participant(*): using security settings from QoS*",
"new_participant(*): required security property * missing*",
#endif
NULL
};
/* Set up the trace sinks to detect the config parsing. */
dds_set_log_mask (DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG);
dds_set_log_sink (&logger, (void *) log_expected);
dds_set_trace_sink (&logger, (void *) log_expected);
/* Create participant with incomplete/nonsensical security configuration: this should always fail */
found = 0;
dds_qos_t *qos = dds_create_qos ();
dds_qset_prop (qos, "dds.sec.nonsense", "");
dds_entity_t domain = dds_create_domain (0, "<Tracing><Category>trace</Category>");
CU_ASSERT_FATAL (domain > 0);
dds_entity_t participant = dds_create_participant (0, qos, NULL);
dds_delete_qos (qos);
CU_ASSERT_FATAL (participant < 0);
(void) dds_delete (domain);
dds_set_log_sink (NULL, NULL);
dds_set_trace_sink (NULL, NULL);
/* All traces should have been provided. */
#ifndef DDSI_INCLUDE_SECURITY
CU_ASSERT_FATAL (found == 0x0);
#else
CU_ASSERT_FATAL (found == 0x3);
#endif
}

View file

@ -125,6 +125,7 @@ static void deadline_init(void)
dds_qset_history(g_qos, DDS_HISTORY_KEEP_ALL, DDS_LENGTH_UNLIMITED); dds_qset_history(g_qos, DDS_HISTORY_KEEP_ALL, DDS_LENGTH_UNLIMITED);
dds_qset_durability(g_qos, DDS_DURABILITY_TRANSIENT_LOCAL); dds_qset_durability(g_qos, DDS_DURABILITY_TRANSIENT_LOCAL);
dds_qset_reliability(g_qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); dds_qset_reliability(g_qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY);
dds_qset_writer_data_lifecycle(g_qos, false);
} }
static void deadline_fini(void) static void deadline_fini(void)
@ -422,7 +423,10 @@ CU_Theory((int32_t n_inst, uint8_t unreg_nth, uint8_t dispose_nth), ddsc_deadlin
n_dispose++; n_dispose++;
} }
} }
n_alive = n_inst - n_dispose - n_unreg; /* FIXME: should unregistered instances cause deadline expirations? I do think so
and that is what it actually implemented
if they shouldn't: n_alive = n_inst - n_dispose - n_unreg */
n_alive = n_inst - n_dispose;
/* Sleep deadline_dur + 50% and check missed deadline count */ /* Sleep deadline_dur + 50% and check missed deadline count */
sleepfor(3 * deadline_dur / 2); sleepfor(3 * deadline_dur / 2);

File diff suppressed because it is too large Load diff

View file

@ -110,6 +110,7 @@ CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities)
CU_ASSERT_FATAL (result == DDS_RETCODE_OK); CU_ASSERT_FATAL (result == DDS_RETCODE_OK);
/* return resets buf[0] (so that it picks up the loan the next time) and zeros the data */ /* return resets buf[0] (so that it picks up the loan the next time) and zeros the data */
CU_ASSERT_FATAL (ptrs[0] == NULL); CU_ASSERT_FATAL (ptrs[0] == NULL);
assert (ptr0copy != NULL); /* clang static analyzer */
CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, sizeof (s)) == 0); CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, sizeof (s)) == 0);
/* read 3, return: should work fine, causes realloc */ /* read 3, return: should work fine, causes realloc */
@ -121,6 +122,7 @@ CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities)
result = dds_return_loan (reader, ptrs, n); result = dds_return_loan (reader, ptrs, n);
CU_ASSERT_FATAL (result == DDS_RETCODE_OK); CU_ASSERT_FATAL (result == DDS_RETCODE_OK);
CU_ASSERT_FATAL (ptrs[0] == NULL); CU_ASSERT_FATAL (ptrs[0] == NULL);
assert (ptr0copy != NULL); /* clang static analyzer */
CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, 3 * sizeof (s)) == 0); CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, 3 * sizeof (s)) == 0);
/* read 1 using loan, expecting to get the same address (no realloc needed), defer return. /* read 1 using loan, expecting to get the same address (no realloc needed), defer return.
@ -145,6 +147,7 @@ CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities)
{ {
const struct RoundTripModule_DataType *a = ptrs[0]; const struct RoundTripModule_DataType *a = ptrs[0];
const struct RoundTripModule_DataType *b = ptrs2[0]; const struct RoundTripModule_DataType *b = ptrs2[0];
assert (a != NULL && b != NULL); /* clang static analyzer */
CU_ASSERT_FATAL (a->payload._length == b->payload._length); CU_ASSERT_FATAL (a->payload._length == b->payload._length);
CU_ASSERT_FATAL (a->payload._buffer != b->payload._buffer); CU_ASSERT_FATAL (a->payload._buffer != b->payload._buffer);
CU_ASSERT_FATAL (a->payload._buffer[0] == b->payload._buffer[0]); CU_ASSERT_FATAL (a->payload._buffer[0] == b->payload._buffer[0]);
@ -164,6 +167,7 @@ CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities)
//This should be a use-after-free //This should be a use-after-free
//CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, sizeof (s)) == 0); //CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, sizeof (s)) == 0);
(void) ptr0copy;
} }
CU_Test (ddsc_loan, take_cleanup, .init = create_entities, .fini = delete_entities) CU_Test (ddsc_loan, take_cleanup, .init = create_entities, .fini = delete_entities)

View file

@ -111,7 +111,7 @@ CU_Test(ddsc_participant, create_with_conf_no_env) {
ddsrt_setenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", CONFIG_ENV_SIMPLE_UDP); ddsrt_setenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", CONFIG_ENV_SIMPLE_UDP);
ddsrt_setenv("MAX_PARTICIPANTS", CONFIG_ENV_MAX_PARTICIPANTS); ddsrt_setenv("MAX_PARTICIPANTS", CONFIG_ENV_MAX_PARTICIPANTS);
char * env_uri = NULL; const char * env_uri = NULL;
ddsrt_getenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &env_uri); ddsrt_getenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &env_uri);
CU_ASSERT_PTR_NOT_EQUAL_FATAL(env_uri, NULL); CU_ASSERT_PTR_NOT_EQUAL_FATAL(env_uri, NULL);

View file

@ -11,6 +11,7 @@
*/ */
#include "CUnit/Test.h" #include "CUnit/Test.h"
#include "dds/dds.h" #include "dds/dds.h"
#include <assert.h>
/**************************************************************************** /****************************************************************************
* Convenience global policies * Convenience global policies
@ -146,7 +147,10 @@ static const char* c_userdata = "user_key";
static const char* c_topicdata = "topic_key"; static const char* c_topicdata = "topic_key";
static const char* c_groupdata = "group_key"; static const char* c_groupdata = "group_key";
static const char* c_partitions[] = {"Partition1", "Partition2"}; static const char* c_partitions[] = {"Partition1", "Partition2"};
static const char* c_property_names[] = {"prop1", "prop2", "prop3"};
static const char* c_property_values[] = {"val1", "val2", "val3"};
static const char* c_bproperty_names[] = {"bprop1", "bprop2", "bprop3"};
static const unsigned char c_bproperty_values[3][3] = {{0x0, 0x1, 0x2}, {0x2, 0x3, 0x4}, {0x5, 0x6, 0x7}};
/**************************************************************************** /****************************************************************************
@ -646,3 +650,191 @@ CU_Test(ddsc_qos, durability_service, .init=qos_init, .fini=qos_fini)
CU_ASSERT_EQUAL_FATAL(p.max_samples_per_instance, g_pol_durability_service.max_samples_per_instance); CU_ASSERT_EQUAL_FATAL(p.max_samples_per_instance, g_pol_durability_service.max_samples_per_instance);
} }
CU_Test(ddsc_qos, property, .init=qos_init, .fini=qos_fini)
{
char * value = NULL;
char ** names = NULL;
uint32_t cnt = 0;
/* NULLs shouldn't crash and be a noops. */
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, NULL, NULL));
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], NULL));
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, NULL, &value));
CU_ASSERT_FATAL (!dds_qget_prop (NULL, c_property_names[0], &value));
dds_qset_prop (g_qos, NULL, NULL);
dds_qset_prop (g_qos, NULL, c_property_values[0]);
dds_qset_prop (NULL, c_property_names[0], c_property_values[0]);
/* Set null value should not succeed, setting empty string should */
dds_qset_prop (g_qos, c_property_names[0], NULL);
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], &value));
dds_qset_prop (g_qos, c_property_names[0], "");
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, "");
dds_free (value);
/* Getting after setting, should yield the original input. */
dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]);
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]);
dds_free (value);
/* Overwrite value for existing property (and reset value) */
dds_qset_prop (g_qos, c_property_names[0], c_property_values[1]);
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[1]);
dds_free (value);
dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]);
/* Set 2nd prop and get length */
dds_qset_prop (g_qos, c_property_names[1], c_property_values[1]);
CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 2);
/* Set another property and get list of property names */
dds_qset_prop (g_qos, c_property_names[2], c_property_values[2]);
CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, &names));
CU_ASSERT_EQUAL_FATAL (cnt, 3);
for (uint32_t i = 0; i < cnt; i++)
{
CU_ASSERT_STRING_EQUAL_FATAL (names[i], c_property_names[i]);
dds_free (names[i]);
}
dds_free (names);
/* Unset a property and check if removed */
dds_qunset_prop (g_qos, c_property_names[1]);
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[1], &value));
CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 2);
CU_ASSERT_FATAL(dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]);
dds_free (value);
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[2], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[2]);
dds_free (value);
dds_qunset_prop (g_qos, c_property_names[0]);
dds_qunset_prop (g_qos, c_property_names[2]);
CU_ASSERT_FATAL (!dds_qget_propnames (g_qos, &cnt, NULL));
}
CU_Test(ddsc_qos, bproperty, .init=qos_init, .fini=qos_fini)
{
void * bvalue = NULL;
size_t size = 0;
char ** names = NULL;
uint32_t cnt = 0;
/* NULLs shouldn't crash and be a noops. */
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, NULL, NULL, NULL));
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_bproperty_names[0], NULL, NULL));
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, NULL, &bvalue, &size));
CU_ASSERT_FATAL (!dds_qget_bprop (NULL, c_bproperty_names[0], &bvalue, &size));
dds_qset_bprop (g_qos, NULL, NULL, 0);
dds_qset_bprop (g_qos, NULL, &c_bproperty_values[0], 0);
dds_qset_bprop (NULL, c_bproperty_names[0], c_bproperty_values[0], 0);
/* Set null value should succeed */
dds_qset_bprop (g_qos, c_bproperty_names[0], NULL, 0);
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size));
CU_ASSERT_EQUAL_FATAL (bvalue, NULL);
CU_ASSERT_EQUAL_FATAL (size, 0);
/* Getting after setting, should yield the original input. */
dds_qset_bprop (g_qos, c_bproperty_names[0], c_bproperty_values[0], 3);
CU_ASSERT_FATAL(dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
assert (c_bproperty_values[0] != NULL); /* for Clang static analyzer */
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0);
dds_free (bvalue);
/* Overwrite value for existing binary property (and reset value) */
dds_qset_bprop (g_qos, c_bproperty_names[0], c_bproperty_values[1], 3);
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
assert (c_bproperty_values[1] != NULL); /* for Clang static analyzer */
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[1], size), 0);
dds_free (bvalue);
dds_qset_bprop (g_qos, c_bproperty_names[0], &c_bproperty_values[0], 3);
/* Set 2nd binary prop and get length */
dds_qset_bprop (g_qos, c_bproperty_names[1], &c_bproperty_values[1], 3);
CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 2);
/* Set another binary property and get list of property names */
dds_qset_bprop (g_qos, c_bproperty_names[2], &c_bproperty_values[2], 3);
CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, &names));
CU_ASSERT_EQUAL_FATAL (cnt, 3);
for (uint32_t i = 0; i < cnt; i++)
{
CU_ASSERT_STRING_EQUAL_FATAL (names[i], c_bproperty_names[i]);
dds_free (names[i]);
}
dds_free (names);
/* Unset a binary property and check if removed */
dds_qunset_bprop (g_qos, c_bproperty_names[1]);
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_bproperty_names[1], &bvalue, &size));
CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 2);
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
assert (c_bproperty_values[0] != NULL); /* for Clang static analyzer */
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0);
dds_free (bvalue);
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[2], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
assert (c_bproperty_values[2] != NULL); /* for Clang static analyzer */
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[2], size), 0);
dds_free (bvalue);
dds_qunset_bprop (g_qos, c_bproperty_names[0]);
dds_qunset_bprop (g_qos, c_bproperty_names[2]);
CU_ASSERT_FATAL (!dds_qget_bpropnames (g_qos, &cnt, NULL));
}
CU_Test(ddsc_qos, property_mixed, .init=qos_init, .fini=qos_fini)
{
char * value = NULL;
void * bvalue = NULL;
size_t size = 0;
uint32_t cnt = 0;
/* Set property and binary property with same name */
dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]);
dds_qset_bprop (g_qos, c_property_names[0], c_bproperty_values[0], 3);
/* Check property values and count */
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_property_names[0], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
assert (c_bproperty_values[0] != NULL); /* for Clang static analyzer */
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0);
dds_free (bvalue);
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]);
dds_free (value);
CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 1);
CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 1);
/* Unset and check */
dds_qunset_bprop (g_qos, c_property_names[0]);
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_property_names[0], &bvalue, &size));
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]);
dds_free (value);
dds_qunset_prop (g_qos, c_property_names[0]);
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_FATAL (!dds_qget_propnames (g_qos, &cnt, NULL));
CU_ASSERT_FATAL (!dds_qget_bpropnames (g_qos, &cnt, NULL));
}

View file

@ -55,7 +55,7 @@
#define MAX_SAMPLES 21 #define MAX_SAMPLES 21
#define RDR_NOT_READ_CNT 11 #define RDR_NOT_READ_CNT 11
#define RDR_INV_READ_CNT 1 #define RDR_INV_READ_CNT 2
int rdr_expected_long_2[RDR_NOT_READ_CNT] = { 0, 1, 2, 6, 7, 9, 11, 13, 14, 16, 19 }; int rdr_expected_long_2[RDR_NOT_READ_CNT] = { 0, 1, 2, 6, 7, 9, 11, 13, 14, 16, 19 };
/* Because we only read one sample at a time, only the first sample of an instance /* Because we only read one sample at a time, only the first sample of an instance

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,326 @@
/*
* Copyright(c) 2020 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 _TEST_ONELINER_H_
#define _TEST_ONELINER_H_
#include <stdint.h>
#include <setjmp.h>
#include "dds/dds.h"
#include "dds/ddsrt/sync.h"
/** @brief run a "test" consisting of a sequence of simplish operations
*
* This operation takes a test description, really a program in a bizarre syntax, and
* executes it. Any failures, be it because of error codes coming out of the Cyclone
* calls or expected values being wrong cause it to fail the test via CU_ASSERT_FATAL.
* While it is doing this, it outputs the test steps to stdout including some actual
* values. An invalid program is mostly reported by calling abort(). It is geared towards
* checking for listener invocations and the effects on statuses.
*
* Entities in play:
*
* - participants: P P' P''
* - subscribers: R R' R''
* - publishers: W W' W''
* - readers: r s t r' s' t' r'' s'' t''
* - writers: w x y w' x' y' w'' x'' y''
*
* The unprimed ones exist in domain 0, the primed ones in domain 1 (but configured such
* that it talks to domain 0), and the double-primed ones in domain 2 (again configured such
* that it talks to domain 0) so that network-related listener invocations can be checked
* as well.
*
* The first mention of an entity creates it as well as its ancestors. Implicitly created
* ancestors always have standard QoS and have no listeners. There is one topic that is
* created implicitly when the participant is created.
*
* Standard QoS is: default + reliable (100ms), by-source-timestamp, keep-all. The QoS of
* a reader/writer can be overridden at the first mention of it (i.e., when it is created)
* by appending a list of QoS overrides between parentheses.
*
* A program consists of a sequence of operations separated by whitespace, ';' or '/'
* (there is no meaning to the separators, they exist to allow visual grouping):
*
* PROGRAM ::= (OP (\s+|;)*)*
*
* OP ::= (LISTENER)* ENTITY-NAME[(QOS[,QOS[,QOS...]])]
*
* If entity ENTITY-NAME does not exist:
* creates the entity with the given listeners installed
* QOS can be used to override the standard QoS
* else
* changes the entity's listeners to the specified ones
* (see above for the valid ENTITY-NAMEs)
*
* | -ENTITY-NAME
*
* Deletes the specified entity
*
* | WRITE-LIKE[fail] ENTITY-NAME K[@DT]
* | WRITE-LIKE[fail] ENTITY-NAME (K,X,Y)[@DT]
*
* Writes/disposes/unregisters (K,0,0) (first form) or (K,X,Y). If
* "fail" is appended, the expectation is that it fails with a
* timeout, if @DT is appended, the timestamp is the start time of
* the test + <dt>s rather than the current time; DT is a
* floating-point number
*
* | READ-LIKE ENTITY-NAME
* | READ-LIKE(A,B) ENTITY-NAME
* | READ-LIKE{[S1[,S2[,S3...]][,...]} ENTITY-NAME
*
* Reads/takes at most 10 samples. The second form counts the
* number of valid and invalid samples seen and checks them against
* A and B.
*
* In the third form, the exact result set is given by the sample
* Si, which is a comma-separated list of samples:
*
* [STATE]K[ENTITY-NAME][@DT]
* [STATE](K,X,Y)[ENTITY-NAME][@DT]
*
* The first form is an invalid sample with only the (integer) key
* value K, the second form also specifies the two (integer)
* attribute fields.
*
* STATE specifies allowed sample (f - not-read (fresh), s - read
* (stale)), instance (a - alive, u - no-writers (unregistered) d -
* disposed) and view states (n - new, o - old). If no sample state
* is specified, all sample states are allowed, &c.
*
* ENTITY-NAME is the name of the publishing writer expected in the
* publication_handle. Not specifying a writer means any writer is
* ok. DT is the timestamp in the same manner as the write-like
* operations. Not specifying a timestamp means any timestamp is
* ok.
*
* If the expected set ends up with "..." there may be other samples
* in the result as well.
*
* | ?LISTENER[(ARGS)] ENTITY-NAME
*
* Waits until the specified listener has been invoked on <entity
* name> using a flag set by the listener function, resets the flag
* and verifies that neither the entity status bit nor the "change"
* fields in the various statuses were set.
*
* ARGS is used to check the status argument most recently passed to
* the listener:
*
* da(A) verifies that it has been invoked A times
* dor(A) see da
* it(A,B) verifies count and change match A and B, policy
* matches RELIABILITY
* lc(A,B,C,D,E) verifies that alive and not-alive counts match A
* and B, that alive and not-alive changes match C and D
* and that the last handle matches E if an entity name
* (ignored if E = "*")
* ll (A,B) verifies count and change match A and B
* odm (A,B) verifies count and change match A and B, last handle
* is ignored
* oiq (A,B,C) verifies that total count and change match A and B
* and that the mismatching QoS is C (using the same
* abbreviations as used for defining QoS on entity
* creation)
* pm (A,B,C,D,E) verifies that total count and change match A and
* B, that current count and change match C and D and
* that the last handle matches E if an entity name
* (ignored if E = "*")
* rdm see odm
* riq see oiq
* sl (A,B) verifies that total count and change match A and B
* sr (A,B,C) verifies total count and change match A and B, and
* that the reason matches C (one of "s" for samples,
* "i" for instances, "spi" for samples per instance)
* sm see pm
*
* | ?!LISTENER
*
* (Not listener) tests that LISTENER has not been invoked since
* last reset
*
* | sleep D
*
* Delay program execution for D s (D is a floating-point number)
*
* | deaf ENTITY-NAME
* | hearing ENTITY-NAME
*
* Makes the domain wherein the specified entity exists deaf,
* respectively restoring hearing. The entity must be either P or
* P' and both must exist. Plays some tricks to speed up lease
* expiry and reconnection (like forcibly deleting a proxy
* participant or triggering the publication of SPDP packets).
*
* WRITE-LIKE ::= wr write
* | wrdisp write-dispose
* | disp dispose
* | unreg unregister
*
* READ-LIKE ::= read dds_read (so any state)
* | take dds_take (so any state)
*
* LISTENER ::= da data available (acts on a reader)
* | dor data on readers (acts on a subcsriber)
* | it incompatible topic (acts on a topic)
* | lc liveliness changed (acts on a reader)
* | ll liveliness lost (acts on a writer)
* | odm offered deadline missed (acts on a writer)
* | oiq offered incompatible QoS (acts on a writer)
* | pm publication matched (acts on a writer)
* | rdm requested deadline missed (acts on a reader)
* | riq requested incompatible QoS (acts on a reader)
* | sl sample lost (acts on a reader)
* | sr sample rejected (acts on a reader)
* | sm subscription matched (acts on a reader)
*
* QOS ::= ad={y|n} auto-dispose unregistered instances
* | d={v|tl|t|p} durability
* | dl={inf|DT} deadline (infinite or DT seconds)
* | ds=DT/H/RL durability service: cleanup delay, history,
* resource limits
* | do={r|s} by-reception or by-source destination order
* | h={N|all} history keep-last-N or keep-all
* | lb={inf|DT} latency budget
* | ll={a[:DT]|p:DT|w:DT} liveliness (automatic, manual by
* participant, manual by topic)
* | ls={inf|DT} lifespan
* | o={s|x[:N]} ownership shared or exclusive (strength N)
* | p={i|t|g} presentation: instance, coherent-topic or
* coherent-group
* | r={be|r[:DT]} best-effort or reliable (with max blocking time)
* | rl=N[/N[/N]] resource limits (sample, instances, samples per
* instance; "inf" is allowed, ommitted ones are
* unlimited)
* | tp=N transport-priority
* | ud=... user data (with escape sequences and hex/octal
* input allowed)
*
* All entities share the listeners with their global state. Only the latest invocation is visible.
*
* @param[in] ops Program to execute.
*
* @return > 0 success, 0 failure, < 0 invalid input
*/
int test_oneliner (const char *ops);
union oneliner_tokval {
int i;
int64_t d;
char n[32];
};
struct oneliner_lex {
const char *inp;
dds_time_t tref;
int tok;
union oneliner_tokval v;
};
struct oneliner_ctx;
struct oneliner_cb {
struct oneliner_ctx *ctx;
dds_listener_t *list;
uint32_t cb_called[DDS_STATUS_ID_MAX + 1];
dds_entity_t cb_topic, cb_writer, cb_reader, cb_subscriber;
dds_inconsistent_topic_status_t cb_inconsistent_topic_status;
dds_liveliness_changed_status_t cb_liveliness_changed_status;
dds_liveliness_lost_status_t cb_liveliness_lost_status;
dds_offered_deadline_missed_status_t cb_offered_deadline_missed_status;
dds_offered_incompatible_qos_status_t cb_offered_incompatible_qos_status;
dds_publication_matched_status_t cb_publication_matched_status;
dds_requested_deadline_missed_status_t cb_requested_deadline_missed_status;
dds_requested_incompatible_qos_status_t cb_requested_incompatible_qos_status;
dds_sample_lost_status_t cb_sample_lost_status;
dds_sample_rejected_status_t cb_sample_rejected_status;
dds_subscription_matched_status_t cb_subscription_matched_status;
};
struct oneliner_ctx {
struct oneliner_lex l;
dds_entity_t es[3 * 9];
dds_entity_t tps[3];
dds_entity_t doms[3];
dds_instance_handle_t esi[3 * 9];
// built-in topic readers for cross-referencing instance handles
dds_entity_t pubrd[3];
dds_entity_t subrd[3];
// topic name used for data
char topicname[100];
const dds_qos_t *qos;
dds_qos_t *rwqos;
int result;
char msg[256];
jmp_buf jb;
ddsrt_mutex_t g_mutex;
ddsrt_cond_t g_cond;
struct oneliner_cb cb[3];
};
/** @brief Initialize a "oneliner test" context
*
* @param[out] ctx context to initialize
*/
void test_oneliner_init (struct oneliner_ctx *ctx);
/** @brief Run a sequence of operations in an initialized context
*
* If the context indicates a preceding step has failed, this is a
* no-op and the previous result is propagated to the return value.
*
* @param[in,out] ctx context to operate in
* @param[in] ops sequence of operations to execute (@ref test_oneliner)
*
* @return integer indicating success or failure
*
* @retval 1 success
* @retval 0 test failure
* @retval <0 syntax error unexpected error
*/
int test_oneliner_step (struct oneliner_ctx *ctx, const char *ops);
/** @brief Get a pointer to the error message from a "oneliner test"
*
* If a preceding step has failed, this returns a pointer to a message
* containing some information about the failure. If no error
* occurred, the message is meaningless.
*
*
* @param[in] ctx context to retrieve message from
*
* @return pointer to null-terminated string aliasing a string in ctx
*/
const char *test_oneliner_message (const struct oneliner_ctx *ctx);
/** @brief Deinitialize a "oneliner test" context
*
* This releases all resources used by the context.
*
* @param[in,out] ctx context to operate in
*
* @return integer indicating success or failure in any of the
* preceding steps. If no steps were taken, the result is success.
*
* @retval 1 success
* @retval 0 test failure
* @retval <0 syntax error unexpected error
*/
int test_oneliner_fini (struct oneliner_ctx *ctx);
#endif

View file

@ -170,7 +170,7 @@ CU_Test(ddsc_topic_create, desc_null, .init=ddsc_topic_init, .fini=ddsc_topic_fi
CU_TheoryDataPoints(ddsc_topic_create, invalid_names) = { CU_TheoryDataPoints(ddsc_topic_create, invalid_names) = {
CU_DataPoints(char *, NULL, "", "mi-dle", "-start", "end-", "1st", "Thus$", "pl+s", "t(4)"), CU_DataPoints(char *, NULL, "", "mi-dle", "-start", "end-", "1st", "Thus$", "pl+s", "t(4)", "DCPSmytopic"),
}; };
CU_Theory((char *name), ddsc_topic_create, invalid_names, .init=ddsc_topic_init, .fini=ddsc_topic_fini) CU_Theory((char *name), ddsc_topic_create, invalid_names, .init=ddsc_topic_init, .fini=ddsc_topic_fini)
{ {

View file

@ -18,11 +18,18 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_raweth.c ddsi_raweth.c
ddsi_ipaddr.c ddsi_ipaddr.c
ddsi_mcgroup.c ddsi_mcgroup.c
ddsi_security_util.c
ddsi_security_omg.c
ddsi_portmapping.c ddsi_portmapping.c
ddsi_handshake.c
ddsi_serdata.c ddsi_serdata.c
ddsi_serdata_default.c ddsi_serdata_default.c
ddsi_serdata_pserop.c
ddsi_serdata_plist.c
ddsi_sertopic.c ddsi_sertopic.c
ddsi_sertopic_default.c ddsi_sertopic_default.c
ddsi_sertopic_pserop.c
ddsi_sertopic_plist.c
ddsi_iid.c ddsi_iid.c
ddsi_tkmap.c ddsi_tkmap.c
ddsi_vendor.c ddsi_vendor.c
@ -81,10 +88,15 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_ipaddr.h ddsi_ipaddr.h
ddsi_mcgroup.h ddsi_mcgroup.h
ddsi_plist_generic.h ddsi_plist_generic.h
ddsi_security_util.h
ddsi_security_omg.h
ddsi_portmapping.h ddsi_portmapping.h
ddsi_handshake.h
ddsi_serdata.h ddsi_serdata.h
ddsi_sertopic.h ddsi_sertopic.h
ddsi_serdata_default.h ddsi_serdata_default.h
ddsi_serdata_pserop.h
ddsi_serdata_plist.h
ddsi_iid.h ddsi_iid.h
ddsi_tkmap.h ddsi_tkmap.h
ddsi_vendor.h ddsi_vendor.h
@ -92,6 +104,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_builtin_topic_if.h ddsi_builtin_topic_if.h
ddsi_rhc.h ddsi_rhc.h
ddsi_guid.h ddsi_guid.h
ddsi_keyhash.h
ddsi_entity_index.h ddsi_entity_index.h
ddsi_deadline.h ddsi_deadline.h
ddsi_deliver_locally.h ddsi_deliver_locally.h
@ -142,6 +155,19 @@ endif()
target_sources(ddsc target_sources(ddsc
PRIVATE ${srcs_ddsi} ${hdrs_private_ddsi}) PRIVATE ${srcs_ddsi} ${hdrs_private_ddsi})
if(ENABLE_SECURITY)
PREPEND(security_srcs "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_security_msg.c
ddsi_security_exchange.c)
PREPEND(security_hdrs "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_security_msg.h
ddsi_security_exchange.h)
target_sources(ddsc
PRIVATE ${security_srcs} ${security_hdrs})
endif()
target_include_directories(ddsc target_include_directories(ddsc
PRIVATE "${CMAKE_CURRENT_LIST_DIR}/include") PRIVATE "${CMAKE_CURRENT_LIST_DIR}/include")

View file

@ -46,6 +46,9 @@ struct ddsi_tran_factory;
struct ddsrt_thread_pool_s; struct ddsrt_thread_pool_s;
struct debug_monitor; struct debug_monitor;
struct ddsi_tkmap; struct ddsi_tkmap;
struct dds_security_context;
struct dds_security_match_index;
struct ddsi_hsadmin;
typedef struct config_in_addr_node { typedef struct config_in_addr_node {
nn_locator_t loc; nn_locator_t loc;
@ -258,6 +261,12 @@ struct ddsi_domaingv {
dds_qos_t spdp_endpoint_xqos; dds_qos_t spdp_endpoint_xqos;
dds_qos_t builtin_endpoint_xqos_rd; dds_qos_t builtin_endpoint_xqos_rd;
dds_qos_t builtin_endpoint_xqos_wr; dds_qos_t builtin_endpoint_xqos_wr;
#ifdef DDSI_INCLUDE_SECURITY
dds_qos_t builtin_volatile_xqos_rd;
dds_qos_t builtin_volatile_xqos_wr;
dds_qos_t builtin_stateless_xqos_rd;
dds_qos_t builtin_stateless_xqos_wr;
#endif
/* SPDP packets get very special treatment (they're the only packets /* SPDP packets get very special treatment (they're the only packets
we accept from writers we don't know) and have their very own we accept from writers we don't know) and have their very own
@ -285,8 +294,18 @@ struct ddsi_domaingv {
transmit queue*/ transmit queue*/
struct serdatapool *serpool; struct serdatapool *serpool;
struct nn_xmsgpool *xmsgpool; struct nn_xmsgpool *xmsgpool;
struct ddsi_sertopic *plist_topic; /* used for all discovery data */ struct ddsi_sertopic *spdp_topic; /* key = participant GUID */
struct ddsi_sertopic *rawcdr_topic; /* used for participant message data */ struct ddsi_sertopic *sedp_reader_topic; /* key = endpoint GUID */
struct ddsi_sertopic *sedp_writer_topic; /* key = endpoint GUID */
struct ddsi_sertopic *pmd_topic; /* participant message data */
#ifdef DDSI_INCLUDE_SECURITY
struct ddsi_sertopic *spdp_secure_topic; /* key = participant GUID */
struct ddsi_sertopic *sedp_reader_secure_topic; /* key = endpoint GUID */
struct ddsi_sertopic *sedp_writer_secure_topic; /* key = endpoint GUID */
struct ddsi_sertopic *pmd_secure_topic; /* participant message data */
struct ddsi_sertopic *pgm_stateless_topic; /* participant generic message */
struct ddsi_sertopic *pgm_volatile_topic; /* participant generic message */
#endif
ddsrt_mutex_t sendq_lock; ddsrt_mutex_t sendq_lock;
ddsrt_cond_t sendq_cond; ddsrt_cond_t sendq_cond;
@ -306,6 +325,14 @@ struct ddsi_domaingv {
ddsrt_mutex_t sertopics_lock; ddsrt_mutex_t sertopics_lock;
struct ddsrt_hh *sertopics; struct ddsrt_hh *sertopics;
/* security globals */
#ifdef DDSI_INCLUDE_SECURITY
struct dds_security_context *security_context;
struct ddsi_hsadmin *hsadmin;
bool handshake_include_optional;
#endif
}; };
#if defined (__cplusplus) #if defined (__cplusplus)

View file

@ -112,6 +112,7 @@ struct entidx_enum_proxy_reader { struct entidx_enum st; };
void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind) ddsrt_nonnull_all; void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind) ddsrt_nonnull_all;
void entidx_enum_init_topic (struct entidx_enum *st, const struct entity_index *gh, enum entity_kind kind, const char *topic, struct match_entities_range_key *max) ddsrt_nonnull_all; void entidx_enum_init_topic (struct entidx_enum *st, const struct entity_index *gh, enum entity_kind kind, const char *topic, struct match_entities_range_key *max) ddsrt_nonnull_all;
void entidx_enum_init_topic_w_prefix (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind, const char *topic, const ddsi_guid_prefix_t *prefix, struct match_entities_range_key *max) ddsrt_nonnull_all;
void *entidx_enum_next_max (struct entidx_enum *st, const struct match_entities_range_key *max) ddsrt_nonnull_all; void *entidx_enum_next_max (struct entidx_enum *st, const struct match_entities_range_key *max) ddsrt_nonnull_all;
void *entidx_enum_next (struct entidx_enum *st) ddsrt_nonnull_all; void *entidx_enum_next (struct entidx_enum *st) ddsrt_nonnull_all;
void entidx_enum_fini (struct entidx_enum *st) ddsrt_nonnull_all; void entidx_enum_fini (struct entidx_enum *st) ddsrt_nonnull_all;

View file

@ -0,0 +1,226 @@
/*
* 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
*/
#ifndef DDSI_HANDSHAKE_H
#define DDSI_HANDSHAKE_H
#include "dds/ddsi/q_entity.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct participant;
struct proxy_participant;
struct ddsi_handshake;
struct dssi_hsadmin;
enum ddsi_handshake_state {
STATE_HANDSHAKE_IN_PROGRESS,
STATE_HANDSHAKE_TIMED_OUT,
STATE_HANDSHAKE_FAILED,
STATE_HANDSHAKE_PROCESSED,
STATE_HANDSHAKE_SEND_TOKENS,
STATE_HANDSHAKE_OK
};
/* The handshake will not use the related handshake object after this callback
* was executed. This means that it can be deleted in this callback. */
typedef void (*ddsi_handshake_end_cb_t)(
struct ddsi_handshake *handshake,
struct participant *pp,
struct proxy_participant *proxypp,
enum ddsi_handshake_state result);
#ifdef DDSI_INCLUDE_SECURITY
#include "dds/ddsi/ddsi_security_msg.h"
/**
* @brief Release the handshake.
*
* This function will decrement the refcount associated with the handshake
* and delete the handshake when the refcount becomes 0.
*
* @param[in] handshake The handshake.
*/
void ddsi_handshake_release(struct ddsi_handshake *handshake);
/**
* @brief Handle an authentication handshake message received from the remote participant.
*
* During the authentication phase handshake messages are being exchanged between the local and
* the remote participant. THis function will handle a handshake message received from a remote
* participant.
*
* @param[in] handshake The handshake.
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
* @param[in] msg The handshake message received.
*/
void ddsi_handshake_handle_message(struct ddsi_handshake *handshake, const struct participant *pp, const struct proxy_participant *proxypp, const struct nn_participant_generic_message *msg);
/**
* @brief Notify the handshake that crypto tokens have been received.
*
* The handshake could be finished at one end while the other side has not yet processed the
* final handshake messages. The arrival of crypto tokens signals that the other side has also finished
* processing the handshake. This function is used to signal the handshake that crypto tokens have been
* received.
*
* @param[in] handshake The handshake.
*/
void ddsi_handshake_crypto_tokens_received(struct ddsi_handshake *handshake);
/**
* @brief Get the shared secret handle.
*
* During the handshake a shared secret is established which is used to encrypt
* and decrypt the crypto token exchange messages. This function will return a
* handle to the shared secret which will be passed to the crypto plugin to
* determine the session keys used for the echange of the the crypto tokens.
*
* @param[in] handshake The handshake.
*
* @returns handle to the shared sercet.
*/
int64_t ddsi_handshake_get_shared_secret(const struct ddsi_handshake *handshake);
/**
* @brief Get the handshake handle
*
* This function returns the handshake handle that was returned by the authentication plugin
* when starting the handshake.
*
* @param[in] handshake The handshake.
*
* @returns The handshake handle.
*/
int64_t ddsi_handshake_get_handle(const struct ddsi_handshake *handshake);
/**
* @brief Create and start the handshake for the participants
*
* This function will create a handshake for the specified local
* and remote participants when it does not yet exists. It will start the
* handshake procedure by calling the corresponding functions of the authentication plugin.
* The callback function is called by the handshake when to report events,
* for example to indicate that the handshake has finished or has failed.
*
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
* @param[in] callback The callback function.
*
*/
void ddsi_handshake_register(struct participant *pp, struct proxy_participant *proxypp, ddsi_handshake_end_cb_t callback);
/**
* @brief Remove the handshake associated with the specified participants.
*
* This function will remove the handshake from the handshake administation and release
* the handshake. When the handshake argument is not specified the handshake is searched
* in the handshake administation.
*
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
*
*/
void ddsi_handshake_remove(struct participant *pp, struct proxy_participant *proxypp);
/**
* @brief Searches for the handshake associated with the specified participants
*
* This function will search through the handshake administration to find the handshake
* corresponding the to specified local and remote participant.
*
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
*
* @returns The handshake
*/
struct ddsi_handshake * ddsi_handshake_find(struct participant *pp, struct proxy_participant *proxypp);
/**
* @brief Searches for the handshake associated with the specified participants
*
* This function will search through the handshake administration to find the handshake
* corresponding the to specified local and remote participant.
*
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
*
* @returns The handshake
*/
struct ddsi_handshake * ddsi_handshake_find(struct participant *pp, struct proxy_participant *proxypp);
/**
* @brief Initialize the handshake administration
*
* @param[in] gv The global parameters
*/
void ddsi_handshake_admin_init(struct ddsi_domaingv *gv);
/**
* @brief Stop handshake background processing.
*
* @param[in] gv The global parameters
*/
void ddsi_handshake_admin_stop(struct ddsi_domaingv *gv);
/**
* @brief Deinitialze the handshake administration.
*
* @param[in] gv The global parameters
*/
void ddsi_handshake_admin_deinit(struct ddsi_domaingv *gv);
#else /* DDSI_INCLUDE_SECURITY */
#include "dds/ddsi/q_unused.h"
inline void ddsi_handshake_register(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(ddsi_handshake_end_cb_t callback))
{
}
inline void ddsi_handshake_release(UNUSED_ARG(struct ddsi_handshake *handshake))
{
}
inline void ddsi_handshake_crypto_tokens_received(UNUSED_ARG(struct ddsi_handshake *handshake))
{
}
inline int64_t ddsi_handshake_get_shared_secret(UNUSED_ARG(const struct ddsi_handshake *handshake))
{
return 0;
}
inline int64_t ddsi_handshake_get_handle(UNUSED_ARG(const struct ddsi_handshake *handshake))
{
return 0;
}
inline void ddsi_handshake_remove(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(struct ddsi_handshake *handshake))
{
}
inline struct ddsi_handshake * ddsi_handshake_find(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp))
{
return NULL;
}
#endif /* DDSI_INCLUDE_SECURITY */
#if defined (__cplusplus)
}
#endif
#endif /* DDSI_HANDSHAKE_H */

View file

@ -0,0 +1,27 @@
/*
* Copyright(c) 2020 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_KEYHASH_H
#define DDSI_KEYHASH_H
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct ddsi_keyhash {
unsigned char value[16];
} ddsi_keyhash_t;
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -14,6 +14,7 @@
#include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/q_feature_check.h"
#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/ddsi_xqos.h"
#include "dds/ddsi/ddsi_keyhash.h"
#include "dds/ddsi/ddsi_tran.h" /* FIXME: eliminate */ #include "dds/ddsi/ddsi_tran.h" /* FIXME: eliminate */
#if defined (__cplusplus) #if defined (__cplusplus)
@ -51,11 +52,15 @@ extern "C" {
#ifdef DDSI_INCLUDE_SSM #ifdef DDSI_INCLUDE_SSM
#define PP_READER_FAVOURS_SSM ((uint64_t)1 << 29) #define PP_READER_FAVOURS_SSM ((uint64_t)1 << 29)
#endif #endif
#define PP_DOMAIN_ID ((uint64_t)1 << 30)
#define PP_DOMAIN_TAG ((uint64_t)1 << 31)
/* Security extensions. */ /* Security extensions. */
#define PP_IDENTITY_TOKEN ((uint64_t)1 << 30) #define PP_IDENTITY_TOKEN ((uint64_t)1 << 32)
#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 31) #define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 33)
#define PP_DOMAIN_ID ((uint64_t)1 << 32) #define PP_ENDPOINT_SECURITY_INFO ((uint64_t)1 << 34)
#define PP_DOMAIN_TAG ((uint64_t)1 << 33) #define PP_PARTICIPANT_SECURITY_INFO ((uint64_t)1 << 35)
#define PP_IDENTITY_STATUS_TOKEN ((uint64_t)1 << 36)
#define PP_DATA_TAGS ((uint64_t)1 << 37)
/* Set for unrecognized parameters that are in the reserved space or /* Set for unrecognized parameters that are in the reserved space or
in our own vendor-specific space that have the in our own vendor-specific space that have the
PID_UNRECOGNIZED_INCOMPATIBLE_FLAG set (see DDSI 2.1 9.6.2.2.1) */ PID_UNRECOGNIZED_INCOMPATIBLE_FLAG set (see DDSI 2.1 9.6.2.2.1) */
@ -93,10 +98,21 @@ typedef uint32_t nn_ipv4address_t;
typedef uint32_t nn_port_t; typedef uint32_t nn_port_t;
typedef struct nn_keyhash { #ifdef DDSI_INCLUDE_SECURITY
unsigned char value[16]; typedef struct nn_tag {
} nn_keyhash_t; char *name;
char *value;
} nn_tag_t;
typedef struct nn_tagseq {
uint32_t n;
nn_tag_t *tags;
} nn_tagseq_t;
typedef struct nn_datatags {
nn_tagseq_t tags;
} nn_datatags_t;
#endif
#ifdef DDSI_INCLUDE_SSM #ifdef DDSI_INCLUDE_SSM
typedef struct nn_reader_favours_ssm { typedef struct nn_reader_favours_ssm {
@ -104,6 +120,57 @@ typedef struct nn_reader_favours_ssm {
} nn_reader_favours_ssm_t; } nn_reader_favours_ssm_t;
#endif #endif
#ifdef DDSI_INCLUDE_SECURITY
typedef struct nn_dataholder
{
char *class_id;
dds_propertyseq_t properties;
dds_binarypropertyseq_t binary_properties;
} nn_dataholder_t;
typedef struct nn_dataholderseq {
uint32_t n;
nn_dataholder_t *tags;
} nn_dataholderseq_t;
typedef nn_dataholder_t nn_token_t;
/* Used for both nn_participant_security_info and nn_endpoint_security_info. */
typedef struct nn_security_info
{
uint32_t security_attributes;
uint32_t plugin_security_attributes;
} nn_security_info_t;
#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_READ_PROTECTED (1u << 0)
#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_WRITE_PROTECTED (1u << 1)
#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (1u << 2)
#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED (1u << 3)
#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED (1u << 4)
#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_KEY_PROTECTED (1u << 5)
#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (1u << 6)
#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID (1u << 31)
#define NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED (1u << 0)
#define NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED (1u << 1)
#define NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED (1u << 2)
#define NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_PROTECTED (1u << 0)
#define NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (1u << 1)
#define NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (1u << 2)
#define NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_VALID (1u << 31)
#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED (1u << 0)
#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED (1u << 1)
#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED (1u << 2)
#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED (1u << 3)
#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED (1u << 4)
#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED (1u << 5)
#else
struct nn_security_info;
typedef struct nn_security_info nn_security_info_t;
#endif
typedef struct nn_adlink_participant_version_info typedef struct nn_adlink_participant_version_info
{ {
uint32_t version; uint32_t version;
@ -142,11 +209,19 @@ typedef struct ddsi_plist {
uint32_t builtin_endpoint_set; uint32_t builtin_endpoint_set;
/* int type_max_size_serialized; */ /* int type_max_size_serialized; */
char *entity_name; char *entity_name;
nn_keyhash_t keyhash; ddsi_keyhash_t keyhash;
uint32_t statusinfo; uint32_t statusinfo;
nn_adlink_participant_version_info_t adlink_participant_version_info; nn_adlink_participant_version_info_t adlink_participant_version_info;
char *type_description; char *type_description;
nn_sequence_number_t coherent_set_seqno; nn_sequence_number_t coherent_set_seqno;
#ifdef DDSI_INCLUDE_SECURITY
nn_token_t identity_token;
nn_token_t permissions_token;
nn_security_info_t endpoint_security_info;
nn_security_info_t participant_security_info;
nn_token_t identity_status_token;
nn_datatags_t data_tags;
#endif
#ifdef DDSI_INCLUDE_SSM #ifdef DDSI_INCLUDE_SSM
nn_reader_favours_ssm_t reader_favours_ssm; nn_reader_favours_ssm_t reader_favours_ssm;
#endif #endif
@ -225,6 +300,7 @@ DDS_EXPORT void ddsi_plist_fini (ddsi_plist_t *ps);
DDS_EXPORT void ddsi_plist_fini_mask (ddsi_plist_t *plist, uint64_t pmask, uint64_t qmask); DDS_EXPORT void ddsi_plist_fini_mask (ddsi_plist_t *plist, uint64_t pmask, uint64_t qmask);
DDS_EXPORT void ddsi_plist_unalias (ddsi_plist_t *plist); DDS_EXPORT void ddsi_plist_unalias (ddsi_plist_t *plist);
DDS_EXPORT void ddsi_plist_addtomsg (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted); DDS_EXPORT void ddsi_plist_addtomsg (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted);
DDS_EXPORT void ddsi_plist_addtomsg_bo (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted, bool be);
DDS_EXPORT void ddsi_plist_init_default_participant (ddsi_plist_t *plist); DDS_EXPORT void ddsi_plist_init_default_participant (ddsi_plist_t *plist);
DDS_EXPORT void ddsi_plist_delta (uint64_t *pdelta, uint64_t *qdelta, const ddsi_plist_t *x, const ddsi_plist_t *y, uint64_t pmask, uint64_t qmask); DDS_EXPORT void ddsi_plist_delta (uint64_t *pdelta, uint64_t *qdelta, const ddsi_plist_t *x, const ddsi_plist_t *y, uint64_t pmask, uint64_t qmask);
DDS_EXPORT void ddsi_plist_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const ddsi_plist_t *plist); DDS_EXPORT void ddsi_plist_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const ddsi_plist_t *plist);
@ -235,7 +311,7 @@ struct nn_rsample_info;
struct nn_rdata; struct nn_rdata;
DDS_EXPORT unsigned char *ddsi_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const ddsi_plist_src_t *src); DDS_EXPORT unsigned char *ddsi_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const ddsi_plist_src_t *src);
DDS_EXPORT const unsigned char *ddsi_plist_findparam_native_unchecked (const void *src, nn_parameterid_t pid); DDS_EXPORT dds_return_t ddsi_plist_findparam_checking (const void *buf, size_t bufsz, uint16_t encoding, nn_parameterid_t needle, void **needlep, size_t *needlesz);
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -19,6 +19,7 @@
#include "dds/export.h" #include "dds/export.h"
#include "dds/ddsrt/attributes.h" #include "dds/ddsrt/attributes.h"
#include "dds/ddsrt/retcode.h"
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
@ -34,6 +35,7 @@ enum pserop {
Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */ Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */
Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */ Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */
XD, XDx2, /* duration, 1 .. 2 in a row */ XD, XDx2, /* duration, 1 .. 2 in a row */
Xl, /* int64_t */
Xo, Xox2, /* octet, 1 .. 2 in a row */ Xo, Xox2, /* octet, 1 .. 2 in a row */
Xb, Xbx2, /* boolean, 1 .. 2 in a row */ Xb, Xbx2, /* boolean, 1 .. 2 in a row */
XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */ XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */
@ -44,21 +46,14 @@ enum pserop {
Xopt, /* remainder is optional on deser, 0-init if not present */ Xopt, /* remainder is optional on deser, 0-init if not present */
} ddsrt_attribute_packed; } ddsrt_attribute_packed;
inline bool pserop_seralign_is_1 (enum pserop op) {
/* NB: XbPROP is never serialized, so its alignment is irrelevant. If ever there
is a need to allow calling this function when op = XbPROP, it needs to be changed
to taking the address of the pserop, and in that case inspect the following
operator */
assert (op != XbPROP && op != Xopt && op != XSTOP);
return (op >= Xo && op <= XK);
}
DDS_EXPORT void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased); DDS_EXPORT void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased);
DDS_EXPORT dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc); DDS_EXPORT dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc);
DDS_EXPORT dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc); DDS_EXPORT dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc);
DDS_EXPORT dds_return_t plist_ser_generic_be (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc);
DDS_EXPORT dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc); DDS_EXPORT dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc);
DDS_EXPORT bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc); DDS_EXPORT bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc);
DDS_EXPORT size_t plist_memsize_generic (const enum pserop * __restrict desc); DDS_EXPORT size_t plist_memsize_generic (const enum pserop * __restrict desc);
DDS_EXPORT size_t plist_print_generic (char * __restrict buf, size_t bufsize, const void * __restrict src, const enum pserop * __restrict desc);
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -12,7 +12,12 @@
#ifndef DDSI_PMD_H #ifndef DDSI_PMD_H
#define DDSI_PMD_H #define DDSI_PMD_H
#include <stdint.h>
#include "dds/ddsrt/time.h" #include "dds/ddsrt/time.h"
#include "dds/ddsi/ddsi_serdata.h"
#include "dds/ddsi/ddsi_plist_generic.h"
#include "dds/ddsi/ddsi_guid.h"
#include "dds/ddsi/ddsi_xqos.h"
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
@ -25,9 +30,20 @@ struct nn_xpack;
struct participant; struct participant;
struct receiver_state; struct receiver_state;
typedef struct ParticipantMessageData {
ddsi_guid_prefix_t participantGuidPrefix;
uint32_t kind; /* really 4 octets */
ddsi_octetseq_t value;
} ParticipantMessageData_t;
extern const enum pserop participant_message_data_ops[];
extern size_t participant_message_data_nops;
extern const enum pserop participant_message_data_ops_key[];
extern size_t participant_message_data_nops_key;
void write_pmd_message_guid (struct ddsi_domaingv * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind); void write_pmd_message_guid (struct ddsi_domaingv * 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 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, ddsrt_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len); void handle_pmd_message (const struct receiver_state *rst, struct ddsi_serdata *sample_common);
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -0,0 +1,49 @@
/*
* 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
*/
#ifndef DDSI_SECURITY_EXCHANGE_H
#define DDSI_SECURITY_EXCHANGE_H
#ifdef DDSI_INCLUDE_SECURITY
#if defined (__cplusplus)
extern "C" {
#endif
#include "dds/ddsi/q_rtps.h"
#include "dds/ddsi/q_radmin.h"
#include "dds/ddsi/q_entity.h"
#include "dds/ddsi/ddsi_security_msg.h"
#define GMCLASSID_SECURITY_PARTICIPANT_CRYPTO_TOKENS "dds.sec.participant_crypto_tokens"
#define GMCLASSID_SECURITY_DATAWRITER_CRYPTO_TOKENS "dds.sec.datawriter_crypto_tokens"
#define GMCLASSID_SECURITY_DATAREADER_CRYPTO_TOKENS "dds.sec.datareader_crypto_tokens"
bool write_auth_handshake_message(const struct participant *pp, const struct proxy_participant *proxypp, nn_dataholderseq_t *mdata, bool request, const nn_message_identity_t *related_message_id);
void handle_auth_handshake_message(const struct receiver_state *rst, ddsi_entityid_t wr_entity_id, struct ddsi_serdata *sample);
void handle_crypto_exchange_message(const struct receiver_state *rst, struct ddsi_serdata *sample);
void auth_get_serialized_participant_data(struct participant *pp, ddsi_octetseq_t *seq);
bool write_crypto_participant_tokens(const struct participant *pp, const struct proxy_participant *proxypp, const nn_dataholderseq_t *tokens);
bool write_crypto_writer_tokens(const struct writer *wr, const struct proxy_reader *prd, const nn_dataholderseq_t *tokens);
bool write_crypto_reader_tokens(const struct reader *rd, const struct proxy_writer *pwr, const nn_dataholderseq_t *tokens);
#if defined (__cplusplus)
}
#endif
#else /* DDSI_INCLUDE_SECURITY */
#define volatile_secure_data_filter NULL
#endif /* DDSI_INCLUDE_SECURITY */
#endif /* DDSI_SECURITY_EXCHANGE_H */

View file

@ -0,0 +1,112 @@
/*
* 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
*/
#ifndef DDSI_SECURITY_MSG_H
#define DDSI_SECURITY_MSG_H
#ifdef DDSI_INCLUDE_SECURITY
#include "dds/ddsi/ddsi_plist.h"
#include "dds/ddsi/ddsi_guid.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsi/ddsi_plist_generic.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct participant;
struct writer;
struct proxy_reader;
struct ddsi_serdata;
#define DDS_SECURITY_AUTH_REQUEST "dds.sec.auth_request"
#define DDS_SECURITY_AUTH_HANDSHAKE "dds.sec.auth"
#define DDS_SECURITY_AUTH_REQUEST_TOKEN_CLASS_ID "DDS:Auth:PKI-DH:1.0+AuthReq"
#define DDS_SECURITY_AUTH_HANDSHAKE_REQUEST_TOKEN_ID "DDS:Auth:PKI-DH:1.0+Req"
#define DDS_SECURITY_AUTH_HANDSHAKE_REPLY_TOKEN_ID "DDS:Auth:PKI-DH:1.0+Reply"
#define DDS_SECURITY_AUTH_HANDSHAKE_FINAL_TOKEN_ID "DDS:Auth:PKI-DH:1.0+Final"
typedef struct nn_message_identity {
ddsi_guid_t source_guid;
int64_t sequence_number;
} nn_message_identity_t;
typedef struct nn_participant_generic_message {
nn_message_identity_t message_identity;
nn_message_identity_t related_message_identity;
ddsi_guid_t destination_participant_guid;
ddsi_guid_t destination_endpoint_guid;
ddsi_guid_t source_endpoint_guid;
const char *message_class_id;
nn_dataholderseq_t message_data;
} nn_participant_generic_message_t;
/*
* The arguments are aliased in the resulting message structure.
* This means that the lifecycle of the arguments should be longer
* then that of the message.
*/
DDS_EXPORT void
nn_participant_generic_message_init(
nn_participant_generic_message_t *msg,
const ddsi_guid_t *wrguid,
int64_t wrseq,
const ddsi_guid_t *dstpguid,
const ddsi_guid_t *dsteguid,
const ddsi_guid_t *srceguid,
const char *classid,
const nn_dataholderseq_t *mdata,
const nn_message_identity_t *rmid);
/*
* Aliased struct variables will not be freed.
*/
DDS_EXPORT void
nn_participant_generic_message_deinit(
nn_participant_generic_message_t *msg);
/*
* Some struct variables are aliased to the given buffer.
* This means that the lifecycle of the data buffer should be
* longer then that of the message.
*/
DDS_EXPORT dds_return_t
nn_participant_generic_message_deseralize(
nn_participant_generic_message_t *msg,
const unsigned char *data,
size_t len,
bool bswap);
DDS_EXPORT dds_return_t
nn_participant_generic_message_serialize(
const nn_participant_generic_message_t *msg,
unsigned char **data,
size_t *len);
DDS_EXPORT extern const enum pserop pserop_participant_generic_message[];
DDS_EXPORT extern const size_t pserop_participant_generic_message_nops;
DDS_EXPORT int
volatile_secure_data_filter(
struct writer *wr,
struct proxy_reader *prd,
struct ddsi_serdata *serdata);
#if defined (__cplusplus)
}
#endif
#endif
#endif /* DDSI_SECURITY_MSG_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
/*
* 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
*/
#ifndef DDSI_SECURITY_UTIL_H
#define DDSI_SECURITY_UTIL_H
#ifdef DDSI_INCLUDE_SECURITY
#include "dds/ddsi/ddsi_plist.h"
#include "dds/security/core/dds_security_utils.h"
#if defined (__cplusplus)
extern "C" {
#endif
void g_omg_shallow_copy_StringSeq(DDS_Security_StringSeq *dst, const ddsi_stringseq_t *src);
void g_omg_shallow_free_StringSeq(DDS_Security_StringSeq *obj);
void q_omg_copy_PropertySeq(DDS_Security_PropertySeq *dst, const dds_propertyseq_t *src);
void q_omg_shallow_copyin_PropertySeq(DDS_Security_PropertySeq *dst, const dds_propertyseq_t *src);
void q_omg_shallow_copyout_PropertySeq(dds_propertyseq_t *dst, const DDS_Security_PropertySeq *src);
void q_omg_shallow_free_PropertySeq(DDS_Security_PropertySeq *obj);
void q_omg_shallow_copyin_BinaryPropertySeq(DDS_Security_BinaryPropertySeq *dst, const dds_binarypropertyseq_t *src);
void q_omg_shallow_copyout_BinaryPropertySeq(dds_binarypropertyseq_t *dst, const DDS_Security_BinaryPropertySeq *src);
void q_omg_shallow_free_BinaryPropertySeq(DDS_Security_BinaryPropertySeq *obj);
void q_omg_shallow_copy_PropertyQosPolicy(DDS_Security_PropertyQosPolicy *dst, const dds_property_qospolicy_t *src);
void q_omg_shallow_copy_security_qos(DDS_Security_Qos *dst, const struct dds_qos *src);
void q_omg_shallow_free_PropertyQosPolicy(DDS_Security_PropertyQosPolicy *obj);
void q_omg_shallow_free_security_qos(DDS_Security_Qos *obj);
void q_omg_security_dataholder_copyin(nn_dataholder_t *dh, const DDS_Security_DataHolder *holder);
void q_omg_security_dataholder_copyout(DDS_Security_DataHolder *holder, const nn_dataholder_t *dh);
void q_omg_shallow_copyin_DataHolder(DDS_Security_DataHolder *dst, const nn_dataholder_t *src);
void q_omg_shallow_copyout_DataHolder(nn_dataholder_t *dst, const DDS_Security_DataHolder *src);
void q_omg_shallow_free_DataHolder(DDS_Security_DataHolder *obj);
void q_omg_shallow_free_nn_dataholder(nn_dataholder_t *holder);
void q_omg_shallow_copyin_DataHolderSeq(DDS_Security_DataHolderSeq *dst, const nn_dataholderseq_t *src);
void q_omg_copyin_DataHolderSeq(DDS_Security_DataHolderSeq *dst, const nn_dataholderseq_t *src);
void q_omg_shallow_copyout_DataHolderSeq(nn_dataholderseq_t *dst, const DDS_Security_DataHolderSeq *src);
void q_omg_shallow_free_DataHolderSeq(DDS_Security_DataHolderSeq *obj);
void q_omg_shallow_free_nn_dataholderseq(nn_dataholderseq_t *obj);
void q_omg_shallow_copy_ParticipantBuiltinTopicDataSecure(DDS_Security_ParticipantBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const ddsi_plist_t *plist);
void q_omg_shallow_free_ParticipantBuiltinTopicDataSecure(DDS_Security_ParticipantBuiltinTopicDataSecure *obj);
void q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure(DDS_Security_SubscriptionBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const struct dds_qos *qos, const nn_security_info_t *secinfo);
void q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(DDS_Security_SubscriptionBuiltinTopicDataSecure *obj);
void q_omg_shallow_copy_PublicationBuiltinTopicDataSecure(DDS_Security_PublicationBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const struct dds_qos *qos, const nn_security_info_t *secinfo);
void q_omg_shallow_free_PublicationBuiltinTopicDataSecure(DDS_Security_PublicationBuiltinTopicDataSecure *obj);
void q_omg_shallow_copy_TopicBuiltinTopicData(DDS_Security_TopicBuiltinTopicData *dst, const char *topic_name, const char *type_name);
void q_omg_shallow_free_TopicBuiltinTopicData(DDS_Security_TopicBuiltinTopicData *obj);
#if defined (__cplusplus)
}
#endif
#endif /* DDSI_INCLUDE_SECURITY */
#endif /* DDSI_SECURITY_UTIL_H */

View file

@ -14,13 +14,13 @@
#include "dds/ddsrt/sockets.h" #include "dds/ddsrt/sockets.h"
#include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_sertopic.h"
#include "dds/ddsi/ddsi_keyhash.h"
#if defined (__cplusplus) #if defined (__cplusplus)
extern "C" { extern "C" {
#endif #endif
struct nn_rdata; struct nn_rdata;
struct nn_keyhash;
enum ddsi_serdata_kind { enum ddsi_serdata_kind {
SDK_EMPTY, SDK_EMPTY,
@ -64,7 +64,7 @@ typedef struct ddsi_serdata * (*ddsi_serdata_from_ser_t) (const struct ddsi_sert
typedef struct ddsi_serdata * (*ddsi_serdata_from_ser_iov_t) (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size); typedef struct ddsi_serdata * (*ddsi_serdata_from_ser_iov_t) (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size);
/* Construct a serdata from a keyhash (an SDK_KEY by definition) */ /* Construct a serdata from a keyhash (an SDK_KEY by definition) */
typedef struct ddsi_serdata * (*ddsi_serdata_from_keyhash_t) (const struct ddsi_sertopic *topic, const struct nn_keyhash *keyhash); typedef struct ddsi_serdata * (*ddsi_serdata_from_keyhash_t) (const struct ddsi_sertopic *topic, const struct ddsi_keyhash *keyhash);
/* Construct a serdata from an application sample /* Construct a serdata from an application sample
- "kind" is KEY or DATA depending on the operation invoked by the application; - "kind" is KEY or DATA depending on the operation invoked by the application;
@ -134,7 +134,10 @@ typedef bool (*ddsi_serdata_eqkey_t) (const struct ddsi_serdata *a, const struct
returning bufsize-1) if it had to truncate) */ returning bufsize-1) if it had to truncate) */
typedef size_t (*ddsi_serdata_print_t) (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size); typedef size_t (*ddsi_serdata_print_t) (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size);
#define DDSI_SERDATA_HAS_FROM_SER_IOV 1 /* Add keyhash (from serdata) to buffer (forcing md5 when necessary).
- key needs to be set within serdata (can already be md5)
- buf needs to be at least 16 bytes large */
typedef void (*ddsi_serdata_get_keyhash_t) (const struct ddsi_serdata *d, struct ddsi_keyhash *buf, bool force_md5);
struct ddsi_serdata_ops { struct ddsi_serdata_ops {
ddsi_serdata_eqkey_t eqkey; ddsi_serdata_eqkey_t eqkey;
@ -151,9 +154,12 @@ struct ddsi_serdata_ops {
ddsi_serdata_topicless_to_sample_t topicless_to_sample; ddsi_serdata_topicless_to_sample_t topicless_to_sample;
ddsi_serdata_free_t free; ddsi_serdata_free_t free;
ddsi_serdata_print_t print; ddsi_serdata_print_t print;
ddsi_serdata_get_keyhash_t get_keyhash;
}; };
#define DDSI_SERDATA_HAS_PRINT 1 #define DDSI_SERDATA_HAS_PRINT 1
#define DDSI_SERDATA_HAS_FROM_SER_IOV 1
#define DDSI_SERDATA_HAS_GET_KEYHASH 1
DDS_EXPORT void ddsi_serdata_init (struct ddsi_serdata *d, const struct ddsi_sertopic *tp, enum ddsi_serdata_kind kind); DDS_EXPORT void ddsi_serdata_init (struct ddsi_serdata *d, const struct ddsi_sertopic *tp, enum ddsi_serdata_kind kind);
@ -180,7 +186,7 @@ DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_ser_iov (const struct d
return topic->serdata_ops->from_ser_iov (topic, kind, niov, iov, size); return topic->serdata_ops->from_ser_iov (topic, kind, niov, iov, size);
} }
DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_keyhash (const struct ddsi_sertopic *topic, const struct nn_keyhash *keyhash) { DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_keyhash (const struct ddsi_sertopic *topic, const struct ddsi_keyhash *keyhash) {
return topic->serdata_ops->from_keyhash (topic, keyhash); return topic->serdata_ops->from_keyhash (topic, keyhash);
} }
@ -230,6 +236,10 @@ DDS_EXPORT inline bool ddsi_serdata_print_topicless (const struct ddsi_sertopic
} }
} }
DDS_EXPORT inline void ddsi_serdata_get_keyhash (const struct ddsi_serdata *d, struct ddsi_keyhash *buf, bool force_md5) {
d->ops->get_keyhash (d, buf, force_md5);
}
#if defined (__cplusplus) #if defined (__cplusplus)
} }
#endif #endif

View file

@ -18,6 +18,7 @@
#include "dds/ddsrt/avl.h" #include "dds/ddsrt/avl.h"
#include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_serdata.h"
#include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_sertopic.h"
#include "dds/ddsi/ddsi_plist_generic.h"
#include "dds/dds.h" #include "dds/dds.h"
@ -46,6 +47,7 @@ typedef struct dds_keyhash {
unsigned char m_hash [16]; /* Key hash value. Also possibly key. Suitably aligned for accessing as uint32_t's */ unsigned char m_hash [16]; /* Key hash value. Also possibly key. Suitably aligned for accessing as uint32_t's */
unsigned m_set : 1; /* has it been initialised? */ unsigned m_set : 1; /* has it been initialised? */
unsigned m_iskey : 1; /* m_hash is key value */ unsigned m_iskey : 1; /* m_hash is key value */
unsigned m_keysize : 5; /* size of the key within the hash buffer */
} dds_keyhash_t; } dds_keyhash_t;
/* Debug builds may want to keep some additional state */ /* Debug builds may want to keep some additional state */
@ -135,8 +137,6 @@ extern DDS_EXPORT const struct ddsi_sertopic_ops ddsi_sertopic_ops_default;
extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_cdr; extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_cdr;
extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey; extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey;
extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_plist;
extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_rawcdr;
struct serdatapool * ddsi_serdatapool_new (void); struct serdatapool * ddsi_serdatapool_new (void);
void ddsi_serdatapool_free (struct serdatapool * pool); void ddsi_serdatapool_free (struct serdatapool * pool);

View file

@ -0,0 +1,76 @@
/*
* 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
*/
#ifndef DDSI_SERDATA_PLIST_H
#define DDSI_SERDATA_PLIST_H
#include "dds/ddsi/q_protocol.h" /* for nn_parameterid_t */
#include "dds/ddsi/ddsi_keyhash.h"
#include "dds/ddsi/ddsi_serdata.h"
#include "dds/ddsi/ddsi_sertopic.h"
#include "dds/dds.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* There is an alignment requirement on the raw data (it must be at
offset mod 8 for the conversion to/from a dds_stream to work).
So we define two types: one without any additional padding, and
one where the appropriate amount of padding is inserted */
#define DDSI_SERDATA_PLIST_PREPAD \
struct ddsi_serdata c; \
uint32_t pos; \
uint32_t size; \
nn_vendorid_t vendorid; \
nn_protocol_version_t protoversion; \
ddsi_keyhash_t keyhash
#define DDSI_SERDATA_PLIST_POSTPAD \
uint16_t identifier; \
uint16_t options; \
char data[]
struct ddsi_serdata_plist_unpadded {
DDSI_SERDATA_PLIST_PREPAD;
DDSI_SERDATA_PLIST_POSTPAD;
};
#ifdef __GNUC__
#define DDSI_SERDATA_PLIST_PAD(n) ((n) % 8)
#else
#define DDSI_SERDATA_PLIST_PAD(n) (n)
#endif
struct ddsi_serdata_plist {
DDSI_SERDATA_PLIST_PREPAD;
char pad[DDSI_SERDATA_PLIST_PAD (8 - (offsetof (struct ddsi_serdata_plist_unpadded, data) % 8))];
DDSI_SERDATA_PLIST_POSTPAD;
};
#undef DDSI_SERDATA_PLIST_PAD
#undef DDSI_SERDATA_PLIST_POSTPAD
#undef DDSI_SERDATA_PLIST_PREPAD
struct ddsi_sertopic_plist {
struct ddsi_sertopic c;
uint16_t native_encoding_identifier; /* PL_CDR_(LE|BE) */
nn_parameterid_t keyparam;
};
extern DDS_EXPORT const struct ddsi_sertopic_ops ddsi_sertopic_ops_plist;
extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_plist;
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,78 @@
/*
* 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
*/
#ifndef DDSI_SERDATA_PSEROP_H
#define DDSI_SERDATA_PSEROP_H
#include "dds/ddsi/ddsi_serdata.h"
#include "dds/ddsi/ddsi_sertopic.h"
#include "dds/ddsi/ddsi_plist_generic.h"
#include "dds/dds.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* There is an alignment requirement on the raw data (it must be at
offset mod 8 for the conversion to/from a dds_stream to work).
So we define two types: one without any additional padding, and
one where the appropriate amount of padding is inserted */
#define DDSI_SERDATA_PSEROP_PREPAD \
struct ddsi_serdata c; \
void *sample; \
bool keyless; /*cached from topic*/ \
uint32_t pos; \
uint32_t size
#define DDSI_SERDATA_PSEROP_POSTPAD \
uint16_t identifier; \
uint16_t options; \
char data[]
struct ddsi_serdata_pserop_unpadded {
DDSI_SERDATA_PSEROP_PREPAD;
DDSI_SERDATA_PSEROP_POSTPAD;
};
#ifdef __GNUC__
#define DDSI_SERDATA_PSEROP_PAD(n) ((n) % 8)
#else
#define DDSI_SERDATA_PSEROP_PAD(n) (n)
#endif
struct ddsi_serdata_pserop {
DDSI_SERDATA_PSEROP_PREPAD;
char pad[DDSI_SERDATA_PSEROP_PAD (8 - (offsetof (struct ddsi_serdata_pserop_unpadded, data) % 8))];
DDSI_SERDATA_PSEROP_POSTPAD;
};
#undef DDSI_SERDATA_PSEROP_PAD
#undef DDSI_SERDATA_PSEROP_POSTPAD
#undef DDSI_SERDATA_PSEROP_PREPAD
struct ddsi_sertopic_pserop {
struct ddsi_sertopic c;
uint16_t native_encoding_identifier; /* CDR_(LE|BE) */
size_t memsize;
size_t nops;
const enum pserop *ops;
size_t nops_key;
const enum pserop *ops_key; /* NULL <=> no key; != NULL <=> 16-byte key at offset 0 */
};
extern DDS_EXPORT const struct ddsi_sertopic_ops ddsi_sertopic_ops_pserop;
extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_pserop;
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -322,6 +322,13 @@ DDS_EXPORT void ddsi_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, ui
DDS_EXPORT void ddsi_xqos_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); DDS_EXPORT void ddsi_xqos_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos);
DDS_EXPORT size_t ddsi_xqos_print (char * __restrict buf, size_t bufsize, const dds_qos_t *xqos); DDS_EXPORT size_t ddsi_xqos_print (char * __restrict buf, size_t bufsize, const dds_qos_t *xqos);
DDS_EXPORT dds_qos_t *ddsi_xqos_dup (const dds_qos_t *src); DDS_EXPORT dds_qos_t *ddsi_xqos_dup (const dds_qos_t *src);
DDS_EXPORT bool ddsi_xqos_has_prop_prefix (const dds_qos_t *xqos, const char *nameprefix);
DDS_EXPORT bool ddsi_xqos_find_prop (const dds_qos_t *xqos, const char *name, const char **value);
#ifdef DDSI_INCLUDE_SECURITY
struct omg_security_configuration_type;
DDS_EXPORT void ddsi_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg);
#endif
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -33,8 +33,8 @@ ddsi_guid_prefix_t nn_hton_guid_prefix (ddsi_guid_prefix_t p);
ddsi_guid_prefix_t nn_ntoh_guid_prefix (ddsi_guid_prefix_t p); ddsi_guid_prefix_t nn_ntoh_guid_prefix (ddsi_guid_prefix_t p);
ddsi_entityid_t nn_hton_entityid (ddsi_entityid_t e); ddsi_entityid_t nn_hton_entityid (ddsi_entityid_t e);
ddsi_entityid_t nn_ntoh_entityid (ddsi_entityid_t e); ddsi_entityid_t nn_ntoh_entityid (ddsi_entityid_t e);
ddsi_guid_t nn_hton_guid (ddsi_guid_t g); DDS_EXPORT ddsi_guid_t nn_hton_guid (ddsi_guid_t g);
ddsi_guid_t nn_ntoh_guid (ddsi_guid_t g); DDS_EXPORT ddsi_guid_t nn_ntoh_guid (ddsi_guid_t g);
void bswap_sequence_number_set_hdr (nn_sequence_number_set_header_t *snset); void bswap_sequence_number_set_hdr (nn_sequence_number_set_header_t *snset);
void bswap_sequence_number_set_bitmap (nn_sequence_number_set_header_t *snset, uint32_t *bits); void bswap_sequence_number_set_bitmap (nn_sequence_number_set_header_t *snset, uint32_t *bits);

View file

@ -161,6 +161,42 @@ enum many_sockets_mode {
MSM_MANY_UNICAST MSM_MANY_UNICAST
}; };
#ifdef DDSI_INCLUDE_SECURITY
typedef struct plugin_library_properties_type{
char *library_path;
char *library_init;
char *library_finalize;
} plugin_library_properties_type;
typedef struct authentication_properties_type{
char *identity_certificate;
char *identity_ca;
char *private_key;
char *password;
char *trusted_ca_dir;
int include_optional_fields;
} authentication_properties_type;
typedef struct access_control_properties_type{
char *permissions;
char *permissions_ca;
char *governance;
} access_control_properties_type;
typedef struct omg_security_configuration_type {
authentication_properties_type authentication_properties;
access_control_properties_type access_control_properties;
plugin_library_properties_type authentication_plugin;
plugin_library_properties_type access_control_plugin;
plugin_library_properties_type cryptography_plugin;
} omg_security_configuration_type;
struct config_omg_security_listelem {
struct config_omg_security_listelem *next;
omg_security_configuration_type cfg;
};
#endif /* DDSI_INCLUDE_SECURITY */
#ifdef DDSI_INCLUDE_SSL #ifdef DDSI_INCLUDE_SSL
struct ssl_min_version { struct ssl_min_version {
int major; int major;
@ -226,8 +262,6 @@ struct config
unsigned delivery_queue_maxsamples; unsigned delivery_queue_maxsamples;
int do_topic_discovery;
uint32_t max_msg_size; uint32_t max_msg_size;
uint32_t fragment_size; uint32_t fragment_size;
@ -333,6 +367,10 @@ struct config
int use_multicast_if_mreqn; int use_multicast_if_mreqn;
struct prune_deleted_ppant prune_deleted_ppant; struct prune_deleted_ppant prune_deleted_ppant;
#ifdef DDSI_INCLUDE_SECURITY
struct config_omg_security_listelem *omg_security_configuration;
#endif
}; };
struct cfgst; struct cfgst;

View file

@ -25,6 +25,12 @@ struct nn_rsample_info;
struct nn_rdata; struct nn_rdata;
struct ddsi_plist; struct ddsi_plist;
struct participant_builtin_topic_data_locators {
struct nn_locators_one def_uni_loc_one, def_multi_loc_one, meta_uni_loc_one, meta_multi_loc_one;
};
void get_participant_builtin_topic_data (const struct participant *pp, ddsi_plist_t *dst, struct participant_builtin_topic_data_locators *locs);
int spdp_write (struct participant *pp); int spdp_write (struct participant *pp);
int spdp_dispose_unregister (struct participant *pp); int spdp_dispose_unregister (struct participant *pp);
@ -33,8 +39,6 @@ int sedp_write_reader (struct reader *rd);
int sedp_dispose_unregister_writer (struct writer *wr); int sedp_dispose_unregister_writer (struct writer *wr);
int sedp_dispose_unregister_reader (struct reader *rd); int sedp_dispose_unregister_reader (struct reader *rd);
int sedp_write_topic (struct participant *pp, const struct ddsi_plist *datap);
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg); int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg);
#if defined (__cplusplus) #if defined (__cplusplus)

View file

@ -18,11 +18,14 @@
#include "dds/ddsrt/fibheap.h" #include "dds/ddsrt/fibheap.h"
#include "dds/ddsrt/sync.h" #include "dds/ddsrt/sync.h"
#include "dds/ddsi/q_rtps.h" #include "dds/ddsi/q_rtps.h"
#include "dds/ddsi/ddsi_plist.h"
#include "dds/ddsi/q_protocol.h" #include "dds/ddsi/q_protocol.h"
#include "dds/ddsi/q_lat_estim.h" #include "dds/ddsi/q_lat_estim.h"
#include "dds/ddsi/q_hbcontrol.h" #include "dds/ddsi/q_hbcontrol.h"
#include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/q_feature_check.h"
#include "dds/ddsi/q_inverse_uint32_set.h" #include "dds/ddsi/q_inverse_uint32_set.h"
#include "dds/ddsi/ddsi_serdata_default.h"
#include "dds/ddsi/ddsi_handshake.h"
#include "dds/ddsi/ddsi_tran.h" #include "dds/ddsi/ddsi_tran.h"
@ -42,6 +45,10 @@ struct whc;
struct dds_qos; struct dds_qos;
struct ddsi_plist; struct ddsi_plist;
struct lease; struct lease;
struct participant_sec_attributes;
struct proxy_participant_sec_attributes;
struct writer_sec_attributes;
struct reader_sec_attributes;
struct proxy_group; struct proxy_group;
struct proxy_endpoint_common; struct proxy_endpoint_common;
@ -80,6 +87,9 @@ typedef void (*status_cb_t) (void *entity, const status_cb_data_t *data);
struct prd_wr_match { struct prd_wr_match {
ddsrt_avl_node_t avlnode; ddsrt_avl_node_t avlnode;
ddsi_guid_t wr_guid; ddsi_guid_t wr_guid;
#ifdef DDSI_INCLUDE_SECURITY
int64_t crypto_handle;
#endif
}; };
struct rd_pwr_match { struct rd_pwr_match {
@ -91,6 +101,9 @@ struct rd_pwr_match {
nn_locator_t ssm_mc_loc; nn_locator_t ssm_mc_loc;
nn_locator_t ssm_src_loc; nn_locator_t ssm_src_loc;
#endif #endif
#ifdef DDSI_INCLUDE_SECURITY
int64_t crypto_handle;
#endif
}; };
struct wr_rd_match { struct wr_rd_match {
@ -115,6 +128,7 @@ struct wr_prd_match {
seqno_t min_seq; /* smallest ack'd seq nr in subtree */ seqno_t min_seq; /* smallest ack'd seq nr in subtree */
seqno_t max_seq; /* sort-of highest ack'd seq nr in subtree (see augment function) */ seqno_t max_seq; /* sort-of highest ack'd seq nr in subtree (see augment function) */
seqno_t seq; /* highest acknowledged seq nr */ seqno_t seq; /* highest acknowledged seq nr */
seqno_t last_seq; /* highest seq send to this reader used when filter is applied */
int32_t num_reliable_readers_where_seq_equals_max; int32_t num_reliable_readers_where_seq_equals_max;
ddsi_guid_t arbitrary_unacked_reader; ddsi_guid_t arbitrary_unacked_reader;
nn_count_t next_acknack; /* next acceptable acknack sequence number */ nn_count_t next_acknack; /* next acceptable acknack sequence number */
@ -124,6 +138,9 @@ struct wr_prd_match {
ddsrt_wctime_t hb_to_ack_latency_tlastlog; ddsrt_wctime_t hb_to_ack_latency_tlastlog;
uint32_t non_responsive_count; uint32_t non_responsive_count;
uint32_t rexmit_requests; uint32_t rexmit_requests;
#ifdef DDSI_INCLUDE_SECURITY
int64_t crypto_handle;
#endif
}; };
enum pwr_rd_match_syncstate { enum pwr_rd_match_syncstate {
@ -142,14 +159,19 @@ struct pwr_rd_match {
ddsrt_etime_t t_heartbeat_accepted; /* (local) time a heartbeat was last accepted */ ddsrt_etime_t t_heartbeat_accepted; /* (local) time a heartbeat was last accepted */
ddsrt_mtime_t t_last_nack; /* (local) time we last sent a NACK */ /* FIXME: probably elapsed time is better */ ddsrt_mtime_t t_last_nack; /* (local) time we last sent a NACK */ /* FIXME: probably elapsed time is better */
seqno_t seq_last_nack; /* last seq for which we requested a retransmit */ seqno_t seq_last_nack; /* last seq for which we requested a retransmit */
seqno_t last_seq; /* last known sequence number from this writer */
struct xevent *acknack_xevent; /* entry in xevent queue for sending acknacks */ struct xevent *acknack_xevent; /* entry in xevent queue for sending acknacks */
enum pwr_rd_match_syncstate in_sync; /* whether in sync with the proxy writer */ enum pwr_rd_match_syncstate in_sync; /* whether in sync with the proxy writer */
unsigned filtered:1;
union { union {
struct { struct {
seqno_t end_of_tl_seq; /* when seq >= end_of_tl_seq, it's in sync, =0 when not tl */ seqno_t end_of_tl_seq; /* when seq >= end_of_tl_seq, it's in sync, =0 when not tl */
struct nn_reorder *reorder; /* can be done (mostly) per proxy writer, but that is harder; only when state=OUT_OF_SYNC */ struct nn_reorder *reorder; /* can be done (mostly) per proxy writer, but that is harder; only when state=OUT_OF_SYNC */
} not_in_sync; } not_in_sync;
} u; } u;
#ifdef DDSI_INCLUDE_SECURITY
int64_t crypto_handle;
#endif
}; };
struct nn_rsample_info; struct nn_rsample_info;
@ -209,8 +231,12 @@ struct participant
int32_t builtin_refc; /* number of 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] */ 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 */ ddsrt_fibheap_t ldur_auto_wr; /* Heap that contains lease duration for writers with automatic liveliness in this participant */
ddsrt_atomic_voidp_t minl_man; /* lease object for shortest manual-by-participant liveliness writer's lease */ ddsrt_atomic_voidp_t minl_man; /* clone of min(leaseheap_man) */
ddsrt_fibheap_t leaseheap_man; /* keeps leases for this participant's writers (with liveliness manual-by-participant) */ ddsrt_fibheap_t leaseheap_man; /* keeps leases for this participant's writers (with liveliness manual-by-participant) */
#ifdef DDSI_INCLUDE_SECURITY
struct participant_sec_attributes *sec_attr;
nn_security_info_t security_info;
#endif
}; };
struct endpoint_common { struct endpoint_common {
@ -257,6 +283,7 @@ struct writer
unsigned reliable: 1; /* iff 1, writer is reliable <=> heartbeat_xevent != NULL */ unsigned reliable: 1; /* iff 1, writer is reliable <=> heartbeat_xevent != NULL */
unsigned handle_as_transient_local: 1; /* controls whether data is retained in WHC */ unsigned handle_as_transient_local: 1; /* controls whether data is retained in WHC */
unsigned include_keyhash: 1; /* iff 1, this writer includes a keyhash; keyless topics => include_keyhash = 0 */ unsigned include_keyhash: 1; /* iff 1, this writer includes a keyhash; keyless topics => include_keyhash = 0 */
unsigned force_md5_keyhash: 1; /* iff 1, when keyhash has to be hashed, no matter the size */
unsigned retransmitting: 1; /* iff 1, this writer is currently retransmitting */ unsigned retransmitting: 1; /* iff 1, this writer is currently retransmitting */
unsigned alive: 1; /* iff 1, the writer is alive (lease for this writer is not expired); field may be modified only when holding both wr->e.lock and wr->c.pp->e.lock */ unsigned alive: 1; /* iff 1, the writer is alive (lease for this writer is not expired); field may be modified only when holding both wr->e.lock and wr->c.pp->e.lock */
#ifdef DDSI_INCLUDE_SSM #ifdef DDSI_INCLUDE_SSM
@ -264,7 +291,7 @@ struct writer
struct addrset *ssm_as; struct addrset *ssm_as;
#endif #endif
uint32_t alive_vclock; /* virtual clock counting transitions between alive/not-alive */ uint32_t alive_vclock; /* virtual clock counting transitions between alive/not-alive */
const struct ddsi_sertopic * topic; /* topic, but may be NULL for built-ins */ const struct ddsi_sertopic * topic; /* topic */
struct addrset *as; /* set of addresses to publish to */ 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 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 */ struct xevent *heartbeat_xevent; /* timed event for "periodically" publishing heartbeats when unack'd data present, NULL <=> unreliable */
@ -273,6 +300,7 @@ struct writer
uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */ uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */
ddsrt_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */ ddsrt_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */
ddsrt_etime_t t_whc_high_upd; /* time "whc_high" was last updated for controlled ramp-up of throughput */ ddsrt_etime_t t_whc_high_upd; /* time "whc_high" was last updated for controlled ramp-up of throughput */
uint32_t num_readers; /* total number of matching PROXY readers */
int32_t num_reliable_readers; /* number of matching reliable PROXY readers */ int32_t num_reliable_readers; /* number of matching reliable PROXY readers */
ddsrt_avl_tree_t readers; /* all matching PROXY readers, see struct wr_prd_match */ ddsrt_avl_tree_t readers; /* all matching PROXY readers, see struct wr_prd_match */
ddsrt_avl_tree_t local_readers; /* all matching LOCAL readers, see struct wr_rd_match */ ddsrt_avl_tree_t local_readers; /* all matching LOCAL readers, see struct wr_rd_match */
@ -288,6 +316,9 @@ struct writer
struct xeventq *evq; /* timed event queue to be used by this writer */ struct xeventq *evq; /* timed event queue to be used by this writer */
struct local_reader_ary rdary; /* LOCAL readers for fast-pathing; if not fast-pathed, fall back to scanning local_readers */ struct local_reader_ary rdary; /* LOCAL readers for fast-pathing; if not fast-pathed, fall back to scanning local_readers */
struct lease *lease; /* for liveliness administration (writer can only become inactive when using manual liveliness) */ struct lease *lease; /* for liveliness administration (writer can only become inactive when using manual liveliness) */
#ifdef DDSI_INCLUDE_SECURITY
struct writer_sec_attributes *sec_attr;
#endif
}; };
inline seqno_t writer_read_seq_xmit (const struct writer *wr) { inline seqno_t writer_read_seq_xmit (const struct writer *wr) {
@ -319,11 +350,15 @@ struct reader
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
struct addrset *as; struct addrset *as;
#endif #endif
const struct ddsi_sertopic * topic; /* topic is NULL for built-in readers */ const struct ddsi_sertopic * topic; /* topic */
uint32_t num_writers; /* total number of matching PROXY writers */
ddsrt_avl_tree_t writers; /* all matching PROXY writers, see struct rd_pwr_match */ ddsrt_avl_tree_t writers; /* all matching PROXY writers, see struct rd_pwr_match */
ddsrt_avl_tree_t local_writers; /* all matching LOCAL writers, see struct rd_wr_match */ ddsrt_avl_tree_t local_writers; /* all matching LOCAL writers, see struct rd_wr_match */
ddsi2direct_directread_cb_t ddsi2direct_cb; ddsi2direct_directread_cb_t ddsi2direct_cb;
void *ddsi2direct_cbarg; void *ddsi2direct_cbarg;
#ifdef DDSI_INCLUDE_SECURITY
struct reader_sec_attributes *sec_attr;
#endif
}; };
struct proxy_participant struct proxy_participant
@ -334,9 +369,9 @@ struct proxy_participant
unsigned bes; /* built-in endpoint set */ unsigned bes; /* built-in endpoint set */
ddsi_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */ ddsi_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */
struct ddsi_plist *plist; /* settings/QoS for this participant */ struct ddsi_plist *plist; /* settings/QoS for this participant */
ddsrt_atomic_voidp_t minl_auto; /* lease object for shortest automatic liveliness pwr's lease (includes this proxypp's lease) */ ddsrt_atomic_voidp_t minl_auto; /* clone of min(leaseheap_auto) */
ddsrt_fibheap_t leaseheap_auto; /* keeps leases for this proxypp and leases for pwrs (with liveliness automatic) */ 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_atomic_voidp_t minl_man; /* clone of min(leaseheap_man) */
ddsrt_fibheap_t leaseheap_man; /* keeps leases for this proxypp and leases for pwrs (with liveliness manual-by-participant) */ 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 lease *lease; /* lease for this proxypp */
struct addrset *as_default; /* default address set to use for user data traffic */ struct addrset *as_default; /* default address set to use for user data traffic */
@ -344,7 +379,6 @@ struct proxy_participant
struct proxy_endpoint_common *endpoints; /* all proxy endpoints can be reached from here */ struct proxy_endpoint_common *endpoints; /* all proxy endpoints can be reached from here */
ddsrt_avl_tree_t groups; /* table of all groups (publisher, subscriber), see struct proxy_group */ ddsrt_avl_tree_t groups; /* table of all groups (publisher, subscriber), see struct proxy_group */
seqno_t seq; /* sequence number of most recent SPDP message */ seqno_t seq; /* sequence number of most recent SPDP message */
unsigned kernel_sequence_numbers : 1; /* whether this proxy participant generates OSPL kernel sequence numbers */
unsigned implicitly_created : 1; /* participants are implicitly created for Cloud/Fog discovered endpoints */ unsigned implicitly_created : 1; /* participants are implicitly created for Cloud/Fog discovered endpoints */
unsigned is_ddsi2_pp: 1; /* if this is the federation-leader on the remote node */ unsigned is_ddsi2_pp: 1; /* if this is the federation-leader on the remote node */
unsigned minimal_bes_mode: 1; unsigned minimal_bes_mode: 1;
@ -352,6 +386,10 @@ struct proxy_participant
unsigned deleting: 1; unsigned deleting: 1;
unsigned proxypp_have_spdp: 1; unsigned proxypp_have_spdp: 1;
unsigned owns_lease: 1; unsigned owns_lease: 1;
#ifdef DDSI_INCLUDE_SECURITY
nn_security_info_t security_info;
struct proxy_participant_sec_attributes *sec_attr;
#endif
}; };
/* Representing proxy subscriber & publishers as "groups": until DDSI2 /* Representing proxy subscriber & publishers as "groups": until DDSI2
@ -379,6 +417,9 @@ struct proxy_endpoint_common
ddsi_guid_t group_guid; /* 0:0:0:0 if not available */ ddsi_guid_t group_guid; /* 0:0:0:0 if not available */
nn_vendorid_t vendor; /* cached from proxypp->vendor */ nn_vendorid_t vendor; /* cached from proxypp->vendor */
seqno_t seq; /* sequence number of most recent SEDP message */ seqno_t seq; /* sequence number of most recent SEDP message */
#ifdef DDSI_INCLUDE_SECURITY
nn_security_info_t security_info;
#endif
}; };
struct generic_proxy_endpoint { struct generic_proxy_endpoint {
@ -401,6 +442,7 @@ struct proxy_writer {
unsigned have_seen_heartbeat: 1; /* iff 1, we have received at least on heartbeat from this proxy writer */ 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 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 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 #ifdef DDSI_INCLUDE_SSM
unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */ unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */
#endif #endif
@ -415,6 +457,9 @@ struct proxy_writer {
struct lease *lease; struct lease *lease;
}; };
typedef int (*filter_fn_t)(struct writer *wr, struct proxy_reader *prd, struct ddsi_serdata *serdata);
struct proxy_reader { struct proxy_reader {
struct entity_common e; struct entity_common e;
struct proxy_endpoint_common c; struct proxy_endpoint_common c;
@ -424,6 +469,7 @@ struct proxy_reader {
unsigned favours_ssm: 1; /* iff 1, this proxy reader favours SSM when available */ unsigned favours_ssm: 1; /* iff 1, this proxy reader favours SSM when available */
#endif #endif
ddsrt_avl_tree_t writers; /* matching LOCAL writers */ ddsrt_avl_tree_t writers; /* matching LOCAL writers */
filter_fn_t filter;
}; };
DDS_EXPORT extern const ddsrt_avl_treedef_t wr_readers_treedef; DDS_EXPORT extern const ddsrt_avl_treedef_t wr_readers_treedef;
@ -507,8 +553,8 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e);
/** /**
* @brief Create a new participant with a given GUID in the domain. * @brief Create a new participant with a given GUID in the domain.
* *
* @param[in] ppguid * @param[in,out] ppguid
* The GUID of the new participant. * The GUID of the new participant, may be adjusted by security.
* @param[in] flags * @param[in] flags
* Zero or more of: * Zero or more of:
* - RTPS_PF_NO_BUILTIN_READERS do not create discovery readers in new ppant * - RTPS_PF_NO_BUILTIN_READERS do not create discovery readers in new ppant
@ -529,7 +575,7 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e);
* @retval DDS_RETCODE_OUT_OF_RESOURCES * @retval DDS_RETCODE_OUT_OF_RESOURCES
* The configured maximum number of participants has been reached. * The configured maximum number of participants has been reached.
*/ */
dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist); dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist);
/** /**
* @brief Create a new participant in the domain. See also new_participant_guid. * @brief Create a new participant in the domain. See also new_participant_guid.
@ -596,9 +642,8 @@ DDS_EXPORT struct writer *get_builtin_writer (const struct participant *pp, unsi
GUID "ppguid". May return NULL if participant unknown or GUID "ppguid". May return NULL if participant unknown or
writer/reader already known. */ writer/reader already known. */
dds_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg); dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg);
dds_return_t new_reader (struct reader **rd_out, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg);
dds_return_t new_reader (struct reader **rd_out, struct ddsi_domaingv *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg);
void update_reader_qos (struct reader *rd, const struct dds_qos *xqos); void update_reader_qos (struct reader *rd, const struct dds_qos *xqos);
void update_writer_qos (struct writer *wr, const struct dds_qos *xqos); void update_writer_qos (struct writer *wr, const struct dds_qos *xqos);
@ -610,7 +655,7 @@ seqno_t writer_max_drop_seq (const struct writer *wr);
int writer_must_have_hb_scheduled (const struct writer *wr, const struct whc_state *whcst); int writer_must_have_hb_scheduled (const struct writer *wr, const struct whc_state *whcst);
void writer_set_retransmitting (struct writer *wr); void writer_set_retransmitting (struct writer *wr);
void writer_clear_retransmitting (struct writer *wr); void writer_clear_retransmitting (struct writer *wr);
dds_return_t writer_wait_for_acks (struct writer *wr, dds_time_t abstimeout); dds_return_t writer_wait_for_acks (struct writer *wr, const ddsi_guid_t *rdguid, dds_time_t abstimeout);
dds_return_t unblock_throttled_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid); dds_return_t unblock_throttled_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid);
dds_return_t delete_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid); dds_return_t delete_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid);
@ -638,22 +683,20 @@ int writer_set_notalive (struct writer *wr, bool notify);
XX -- XX --
*/ */
/* Set this custom flag when using nn_adlink_writer_info_t iso nn_adlink_writer_info_old_t */
#define CF_INC_KERNEL_SEQUENCE_NUMBERS (1 << 0)
/* Set when this proxy participant is created implicitly and has to be deleted upon disappearance /* Set when this proxy participant is created implicitly and has to be deleted upon disappearance
of its last endpoint. FIXME: Currently there is a potential race with adding a new endpoint of its last endpoint. FIXME: Currently there is a potential race with adding a new endpoint
in parallel to deleting the last remaining one. The endpoint will then be created, added to the in parallel to deleting the last remaining one. The endpoint will then be created, added to the
proxy participant and then both are deleted. With the current single-threaded discovery proxy participant and then both are deleted. With the current single-threaded discovery
this can only happen when it is all triggered by lease expiry. */ this can only happen when it is all triggered by lease expiry. */
#define CF_IMPLICITLY_CREATED_PROXYPP (1 << 1) #define CF_IMPLICITLY_CREATED_PROXYPP (1 << 0)
/* Set when this proxy participant is a DDSI2 participant, to help Cloud figure out whom to send /* Set when this proxy participant is a DDSI2 participant, to help Cloud figure out whom to send
discovery data when used in conjunction with the networking bridge */ discovery data when used in conjunction with the networking bridge */
#define CF_PARTICIPANT_IS_DDSI2 (1 << 2) #define CF_PARTICIPANT_IS_DDSI2 (1 << 1)
/* Set when this proxy participant is not to be announced on the built-in topics yet */ /* Set when this proxy participant is not to be announced on the built-in topics yet */
#define CF_PROXYPP_NO_SPDP (1 << 3) #define CF_PROXYPP_NO_SPDP (1 << 2)
void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct ddsi_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, ddsrt_wctime_t timestamp, seqno_t seq); bool new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct ddsi_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, ddsrt_wctime_t timestamp, seqno_t seq);
int delete_proxy_participant_by_guid (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, ddsrt_wctime_t timestamp, int isimplicit); DDS_EXPORT int delete_proxy_participant_by_guid (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, ddsrt_wctime_t timestamp, int isimplicit);
int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, ddsrt_wctime_t timestamp); int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, ddsrt_wctime_t timestamp);
int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, ddsrt_wctime_t timestamp); int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, ddsrt_wctime_t timestamp);
@ -696,6 +739,10 @@ void rebuild_or_clear_writer_addrsets(struct ddsi_domaingv *gv, int rebuild);
void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok); void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok);
void connect_writer_with_proxy_reader_secure(struct writer *wr, struct proxy_reader *prd, ddsrt_mtime_t tnow, int64_t crypto_handle);
void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, ddsrt_mtime_t tnow, int64_t crypto_handle);
struct ddsi_writer_info; struct ddsi_writer_info;
DDS_EXPORT void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos, uint32_t statusinfo); DDS_EXPORT void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos, uint32_t statusinfo);

View file

@ -18,6 +18,7 @@ extern "C" {
struct writer; struct writer;
struct whc_state; struct whc_state;
struct proxy_reader;
struct hbcontrol { struct hbcontrol {
ddsrt_mtime_t t_of_last_write; ddsrt_mtime_t t_of_last_write;
@ -36,6 +37,11 @@ struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_
int writer_hbcontrol_must_send (const struct writer *wr, const struct whc_state *whcst, ddsrt_mtime_t tnow); int writer_hbcontrol_must_send (const struct writer *wr, const struct whc_state *whcst, ddsrt_mtime_t tnow);
struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const struct whc_state *whcst, ddsrt_mtime_t tnow, int hbansreq, int issync); struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const struct whc_state *whcst, ddsrt_mtime_t tnow, int hbansreq, int issync);
#ifdef DDSI_INCLUDE_SECURITY
struct nn_xmsg *writer_hbcontrol_p2p(struct writer *wr, const struct whc_state *whcst, int hbansreq, struct proxy_reader *prd);
#endif
#if defined (__cplusplus) #if defined (__cplusplus)
} }
#endif #endif

View file

@ -28,8 +28,8 @@ struct ddsi_domaingv; /* FIXME: make a special for the lease admin */
struct lease { struct lease {
ddsrt_fibheap_node_t heapnode; ddsrt_fibheap_node_t heapnode;
ddsrt_fibheap_node_t pp_heapnode; ddsrt_fibheap_node_t pp_heapnode;
ddsrt_etime_t tsched; /* access guarded by leaseheap_lock */ ddsrt_etime_t tsched; /* access guarded by leaseheap_lock */
ddsrt_atomic_uint64_t tend; /* really an nn_etime_t */ ddsrt_atomic_uint64_t tend; /* really an ddsrt_etime_t */
dds_duration_t tdur; /* constant (renew depends on it) */ dds_duration_t tdur; /* constant (renew depends on it) */
struct entity_common *entity; /* constant */ struct entity_common *entity; /* constant */
}; };

View file

@ -35,7 +35,10 @@ unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr);
int WildcardOverlap(char * p1, char * p2); int WildcardOverlap(char * p1, char * p2);
#endif #endif
int ddsi2_patmatch (const char *pat, const char *str); DDS_EXPORT bool guid_prefix_zero (const ddsi_guid_prefix_t *a);
DDS_EXPORT int guid_prefix_eq (const ddsi_guid_prefix_t *a, const ddsi_guid_prefix_t *b);
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);
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -89,13 +89,21 @@ typedef struct {
#define NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER (1u << 12) #define NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER (1u << 12)
#define NN_DISC_BUILTIN_ENDPOINT_TOPIC_DETECTOR (1u << 13) #define NN_DISC_BUILTIN_ENDPOINT_TOPIC_DETECTOR (1u << 13)
/* Adlink extensions: */ /* Security extensions: */
#define NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER (1u << 0) #define NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_ANNOUNCER (1u<<16)
#define NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_READER (1u << 1) #define NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_DETECTOR (1u<<17)
#define NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER (1u << 2) #define NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_ANNOUNCER (1u<<18)
#define NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_READER (1u << 3) #define NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_DETECTOR (1u<<19)
#define NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER (1u << 4) #define NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_ANNOUNCER (1u<<20)
#define NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_READER (1u << 5) #define NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_DETECTOR (1u<<21)
#define NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_ANNOUNCER (1u<<22)
#define NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_DETECTOR (1u<<23)
#define NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_ANNOUNCER (1u<<24)
#define NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_DETECTOR (1u<<25)
#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER (1u << 26)
#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_DETECTOR (1u << 27)
#define NN_BES_MASK_NON_SECURITY 0xf000ffffu
#define NN_LOCATOR_KIND_INVALID -1 #define NN_LOCATOR_KIND_INVALID -1
#define NN_LOCATOR_KIND_RESERVED 0 #define NN_LOCATOR_KIND_RESERVED 0
@ -149,6 +157,12 @@ typedef enum SubmessageKind {
SMID_HEARTBEAT_FRAG = 0x13, SMID_HEARTBEAT_FRAG = 0x13,
SMID_DATA = 0x15, SMID_DATA = 0x15,
SMID_DATA_FRAG = 0x16, SMID_DATA_FRAG = 0x16,
/* security-specific sub messages */
SMID_SEC_BODY = 0x30,
SMID_SEC_PREFIX = 0x31,
SMID_SEC_POSTFIX = 0x32,
SMID_SRTPS_PREFIX = 0x33,
SMID_SRTPS_POSTFIX = 0x34,
/* vendor-specific sub messages (0x80 .. 0xff) */ /* vendor-specific sub messages (0x80 .. 0xff) */
SMID_ADLINK_MSG_LEN = 0x81, SMID_ADLINK_MSG_LEN = 0x81,
SMID_ADLINK_ENTITY_ID = 0x82 SMID_ADLINK_ENTITY_ID = 0x82
@ -189,7 +203,7 @@ typedef uint16_t nn_parameterid_t; /* spec says short */
typedef struct nn_parameter { typedef struct nn_parameter {
nn_parameterid_t parameterid; nn_parameterid_t parameterid;
uint16_t length; /* spec says signed short */ uint16_t length; /* spec says signed short */
/* char value[]; O! how I long for C99 */ /* char value[] */
} nn_parameter_t; } nn_parameter_t;
typedef struct Data_DataFrag_common { typedef struct Data_DataFrag_common {
@ -304,18 +318,10 @@ typedef union Submessage {
NackFrag_t nackfrag; NackFrag_t nackfrag;
} Submessage_t; } Submessage_t;
DDSRT_WARNING_MSVC_OFF(4200)
typedef struct ParticipantMessageData {
ddsi_guid_prefix_t participantGuidPrefix;
uint32_t kind; /* really 4 octets */
uint32_t length;
char value[];
} ParticipantMessageData_t;
DDSRT_WARNING_MSVC_ON(4200)
#define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN 0x0u #define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN 0x0u
#define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE 0x1u #define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE 0x1u
#define PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE 0x2u #define PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE 0x2u
#define PARTICIPANT_MESSAGE_DATA_VENDER_SPECIFIC_KIND_FLAG 0x8000000u #define PARTICIPANT_MESSAGE_DATA_VENDOR_SPECIFIC_KIND_FLAG 0x8000000u
#define PID_VENDORSPECIFIC_FLAG 0x8000u #define PID_VENDORSPECIFIC_FLAG 0x8000u
#define PID_UNRECOGNIZED_INCOMPATIBLE_FLAG 0x4000u #define PID_UNRECOGNIZED_INCOMPATIBLE_FLAG 0x4000u
@ -384,6 +390,10 @@ DDSRT_WARNING_MSVC_ON(4200)
/* Security related PID values. */ /* Security related PID values. */
#define PID_IDENTITY_TOKEN 0x1001u #define PID_IDENTITY_TOKEN 0x1001u
#define PID_PERMISSIONS_TOKEN 0x1002u #define PID_PERMISSIONS_TOKEN 0x1002u
#define PID_DATA_TAGS 0x1003u
#define PID_ENDPOINT_SECURITY_INFO 0x1004u
#define PID_PARTICIPANT_SECURITY_INFO 0x1005u
#define PID_IDENTITY_STATUS_TOKEN 0x1006u
#ifdef DDSI_INCLUDE_SSM #ifdef DDSI_INCLUDE_SSM
/* To indicate whether a reader favours the use of SSM. Iff the /* To indicate whether a reader favours the use of SSM. Iff the

View file

@ -110,10 +110,11 @@ whichever is larger. */
#define ALIGNOF_RMSG (sizeof(void *) > 8 ? sizeof(void *) : 8) #define ALIGNOF_RMSG (sizeof(void *) > 8 ? sizeof(void *) : 8)
struct receiver_state { struct receiver_state {
ddsi_guid_prefix_t src_guid_prefix; /* 12 */ ddsi_guid_prefix_t src_guid_prefix; /* 12 */
ddsi_guid_prefix_t dst_guid_prefix; /* 12 */ ddsi_guid_prefix_t dst_guid_prefix; /* 12 */
struct addrset *reply_locators; /* 4/8 */ struct addrset *reply_locators; /* 4/8 */
int forme; /* 4 */ uint32_t forme:1; /* 4 */
uint32_t rtps_encoded:1; /* - */
nn_vendorid_t vendor; /* 2 */ nn_vendorid_t vendor; /* 2 */
nn_protocol_version_t protocol_version; /* 2 => 44/48 */ nn_protocol_version_t protocol_version; /* 2 => 44/48 */
ddsi_tran_conn_t conn; /* Connection for request */ ddsi_tran_conn_t conn; /* Connection for request */
@ -223,6 +224,7 @@ void nn_defrag_free (struct nn_defrag *defrag);
struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata *rdata, const struct nn_rsample_info *sampleinfo); struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata *rdata, const struct nn_rsample_info *sampleinfo);
void nn_defrag_notegap (struct nn_defrag *defrag, seqno_t min, seqno_t maxp1); void nn_defrag_notegap (struct nn_defrag *defrag, seqno_t min, seqno_t maxp1);
int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnum, struct nn_fragment_number_set_header *map, uint32_t *mapbits, uint32_t maxsz); int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnum, struct nn_fragment_number_set_header *map, uint32_t *mapbits, uint32_t maxsz);
void nn_defrag_prune (struct nn_defrag *defrag, ddsi_guid_prefix_t *dst, seqno_t min);
struct nn_reorder *nn_reorder_new (const struct ddsrt_log_cfg *logcfg, enum nn_reorder_mode mode, uint32_t max_samples, bool late_ack_mode); struct nn_reorder *nn_reorder_new (const struct ddsrt_log_cfg *logcfg, enum nn_reorder_mode mode, uint32_t max_samples, bool late_ack_mode);
void nn_reorder_free (struct nn_reorder *r); void nn_reorder_free (struct nn_reorder *r);
@ -233,6 +235,7 @@ nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reord
int nn_reorder_wantsample (struct nn_reorder *reorder, seqno_t seq); int nn_reorder_wantsample (struct nn_reorder *reorder, seqno_t seq);
unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t maxseq, struct nn_sequence_number_set_header *map, uint32_t *mapbits, uint32_t maxsz, int notail); unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t maxseq, struct nn_sequence_number_set_header *map, uint32_t *mapbits, uint32_t maxsz, int notail);
seqno_t nn_reorder_next_seq (const struct nn_reorder *reorder); seqno_t nn_reorder_next_seq (const struct nn_reorder *reorder);
void nn_reorder_set_next_seq (struct nn_reorder *reorder, seqno_t seq);
struct nn_dqueue *nn_dqueue_new (const char *name, const struct ddsi_domaingv *gv, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg); struct nn_dqueue *nn_dqueue_new (const char *name, const struct ddsi_domaingv *gv, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg);
void nn_dqueue_free (struct nn_dqueue *q); void nn_dqueue_free (struct nn_dqueue *q);

View file

@ -21,11 +21,25 @@ struct nn_rsample_info;
struct nn_rdata; struct nn_rdata;
struct ddsi_tran_listener; struct ddsi_tran_listener;
struct recv_thread_arg; struct recv_thread_arg;
struct writer;
struct proxy_reader;
struct nn_gap_info {
int64_t gapstart;
int64_t gapend;
unsigned gapnumbits;
unsigned gapbits[256 / 32];
};
void nn_gap_info_init(struct nn_gap_info *gi);
void nn_gap_info_update(struct ddsi_domaingv *gv, struct nn_gap_info *gi, int64_t seqnr);
struct nn_xmsg * nn_gap_info_create_gap(struct writer *wr, struct proxy_reader *prd, struct nn_gap_info *gi);
void trigger_recv_threads (const struct ddsi_domaingv *gv); void trigger_recv_threads (const struct ddsi_domaingv *gv);
uint32_t recv_thread (void *vrecv_thread_arg); uint32_t recv_thread (void *vrecv_thread_arg);
uint32_t listen_thread (struct ddsi_tran_listener * listener); uint32_t listen_thread (struct ddsi_tran_listener * listener);
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg); int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg);
int add_Gap (struct nn_xmsg *msg, struct writer *wr, struct proxy_reader *prd, seqno_t start, seqno_t base, uint32_t numbits, const uint32_t *bits);
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -45,6 +45,20 @@ typedef int64_t seqno_t;
#define NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER 0x100c7 #define NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER 0x100c7
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER 0x200c2 #define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER 0x200c2
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER 0x200c7 #define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER 0x200c7
#define NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER 0xff0003c2
#define NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER 0xff0003c7
#define NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER 0xff0004c2
#define NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER 0xff0004c7
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER 0x201c3
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER 0x201c4
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER 0xff0200c2
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER 0xff0200c7
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER 0xff0202c3
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER 0xff0202c4
#define NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER 0xff0101c2
#define NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER 0xff0101c7
#define NN_ENTITYID_SOURCE_MASK 0xc0 #define NN_ENTITYID_SOURCE_MASK 0xc0
#define NN_ENTITYID_SOURCE_USER 0x00 #define NN_ENTITYID_SOURCE_USER 0x00
#define NN_ENTITYID_SOURCE_BUILTIN 0xc0 #define NN_ENTITYID_SOURCE_BUILTIN 0xc0

View file

@ -44,6 +44,7 @@ dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const stru
int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew); int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct ddsi_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, int hbliveliness, 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 ddsi_domaingv * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp); dds_return_t write_hb_liveliness (struct ddsi_domaingv * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp);
int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, struct proxy_reader *prd);
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -50,8 +50,10 @@ DDS_EXPORT dds_return_t xeventq_start (struct xeventq *evq, const char *name); /
DDS_EXPORT void xeventq_stop (struct xeventq *evq); DDS_EXPORT void xeventq_stop (struct xeventq *evq);
DDS_EXPORT void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg); DDS_EXPORT void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg);
DDS_EXPORT void qxev_pwr_entityid (struct proxy_writer * pwr, ddsi_guid_prefix_t * id);
DDS_EXPORT void qxev_prd_entityid (struct proxy_reader * prd, ddsi_guid_prefix_t * id); DDS_EXPORT void qxev_pwr_entityid (struct proxy_writer * pwr, const ddsi_guid_t *guid);
DDS_EXPORT void qxev_prd_entityid (struct proxy_reader * prd, const ddsi_guid_t *guid);
DDS_EXPORT void qxev_nt_callback (struct xeventq *evq, void (*cb) (void *arg), void *arg);
/* Returns 1 if queued, 0 otherwise (no point in returning the /* Returns 1 if queued, 0 otherwise (no point in returning the
event, you can't do anything with it anyway) */ event, you can't do anything with it anyway) */

View file

@ -26,6 +26,8 @@ struct ddsi_serdata;
struct addrset; struct addrset;
struct proxy_reader; struct proxy_reader;
struct proxy_writer; struct proxy_writer;
struct writer;
struct participant;
struct nn_adlink_participant_version_info; struct nn_adlink_participant_version_info;
struct nn_xmsgpool; struct nn_xmsgpool;
@ -41,7 +43,8 @@ struct nn_xmsg_marker {
enum nn_xmsg_kind { enum nn_xmsg_kind {
NN_XMSG_KIND_CONTROL, NN_XMSG_KIND_CONTROL,
NN_XMSG_KIND_DATA, NN_XMSG_KIND_DATA,
NN_XMSG_KIND_DATA_REXMIT NN_XMSG_KIND_DATA_REXMIT,
NN_XMSG_KIND_DATA_REXMIT_NOMERGE
}; };
/* XMSGPOOL */ /* XMSGPOOL */
@ -54,10 +57,11 @@ void nn_xmsgpool_free (struct nn_xmsgpool *pool);
/* To allocate a new xmsg from the pool; if expected_size is NOT /* To allocate a new xmsg from the pool; if expected_size is NOT
exceeded, no reallocs will be performed, else the address of the exceeded, no reallocs will be performed, else the address of the
xmsg may change because of reallocing when appending to it. */ xmsg may change because of reallocing when appending to it. */
struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind); struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_t *src_guid, struct participant *pp, size_t expected_size, enum nn_xmsg_kind kind);
/* For sending to a particular destination (participant) */ /* For sending to a particular destination (participant) */
void nn_xmsg_setdst1 (struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *addr); void nn_xmsg_setdst1 (struct ddsi_domaingv *gv, struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *addr);
bool nn_xmsg_getdst1prefix (struct nn_xmsg *m, ddsi_guid_prefix_t *gp);
/* For sending to a particular proxy reader; this is a convenience /* For sending to a particular proxy reader; this is a convenience
routine that extracts a suitable address from the proxy reader's routine that extracts a suitable address from the proxy reader's
@ -114,15 +118,23 @@ void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, ddsi_guid_t *wrguid, seqn
void *nn_xmsg_submsg_from_marker (struct nn_xmsg *msg, struct nn_xmsg_marker marker); void *nn_xmsg_submsg_from_marker (struct nn_xmsg *msg, struct nn_xmsg_marker marker);
void *nn_xmsg_append (struct nn_xmsg *m, struct nn_xmsg_marker *marker, size_t sz); void *nn_xmsg_append (struct nn_xmsg *m, struct nn_xmsg_marker *marker, size_t sz);
void nn_xmsg_shrink (struct nn_xmsg *m, struct nn_xmsg_marker marker, size_t sz); void nn_xmsg_shrink (struct nn_xmsg *m, struct nn_xmsg_marker marker, size_t sz);
void nn_xmsg_serdata (struct nn_xmsg *m, struct ddsi_serdata *serdata, size_t off, size_t len); void nn_xmsg_serdata (struct nn_xmsg *m, struct ddsi_serdata *serdata, size_t off, size_t len, struct writer *wr);
#ifdef DDSI_INCLUDE_SECURITY
size_t nn_xmsg_submsg_size (struct nn_xmsg *msg, struct nn_xmsg_marker marker);
void nn_xmsg_submsg_remove (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker);
void nn_xmsg_submsg_replace (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker, unsigned char *new_submsg, size_t new_len);
void nn_xmsg_submsg_append_refd_payload (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker);
#endif
void nn_xmsg_submsg_setnext (struct nn_xmsg *msg, struct nn_xmsg_marker marker); void nn_xmsg_submsg_setnext (struct nn_xmsg *msg, struct nn_xmsg_marker marker);
void nn_xmsg_submsg_init (struct nn_xmsg *msg, struct nn_xmsg_marker marker, SubmessageKind_t smkind); void nn_xmsg_submsg_init (struct nn_xmsg *msg, struct nn_xmsg_marker marker, SubmessageKind_t smkind);
void nn_xmsg_add_timestamp (struct nn_xmsg *m, ddsrt_wctime_t t); void nn_xmsg_add_timestamp (struct nn_xmsg *m, ddsrt_wctime_t t);
void nn_xmsg_add_entityid (struct nn_xmsg * m); void nn_xmsg_add_entityid (struct nn_xmsg * m);
void *nn_xmsg_addpar_bo (struct nn_xmsg *m, nn_parameterid_t pid, size_t len, bool be);
void *nn_xmsg_addpar (struct nn_xmsg *m, nn_parameterid_t pid, size_t len); void *nn_xmsg_addpar (struct nn_xmsg *m, nn_parameterid_t pid, size_t len);
void nn_xmsg_addpar_keyhash (struct nn_xmsg *m, const struct ddsi_serdata *serdata); void nn_xmsg_addpar_keyhash (struct nn_xmsg *m, const struct ddsi_serdata *serdata, bool force_md5);
void nn_xmsg_addpar_statusinfo (struct nn_xmsg *m, unsigned statusinfo); void nn_xmsg_addpar_statusinfo (struct nn_xmsg *m, unsigned statusinfo);
void nn_xmsg_addpar_sentinel (struct nn_xmsg *m); void nn_xmsg_addpar_sentinel (struct nn_xmsg *m);
void nn_xmsg_addpar_sentinel_bo (struct nn_xmsg * m, bool be);
int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg *m); int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg *m);
/* XPACK */ /* XPACK */

View file

@ -364,7 +364,8 @@ static void dds_stream_countops1 (const uint32_t * __restrict ops, const uint32_
break; break;
} }
case DDS_OP_JSR: { case DDS_OP_JSR: {
dds_stream_countops1 (ops + DDS_OP_JUMP (insn), ops_end); if (DDS_OP_JUMP (insn) > 0)
dds_stream_countops1 (ops + DDS_OP_JUMP (insn), ops_end);
ops++; ops++;
break; break;
} }
@ -1909,7 +1910,10 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t *
const struct ddsi_sertopic_default_desc *desc = &topic->type; const struct ddsi_sertopic_default_desc *desc = &topic->type;
kh->m_set = 1; kh->m_set = 1;
if (desc->m_nkeys == 0) if (desc->m_nkeys == 0)
{
kh->m_iskey = 1; kh->m_iskey = 1;
kh->m_keysize = 0;
}
else if (desc->m_flagset & DDS_TOPIC_FIXED_KEY) else if (desc->m_flagset & DDS_TOPIC_FIXED_KEY)
{ {
dds_ostreamBE_t os; dds_ostreamBE_t os;
@ -1922,12 +1926,14 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t *
else else
dds_stream_extract_keyBE_from_data (is, &os, topic); dds_stream_extract_keyBE_from_data (is, &os, topic);
assert (os.x.m_index <= 16); assert (os.x.m_index <= 16);
kh->m_keysize = (unsigned)os.x.m_index & 0x1f;
} }
else else
{ {
dds_ostreamBE_t os; dds_ostreamBE_t os;
ddsrt_md5_state_t md5st; ddsrt_md5_state_t md5st;
kh->m_iskey = 0; kh->m_iskey = 0;
kh->m_keysize = 16;
dds_ostreamBE_init (&os, 0); dds_ostreamBE_init (&os, 0);
if (just_key) if (just_key)
dds_stream_extract_keyBE_from_key (is, &os, topic); dds_stream_extract_keyBE_from_key (is, &os, topic);
@ -1990,14 +1996,42 @@ static size_t isprint_runlen (const unsigned char *s, size_t n)
return m; return m;
} }
static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, enum dds_stream_typecode type) static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, enum dds_stream_typecode type, unsigned flags)
{ {
switch (type) switch (type)
{ {
case DDS_OP_VAL_1BY: return prtf (buf, bufsize, "%"PRIu8, dds_is_get1 (is)); case DDS_OP_VAL_1BY: {
case DDS_OP_VAL_2BY: return prtf (buf, bufsize, "%"PRIu16, dds_is_get2 (is)); const union { int8_t s; uint8_t u; } x = { .u = dds_is_get1 (is) };
case DDS_OP_VAL_4BY: return prtf (buf, bufsize, "%"PRIu32, dds_is_get4 (is)); if (flags & DDS_OP_FLAG_SGN)
case DDS_OP_VAL_8BY: return prtf (buf, bufsize, "%"PRIu64, dds_is_get8 (is)); return prtf (buf, bufsize, "%"PRId8, x.s);
else
return prtf (buf, bufsize, "%"PRIu8, x.u);
}
case DDS_OP_VAL_2BY: {
const union { int16_t s; uint16_t u; } x = { .u = dds_is_get2 (is) };
if (flags & DDS_OP_FLAG_SGN)
return prtf (buf, bufsize, "%"PRId16, x.s);
else
return prtf (buf, bufsize, "%"PRIu16, x.u);
}
case DDS_OP_VAL_4BY: {
const union { int32_t s; uint32_t u; float f; } x = { .u = dds_is_get4 (is) };
if (flags & DDS_OP_FLAG_FP)
return prtf (buf, bufsize, "%g", x.f);
else if (flags & DDS_OP_FLAG_SGN)
return prtf (buf, bufsize, "%"PRId32, x.s);
else
return prtf (buf, bufsize, "%"PRIu32, x.u);
}
case DDS_OP_VAL_8BY: {
const union { int64_t s; uint64_t u; double f; } x = { .u = dds_is_get8 (is) };
if (flags & DDS_OP_FLAG_FP)
return prtf (buf, bufsize, "%g", x.f);
else if (flags & DDS_OP_FLAG_SGN)
return prtf (buf, bufsize, "%"PRId64, x.s);
else
return prtf (buf, bufsize, "%"PRIu64, x.u);
}
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: return prtf_str (buf, bufsize, is); case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: return prtf_str (buf, bufsize, is);
case DDS_OP_VAL_ARR: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: case DDS_OP_VAL_ARR: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
abort (); abort ();
@ -2005,7 +2039,7 @@ static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dd
return false; return false;
} }
static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, uint32_t num, enum dds_stream_typecode type) static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, uint32_t num, enum dds_stream_typecode type, unsigned flags)
{ {
bool cont = prtf (buf, bufsize, "{"); bool cont = prtf (buf, bufsize, "{");
switch (type) switch (type)
@ -2028,7 +2062,7 @@ static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsi
{ {
if (i != 0) if (i != 0)
(void) prtf (buf, bufsize, ","); (void) prtf (buf, bufsize, ",");
cont = prtf_simple (buf, bufsize, is, type); cont = prtf_simple (buf, bufsize, is, type, flags);
i++; i++;
} }
} }
@ -2040,7 +2074,7 @@ static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsi
{ {
if (i != 0) if (i != 0)
(void) prtf (buf, bufsize, ","); (void) prtf (buf, bufsize, ",");
cont = prtf_simple (buf, bufsize, is, type); cont = prtf_simple (buf, bufsize, is, type, flags);
} }
break; break;
default: default:
@ -2065,10 +2099,10 @@ static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_is
switch (subtype) switch (subtype)
{ {
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
(void) prtf_simple_array (buf, bufsize, is, num, subtype); (void) prtf_simple_array (buf, bufsize, is, num, subtype, DDS_OP_FLAGS (insn));
return ops + 2; return ops + 2;
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
(void) prtf_simple_array (buf, bufsize, is, num, subtype); (void) prtf_simple_array (buf, bufsize, is, num, subtype, DDS_OP_FLAGS (insn));
return ops + (subtype == DDS_OP_VAL_STR ? 2 : 3); 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: { 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]); const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
@ -2093,10 +2127,10 @@ static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_is
switch (subtype) switch (subtype)
{ {
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
(void) prtf_simple_array (buf, bufsize, is, num, subtype); (void) prtf_simple_array (buf, bufsize, is, num, subtype, DDS_OP_FLAGS (insn));
return ops + 3; return ops + 3;
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
(void) prtf_simple_array (buf, bufsize, is, num, subtype); (void) prtf_simple_array (buf, bufsize, is, num, subtype, DDS_OP_FLAGS (insn));
return ops + (subtype == DDS_OP_VAL_STR ? 3 : 5); 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: { 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]); const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
@ -2127,7 +2161,7 @@ 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_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: case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
(void) prtf_simple (buf, bufsize, is, valtype); (void) prtf_simple (buf, bufsize, is, valtype, DDS_OP_FLAGS (jeq_op[0]));
break; break;
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case 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); (void) dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
@ -2156,11 +2190,11 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric
{ {
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: 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_STR:
cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn)); cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn), DDS_OP_FLAGS (insn));
ops += 2; ops += 2;
break; break;
case DDS_OP_VAL_BST: case DDS_OP_VAL_BST:
cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn)); cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn), DDS_OP_FLAGS (insn));
ops += 3; ops += 3;
break; break;
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_SEQ:
@ -2212,10 +2246,10 @@ size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_se
{ {
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: 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: case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
cont = prtf_simple (&buf, &bufsize, is, DDS_OP_TYPE (*op)); cont = prtf_simple (&buf, &bufsize, is, DDS_OP_TYPE (*op), DDS_OP_FLAGS (*op));
break; break;
case DDS_OP_VAL_ARR: case DDS_OP_VAL_ARR:
cont = prtf_simple_array (&buf, &bufsize, is, op[2], DDS_OP_SUBTYPE (*op)); cont = prtf_simple_array (&buf, &bufsize, is, op[2], DDS_OP_SUBTYPE (*op), DDS_OP_FLAGS (*op));
break; break;
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
abort (); abort ();

View file

@ -25,8 +25,8 @@ static void instance_deadline_missed_cb (struct xevent *xev, void *varg, ddsrt_m
/* Gets the instance from the list in deadline admin that has the earliest missed deadline and /* Gets the instance from the list in deadline admin that has the earliest missed deadline and
* removes the instance element from the list. If no more instances with missed deadline exist * removes the instance element from the list. If no more instances with missed deadline exist
* in the list, the deadline (nn_mtime_t) for the first instance to 'expire' is returned. If the * in the list, the deadline (ddsrt_mtime_t) for the first instance to 'expire' is returned. If
* list is empty, DDSRT_MTIME_NEVER is returned */ * the list is empty, DDSRT_MTIME_NEVER is returned */
ddsrt_mtime_t deadline_next_missed_locked (struct deadline_adm *deadline_adm, ddsrt_mtime_t tnow, void **instance) ddsrt_mtime_t deadline_next_missed_locked (struct deadline_adm *deadline_adm, ddsrt_mtime_t tnow, void **instance)
{ {
struct deadline_elem *elem = NULL; struct deadline_elem *elem = NULL;

View file

@ -70,20 +70,6 @@ static int entity_guid_eq_wrapper (const void *a, const void *b)
return entity_guid_eq (a, b); return entity_guid_eq (a, b);
} }
static int all_entities_compare_isbuiltin (const struct entity_common *e, nn_vendorid_t vendor)
{
const unsigned char *guid_bytes = (const unsigned char *) &e->guid;
if (guid_bytes[0] != 0 && guid_bytes[0] != 0xff)
return is_builtin_endpoint (e->guid.entityid, vendor);
else
{
for (size_t i = 1; i < sizeof (e->guid); i++)
if (guid_bytes[i] != guid_bytes[0])
return is_builtin_endpoint (e->guid.entityid, vendor) && !is_local_orphan_endpoint (e);
return 0;
}
}
static int all_entities_compare (const void *va, const void *vb) static int all_entities_compare (const void *va, const void *vb)
{ {
const struct entity_common *a = va; const struct entity_common *a = va;
@ -104,28 +90,20 @@ static int all_entities_compare (const void *va, const void *vb)
case EK_WRITER: { case EK_WRITER: {
const struct writer *wra = va; const struct writer *wra = va;
const struct writer *wrb = vb; const struct writer *wrb = vb;
if (!all_entities_compare_isbuiltin (a, NN_VENDORID_ECLIPSE)) { assert ((wra->xqos->present & QP_TOPIC_NAME) && wra->xqos->topic_name);
assert ((wra->xqos->present & QP_TOPIC_NAME) && wra->xqos->topic_name); assert ((wrb->xqos->present & QP_TOPIC_NAME) && wrb->xqos->topic_name);
tp_a = wra->xqos->topic_name; tp_a = wra->xqos->topic_name;
} tp_b = wrb->xqos->topic_name;
if (!all_entities_compare_isbuiltin (b, NN_VENDORID_ECLIPSE)) {
assert ((wrb->xqos->present & QP_TOPIC_NAME) && wrb->xqos->topic_name);
tp_b = wrb->xqos->topic_name;
}
break; break;
} }
case EK_READER: { case EK_READER: {
const struct reader *rda = va; const struct reader *rda = va;
const struct reader *rdb = vb; const struct reader *rdb = vb;
if (!all_entities_compare_isbuiltin (a, NN_VENDORID_ECLIPSE)) { assert ((rda->xqos->present & QP_TOPIC_NAME) && rda->xqos->topic_name);
assert ((rda->xqos->present & QP_TOPIC_NAME) && rda->xqos->topic_name); assert ((rdb->xqos->present & QP_TOPIC_NAME) && rdb->xqos->topic_name);
tp_a = rda->xqos->topic_name; tp_a = rda->xqos->topic_name;
} tp_b = rdb->xqos->topic_name;
if (!all_entities_compare_isbuiltin (b, NN_VENDORID_ECLIPSE)) {
assert ((rdb->xqos->present & QP_TOPIC_NAME) && rdb->xqos->topic_name);
tp_b = rdb->xqos->topic_name;
}
break; break;
} }
@ -133,14 +111,11 @@ static int all_entities_compare (const void *va, const void *vb)
case EK_PROXY_READER: { case EK_PROXY_READER: {
const struct generic_proxy_endpoint *ga = va; const struct generic_proxy_endpoint *ga = va;
const struct generic_proxy_endpoint *gb = vb; const struct generic_proxy_endpoint *gb = vb;
if (!all_entities_compare_isbuiltin (a, ga->c.vendor)) { /* built-in reader/writer proxies don't have topic name set */
assert ((ga->c.xqos->present & QP_TOPIC_NAME) && ga->c.xqos->topic_name); if (ga->c.xqos->present & QP_TOPIC_NAME)
tp_a = ga->c.xqos->topic_name; tp_a = ga->c.xqos->topic_name;
} if (gb->c.xqos->present & QP_TOPIC_NAME)
if (!all_entities_compare_isbuiltin (b, gb->c.vendor)) {
assert ((gb->c.xqos->present & QP_TOPIC_NAME) && gb->c.xqos->topic_name);
tp_b = gb->c.xqos->topic_name; tp_b = gb->c.xqos->topic_name;
}
break; break;
} }
} }
@ -439,6 +414,18 @@ void entidx_enum_init_topic (struct entidx_enum *st, const struct entity_index *
st->cur = NULL; st->cur = NULL;
} }
void entidx_enum_init_topic_w_prefix (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind, const char *topic, const ddsi_guid_prefix_t *prefix, struct match_entities_range_key *max)
{
assert (kind == EK_READER || kind == EK_WRITER || kind == EK_PROXY_READER || kind == EK_PROXY_WRITER);
struct match_entities_range_key min;
match_endpoint_range (kind, topic, &min, max);
min.entity.e.guid.prefix = *prefix;
max->entity.e.guid.prefix = *prefix;
entidx_enum_init_minmax_int (st, ei, &min);
if (st->cur && all_entities_compare (st->cur, &max->entity) > 0)
st->cur = NULL;
}
void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind) void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind)
{ {
struct match_entities_range_key min; struct match_entities_range_key min;

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@ static void lifespan_rhc_node_exp (struct xevent *xev, void *varg, ddsrt_mtime_t
/* Gets the sample from the fibheap in lifespan admin that was expired first. If no more /* Gets the sample from the fibheap in lifespan admin that was expired first. If no more
* expired samples exist in the fibheap, the expiry time (nn_mtime_t) for the next sample to * expired samples exist in the fibheap, the expiry time (ddsrt_mtime_t) for the next sample to
* expire is returned. If the fibheap contains no more samples, DDSRT_MTIME_NEVER is returned */ * expire is returned. If the fibheap contains no more samples, DDSRT_MTIME_NEVER is returned */
ddsrt_mtime_t lifespan_next_expired_locked (const struct lifespan_adm *lifespan_adm, ddsrt_mtime_t tnow, void **sample) ddsrt_mtime_t lifespan_next_expired_locked (const struct lifespan_adm *lifespan_adm, ddsrt_mtime_t tnow, void **sample)
{ {

View file

@ -203,7 +203,7 @@ static int joinleave_mcgroups (const struct ddsi_domaingv *gv, ddsi_tran_conn_t
{ {
if (gv->recvips_mode == RECVIPS_MODE_ALL || interface_in_recvips_p (gv->recvips, &gv->interfaces[i])) if (gv->recvips_mode == RECVIPS_MODE_ALL || interface_in_recvips_p (gv->recvips, &gv->interfaces[i]))
{ {
if ((rc = joinleave_mcgroup (conn, join, srcloc, mcloc, &gv->interfaces[i])) < 0) if (joinleave_mcgroup (conn, join, srcloc, mcloc, &gv->interfaces[i]) < 0)
fails++; fails++;
else else
oks++; oks++;

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