Initial contribution

This commit is contained in:
Michiel Beemster 2018-04-10 17:03:59 +02:00
parent 7b5cc4fa59
commit 11d9ce37aa
580 changed files with 155133 additions and 162 deletions

42
src/core/ddsi/.fileids Normal file
View file

@ -0,0 +1,42 @@
# ddsi sources
1 src/ddsi_ser.c
2 src/ddsi_ssl.c
3 src/ddsi_tcp.c
4 src/ddsi_tran.c
5 src/ddsi_udp.c
6 src/q_addrset.c
7 src/q_bitset_inlines.c
8 src/q_bswap.c
9 src/q_bswap_inlines.c
10 src/q_config.c
11 src/q_ddsi_discovery.c
12 src/q_debmon.c
13 src/q_entity.c
14 src/q_ephash.c
15 src/q_gc.c
16 src/q_init.c
17 src/q_lat_estim.c
18 src/q_lease.c
19 src/q_log.c
20 src/q_md5.c
21 src/q_misc.c
22 src/q_nwif.c
23 src/q_pcap.c
24 src/q_plist.c
25 src/q_qosmatch.c
26 src/q_radmin.c
27 src/q_receive.c
28 src/q_security.c
29 src/q_servicelease.c
30 src/q_sockwaitset.c
31 src/q_thread.c
32 src/q_thread_inlines.c
33 src/q_time.c
34 src/q_transmit.c
35 src/q_whc.c
36 src/q_xevent.c
37 src/q_xmsg.c
38 src/q_freelist.c
39 src/sysdeps.c
71 src/q_builtin_topic.c

View file

@ -0,0 +1,120 @@
#
# 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
#
PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_ser.c
ddsi_ssl.c
ddsi_tcp.c
ddsi_tran.c
ddsi_udp.c
q_addrset.c
q_bitset_inlines.c
q_bswap.c
q_bswap_inlines.c
q_builtin_topic.c
q_config.c
q_ddsi_discovery.c
q_debmon.c
q_entity.c
q_ephash.c
q_gc.c
q_init.c
q_lat_estim.c
q_lease.c
q_log.c
q_md5.c
q_misc.c
q_nwif.c
q_pcap.c
q_plist.c
q_qosmatch.c
q_radmin.c
q_receive.c
q_security.c
q_servicelease.c
q_sockwaitset.c
q_thread.c
q_thread_inlines.c
q_time.c
q_transmit.c
q_whc.c
q_xevent.c
q_xmsg.c
q_freelist.c
sysdeps.c
)
# The includes should reside close to the code. As long as that's not the case,
# pull them in from this CMakeLists.txt.
PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/ddsi"
ddsi_ser.h
ddsi_ssl.h
ddsi_tcp.h
ddsi_tran.h
ddsi_udp.h
probes-constants.h
q_addrset.h
q_align.h
q_bitset.h
q_bitset_template.h
q_bswap.h
q_bswap_template.h
q_builtin_topic.h
q_config.h
q_ddsi_discovery.h
q_debmon.h
q_entity.h
q_ephash.h
q_error.h
q_feature_check.h
q_freelist.h
q_gc.h
q_globals.h
q_hbcontrol.h
q_inline.h
q_lat_estim.h
q_lease.h
q_log.h
q_md5.h
q_misc.h
q_nwif.h
q_pcap.h
q_plist.h
q_protocol.h
q_qosmatch.h
q_radmin.h
q_receive.h
q_rtps.h
q_security.h
q_servicelease.h
q_sockwaitset.h
q_static_assert.h
q_thread.h
q_thread_template.h
q_time.h
q_transmit.h
q_unused.h
q_whc.h
q_xevent.h
q_xmsg.h
q_xqos.h
sysdeps.h
)
target_sources(ddsc
PRIVATE
${srcs_ddsi}
${hdrs_private_ddsi}
)
target_include_directories(ddsc
PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/include")

View file

@ -0,0 +1,192 @@
/*
* 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_SER_H
#define DDSI_SER_H
#include "os/os.h"
#include "ddsi/q_plist.h" /* for nn_prismtech_writer_info */
#include "ddsi/q_freelist.h"
#include "util/ut_avl.h"
#include "sysdeps.h"
#include "ddsc/dds.h"
#include "dds__topic.h"
#ifndef PLATFORM_IS_LITTLE_ENDIAN
# if OS_ENDIANNESS == OS_BIG_ENDIAN
# define PLATFORM_IS_LITTLE_ENDIAN 0
# elif OS_ENDIANNESS == OS_LITTLE_ENDIAN
# define PLATFORM_IS_LITTLE_ENDIAN 1
# else
# error "invalid endianness setting"
# endif
#endif /* PLATFORM_IS_LITTLE_ENDIAN */
#if PLATFORM_IS_LITTLE_ENDIAN
#define CDR_BE 0x0000
#define CDR_LE 0x0100
#else
#define CDR_BE 0x0000
#define CDR_LE 0x0001
#endif
typedef struct serstatepool * serstatepool_t;
typedef struct serstate * serstate_t;
typedef struct serdata * serdata_t;
typedef struct sertopic * sertopic_t;
struct CDRHeader
{
unsigned short identifier;
unsigned short options;
};
struct serdata_msginfo
{
unsigned statusinfo;
nn_wctime_t timestamp;
};
enum serstate_kind {
STK_EMPTY,
STK_KEY,
STK_DATA
};
struct serstate
{
serdata_t data;
nn_mtime_t twrite; /* write time, not source timestamp, set post-throttling */
os_atomic_uint32_t refcount;
size_t pos;
size_t size;
const struct sertopic * topic;
enum serstate_kind kind;
serstatepool_t pool;
struct serstate *next; /* in pool->freelist */
};
struct serstatepool
{
struct nn_freelist freelist;
};
#define DDS_KEY_SET 0x0001
#define DDS_KEY_HASH_SET 0x0002
#define DDS_KEY_IS_HASH 0x0004
typedef struct dds_key_hash
{
char m_hash [16]; /* Key hash value. Also possibly key. */
uint32_t m_key_len; /* Length of key (may be in m_hash or m_key_buff) */
uint32_t m_key_buff_size; /* Size of allocated key buffer (m_key_buff) */
char * m_key_buff; /* Key buffer */
uint32_t m_flags; /* State of key/hash (see DDS_KEY_XXX) */
}
dds_key_hash_t;
struct serdata_base
{
serstate_t st; /* back pointer to (opaque) serstate so RTPS impl only needs serdata */
struct serdata_msginfo msginfo;
int hash_valid; /* whether hash is valid or must be computed from key/data */
uint32_t hash; /* cached serdata hash, valid only if hash_valid != 0 */
dds_key_hash_t keyhash;
bool bswap; /* Whether state is native endian or requires swapping */
};
struct serdata
{
struct serdata_base v;
/* padding to ensure CDRHeader is at an offset 4 mod 8 from the
start of the memory, so that data is 8-byte aligned provided
serdata is 8-byte aligned */
char pad[8 - ((sizeof (struct serdata_base) + 4) % 8)];
struct CDRHeader hdr;
char data[1];
};
struct dds_key_descriptor;
struct dds_topic;
typedef void (*topic_cb_t) (struct dds_topic * topic);
#ifndef DDS_TOPIC_INTERN_FILTER_FN_DEFINED
#define DDS_TOPIC_INTERN_FILTER_FN_DEFINED
typedef bool (*dds_topic_intern_filter_fn) (const void * sample, void *ctx);
#endif
struct sertopic
{
ut_avlNode_t avlnode;
char * name_typename;
char * name;
char * typename;
void * type;
unsigned nkeys;
uint32_t id;
uint32_t hash;
uint32_t flags;
size_t opt_size;
os_atomic_uint32_t refcount;
topic_cb_t status_cb;
dds_topic_intern_filter_fn filter_fn;
void * filter_sample;
void * filter_ctx;
struct dds_topic * status_cb_entity;
const struct dds_key_descriptor * keys;
/*
Array of keys, represented as offset in the OpenSplice internal
format data blob. Keys must be stored in the order visited by
serializer (so that the serializer can simply compare the current
offset with the next key offset). Also: keys[nkeys].off =def=
~0u, which won't equal any real offset so that there is no need
to test for the end of the array.
Offsets work 'cos only primitive types, enums and strings are
accepted as keys. So there is no ambiguity if a key happens to
be inside a nested struct.
*/
};
serstatepool_t ddsi_serstatepool_new (void);
void ddsi_serstatepool_free (serstatepool_t pool);
serdata_t ddsi_serdata_ref (serdata_t serdata);
OSAPI_EXPORT void ddsi_serdata_unref (serdata_t serdata);
int ddsi_serdata_refcount_is_1 (serdata_t serdata);
nn_mtime_t ddsi_serdata_twrite (const struct serdata * serdata);
void ddsi_serdata_set_twrite (struct serdata * serdata, nn_mtime_t twrite);
uint32_t ddsi_serdata_size (const struct serdata * serdata);
int ddsi_serdata_is_key (const struct serdata * serdata);
int ddsi_serdata_is_empty (const struct serdata * serdata);
OSAPI_EXPORT void ddsi_serstate_append_blob (serstate_t st, size_t align, size_t sz, const void *data);
OSAPI_EXPORT void ddsi_serstate_set_msginfo
(
serstate_t st, unsigned statusinfo, nn_wctime_t timestamp,
void * dummy
);
OSAPI_EXPORT serstate_t ddsi_serstate_new (serstatepool_t pool, const struct sertopic * topic);
OSAPI_EXPORT serdata_t ddsi_serstate_fix (serstate_t st);
nn_mtime_t ddsi_serstate_twrite (const struct serstate *serstate);
void ddsi_serstate_set_twrite (struct serstate *serstate, nn_mtime_t twrite);
void ddsi_serstate_release (serstate_t st);
void * ddsi_serstate_append (serstate_t st, size_t n);
void * ddsi_serstate_append_align (serstate_t st, size_t a);
void * ddsi_serstate_append_aligned (serstate_t st, size_t n, size_t a);
#endif

View file

@ -0,0 +1,28 @@
/*
* 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_SSL_H_
#define _DDSI_SSL_H_
#ifdef DDSI_INCLUDE_SSL
#ifdef _WIN32
/* WinSock2 must be included before openssl headers
otherwise winsock will be used */
#include <WinSock2.h>
#endif
#include <openssl/ssl.h>
void ddsi_ssl_plugin (void);
#endif
#endif

View file

@ -0,0 +1,41 @@
/*
* 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_TCP_H_
#define _DDSI_TCP_H_
#include "ddsi/ddsi_tran.h"
#ifdef DDSI_INCLUDE_SSL
#include "ddsi/ddsi_ssl.h"
struct ddsi_ssl_plugins
{
void (*config) (void);
c_bool (*init) (void);
void (*fini) (void);
void (*ssl_free) (SSL * ssl);
void (*bio_vfree) (BIO * bio);
os_ssize_t (*read) (SSL * ssl, void * buf, os_size_t len, int * err);
os_ssize_t (*write) (SSL * ssl, const void * msg, os_size_t len, int * err);
SSL * (*connect) (os_socket sock);
BIO * (*listen) (os_socket sock);
SSL * (*accept) (BIO * bio, os_socket * sock);
};
struct ddsi_ssl_plugins ddsi_tcp_ssl_plugin;
#endif
int ddsi_tcp_init (void);
#endif

View file

@ -0,0 +1,191 @@
/*
* 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_TRAN_H_
#define _DDSI_TRAN_H_
/* DDSI Transport module */
#include "ddsi/q_globals.h"
#include "ddsi/q_protocol.h"
/* Types supporting handles */
#define DDSI_TRAN_CONN 1
#define DDSI_TRAN_LISTENER 2
/* Flags */
#define DDSI_TRAN_ON_CONNECT 0x0001
/* Core types */
typedef struct ddsi_tran_base * ddsi_tran_base_t;
typedef struct ddsi_tran_conn * ddsi_tran_conn_t;
typedef struct ddsi_tran_listener * ddsi_tran_listener_t;
typedef struct ddsi_tran_factory * ddsi_tran_factory_t;
typedef struct ddsi_tran_qos * ddsi_tran_qos_t;
/* Function pointer types */
typedef ssize_t (*ddsi_tran_read_fn_t) (ddsi_tran_conn_t , unsigned char *, size_t);
typedef ssize_t (*ddsi_tran_write_fn_t) (ddsi_tran_conn_t, const struct msghdr *, size_t, uint32_t);
typedef int (*ddsi_tran_locator_fn_t) (ddsi_tran_base_t, nn_locator_t *);
typedef bool (*ddsi_tran_supports_fn_t) (int32_t);
typedef os_handle (*ddsi_tran_handle_fn_t) (ddsi_tran_base_t);
typedef int (*ddsi_tran_listen_fn_t) (ddsi_tran_listener_t);
typedef void (*ddsi_tran_free_fn_t) (void);
typedef void (*ddsi_tran_peer_locator_fn_t) (ddsi_tran_conn_t, nn_locator_t *);
typedef ddsi_tran_conn_t (*ddsi_tran_accept_fn_t) (ddsi_tran_listener_t);
typedef ddsi_tran_conn_t (*ddsi_tran_create_conn_fn_t) (uint32_t, ddsi_tran_qos_t);
typedef ddsi_tran_listener_t (*ddsi_tran_create_listener_fn_t) (int port, ddsi_tran_qos_t);
typedef void (*ddsi_tran_release_conn_fn_t) (ddsi_tran_conn_t);
typedef void (*ddsi_tran_close_conn_fn_t) (ddsi_tran_conn_t);
typedef void (*ddsi_tran_unblock_listener_fn_t) (ddsi_tran_listener_t);
typedef void (*ddsi_tran_release_listener_fn_t) (ddsi_tran_listener_t);
typedef int (*ddsi_tran_join_mc_fn_t) (ddsi_tran_conn_t, const nn_locator_t *srcip, const nn_locator_t *mcip);
typedef int (*ddsi_tran_leave_mc_fn_t) (ddsi_tran_conn_t, const nn_locator_t *srcip, const nn_locator_t *mcip);
/* Data types */
struct ddsi_tran_base
{
/* Data */
uint32_t m_port;
uint32_t m_trantype;
bool m_multicast;
/* Functions */
ddsi_tran_locator_fn_t m_locator_fn;
ddsi_tran_handle_fn_t m_handle_fn;
};
struct ddsi_tran_conn
{
struct ddsi_tran_base m_base;
/* Functions */
ddsi_tran_read_fn_t m_read_fn;
ddsi_tran_write_fn_t m_write_fn;
ddsi_tran_peer_locator_fn_t m_peer_locator_fn;
/* Data */
bool m_server;
bool m_connless;
bool m_stream;
bool m_closed;
os_atomic_uint32_t m_count;
/* Relationships */
ddsi_tran_factory_t m_factory;
ddsi_tran_listener_t m_listener;
ddsi_tran_conn_t m_conn;
};
struct ddsi_tran_listener
{
struct ddsi_tran_base m_base;
/* Functions */
ddsi_tran_listen_fn_t m_listen_fn;
ddsi_tran_accept_fn_t m_accept_fn;
/* Relationships */
ddsi_tran_conn_t m_connections;
ddsi_tran_factory_t m_factory;
ddsi_tran_listener_t m_listener;
};
struct ddsi_tran_factory
{
/* Functions */
ddsi_tran_create_conn_fn_t m_create_conn_fn;
ddsi_tran_create_listener_fn_t m_create_listener_fn;
ddsi_tran_release_conn_fn_t m_release_conn_fn;
ddsi_tran_close_conn_fn_t m_close_conn_fn;
ddsi_tran_unblock_listener_fn_t m_unblock_listener_fn;
ddsi_tran_release_listener_fn_t m_release_listener_fn;
ddsi_tran_supports_fn_t m_supports_fn;
ddsi_tran_free_fn_t m_free_fn;
ddsi_tran_join_mc_fn_t m_join_mc_fn;
ddsi_tran_leave_mc_fn_t m_leave_mc_fn;
/* Data */
int32_t m_kind;
const char * m_typename;
bool m_connless;
bool m_stream;
/* Relationships */
ddsi_tran_factory_t m_factory;
};
struct ddsi_tran_qos
{
/* QoS Data */
bool m_multicast;
int m_diffserv;
};
/* Functions and pseudo functions (macro wrappers) */
#define ddsi_tran_type(b) (((ddsi_tran_base_t) (b))->m_trantype)
#define ddsi_tran_port(b) (((ddsi_tran_base_t) (b))->m_port)
int ddsi_tran_locator (ddsi_tran_base_t base, nn_locator_t * loc);
void ddsi_tran_free (ddsi_tran_base_t base);
void ddsi_tran_free_qos (ddsi_tran_qos_t qos);
ddsi_tran_qos_t ddsi_tran_create_qos (void);
os_handle ddsi_tran_handle (ddsi_tran_base_t base);
#define ddsi_factory_create_listener(f,p,q) (((f)->m_create_listener_fn) ((p), (q)))
#define ddsi_factory_supports(f,k) (((f)->m_supports_fn) (k))
ddsi_tran_conn_t ddsi_factory_create_conn
(
ddsi_tran_factory_t factory,
uint32_t port,
ddsi_tran_qos_t qos
);
void ddsi_tran_factories_fini (void);
void ddsi_factory_add (ddsi_tran_factory_t factory);
void ddsi_factory_free (ddsi_tran_factory_t factory);
ddsi_tran_factory_t ddsi_factory_find (const char * type);
void ddsi_factory_conn_init (ddsi_tran_factory_t factory, ddsi_tran_conn_t conn);
#define ddsi_conn_handle(c) (ddsi_tran_handle (&(c)->m_base))
#define ddsi_conn_locator(c,l) (ddsi_tran_locator (&(c)->m_base,(l)))
OSAPI_EXPORT ssize_t ddsi_conn_write (ddsi_tran_conn_t conn, const struct msghdr * msg, size_t len, uint32_t flags);
ssize_t ddsi_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len);
bool ddsi_conn_peer_locator (ddsi_tran_conn_t conn, nn_locator_t * loc);
void ddsi_conn_add_ref (ddsi_tran_conn_t conn);
void ddsi_conn_free (ddsi_tran_conn_t conn);
int ddsi_conn_join_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcip, const nn_locator_t *mcip);
int ddsi_conn_leave_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcip, const nn_locator_t *mcip);
#define ddsi_listener_locator(s,l) (ddsi_tran_locator (&(s)->m_base,(l)))
ddsi_tran_conn_t ddsi_listener_accept (ddsi_tran_listener_t listener);
int ddsi_listener_listen (ddsi_tran_listener_t listener);
void ddsi_listener_unblock (ddsi_tran_listener_t listener);
void ddsi_listener_free (ddsi_tran_listener_t listener);
#endif

View file

@ -0,0 +1,17 @@
/*
* 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_UDP_H_
#define _DDSI_UDP_H_
int ddsi_udp_init (void);
#endif

View file

@ -0,0 +1,18 @@
/*
* 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 PROBES_CONSTANTS_H
#define PROBES_CONSTANTS_H
#define DROP_QUEUE_FULL 1
#define DROP_TOO_OLD 2
#define DROP_REORDER_FULL 3
#define DROP_DUPLICATE 4
#endif

View file

@ -0,0 +1,92 @@
/*
* 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 NN_ADDRSET_H
#define NN_ADDRSET_H
#include "os/os.h"
#include "util/ut_avl.h"
#include "ddsi/q_log.h"
#include "ddsi/q_protocol.h"
#include "ddsi/q_feature_check.h"
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct addrset_node {
ut_avlNode_t avlnode;
nn_locator_t loc;
} * addrset_node_t;
struct addrset {
os_mutex lock;
os_atomic_uint32_t refc;
ut_avlCTree_t ucaddrs, mcaddrs;
};
typedef void (*addrset_forall_fun_t) (const nn_locator_t *loc, void *arg);
typedef ssize_t (*addrset_forone_fun_t) (const nn_locator_t *loc, void *arg);
struct addrset *new_addrset (void);
struct addrset *ref_addrset (struct addrset *as);
void unref_addrset (struct addrset *as);
void add_to_addrset (struct addrset *as, const nn_locator_t *loc);
void remove_from_addrset (struct addrset *as, const nn_locator_t *loc);
int addrset_purge (struct addrset *as);
int compare_locators (const nn_locator_t *a, const nn_locator_t *b);
/* These lock ASADD, then lock/unlock AS any number of times, then
unlock ASADD */
void copy_addrset_into_addrset_uc (struct addrset *as, const struct addrset *asadd);
void copy_addrset_into_addrset_mc (struct addrset *as, const struct addrset *asadd);
void copy_addrset_into_addrset (struct addrset *as, const struct addrset *asadd);
size_t addrset_count (const struct addrset *as);
size_t addrset_count_uc (const struct addrset *as);
size_t addrset_count_mc (const struct addrset *as);
int addrset_empty_uc (const struct addrset *as);
int addrset_empty_mc (const struct addrset *as);
int addrset_empty (const struct addrset *as);
int addrset_any_uc (const struct addrset *as, nn_locator_t *dst);
int addrset_any_mc (const struct addrset *as, nn_locator_t *dst);
/* Keeps AS locked */
int addrset_forone (struct addrset *as, addrset_forone_fun_t f, void *arg);
void addrset_forall (struct addrset *as, addrset_forall_fun_t f, void *arg);
size_t addrset_forall_count (struct addrset *as, addrset_forall_fun_t f, void *arg);
void nn_log_addrset (logcat_t tf, const char *prefix, const struct addrset *as);
/* Tries to lock A then B for a decent check, returning false if
trylock B fails */
int addrset_eq_onesidederr (const struct addrset *a, const struct addrset *b);
int is_mcaddr (const nn_locator_t *loc);
int is_unspec_locator (const nn_locator_t *loc);
void set_unspec_locator (nn_locator_t *loc);
int add_addresses_to_addrset (struct addrset *as, const char *addrs, int port_mode, const char *msgtag, int req_mc);
#ifdef DDSI_INCLUDE_SSM
int is_ssm_mcaddr (const nn_locator_t *loc);
int addrset_contains_ssm (const struct addrset *as);
int addrset_any_ssm (const struct addrset *as, nn_locator_t *dst);
int addrset_any_non_ssm_mc (const struct addrset *as, nn_locator_t *dst);
void copy_addrset_into_addrset_no_ssm_mc (struct addrset *as, const struct addrset *asadd);
void copy_addrset_into_addrset_no_ssm (struct addrset *as, const struct addrset *asadd);
void addrset_pruge_ssm (struct addrset *as);
#endif
#if defined (__cplusplus)
}
#endif
#endif /* NN_ADDRSET_H */

View file

@ -0,0 +1,18 @@
/*
* 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 NN_ALIGN_H
#define NN_ALIGN_H
#define ALIGN4(x) (((x) + 3) & -4u)
#define ALIGN8(x) (((x) + 7) & -8u)
#endif /* NN_ALIGN_H */

View file

@ -0,0 +1,36 @@
/*
* 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 NN_BITSET_H
#define NN_BITSET_H
#include <assert.h>
#include <string.h>
#include "ddsi/q_inline.h"
#if NN_HAVE_C99_INLINE && !defined SUPPRESS_BITSET_INLINES
#include "q_bitset_template.h"
#else
#if defined (__cplusplus)
extern "C" {
#endif
int nn_bitset_isset (unsigned numbits, const unsigned *bits, unsigned idx);
void nn_bitset_set (unsigned numbits, unsigned *bits, unsigned idx);
void nn_bitset_clear (unsigned numbits, unsigned *bits, unsigned idx);
void nn_bitset_zero (unsigned numbits, unsigned *bits);
void nn_bitset_one (unsigned numbits, unsigned *bits);
#if defined (__cplusplus)
}
#endif
#endif
#endif /* NN_BITSET_H */

View file

@ -0,0 +1,53 @@
/*
* 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
*/
/* -*- c -*- */
#include "ddsi/q_unused.h"
#if defined SUPPRESS_BITSET_INLINES && defined NN_C99_INLINE
#undef NN_C99_INLINE
#define NN_C99_INLINE
#endif
NN_C99_INLINE int nn_bitset_isset (unsigned numbits, const unsigned *bits, unsigned idx)
{
return idx < numbits && (bits[idx/32] & (1u << (31 - (idx%32))));
}
NN_C99_INLINE void nn_bitset_set (UNUSED_ARG_NDEBUG (unsigned numbits), unsigned *bits, unsigned idx)
{
assert (idx < numbits);
bits[idx/32] |= 1u << (31 - (idx%32));
}
NN_C99_INLINE void nn_bitset_clear (UNUSED_ARG_NDEBUG (unsigned numbits), unsigned *bits, unsigned idx)
{
assert (idx < numbits);
bits[idx/32] &= ~(1u << (31 - (idx%32)));
}
NN_C99_INLINE void nn_bitset_zero (unsigned numbits, unsigned *bits)
{
memset (bits, 0, 4 * ((numbits + 31) / 32));
}
NN_C99_INLINE void nn_bitset_one (unsigned numbits, unsigned *bits)
{
memset (bits, 0xff, 4 * ((numbits + 31) / 32));
/* clear bits "accidentally" set */
{
const unsigned k = numbits / 32;
const unsigned n = numbits % 32;
bits[k] &= ~(~0u >> n);
}
}

View file

@ -0,0 +1,87 @@
/*
* 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 NN_BSWAP_H
#define NN_BSWAP_H
#include "os/os.h"
#include "ddsi/q_inline.h"
#include "ddsi/q_rtps.h" /* for nn_guid_t, nn_guid_prefix_t */
#include "ddsi/q_protocol.h" /* for nn_sequence_number_t */
#define bswap2(x) ((short) bswap2u ((unsigned short) (x)))
#define bswap4(x) ((int) bswap4u ((unsigned) (x)))
#define bswap8(x) ((long long) bswap8u ((unsigned long long) (x)))
#if NN_HAVE_C99_INLINE && !defined SUPPRESS_BSWAP_INLINES
#include "q_bswap_template.h"
#else
#if defined (__cplusplus)
extern "C" {
#endif
unsigned short bswap2u (unsigned short x);
unsigned bswap4u (unsigned x);
unsigned long long bswap8u (unsigned long long x);
void bswapSN (nn_sequence_number_t *sn);
#if defined (__cplusplus)
}
#endif
#endif
#if OS_ENDIANNESS == OS_LITTLE_ENDIAN
#define toBE2(x) bswap2 (x)
#define toBE2u(x) bswap2u (x)
#define toBE4(x) bswap4 (x)
#define toBE4u(x) bswap4u (x)
#define toBE8(x) bswap8 (x)
#define toBE8u(x) bswap8u (x)
#define fromBE2(x) bswap2 (x)
#define fromBE2u(x) bswap2u (x)
#define fromBE4(x) bswap4 (x)
#define fromBE4u(x) bswap4u (x)
#define fromBE8(x) bswap8 (x)
#define fromBE8u(x) bswap8u (x)
#else
#define toBE2u(x) (x)
#define toBE4(x) (x)
#define toBE4u(x) (x)
#define toBE8(x) (x)
#define toBE8u(x) (x)
#define fromBE2(x) (x)
#define fromBE2u(x) (x)
#define fromBE4(x) (x)
#define fromBE4u(x) (x)
#define fromBE8(x) (x)
#define fromBE8u(x) (x)
#endif
#if defined (__cplusplus)
extern "C" {
#endif
nn_guid_prefix_t nn_hton_guid_prefix (nn_guid_prefix_t p);
nn_guid_prefix_t nn_ntoh_guid_prefix (nn_guid_prefix_t p);
nn_entityid_t nn_hton_entityid (nn_entityid_t e);
nn_entityid_t nn_ntoh_entityid (nn_entityid_t e);
nn_guid_t nn_hton_guid (nn_guid_t g);
nn_guid_t nn_ntoh_guid (nn_guid_t g);
void bswap_sequence_number_set_hdr (nn_sequence_number_set_t *snset);
void bswap_sequence_number_set_bitmap (nn_sequence_number_set_t *snset);
void bswap_fragment_number_set_hdr (nn_fragment_number_set_t *fnset);
void bswap_fragment_number_set_bitmap (nn_fragment_number_set_t *fnset);
#if defined (__cplusplus)
}
#endif
#endif /* NN_BSWAP_H */

View file

@ -0,0 +1,41 @@
/*
* 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
*/
/* -*- c -*- */
#if defined SUPPRESS_BSWAP_INLINES && defined VDDS_INLINE
#undef VDDS_INLINE
#define VDDS_INLINE
#endif
VDDS_INLINE unsigned short bswap2u (unsigned short x)
{
return (unsigned short) ((x >> 8) | (x << 8));
}
VDDS_INLINE unsigned bswap4u (unsigned x)
{
return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24);
}
VDDS_INLINE unsigned long long bswap8u (unsigned long long x)
{
const unsigned newhi = bswap4u ((unsigned) x);
const unsigned newlo = bswap4u ((unsigned) (x >> 32));
return ((unsigned long long) newhi << 32) | (unsigned long long) newlo;
}
VDDS_INLINE void bswapSN (nn_sequence_number_t *sn)
{
sn->high = bswap4 (sn->high);
sn->low = bswap4u (sn->low);
}

View file

@ -0,0 +1,75 @@
/*
* 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 Q_BUILTIN_TOPIC_H
#define Q_BUILTIN_TOPIC_H
#include "ddsi/q_time.h"
#include "dds_builtinTopics.h"
struct entity_common;
struct nn_plist;
/* Functions called at proxy entity creation/deletion time, so they
can do whatever is necessary to get the builtin topics function
correctly.
These probably should return an error code, but I don't quite know
how to handle it yet and this way we have Coverity on our side.
Implementation is outside the common core.
These may assume the proxy entities are stable, without parallel QoS
changes. */
void
propagate_builtin_topic_participant(
_In_ const struct entity_common *proxypp,
_In_ const nn_plist_t *plist,
_In_ nn_wctime_t timestamp,
_In_ int alive);
void
propagate_builtin_topic_cmparticipant(
_In_ const struct entity_common *proxypp,
_In_ const nn_plist_t *plist,
_In_ nn_wctime_t timestamp,
_In_ int alive);
#if 0
void dispose_builtin_topic_proxy_participant (const struct proxy_participant *proxypp, nn_wctime_t timestamp, int isimplicit);
void write_builtin_topic_proxy_writer (const struct proxy_writer *pwr, nn_wctime_t timestamp);
void dispose_builtin_topic_proxy_writer (const struct proxy_writer *pwr, nn_wctime_t timestamp, int isimplicit);
void write_builtin_topic_proxy_reader (const struct proxy_reader *prd, nn_wctime_t timestamp);
void dispose_builtin_topic_proxy_reader (const struct proxy_reader *prd, nn_wctime_t timestamp, int isimplicit);
void write_builtin_topic_proxy_group (const struct proxy_group *pgroup, nn_wctime_t timestamp);
void dispose_builtin_topic_proxy_group (const struct proxy_group *pgroup, nn_wctime_t timestamp, int isimplicit);
void write_builtin_topic_proxy_topic (const struct nn_plist *datap, nn_wctime_t timestamp);
#endif
/*
* Let the layer on top of DDSI handle the received builtin data when it wants to.
*/
extern void
forward_builtin_participant(
_In_ DDS_ParticipantBuiltinTopicData *data,
_In_ nn_wctime_t timestamp,
_In_ int alive);
extern void
forward_builtin_cmparticipant(
_In_ DDS_CMParticipantBuiltinTopicData *data,
_In_ nn_wctime_t timestamp,
_In_ int alive);
#endif

View file

@ -0,0 +1,446 @@
/*
* 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 NN_CONFIG_H
#define NN_CONFIG_H
#include "os/os.h"
#include "ddsi/q_log.h"
#include "ddsi/q_thread.h"
#ifdef DDSI_INCLUDE_ENCRYPTION
#include "ddsi/q_security.h"
#endif /* DDSI_INCLUDE_ENCRYPTION */
#include "ddsi/q_xqos.h"
#include "ddsi/ddsi_tran.h"
#include "ddsi/q_feature_check.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* FIXME: should eventually move to abstraction layer */
typedef enum q__schedPrioClass {
Q__SCHED_PRIO_RELATIVE,
Q__SCHED_PRIO_ABSOLUTE
} q__schedPrioClass;
enum nn_standards_conformance {
NN_SC_PEDANTIC,
NN_SC_STRICT,
NN_SC_LAX
};
#define NN_PEDANTIC_P (config.standards_conformance <= NN_SC_PEDANTIC)
#define NN_STRICT_P (config.standards_conformance <= NN_SC_STRICT)
enum besmode {
BESMODE_FULL,
BESMODE_WRITERS,
BESMODE_MINIMAL
};
enum retransmit_merging {
REXMIT_MERGE_NEVER,
REXMIT_MERGE_ADAPTIVE,
REXMIT_MERGE_ALWAYS
};
enum boolean_default {
BOOLDEF_DEFAULT,
BOOLDEF_FALSE,
BOOLDEF_TRUE
};
enum durability_cdr
{
DUR_CDR_LE,
DUR_CDR_BE,
DUR_CDR_SERVER,
DUR_CDR_CLIENT
};
#define PARTICIPANT_INDEX_AUTO -1
#define PARTICIPANT_INDEX_NONE -2
/* config_listelem must be an overlay for all used listelem types */
struct config_listelem {
struct config_listelem *next;
};
#ifdef DDSI_INCLUDE_ENCRYPTION
struct q_security_plugins
{
c_bool (*encode) (q_securityEncoderSet, uint32_t, void *, uint32_t, uint32_t *);
c_bool (*decode) (q_securityDecoderSet, void *, size_t, size_t *);
q_securityEncoderSet (*new_encoder) (void);
q_securityDecoderSet (*new_decoder) (void);
c_bool (*free_encoder) (q_securityEncoderSet);
c_bool (*free_decoder) (q_securityDecoderSet);
ssize_t (*send_encoded) (ddsi_tran_conn_t, struct msghdr *, q_securityEncoderSet *, uint32_t, uint32_t);
char * (*cipher_type) (q_cipherType);
c_bool (*cipher_type_from_string) (const char *, q_cipherType *);
uint32_t (*header_size) (q_securityEncoderSet, uint32_t);
q_cipherType (*encoder_type) (q_securityEncoderSet, uint32_t);
c_bool (*valid_uri) (q_cipherType, const char *);
};
struct q_security_plugins q_security_plugin;
struct config_securityprofile_listelem
{
struct config_securityprofile_listelem *next;
char *name;
q_cipherType cipher;
char *key;
};
#endif /* DDSI_INCLUDE_ENCRYPTION */
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
struct config_networkpartition_listelem {
struct config_networkpartition_listelem *next;
char *name;
char *address_string;
struct addrset *as;
int connected;
#ifdef DDSI_INCLUDE_ENCRYPTION
char *profileName;
struct config_securityprofile_listelem *securityProfile;
#endif /* DDSI_INCLUDE_ENCRYPTION */
uint32_t partitionHash;
uint32_t partitionId;
};
struct config_ignoredpartition_listelem {
struct config_ignoredpartition_listelem *next;
char *DCPSPartitionTopic;
};
struct config_partitionmapping_listelem {
struct config_partitionmapping_listelem *next;
char *networkPartition;
char *DCPSPartitionTopic;
struct config_networkpartition_listelem *partition;
};
#endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
struct config_channel_listelem {
struct config_channel_listelem *next;
char *name;
int priority;
int64_t resolution;
#ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING
uint32_t data_bandwidth_limit;
uint32_t auxiliary_bandwidth_limit;
#endif
int diffserv_field;
struct thread_state1 *channel_reader_ts; /* keeping an handle to the running thread for this channel */
struct nn_dqueue *dqueue; /* The handle of teh delivery queue servicing incoming data for this channel*/
struct xeventq *evq; /* The handle of the event queue servicing this channel*/
uint32_t queueId; /* the index of the networkqueue serviced by this channel*/
struct ddsi_tran_conn * transmit_conn; /* the connection used for sending data out via this channel */
};
#endif /* DDSI_INCLUDE_NETWORK_CHANNELS */
struct config_maybe_int32 {
int isdefault;
int32_t value;
};
struct config_maybe_uint32 {
int isdefault;
uint32_t value;
};
struct config_maybe_int64 {
int isdefault;
int64_t value;
};
struct config_thread_properties_listelem {
struct config_thread_properties_listelem *next;
char *name;
os_schedClass sched_class;
struct config_maybe_int32 sched_priority;
struct config_maybe_uint32 stack_size;
};
struct config_peer_listelem
{
struct config_peer_listelem *next;
char *peer;
};
struct prune_deleted_ppant {
int64_t delay;
int enforce_delay;
};
/* allow multicast bits: */
#define AMC_FALSE 0u
#define AMC_SPDP 1u
#define AMC_ASM 2u
#ifdef DDSI_INCLUDE_SSM
#define AMC_SSM 4u
#define AMC_TRUE (AMC_SPDP | AMC_ASM | AMC_SSM)
#else
#define AMC_TRUE (AMC_SPDP | AMC_ASM)
#endif
struct config
{
int valid;
logcat_t enabled_logcats;
char *servicename;
char *pcap_file;
char *networkAddressString;
char **networkRecvAddressStrings;
char *externalAddressString;
char *externalMaskString;
FILE *tracingOutputFile;
char *tracingOutputFileName;
int tracingTimestamps;
int tracingRelativeTimestamps;
int tracingAppendToFile;
unsigned allowMulticast;
int useIpv6;
int dontRoute;
int enableMulticastLoopback;
int domainId;
int participantIndex;
int maxAutoParticipantIndex;
int port_base;
struct config_maybe_int32 discoveryDomainId;
char *spdpMulticastAddressString;
char *defaultMulticastAddressString;
char *assumeMulticastCapable;
int64_t spdp_interval;
int64_t spdp_response_delay_max;
int64_t startup_mode_duration;
int64_t lease_duration;
int64_t const_hb_intv_sched;
int64_t const_hb_intv_sched_min;
int64_t const_hb_intv_sched_max;
int64_t const_hb_intv_min;
enum retransmit_merging retransmit_merging;
int64_t retransmit_merging_period;
int squash_participants;
int startup_mode_full;
int forward_all_messages;
int noprogress_log_stacktraces;
int prioritize_retransmit;
int xpack_send_async;
unsigned primary_reorder_maxsamples;
unsigned secondary_reorder_maxsamples;
unsigned delivery_queue_maxsamples;
float servicelease_expiry_time;
float servicelease_update_factor;
int enableLoopback;
enum durability_cdr durability_cdr;
int buggy_datafrag_flags_mode;
int do_topic_discovery;
uint32_t max_msg_size;
uint32_t fragment_size;
int publish_uc_locators; /* Publish discovery unicast locators */
/* TCP transport configuration */
int tcp_enable;
int tcp_nodelay;
int tcp_port;
int64_t tcp_read_timeout;
int64_t tcp_write_timeout;
#ifdef DDSI_INCLUDE_SSL
/* SSL support for TCP */
int ssl_enable;
int ssl_verify;
int ssl_verify_client;
int ssl_self_signed;
char * ssl_keystore;
char * ssl_rand_file;
char * ssl_key_pass;
char * ssl_ciphers;
#endif
/* Thread pool configuration */
int tp_enable;
uint32_t tp_threads;
uint32_t tp_max_threads;
int advertise_builtin_topic_writers;
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
struct config_channel_listelem *channels;
struct config_channel_listelem *max_channel; /* channel with highest prio; always computed */
#endif /* DDSI_INCLUDE_NETWORK_CHANNELS */
#ifdef DDSI_INCLUDE_ENCRYPTION
struct config_securityprofile_listelem *securityProfiles;
#endif /* DDSI_INCLUDE_ENCRYPTION */
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
struct config_networkpartition_listelem *networkPartitions;
unsigned nof_networkPartitions;
struct config_ignoredpartition_listelem *ignoredPartitions;
struct config_partitionmapping_listelem *partitionMappings;
#endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */
struct config_peer_listelem *peers;
struct config_peer_listelem *peers_group;
struct config_thread_properties_listelem *thread_properties;
/* debug/test/undoc features: */
int xmit_lossiness; /**<< fraction of packets to drop on xmit, in units of 1e-3 */
uint32_t rmsg_chunk_size; /**<< size of a chunk in the receive buffer */
uint32_t rbuf_size; /* << size of a single receiver buffer */
enum besmode besmode;
int aggressive_keep_last_whc;
int conservative_builtin_reader_startup;
int meas_hb_to_ack_latency;
int suppress_spdp_multicast;
int unicast_response_to_spdp_messages;
int synchronous_delivery_priority_threshold;
int64_t synchronous_delivery_latency_bound;
/* Write cache */
int whc_batch;
uint32_t whc_lowwater_mark;
uint32_t whc_highwater_mark;
struct config_maybe_uint32 whc_init_highwater_mark;
int whc_adaptive;
unsigned defrag_unreliable_maxsamples;
unsigned defrag_reliable_maxsamples;
unsigned accelerate_rexmit_block_size;
int64_t responsiveness_timeout;
uint32_t max_participants;
int64_t writer_linger_duration;
int multicast_ttl;
struct config_maybe_uint32 socket_min_rcvbuf_size;
uint32_t socket_min_sndbuf_size;
int64_t nack_delay;
int64_t preemptive_ack_delay;
int64_t schedule_time_rounding;
int64_t auto_resched_nack_delay;
int64_t ds_grace_period;
#ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING
uint32_t auxiliary_bandwidth_limit; /* bytes/second */
#endif
uint32_t max_queued_rexmit_bytes;
unsigned max_queued_rexmit_msgs;
unsigned ddsi2direct_max_threads;
int late_ack_mode;
int retry_on_reject_besteffort;
int generate_keyhash;
uint32_t max_sample_size;
/* compability options */
enum nn_standards_conformance standards_conformance;
int explicitly_publish_qos_set_to_default;
int many_sockets_mode;
int arrival_of_data_asserts_pp_and_ep_liveliness;
int acknack_numbits_emptyset;
int respond_to_rti_init_zero_ack_with_invalid_heartbeat;
int assume_rti_has_pmd_endpoints;
int port_dg;
int port_pg;
int port_d0;
int port_d1;
int port_d2;
int port_d3;
int monitor_port;
int enable_control_topic;
int initial_deaf;
int initial_mute;
int64_t initial_deaf_mute_reset;
int use_multicast_if_mreqn;
struct prune_deleted_ppant prune_deleted_ppant;
/* not used by ddsi2, only validated; user layer directly accesses
the configuration tree */
os_schedClass watchdog_sched_class;
int32_t watchdog_sched_priority;
q__schedPrioClass watchdog_sched_priority_class;
};
struct rhc;
struct nn_xqos;
struct tkmap_instance;
struct nn_rsample_info;
struct serdata;
struct sertopic;
struct proxy_writer;
struct proxy_writer_info;
struct ddsi_plugin
{
int (*init_fn) (void);
void (*fini_fn) (void);
/* Read cache */
void (*rhc_free_fn) (struct rhc *rhc);
void (*rhc_fini_fn) (struct rhc *rhc);
bool (*rhc_store_fn)
(struct rhc * __restrict rhc, const struct nn_rsample_info * __restrict sampleinfo,
struct serdata * __restrict sample, struct tkmap_instance * __restrict tk);
void (*rhc_unregister_wr_fn)
(struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
void (*rhc_relinquish_ownership_fn)
(struct rhc * __restrict rhc, const uint64_t wr_iid);
void (*rhc_set_qos_fn) (struct rhc * rhc, const struct nn_xqos * qos);
struct tkmap_instance * (*rhc_lookup_fn) (struct serdata *serdata);
void (*rhc_unref_fn) (struct tkmap_instance *tk);
/* IID generator */
uint64_t (*iidgen_fn) (void);
};
extern struct config OSAPI_EXPORT config;
extern struct ddsi_plugin ddsi_plugin;
struct cfgst;
struct cfgst *config_init (_In_opt_ const char *configfile);
void config_print_cfgst (_In_ struct cfgst *cfgst);
void config_fini (_In_ struct cfgst *cfgst);
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
struct config_partitionmapping_listelem *find_partitionmapping (const char *partition, const char *topic);
struct config_networkpartition_listelem *find_networkpartition_by_id (uint32_t id);
int is_ignored_partition (const char *partition, const char *topic);
#endif
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
struct config_channel_listelem *find_channel (nn_transport_priority_qospolicy_t transport_priority);
#endif
#if defined (__cplusplus)
}
#endif
#endif /* NN_CONFIG_H */

View file

@ -0,0 +1,47 @@
/*
* 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 NN_DDSI_DISCOVERY_H
#define NN_DDSI_DISCOVERY_H
#include "ddsi/q_unused.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct participant;
struct writer;
struct reader;
struct nn_rsample_info;
struct nn_rdata;
struct nn_plist;
int spdp_write (struct participant *pp);
int spdp_dispose_unregister (struct participant *pp);
int sedp_write_writer (struct writer *wr);
int sedp_write_reader (struct reader *rd);
int sedp_dispose_unregister_writer (struct writer *wr);
int sedp_dispose_unregister_reader (struct reader *rd);
int sedp_write_topic (struct participant *pp, const struct nn_plist *datap);
int sedp_write_cm_participant (struct participant *pp, int alive);
int sedp_write_cm_publisher (const struct nn_plist *datap, int alive);
int sedp_write_cm_subscriber (const struct nn_plist *datap, int alive);
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, void *qarg);
#if defined (__cplusplus)
}
#endif
#endif /* NN_DDSI_DISCOVERY_H */

View file

@ -0,0 +1,23 @@
/*
* 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 Q_DEBMON_H
#define Q_DEBMON_H
struct debug_monitor;
typedef int (*debug_monitor_cpf_t) (ddsi_tran_conn_t conn, const char *fmt, ...);
typedef int (*debug_monitor_plugin_t) (ddsi_tran_conn_t conn, debug_monitor_cpf_t cpf, void *arg);
struct debug_monitor *new_debug_monitor (int port);
void add_debug_monitor_plugin (struct debug_monitor *dm, debug_monitor_plugin_t fn, void *arg);
void free_debug_monitor (struct debug_monitor *dm);
#endif /* defined(__ospli_osplo__q_debmon__) */

View file

@ -0,0 +1,579 @@
/*
* 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 Q_ENTITY_H
#define Q_ENTITY_H
#include "os/os.h"
#include "util/ut_avl.h"
#include "ddsi/q_rtps.h"
#include "ddsi/q_protocol.h"
#include "ddsi/q_lat_estim.h"
#include "ddsi/q_ephash.h"
#include "ddsi/q_hbcontrol.h"
#include "ddsi/q_feature_check.h"
#include "ddsi/ddsi_tran.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct xevent;
struct nn_reorder;
struct nn_defrag;
struct nn_dqueue;
struct addrset;
struct sertopic;
struct whc;
struct nn_xqos;
struct nn_plist;
struct v_gid_s;
struct proxy_group;
struct proxy_endpoint_common;
typedef void (*ddsi2direct_directread_cb_t) (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, void *arg);
typedef struct status_cb_data
{
uint32_t status;
uint32_t extra;
uint64_t handle;
bool add;
}
status_cb_data_t;
typedef void (*status_cb_t) (void * entity, const status_cb_data_t * data);
struct prd_wr_match {
ut_avlNode_t avlnode;
nn_guid_t wr_guid;
};
struct rd_pwr_match {
ut_avlNode_t avlnode;
nn_guid_t pwr_guid;
#ifdef DDSI_INCLUDE_SSM
nn_locator_t ssm_mc_loc;
nn_locator_t ssm_src_loc;
#endif
};
struct wr_rd_match {
ut_avlNode_t avlnode;
nn_guid_t rd_guid;
};
struct rd_wr_match {
ut_avlNode_t avlnode;
nn_guid_t wr_guid;
};
struct wr_prd_match {
ut_avlNode_t avlnode;
nn_guid_t prd_guid; /* guid of the proxy reader */
unsigned assumed_in_sync: 1; /* set to 1 upon receipt of ack not nack'ing msgs */
unsigned has_replied_to_hb: 1; /* we must keep sending HBs until all readers have this set */
unsigned all_have_replied_to_hb: 1; /* true iff 'has_replied_to_hb' for all readers in subtree */
unsigned is_reliable: 1; /* true iff reliable proxy reader */
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 seq; /* highest acknowledged seq nr */
int num_reliable_readers_where_seq_equals_max;
nn_guid_t arbitrary_unacked_reader;
nn_count_t next_acknack; /* next acceptable acknack sequence number */
nn_count_t next_nackfrag; /* next acceptable nackfrag sequence number */
nn_etime_t t_acknack_accepted; /* (local) time an acknack was last accepted */
struct nn_lat_estim hb_to_ack_latency;
nn_wctime_t hb_to_ack_latency_tlastlog;
uint32_t non_responsive_count;
uint32_t rexmit_requests;
};
enum pwr_rd_match_syncstate {
PRMSS_SYNC, /* in sync with proxy writer, has caught up with historical data */
PRMSS_TLCATCHUP, /* in sync with proxy writer, pwr + readers still catching up on historical data */
PRMSS_OUT_OF_SYNC /* not in sync with proxy writer */
};
struct pwr_rd_match {
ut_avlNode_t avlnode;
nn_guid_t rd_guid;
nn_mtime_t tcreate;
nn_count_t count; /* most recent acknack sequence number */
nn_count_t next_heartbeat; /* next acceptable heartbeat (see also add_proxy_writer_to_reader) */
nn_wctime_t hb_timestamp; /* time of most recent heartbeat that rescheduled the ack event */
nn_etime_t t_heartbeat_accepted; /* (local) time a heartbeat was last accepted */
nn_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 */
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 */
union {
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_out_of_sync_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 */
} not_in_sync;
} u;
};
struct nn_rsample_info;
struct nn_rdata;
struct entity_common {
enum entity_kind kind;
nn_guid_t guid;
char *name;
uint64_t iid;
os_mutex lock;
bool onlylocal;
};
struct local_reader_ary {
os_mutex rdary_lock;
unsigned valid: 1; /* always true until (proxy-)writer is being deleted; !valid => !fastpath_ok */
unsigned fastpath_ok: 1; /* if not ok, fall back to using GUIDs (gives access to the reader-writer match data for handling readers that bumped into resource limits, hence can flip-flop, unlike "valid") */
int n_readers;
struct reader **rdary; /* for efficient delivery, null-pointer terminated */
};
struct participant
{
struct entity_common e;
long long lease_duration; /* constant */
unsigned bes; /* built-in endpoint set */
unsigned prismtech_bes; /* prismtech-specific extension of built-in endpoints set */
unsigned is_ddsi2_pp: 1; /* true for the "federation leader", the ddsi2 participant itself in OSPL; FIXME: probably should use this for broker mode as well ... */
nn_plist_t *plist; /* settings/QoS for this participant */
struct xevent *spdp_xevent; /* timed event for periodically publishing SPDP */
struct xevent *pmd_update_xevent; /* timed event for periodically publishing ParticipantMessageData */
nn_locator_t m_locator;
ddsi_tran_conn_t m_conn;
unsigned next_entityid; /* next available entity id [e.lock] */
os_mutex refc_lock;
int32_t user_refc; /* number of non-built-in endpoints in this participant [refc_lock] */
int32_t builtin_refc; /* number of built-in endpoints in this participant [refc_lock] */
int builtins_deleted; /* whether deletion of built-in endpoints has been initiated [refc_lock] */
};
struct endpoint_common {
struct participant *pp;
nn_guid_t group_guid;
};
struct generic_endpoint { /* FIXME: currently only local endpoints; proxies use entity_common + proxy_endpoint common */
struct entity_common e;
struct endpoint_common c;
};
enum writer_state {
WRST_OPERATIONAL, /* normal situation */
WRST_LINGERING, /* writer deletion has been requested but still has unack'd data */
WRST_DELETING /* writer is actually being deleted (removed from hash table) */
};
#if OS_ATOMIC64_SUPPORT
typedef os_atomic_uint64_t seq_xmit_t;
#define INIT_SEQ_XMIT(wr, v) os_atomic_st64(&(wr)->seq_xmit, (uint64_t) (v))
#define READ_SEQ_XMIT(wr) ((seqno_t) os_atomic_ld64(&(wr)->seq_xmit))
#define UPDATE_SEQ_XMIT_LOCKED(wr, nv) do { uint64_t ov_; do { \
ov_ = os_atomic_ld64(&(wr)->seq_xmit); \
if ((uint64_t) nv <= ov_) break; \
} while (!os_atomic_cas64(&(wr)->seq_xmit, ov_, (uint64_t) nv)); } while (0)
#define UPDATE_SEQ_XMIT_UNLOCKED(sx, nv) UPDATE_SEQ_XMIT_LOCKED(sx, nv)
#else
typedef seqno_t seq_xmit_t;
#define INIT_SEQ_XMIT(wr, v) ((wr)->seq_xmit = (v))
#define READ_SEQ_XMIT(wr) ((wr)->seq_xmit)
#define UPDATE_SEQ_XMIT_LOCKED(wr, nv) do { \
if ((nv) > (wr)->seq_xmit) { (wr)->seq_xmit = (nv); } \
} while (0)
#define UPDATE_SEQ_XMIT_UNLOCKED(wr, nv) do { \
os_mutexLock (&(wr)->e.lock); \
if ((nv) > (wr)->seq_xmit) { (wr)->seq_xmit = (nv); } \
os_mutexUnlock (&(wr)->e.lock); \
} while (0)
#endif
struct writer
{
struct entity_common e;
struct endpoint_common c;
status_cb_t status_cb;
void * status_cb_entity;
os_cond throttle_cond; /* used to trigger a transmit thread blocked in throttle_writer() */
seqno_t seq; /* last sequence number (transmitted seqs are 1 ... seq) */
seqno_t cs_seq; /* 1st seq in coherent set (or 0) */
seq_xmit_t seq_xmit; /* last sequence number actually transmitted */
seqno_t min_local_readers_reject_seq; /* mimum of local_readers->last_deliv_seq */
nn_count_t hbcount; /* last hb seq number */
nn_count_t hbfragcount; /* last hb frag seq number */
int throttling; /* non-zero when some thread is waiting for the WHC to shrink */
struct hbcontrol hbcontrol; /* controls heartbeat timing, piggybacking */
struct nn_xqos *xqos;
enum writer_state state;
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 aggressive_keep_last: 1; /* controls whether KEEP_LAST will overwrite samples that haven't been ACK'd yet */
unsigned startup_mode: 1; /* causes data to be treated as T-L for a while */
unsigned include_keyhash: 1; /* iff 1, this writer includes a keyhash; keyless topics => include_keyhash = 0 */
unsigned retransmitting: 1; /* iff 1, this writer is currently retransmitting */
#ifdef DDSI_INCLUDE_SSM
unsigned supports_ssm: 1;
struct addrset *ssm_as;
#endif
const struct sertopic * topic; /* topic, but may be NULL for built-ins */
struct addrset *as; /* set of addresses to publish to */
struct addrset *as_group; /* alternate case, used for SPDP, when using Cloud with multiple bootstrap locators */
struct xevent *heartbeat_xevent; /* timed event for "periodically" publishing heartbeats when unack'd data present, NULL <=> unreliable */
long long lease_duration;
struct whc *whc; /* WHC tracking history, T-L durability service history + samples by sequence number for retransmit */
uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */
nn_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */
nn_etime_t t_whc_high_upd; /* time "whc_high" was last updated for controlled ramp-up of throughput */
int num_reliable_readers; /* number of matching reliable PROXY readers */
ut_avlTree_t readers; /* all matching PROXY readers, see struct wr_prd_match */
ut_avlTree_t local_readers; /* all matching LOCAL readers, see struct wr_rd_match */
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
uint32_t partition_id;
#endif
uint32_t num_acks_received; /* cum received ACKNACKs with no request for retransmission */
uint32_t num_nacks_received; /* cum received ACKNACKs that did request retransmission */
uint32_t throttle_count; /* cum times transmitting was throttled (whc hitting high-level mark) */
uint32_t throttle_tracing;
uint32_t rexmit_count; /* cum samples retransmitted (counting events; 1 sample can be counted many times) */
uint32_t rexmit_lost_count; /* cum samples lost but retransmit requested (also counting events) */
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 reader
{
struct entity_common e;
struct endpoint_common c;
status_cb_t status_cb;
void * status_cb_entity;
struct rhc * rhc; /* reader history, tracks registrations and data */
struct nn_xqos *xqos;
unsigned reliable: 1; /* 1 iff reader is reliable */
unsigned handle_as_transient_local: 1; /* 1 iff reader wants historical data from proxy writers */
#ifdef DDSI_INCLUDE_SSM
unsigned favours_ssm: 1; /* iff 1, this reader favours SSM */
#endif
nn_count_t init_acknack_count; /* initial value for "count" (i.e. ACK seq num) for newly matched proxy writers */
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
struct addrset *as;
#endif
const struct sertopic * topic; /* topic is NULL for built-in readers */
ut_avlTree_t writers; /* all matching PROXY writers, see struct rd_pwr_match */
ut_avlTree_t local_writers; /* all matching LOCAL writers, see struct rd_wr_match */
ddsi2direct_directread_cb_t ddsi2direct_cb;
void *ddsi2direct_cbarg;
};
struct proxy_participant
{
struct entity_common e;
uint32_t refc; /* number of proxy endpoints (both user & built-in; not groups, they don't have a life of their own) */
nn_vendorid_t vendor; /* vendor code from discovery */
unsigned bes; /* built-in endpoint set */
unsigned prismtech_bes; /* prismtech-specific extension of built-in endpoints set */
nn_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */
nn_plist_t *plist; /* settings/QoS for this participant */
os_atomic_voidp_t lease; /* lease object for this participant, for automatic leases */
struct addrset *as_default; /* default address set to use for user data traffic */
struct addrset *as_meta; /* default address set to use for discovery traffic */
struct proxy_endpoint_common *endpoints; /* all proxy endpoints can be reached from here */
ut_avlTree_t groups; /* table of all groups (publisher, subscriber), see struct proxy_group */
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 is_ddsi2_pp: 1; /* if this is the federation-leader on the remote node */
unsigned minimal_bes_mode: 1;
unsigned lease_expired: 1;
unsigned proxypp_have_spdp: 1;
unsigned proxypp_have_cm: 1;
unsigned owns_lease: 1;
};
/* Representing proxy subscriber & publishers as "groups": until DDSI2
gets a reason to care about these other than for the generation of
CM topics, there's little value in distinguishing between the two.
In another way, they're secondly-class citizens, too: "real"
entities are garbage collected and found using lock-free hash
tables, but "groups" only live in the context of a proxy
participant. */
struct proxy_group {
ut_avlNode_t avlnode;
nn_guid_t guid;
char *name;
struct proxy_participant *proxypp; /* uncounted backref to proxy participant */
struct nn_xqos *xqos; /* publisher/subscriber QoS */
};
struct proxy_endpoint_common
{
struct proxy_participant *proxypp; /* counted backref to proxy participant */
struct proxy_endpoint_common *next_ep; /* next \ endpoint belonging to this proxy participant */
struct proxy_endpoint_common *prev_ep; /* prev / -- this is in arbitrary ordering */
struct nn_xqos *xqos; /* proxy endpoint QoS lives here; FIXME: local ones should have it moved to common as well */
const struct sertopic * topic; /* topic may be NULL: for built-ins, but also for never-yet matched proxies (so we don't have to know the topic; when we match, we certainly do know) */
struct addrset *as; /* address set to use for communicating with this endpoint */
nn_guid_t group_guid; /* 0:0:0:0 if not available */
nn_vendorid_t vendor; /* cached from proxypp->vendor */
};
struct proxy_writer {
struct entity_common e;
struct proxy_endpoint_common c;
ut_avlTree_t readers; /* matching LOCAL readers, see pwr_rd_match */
int n_reliable_readers; /* number of those that are reliable */
int n_readers_out_of_sync; /* number of those that require special handling (accepting historical data, waiting for historical data set to become complete) */
seqno_t last_seq; /* highest known seq published by the writer, not last delivered */
uint32_t last_fragnum; /* last known frag for last_seq, or ~0u if last_seq not partial */
nn_count_t nackfragcount; /* last nackfrag seq number */
os_atomic_uint32_t next_deliv_seq_lowword; /* lower 32-bits for next sequence number that will be delivered; for generating acks; 32-bit so atomic reads on all supported platforms */
unsigned last_fragnum_reset: 1; /* iff set, heartbeat advertising last_seq as highest seq resets last_fragnum */
unsigned deliver_synchronously: 1; /* iff 1, delivery happens straight from receive thread for non-historical data; else through delivery queue "dqueue" */
unsigned have_seen_heartbeat: 1; /* iff 1, we have received at least on heartbeat from this proxy writer */
unsigned assert_pp_lease: 1; /* iff 1, renew the proxy-participant's lease when data comes in */
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 */
#ifdef DDSI_INCLUDE_SSM
unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */
#endif
struct nn_defrag *defrag; /* defragmenter for this proxy writer; FIXME: perhaps shouldn't be for historical data */
struct nn_reorder *reorder; /* message reordering for this proxy writer, out-of-sync readers can have their own, see pwr_rd_match */
struct nn_dqueue *dqueue; /* delivery queue for asynchronous delivery (historical data is always delivered asynchronously) */
struct xeventq *evq; /* timed event queue to be used for ACK generation */
struct local_reader_ary rdary; /* LOCAL readers for fast-pathing; if not fast-pathed, fall back to scanning local_readers */
ddsi2direct_directread_cb_t ddsi2direct_cb;
void *ddsi2direct_cbarg;
};
struct proxy_reader {
struct entity_common e;
struct proxy_endpoint_common c;
unsigned deleting: 1; /* set when being deleted */
unsigned is_fict_trans_reader: 1; /* only true when it is certain that is a fictitious transient data reader (affects built-in topic generation) */
unsigned assert_pp_lease: 1; /* iff 1, renew the proxy-participant's lease when data comes in */
#ifdef DDSI_INCLUDE_SSM
unsigned favours_ssm: 1; /* iff 1, this proxy reader favours SSM when available */
#endif
ut_avlTree_t writers; /* matching LOCAL writers */
};
extern const ut_avlTreedef_t wr_readers_treedef;
extern const ut_avlTreedef_t wr_local_readers_treedef;
extern const ut_avlTreedef_t rd_writers_treedef;
extern const ut_avlTreedef_t rd_local_writers_treedef;
extern const ut_avlTreedef_t pwr_readers_treedef;
extern const ut_avlTreedef_t prd_writers_treedef;
extern const ut_avlTreedef_t deleted_participants_treedef;
#define DPG_LOCAL 1
#define DPG_REMOTE 2
int deleted_participants_admin_init (void);
void deleted_participants_admin_fini (void);
int is_deleted_participant_guid (const struct nn_guid *guid, unsigned for_what);
nn_entityid_t to_entityid (unsigned u);
int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid);
int is_writer_entityid (nn_entityid_t id);
int is_reader_entityid (nn_entityid_t id);
int pp_allocate_entityid (nn_entityid_t *id, unsigned kind, struct participant *pp);
/* Interface for glue code between the OpenSplice kernel and the DDSI
entities. These all return 0 iff successful. All GIDs supplied
__MUST_BE_UNIQUE__. All hell may break loose if they aren't.
All delete operations synchronously remove the entity being deleted
from the various global hash tables on GUIDs. This ensures no new
operations can be invoked by the glue code, discovery, protocol
messages, &c. The entity is then scheduled for garbage collection.
There is one exception: a participant without built-in
endpoints: that one synchronously reaches reference count zero
and is then freed immediately.
If new_writer() and/or new_reader() may be called in parallel to
delete_participant(), trouble ensues. The current glue code
performs all local discovery single-threaded, and can't ever get
into that issue.
A garbage collector thread is used to perform the actual freeing of
an entity, but it never does so before all threads have made
sufficient progress to guarantee they are not using that entity any
longer, with the exception of use via internal pointers in the
entity data structures.
An example of the latter is that (proxy) endpoints have a pointer
to the owning (proxy) participant, but the (proxy) participant is
reference counted to make this safe.
The case of a proxy writer is particularly complicated is it has to
pass through a multiple-stage delay in the garbage collector before
it may be freed: first there is the possibility of a parallel
delete or protocol message, then there is still the possibility of
data in a delivery queue. This is dealt by requeueing garbage
collection and sending bubbles through the delivery queue. */
/* Set this flag in new_participant to prevent the creation SPDP, SEDP
and PMD readers for that participant. It doesn't really need it,
they all share the information anyway. But you do need it once. */
#define RTPS_PF_NO_BUILTIN_READERS 1u
/* Set this flag to prevent the creation of SPDP, SEDP and PMD
writers. It will then rely on the "privileged participant", which
must exist at the time of creation. It creates a reference to that
"privileged participant" to ensure it won't disappear too early. */
#define RTPS_PF_NO_BUILTIN_WRITERS 2u
/* Set this flag to mark the participant as the "privileged
participant", there can only be one of these. The privileged
participant MUST have all builtin readers and writers. */
#define RTPS_PF_PRIVILEGED_PP 4u
/* Set this flag to mark the participant as is_ddsi2_pp. */
#define RTPS_PF_IS_DDSI2_PP 8u
/* Set this flag to mark the participant as an local entity only. */
#define RTPS_PF_ONLY_LOCAL 16u
/* To create a DDSI participant given a GUID. May return ERR_OUT_OF_IDS
(a.o.) */
int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const struct nn_plist *plist);
int new_participant (struct nn_guid *ppguid, unsigned flags, const struct nn_plist *plist);
/* To delete a DDSI participant: this only removes the participant
from the hash tables and schedules the actual delete operation,
which will start doing scary things once all but the DDSI built-in
endpoints are gone. It is acceptable to call delete_participant()
before all its readers and writers have been deleted (which also
fits nicely with model where the glue calls merely schedules
garbage-collection). */
int delete_participant (const struct nn_guid *ppguid);
/* To obtain the builtin writer to be used for publishing SPDP, SEDP,
PMD stuff for PP and its endpoints, given the entityid. If PP has
its own writer, use it; else use the privileged participant. */
struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid);
/* To create a new DDSI writer or reader belonging to participant with
GUID "ppguid". May return NULL if participant unknown or
writer/reader already known. */
struct writer * new_writer
(
struct nn_guid *wrguid,
const struct nn_guid *group_guid,
const struct nn_guid *ppguid,
const struct sertopic *topic,
const struct nn_xqos *xqos,
status_cb_t status_cb,
void * status_cb_arg
);
struct reader * new_reader
(
struct nn_guid *rdguid,
const struct nn_guid *group_guid,
const struct nn_guid *ppguid,
const struct sertopic *topic,
const struct nn_xqos *xqos,
struct rhc * rhc,
status_cb_t status_cb,
void * status_cb_arg
);
struct whc_node;
unsigned remove_acked_messages (struct writer *wr, struct whc_node **deferred_free_list);
unsigned remove_acked_messages_and_free (struct writer *wr);
seqno_t writer_max_drop_seq (const struct writer *wr);
int writer_must_have_hb_scheduled (const struct writer *wr);
void writer_set_retransmitting (struct writer *wr);
void writer_clear_retransmitting (struct writer *wr);
int delete_writer (const struct nn_guid *guid);
int delete_writer_nolinger (const struct nn_guid *guid);
int delete_writer_nolinger_locked (struct writer *wr);
int delete_reader (const struct nn_guid *guid);
uint64_t reader_instance_id (const struct nn_guid *guid);
/* To create or delete a new proxy participant: "guid" MUST have the
pre-defined participant entity id. Unlike delete_participant(),
deleting a proxy participant will automatically delete all its
readers & writers. Delete removes the participant from a hash table
and schedules the actual deletion.
-- XX what about proxy participants without built-in endpoints?
XX --
*/
/* Set this custom flag when using nn_prismtech_writer_info_t iso nn_prismtech_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
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
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. */
#define CF_IMPLICITLY_CREATED_PROXYPP (1 << 1)
/* 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 */
#define CF_PARTICIPANT_IS_DDSI2 (1 << 2)
/* Set when this proxy participant is not to be announced on the built-in topics yet */
#define CF_PROXYPP_NO_SPDP (1 << 3)
void new_proxy_participant (const struct nn_guid *guid, unsigned bes, unsigned prismtech_bes, const struct nn_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, int64_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp);
int delete_proxy_participant_by_guid (const struct nn_guid * guid, nn_wctime_t timestamp, int isimplicit);
uint64_t participant_instance_id (const struct nn_guid *guid);
enum update_proxy_participant_source {
UPD_PROXYPP_SPDP,
UPD_PROXYPP_CM
};
int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp);
int update_proxy_participant_plist (struct proxy_participant *proxypp, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp);
void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct lease *newlease);
void purge_proxy_participants (const nn_locator_t *loc, bool delete_from_as_disc);
/* To create a new proxy writer or reader; the proxy participant is
determined from the GUID and must exist. */
int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp);
int new_proxy_reader (const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, nn_wctime_t timestamp
#ifdef DDSI_INCLUDE_SSM
, int favours_ssm
#endif
);
/* To delete a proxy writer or reader; these synchronously hide it
from the outside world, preventing it from being matched to a
reader or writer. Actual deletion is scheduled in the future, when
no outstanding references may still exist (determined by checking
thread progress, &c.). */
int delete_proxy_writer (const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
int delete_proxy_reader (const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
void update_proxy_reader (struct proxy_reader * prd, struct addrset *as);
void update_proxy_writer (struct proxy_writer * pwr, struct addrset *as);
int new_proxy_group (const struct nn_guid *guid, const struct v_gid_s *gid, const char *name, const struct nn_xqos *xqos, nn_wctime_t timestamp);
void delete_proxy_group (const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
void writer_exit_startup_mode (struct writer *wr);
uint64_t writer_instance_id (const struct nn_guid *guid);
#if defined (__cplusplus)
}
#endif
#endif /* Q_ENTITY_H */

View file

@ -0,0 +1,142 @@
/*
* 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 Q_EPHASH_H
#define Q_EPHASH_H
#include "os/os_defs.h"
#include "util/ut_hopscotch.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct ephash;
struct participant;
struct reader;
struct writer;
struct proxy_participant;
struct proxy_reader;
struct proxy_writer;
struct nn_guid;
enum entity_kind {
EK_PARTICIPANT,
EK_PROXY_PARTICIPANT,
EK_WRITER,
EK_PROXY_WRITER,
EK_READER,
EK_PROXY_READER
};
#define EK_NKINDS ((int) EK_PROXY_READER + 1)
struct ephash_enum
{
struct ut_chhIter it;
enum entity_kind kind;
struct entity_common *cur;
};
/* Readers & writers are both in a GUID- and in a GID-keyed table. If
they are in the GID-based one, they are also in the GUID-based one,
but not the way around, for two reasons:
- firstly, there are readers & writers that do not have a GID
(built-in endpoints, fictitious transient data readers),
- secondly, they are inserted first in the GUID-keyed one, and then
in the GID-keyed one.
The GID is used solely for the interface with the OpenSplice
kernel, all internal state and protocol handling is done using the
GUID. So all this means is that, e.g., a writer being deleted
becomes invisible to the network reader slightly before it
disappears in the protocol handling, or that a writer might exist
at the protocol level slightly before the network reader can use it
to transmit data. */
struct ephash *ephash_new (void);
void ephash_free (struct ephash *ephash);
void ephash_insert_participant_guid (struct participant *pp);
void ephash_insert_proxy_participant_guid (struct proxy_participant *proxypp);
void ephash_insert_writer_guid (struct writer *wr);
void ephash_insert_reader_guid (struct reader *rd);
void ephash_insert_proxy_writer_guid (struct proxy_writer *pwr);
void ephash_insert_proxy_reader_guid (struct proxy_reader *prd);
void ephash_remove_participant_guid (struct participant *pp);
void ephash_remove_proxy_participant_guid (struct proxy_participant *proxypp);
void ephash_remove_writer_guid (struct writer *wr);
void ephash_remove_reader_guid (struct reader *rd);
void ephash_remove_proxy_writer_guid (struct proxy_writer *pwr);
void ephash_remove_proxy_reader_guid (struct proxy_reader *prd);
void *ephash_lookup_guid (const struct nn_guid *guid, enum entity_kind kind);
struct participant *ephash_lookup_participant_guid (const struct nn_guid *guid);
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct nn_guid *guid);
struct writer *ephash_lookup_writer_guid (const struct nn_guid *guid);
struct reader *ephash_lookup_reader_guid (const struct nn_guid *guid);
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct nn_guid *guid);
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct nn_guid *guid);
/* Enumeration of entries in the hash table:
- "next" visits at least all entries that were in the hash table at
the time of calling init and that have not subsequently been
removed;
- "next" may visit an entry more than once, but will do so only
because of rare events (i.e., resize or so);
- the order in which entries are visited is arbitrary;
- the caller must call init() before it may call next(); it must
call fini() before it may call init() again. */
struct ephash_enum_participant { struct ephash_enum st; };
struct ephash_enum_writer { struct ephash_enum st; };
struct ephash_enum_reader { struct ephash_enum st; };
struct ephash_enum_proxy_participant { struct ephash_enum st; };
struct ephash_enum_proxy_writer { struct ephash_enum st; };
struct ephash_enum_proxy_reader { struct ephash_enum st; };
void ephash_enum_init (struct ephash_enum *st, enum entity_kind kind);
void *ephash_enum_next (struct ephash_enum *st);
void ephash_enum_fini (struct ephash_enum *st);
void ephash_enum_writer_init (struct ephash_enum_writer *st);
void ephash_enum_reader_init (struct ephash_enum_reader *st);
void ephash_enum_proxy_writer_init (struct ephash_enum_proxy_writer *st);
void ephash_enum_proxy_reader_init (struct ephash_enum_proxy_reader *st);
void ephash_enum_participant_init (struct ephash_enum_participant *st);
void ephash_enum_proxy_participant_init (struct ephash_enum_proxy_participant *st);
struct writer *ephash_enum_writer_next (struct ephash_enum_writer *st);
struct reader *ephash_enum_reader_next (struct ephash_enum_reader *st);
struct proxy_writer *ephash_enum_proxy_writer_next (struct ephash_enum_proxy_writer *st);
struct proxy_reader *ephash_enum_proxy_reader_next (struct ephash_enum_proxy_reader *st);
struct participant *ephash_enum_participant_next (struct ephash_enum_participant *st);
struct proxy_participant *ephash_enum_proxy_participant_next (struct ephash_enum_proxy_participant *st);
void ephash_enum_writer_fini (struct ephash_enum_writer *st);
void ephash_enum_reader_fini (struct ephash_enum_reader *st);
void ephash_enum_proxy_writer_fini (struct ephash_enum_proxy_writer *st);
void ephash_enum_proxy_reader_fini (struct ephash_enum_proxy_reader *st);
void ephash_enum_participant_fini (struct ephash_enum_participant *st);
void ephash_enum_proxy_participant_fini (struct ephash_enum_proxy_participant *st);
#if defined (__cplusplus)
}
#endif
#endif /* Q_EPHASH_H */

View file

@ -0,0 +1,26 @@
/*
* 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 NN_ERROR_H
#define NN_ERROR_H
#define ERR_UNSPECIFIED -1
#define ERR_INVALID -2
#define ERR_OUT_OF_MEMORY -3
#define ERR_ENTITY_EXISTS -4
#define ERR_UNKNOWN_ENTITY -5
#define ERR_OUT_OF_IDS -6
#define ERR_INVALID_DATA -7
#define ERR_BUSY -8
#define ERR_NO_ADDRESS -9
#define ERR_TIMEOUT -10
#endif /* NN_ERROR_H */

View file

@ -0,0 +1,57 @@
/*
* 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
*/
/* Feature macros:
- ENCRYPTION: support for encryption
requires: NETWORK_PARTITIONS
- SSM: support for source-specific multicast
requires: NETWORK_PARTIITONS
also requires platform support; SSM is silently disabled if the
platform doesn't support it
- BANDWIDTH_LIMITING: transmit-side bandwidth limiting
requires: NETWORK_CHANNELS (for now, anyway)
- IPV6: support for IPV6
requires: platform support (which itself is not part of DDSI)
- NETWORK_PARTITIONS: support for multiple network partitions
- NETWORK_CHANNELS: support for multiple network channels
*/
#ifdef DDSI_INCLUDE_ENCRYPTION
#ifndef DDSI_INCLUDE_NETWORK_PARTITIONS
#error "ENCRYPTION requires NETWORK_PARTITIONS"
#endif
#endif
#ifdef DDSI_INCLUDE_SSM
#ifndef DDSI_INCLUDE_NETWORK_PARTITIONS
#error "SSM requires NETWORK_PARTITIONS"
#endif
#include "os/os_socket.h"
#ifndef OS_SOCKET_HAS_SSM
#error "OS_SOCKET_HAS_SSM should be defined"
#elif ! OS_SOCKET_HAS_SSM
#undef DDSI_INCLUDE_SSM
#endif
#endif
#ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING
#ifndef DDSI_INCLUDE_NETWORK_CHANNELS
#error "BANDWIDTH_LIMITING requires NETWORK_CHANNELS"
#endif
#endif

View file

@ -0,0 +1,77 @@
/*
* 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 NN_FREELIST_H
#define NN_FREELIST_H
#include "os/os.h"
#include "ddsi/sysdeps.h"
#define FREELIST_SIMPLE 1
#define FREELIST_ATOMIC_LIFO 2
#define FREELIST_DOUBLE 3
#define FREELIST_TYPE FREELIST_DOUBLE
#if 0
#if HAVE_ATOMIC_LIFO
#define FREELIST_TYPE FREELIST_ATOMIC_LIFO
#else
#define FREELIST_TYPE FREELIST_SIMPLE
#endif
#endif
#if FREELIST_TYPE == FREELIST_ATOMIC_LIFO
struct nn_freelist {
os_atomic_lifo_t x;
os_atomic_uint32_t count;
uint32_t max;
off_t linkoff;
};
#elif FREELIST_TYPE == FREELIST_DOUBLE
#define NN_FREELIST_NPAR 4
#define NN_FREELIST_NPAR_LG2 2
#define NN_FREELIST_MAGSIZE 256
struct nn_freelistM {
void *x[NN_FREELIST_MAGSIZE];
void *next;
};
struct nn_freelist1 {
os_mutex lock;
uint32_t count;
struct nn_freelistM *m;
};
struct nn_freelist {
struct nn_freelist1 inner[NN_FREELIST_NPAR];
os_atomic_uint32_t cc;
os_mutex lock;
struct nn_freelistM *mlist;
struct nn_freelistM *emlist;
uint32_t count;
uint32_t max;
off_t linkoff;
};
#endif
void nn_freelist_init (_Out_ struct nn_freelist *fl, uint32_t max, off_t linkoff);
void nn_freelist_fini (_Inout_ _Post_invalid_ struct nn_freelist *fl, _In_ void (*free) (void *elem));
_Check_return_ bool nn_freelist_push (_Inout_ struct nn_freelist *fl, _Inout_ _When_ (return != 0, _Post_invalid_) void *elem);
_Check_return_ _Ret_maybenull_ void *nn_freelist_pushmany (_Inout_ struct nn_freelist *fl, _Inout_opt_ _When_ (return != 0, _Post_invalid_) void *first, _Inout_opt_ _When_ (return != 0, _Post_invalid_) void *last, uint32_t n);
_Check_return_ _Ret_maybenull_ void *nn_freelist_pop (_Inout_ struct nn_freelist *fl);
#endif /* NN_FREELIST_H */

View file

@ -0,0 +1,57 @@
/*
* 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 Q_GC_H
#define Q_GC_H
#include "ddsi/q_thread.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct gcreq;
struct gcreq_queue;
struct writer;
struct reader;
struct proxy_writer;
struct proxy_reader;
typedef void (*gcreq_cb_t) (struct gcreq *gcreq);
struct idx_vtime {
unsigned idx;
vtime_t vtime;
};
struct gcreq {
struct gcreq *next;
struct gcreq_queue *queue;
gcreq_cb_t cb;
void *arg;
unsigned nvtimes;
struct idx_vtime vtimes[1 /* really a flex ary */];
};
struct gcreq_queue *gcreq_queue_new (void);
void gcreq_queue_free (struct gcreq_queue *q);
struct gcreq *gcreq_new (struct gcreq_queue *gcreq_queue, gcreq_cb_t cb);
void gcreq_free (struct gcreq *gcreq);
void gcreq_enqueue (struct gcreq *gcreq);
int gcreq_requeue (struct gcreq *gcreq, gcreq_cb_t cb);
#if defined (__cplusplus)
}
#endif
#endif /* Q_GC_H */

View file

@ -0,0 +1,310 @@
/*
* 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 Q_GLOBALS_H
#define Q_GLOBALS_H
#include <stdio.h>
#include "os/os.h"
#include "util/ut_fibheap.h"
#include "ddsi/q_plist.h"
#include "ddsi/q_protocol.h"
#include "ddsi/q_nwif.h"
#include "ddsi/q_sockwaitset.h"
#ifdef DDSI_INCLUDE_ENCRYPTION
#include "ddsi/q_security.h" /* for q_securityDecoderSet */
#endif /* DDSI_INCLUDE_ENCRYPTION */
#if defined (__cplusplus)
extern "C" {
#endif
struct nn_xmsgpool;
struct serstatepool;
struct nn_dqueue;
struct nn_reorder;
struct nn_defrag;
struct addrset;
struct xeventq;
struct gcreq_queue;
struct ephash;
struct lease;
struct ddsi_tran_conn;
struct ddsi_tran_listener;
struct ddsi_tran_factory;
struct ut_thread_pool_s;
struct debug_monitor;
struct tkmap;
typedef struct ospl_in_addr_node {
os_sockaddr_storage addr;
struct ospl_in_addr_node *next;
} ospl_in_addr_node;
enum recvips_mode {
RECVIPS_MODE_ALL, /* all MC capable interfaces */
RECVIPS_MODE_ANY, /* kernel-default interface */
RECVIPS_MODE_PREFERRED, /* selected interface only */
RECVIPS_MODE_NONE, /* no interfaces at all */
RECVIPS_MODE_SOME /* explicit list of interfaces; only one requiring recvips */
};
#define N_LEASE_LOCKS_LG2 4
#define N_LEASE_LOCKS ((int) (1 << N_LEASE_LOCKS_LG2))
struct q_globals {
volatile int terminate;
volatile int exception;
volatile int deaf;
volatile int mute;
struct tkmap * m_tkmap;
/* Hash tables for participants, readers, writers, proxy
participants, proxy readers and proxy writers by GUID
(guid_hash) */
struct ephash *guid_hash;
/* Timed events admin */
struct xeventq *xevents;
/* Queue for garbage collection requests */
struct gcreq_queue *gcreq_queue;
struct nn_servicelease *servicelease;
/* Lease junk */
os_mutex leaseheap_lock;
os_mutex lease_locks[N_LEASE_LOCKS];
ut_fibheap_t leaseheap;
/* Transport factory */
struct ddsi_tran_factory * m_factory;
/* Connections for multicast discovery & data, and those that correspond
to the one DDSI participant index that the DDSI2 service uses. The
DCPS participant of DDSI2 itself will be mirrored in a DDSI
participant, and in multi-socket mode that one gets its own
socket. */
struct ddsi_tran_conn * disc_conn_mc;
struct ddsi_tran_conn * data_conn_mc;
struct ddsi_tran_conn * disc_conn_uc;
struct ddsi_tran_conn * data_conn_uc;
/* TCP listener */
struct ddsi_tran_listener * listener;
/* Thread pool */
struct ut_thread_pool_s * thread_pool;
/* Receive thread triggering: must have a socket per receive thread
because all receive threads must be triggered, even though each
receive thread takes the trigger message from the socket. With one
trigger socket, we can only have one receive thread (which enables
other optimisations that we don't currently do). */
os_sockWaitset waitset;
/* In many sockets mode, the receive threads maintain a local array
with participant GUIDs and sockets, participant_set_generation is
used to notify them. */
os_atomic_uint32_t participant_set_generation;
/* nparticipants is used primarily for limiting the number of active
participants, but also during shutdown to determine when it is
safe to stop the GC thread. */
os_mutex participant_set_lock;
os_cond participant_set_cond;
uint32_t nparticipants;
/* For participants without (some) built-in writers, we fall back to
this participant, which is the first one created with all
built-in writers present. It MUST be created before any in need
of it pops up! */
struct participant *privileged_pp;
os_mutex privileged_pp_lock;
/* GUID to be used in next call to new_participant; also protected
by privileged_pp_lock */
struct nn_guid next_ppguid;
/* number of up, non-loopback, IPv4/IPv6 interfaces, the index of
the selected/preferred one, and the discovered interfaces. */
int n_interfaces;
int selected_interface;
struct nn_interface interfaces[MAX_INTERFACES];
#if OS_SOCKET_HAS_IPV6
/* whether we're using an IPv6 link-local address (and therefore
only listening to multicasts on that interface) */
int ipv6_link_local;
#endif
/* Addressing: actual own (preferred) IP address, IP address
advertised in discovery messages (so that an external IP address on
a NAT may be advertised), and the DDSI multi-cast address. */
enum recvips_mode recvips_mode;
struct ospl_in_addr_node *recvips;
struct in_addr extmask;
os_sockaddr_storage ownip;
os_sockaddr_storage extip;
/* InterfaceNo that the OwnIP is tied to */
unsigned interfaceNo;
/* Locators */
nn_locator_t loc_spdp_mc;
nn_locator_t loc_meta_mc;
nn_locator_t loc_meta_uc;
nn_locator_t loc_default_mc;
nn_locator_t loc_default_uc;
/*
Initial discovery address set, and the current discovery address
set. These are the addresses that SPDP pings get sent to. The
as_disc_group is an FT group (only use first working).
*/
struct addrset *as_disc;
struct addrset *as_disc_group;
/* qoslock serializes QoS changes, probably not strictly necessary,
but a lot more straightforward that way */
os_rwlock qoslock;
os_mutex lock;
/* guarantees serialisation of attach/detach operations on waitsets
-- a single global lock is a bit coarse, but these operations are
rare and at initialisation time anyway */
os_mutex attach_lock;
/* Receive thread. (We can only has one for now, cos of the signal
trigger socket.) Receive buffer pool is per receive thread,
practical considerations led to it being a global variable
TEMPORARILY. */
struct thread_state1 *recv_ts;
struct nn_rbufpool *rbufpool;
/* Listener thread for connection based transports */
struct thread_state1 *listen_ts;
/* Flag cleared when stopping (receive threads). FIXME. */
int rtps_keepgoing;
/* Startup mode causes data to be treated as transient-local with
depth 1 (i.e., stored in the WHCs and regurgitated on request) to
cover the start-up delay of the discovery protocols. Because all
discovery data is shared, this is strictly a start-up issue of the
service. */
int startup_mode;
/* Start time of the DDSI2 service, for logging relative time stamps,
should I ever so desire. */
nn_wctime_t tstart;
/* Default QoSs for participant, readers and writers (needed for
eliminating default values in outgoing discovery packets, and for
supplying values for missing QoS settings in incoming discovery
packets); plus the actual QoSs needed for the builtin
endpoints. */
nn_plist_t default_plist_pp;
nn_xqos_t default_xqos_rd;
nn_xqos_t default_xqos_wr;
nn_xqos_t default_xqos_wr_nad;
nn_xqos_t default_xqos_tp;
nn_xqos_t default_xqos_sub;
nn_xqos_t default_xqos_pub;
nn_xqos_t spdp_endpoint_xqos;
nn_xqos_t builtin_endpoint_xqos_rd;
nn_xqos_t builtin_endpoint_xqos_wr;
/* SPDP packets get very special treatment (they're the only packets
we accept from writers we don't know) and have their very own
do-nothing defragmentation and reordering thingummies, as well as a
global mutex to in lieu of the proxy writer lock. */
os_mutex spdp_lock;
struct nn_defrag *spdp_defrag;
struct nn_reorder *spdp_reorder;
/* Built-in stuff other than SPDP gets funneled through the builtins
delivery queue; currently just SEDP and PMD */
struct nn_dqueue *builtins_dqueue;
/* Connection used by general timed-event queue for transmitting data */
struct ddsi_tran_conn * tev_conn;
struct debug_monitor *debmon;
#ifndef DDSI_INCLUDE_NETWORK_CHANNELS
uint32_t networkQueueId;
struct thread_state1 *channel_reader_ts;
/* Application data gets its own delivery queue */
struct nn_dqueue *user_dqueue;
#endif
/* Transmit side: pools for the serializer & transmit messages and a
transmit queue*/
struct serstatepool *serpool;
struct nn_xmsgpool *xmsgpool;
/* Network ID needed by v_groupWrite -- FIXME: might as well pass it
to the receive thread instead of making it global (and that would
remove the need to include kernelModule.h) */
uint32_t myNetworkId;
os_mutex sendq_lock;
os_cond sendq_cond;
unsigned sendq_length;
struct nn_xpack *sendq_head;
struct nn_xpack *sendq_tail;
int sendq_stop;
struct thread_state1 *sendq_ts;
#ifdef DDSI_INCLUDE_ENCRYPTION
/* Codecs needed for decoding incoming encrypted messages
FIXME: should be a property of the receiver thread, and pass down
while processing messages. For now made global */
q_securityDecoderSet recvSecurityCodec;
#endif /* DDSI_INCLUDE_ENCRYPTION */
/* File for dumping captured packets, NULL if disabled */
FILE *pcap_fp;
os_mutex pcap_lock;
/* Data structure to capture power events */
os_timePowerEvents powerEvents;
/* Static log buffer, for those rare cases a thread calls nn_vlogb
without having its own log buffer (happens during config file
processing and for listeners, &c. */
int static_logbuf_lock_inited;
os_mutex static_logbuf_lock;
struct logbuf static_logbuf;
};
extern struct q_globals OSAPI_EXPORT gv;
#if defined (__cplusplus)
}
#endif
#endif /* Q_GLOBALS_H */

View file

@ -0,0 +1,42 @@
/*
* 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 Q_HBCONTROL_H
#define Q_HBCONTROL_H
#if defined (__cplusplus)
extern "C" {
#endif
struct writer;
struct hbcontrol {
nn_mtime_t t_of_last_write;
nn_mtime_t t_of_last_hb;
nn_mtime_t t_of_last_ackhb;
nn_mtime_t tsched;
unsigned hbs_since_last_write;
unsigned last_packetid;
};
void writer_hbcontrol_init (struct hbcontrol *hbc);
int64_t writer_hbcontrol_intv (const struct writer *wr, nn_mtime_t tnow);
void writer_hbcontrol_note_asyncwrite (struct writer *wr, nn_mtime_t tnow);
int writer_hbcontrol_ack_required (const struct writer *wr, nn_mtime_t tnow);
struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, nn_mtime_t tnow, unsigned packetid, int *hbansreq);
int writer_hbcontrol_must_send (const struct writer *wr, nn_mtime_t tnow);
struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, nn_mtime_t tnow, int hbansreq, int issync);
#if defined (__cplusplus)
}
#endif
#endif /* Q_HBCONTROL_H */

View file

@ -0,0 +1,70 @@
/*
* 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 NN_INLINE_H
#define NN_INLINE_H
#ifdef NN_SUPPRESS_C99_INLINE
#define NN_HAVE_C99_INLINE 0
#else
/* We want to inline these, but we don't want to emit an exernally
visible symbol for them and we don't want warnings if we don't use
them.
It appears as if a plain "inline" will do just that in C99.
In traditional GCC one had to use "extern inline" to achieve that
effect, but that will cause an externally visible symbol to be
emitted by a C99 compiler.
Starting with GCC 4.3, GCC conforms to the C99 standard if
compiling in C99 mode, unless -fgnu89-inline is specified. It
defines __GNUC_STDC_INLINE__ if "inline"/"extern inline" behaviour
is conforming the C99 standard.
So: GCC >= 4.3: choose between "inline" & "extern inline" based
upon __GNUC_STDC_INLINE__; for GCCs < 4.2, rely on the traditional
GCC behaiour; and for other compilers assume they behave conforming
the standard if they advertise themselves as C99 compliant (use
"inline"), and assume they do not support the inline keywords
otherwise.
GCC when not optimizing ignores "extern inline" functions. So we
need to distinguish between optimizing & non-optimizing ... */
#if __GNUC__
# if __OPTIMIZE__
# if 1 || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
# ifdef __GNUC_STDC_INLINE__
# define NN_HAVE_C99_INLINE 1
# define NN_C99_INLINE inline
# else
# define NN_HAVE_C99_INLINE 1
# define NN_C99_INLINE extern inline
# endif
# else
# define NN_HAVE_C99_INLINE 1
# define NN_C99_INLINE extern inline
# endif
# endif
#elif __STDC_VERSION__ >= 199901L
# define NN_HAVE_C99_INLINE 1
# define NN_C99_INLINE inline
#endif
#endif /* NN_SUPPRESS_C99_INLINE */
#if ! NN_HAVE_C99_INLINE
#define NN_C99_INLINE
#endif
#endif /* NN_INLINE_H */

View file

@ -0,0 +1,44 @@
/*
* 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 NN_LAT_ESTIM_H
#define NN_LAT_ESTIM_H
#include "os/os_defs.h"
#include "ddsi/q_log.h"
#if defined (__cplusplus)
extern "C" {
#endif
#define NN_LAT_ESTIM_MEDIAN_WINSZ 7
struct nn_lat_estim {
/* median filtering with a small window in an attempt to remove the
worst outliers */
int index;
float window[NN_LAT_ESTIM_MEDIAN_WINSZ];
/* simple alpha filtering for smoothing */
float smoothed;
};
void nn_lat_estim_init (struct nn_lat_estim *le);
void nn_lat_estim_fini (struct nn_lat_estim *le);
void nn_lat_estim_update (struct nn_lat_estim *le, int64_t est);
double nn_lat_estim_current (const struct nn_lat_estim *le);
int nn_lat_estim_log (logcat_t logcat, const char *tag, const struct nn_lat_estim *le);
#if defined (__cplusplus)
}
#endif
#endif /* NN_LAT_ESTIM_H */

View file

@ -0,0 +1,42 @@
/*
* 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 Q_LEASE_H
#define Q_LEASE_H
#include "ddsi/q_time.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct receiver_state;
struct participant;
struct lease;
struct entity_common;
struct thread_state1;
void lease_management_init (void);
void lease_management_term (void);
struct lease *lease_new (nn_etime_t texpire, int64_t tdur, struct entity_common *e);
void lease_register (struct lease *l);
void lease_free (struct lease *l);
void lease_renew (struct lease *l, nn_etime_t tnow);
void lease_set_expiry (struct lease *l, nn_etime_t when);
void check_and_handle_lease_expiration (struct thread_state1 *self, nn_etime_t tnow);
void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len);
#if defined (__cplusplus)
}
#endif
#endif /* Q_LEASE_H */

View file

@ -0,0 +1,85 @@
/*
* 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 NN_LOG_H
#define NN_LOG_H
#include <stdarg.h>
#include "os/os.h"
#include "ddsi/q_time.h"
#if defined (__cplusplus)
extern "C" {
#endif
#define LC_FATAL 1u
#define LC_ERROR 2u
#define LC_WARNING 4u
#define LC_CONFIG 8u
#define LC_INFO 16u
#define LC_DISCOVERY 32u
#define LC_DATA 64u
#define LC_TRACE 128u
#define LC_RADMIN 256u
#define LC_TIMING 512u
#define LC_TRAFFIC 1024u
#define LC_TOPIC 2048u
#define LC_TCP 4096u
#define LC_PLIST 8192u
#define LC_WHC 16384u
#define LC_THROTTLE 32768u
#define LC_ALLCATS (LC_FATAL | LC_ERROR | LC_WARNING | LC_CONFIG | LC_INFO | LC_DISCOVERY | LC_DATA | LC_TRACE | LC_TIMING | LC_TRAFFIC | LC_TCP | LC_THROTTLE)
typedef unsigned logcat_t;
typedef struct logbuf {
char buf[2048];
size_t bufsz;
size_t pos;
nn_wctime_t tstamp;
} *logbuf_t;
logbuf_t logbuf_new (void);
void logbuf_init (logbuf_t lb);
void logbuf_free (logbuf_t lb);
int nn_vlog (logcat_t cat, const char *fmt, va_list ap);
OSAPI_EXPORT int nn_log (_In_ logcat_t cat, _In_z_ _Printf_format_string_ const char *fmt, ...) __attribute_format__((printf,2,3));
OSAPI_EXPORT int nn_trace (_In_z_ _Printf_format_string_ const char *fmt, ...) __attribute_format__((printf,1,2));
void nn_log_set_tstamp (nn_wctime_t tnow);
#define TRACE(args) ((config.enabled_logcats & LC_TRACE) ? (nn_trace args) : 0)
#define LOG_THREAD_CPUTIME(guard) do { \
if (config.enabled_logcats & LC_TIMING) \
{ \
nn_mtime_t tnowlt = now_mt (); \
if (tnowlt.v >= (guard).v) \
{ \
int64_t ts = get_thread_cputime (); \
nn_log (LC_TIMING, "thread_cputime %d.%09d\n", \
(int) (ts / T_SECOND), (int) (ts % T_SECOND)); \
(guard).v = tnowlt.v + T_SECOND; \
} \
} \
} while (0)
#define NN_WARNING(fmt,...) nn_log (LC_WARNING, ("<Warning> " fmt),##__VA_ARGS__)
#define NN_ERROR(fmt,...) nn_log (LC_ERROR, ("<Error> " fmt),##__VA_ARGS__)
#define NN_FATAL(fmt,...) nn_log (LC_FATAL, ("<Fatal> " fmt),##__VA_ARGS__)
#if defined (__cplusplus)
}
#endif
#endif /* NN_LOG_H */

View file

@ -0,0 +1,48 @@
/*
* 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 NN_MISC_H
#define NN_MISC_H
#include "ddsi/q_protocol.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct v_gid_s;
struct nn_guid;
int vendor_is_opensplice (nn_vendorid_t vid);
int vendor_is_rti (nn_vendorid_t vendor);
int vendor_is_twinoaks (nn_vendorid_t vendor);
int vendor_is_prismtech (nn_vendorid_t vendor);
int vendor_is_cloud (nn_vendorid_t vendor);
int is_own_vendor (nn_vendorid_t vendor);
unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr, int datafrag_as_data);
seqno_t fromSN (const nn_sequence_number_t sn);
nn_sequence_number_t toSN (seqno_t);
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
int WildcardOverlap(char * p1, char * p2);
#endif
int ddsi2_patmatch (const char *pat, const char *str);
uint32_t crc32_calc (const void *buf, uint32_t length);
#if defined (__cplusplus)
}
#endif
#endif /* NN_MISC_H */

View file

@ -0,0 +1,62 @@
/*
* 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 Q_NWIF_H
#define Q_NWIF_H
#include "os/os_socket.h"
#include "ddsi/q_protocol.h" /* for nn_locator_t */
#if defined (__cplusplus)
extern "C" {
#endif
#define INET6_ADDRSTRLEN_EXTENDED (INET6_ADDRSTRLEN + 8) /* 13: '[' + ']' + ':' + PORT */
#define MAX_INTERFACES 128
struct nn_interface {
os_sockaddr_storage addr;
os_sockaddr_storage netmask;
unsigned if_index;
unsigned mc_capable: 1;
unsigned point_to_point: 1;
char *name;
};
struct nn_group_membership;
void nn_loc_to_address (os_sockaddr_storage *dst, const nn_locator_t *src);
void nn_address_to_loc (nn_locator_t *dst, const os_sockaddr_storage *src, int32_t kind);
char *sockaddr_to_string_no_port (char addrbuf[INET6_ADDRSTRLEN_EXTENDED], const os_sockaddr_storage *src);
char *sockaddr_to_string_with_port (char addrbuf[INET6_ADDRSTRLEN_EXTENDED], const os_sockaddr_storage *src);
char *locator_to_string_no_port (char addrbuf[INET6_ADDRSTRLEN_EXTENDED], const nn_locator_t *loc);
char *locator_to_string_with_port (char addrbuf[INET6_ADDRSTRLEN_EXTENDED], const nn_locator_t *loc);
void print_sockerror (const char *msg);
int make_socket (os_socket *socket, unsigned short port, bool stream, bool reuse);
int find_own_ip (const char *requested_address);
unsigned short get_socket_port (os_socket socket);
struct nn_group_membership *new_group_membership (void);
void free_group_membership (struct nn_group_membership *mship);
int join_mcgroups (struct nn_group_membership *mship, os_socket socket, const os_sockaddr_storage *srcip, const os_sockaddr_storage *mcip);
int leave_mcgroups (struct nn_group_membership *mship, os_socket socket, const os_sockaddr_storage *srcip, const os_sockaddr_storage *mcip);
void sockaddr_set_port (os_sockaddr_storage *addr, unsigned short port);
unsigned short sockaddr_get_port (const os_sockaddr_storage *addr);
unsigned sockaddr_to_hopefully_unique_uint32 (const os_sockaddr_storage *src);
#if defined (__cplusplus)
}
#endif
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
void set_socket_diffserv (os_socket sock, int diffserv);
#endif
#endif /* Q_NWIF_H */

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 Q_PCAP_H
#define Q_PCAP_H
#include <stdio.h>
#include "ddsi/q_time.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct msghdr;
FILE * new_pcap_file (const char *name);
void write_pcap_received
(
FILE * fp,
nn_wctime_t tstamp,
const os_sockaddr_storage * src,
const os_sockaddr_storage * dst,
unsigned char * buf,
size_t sz
);
void write_pcap_sent
(
FILE * fp,
nn_wctime_t tstamp,
const os_sockaddr_storage * src,
const struct msghdr * hdr,
size_t sz
);
#if defined (__cplusplus)
}
#endif
#endif /* Q_PCAP_H */

View file

@ -0,0 +1,241 @@
/*
* 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 NN_PLIST_H
#define NN_PLIST_H
#include "ddsi/q_feature_check.h"
#include "ddsi/q_xqos.h"
#if defined (__cplusplus)
extern "C" {
#endif
#define PP_PROTOCOL_VERSION ((uint64_t)1 << 0)
#define PP_VENDORID ((uint64_t)1 << 1)
#define PP_UNICAST_LOCATOR ((uint64_t)1 << 2)
#define PP_MULTICAST_LOCATOR ((uint64_t)1 << 3)
#define PP_DEFAULT_UNICAST_LOCATOR ((uint64_t)1 << 4)
#define PP_DEFAULT_MULTICAST_LOCATOR ((uint64_t)1 << 5)
#define PP_METATRAFFIC_UNICAST_LOCATOR ((uint64_t)1 << 6)
#define PP_METATRAFFIC_MULTICAST_LOCATOR ((uint64_t)1 << 7)
#define PP_EXPECTS_INLINE_QOS ((uint64_t)1 << 8)
#define PP_PARTICIPANT_MANUAL_LIVELINESS_COUNT ((uint64_t)1 << 9)
#define PP_PARTICIPANT_BUILTIN_ENDPOINTS ((uint64_t)1 << 10)
#define PP_PARTICIPANT_LEASE_DURATION ((uint64_t)1 << 11)
#define PP_CONTENT_FILTER_PROPERTY ((uint64_t)1 << 12)
#define PP_PARTICIPANT_GUID ((uint64_t)1 << 13)
#define PP_PARTICIPANT_ENTITYID ((uint64_t)1 << 14)
#define PP_GROUP_GUID ((uint64_t)1 << 15)
#define PP_GROUP_ENTITYID ((uint64_t)1 << 16)
#define PP_BUILTIN_ENDPOINT_SET ((uint64_t)1 << 17)
#define PP_PROPERTIES ((uint64_t)1 << 18)
#define PP_TYPE_MAX_SIZE_SERIALIZED ((uint64_t)1 << 19)
#define PP_ENTITY_NAME ((uint64_t)1 << 20)
#define PP_KEYHASH ((uint64_t)1 << 21)
#define PP_STATUSINFO ((uint64_t)1 << 22)
#define PP_ORIGINAL_WRITER_INFO ((uint64_t)1 << 23)
#define PP_ENDPOINT_GUID ((uint64_t)1 << 24)
#define PP_PRISMTECH_WRITER_INFO ((uint64_t)1 << 25)
#define PP_PRISMTECH_PARTICIPANT_VERSION_INFO ((uint64_t)1 << 26)
#define PP_PRISMTECH_NODE_NAME ((uint64_t)1 << 27)
#define PP_PRISMTECH_EXEC_NAME ((uint64_t)1 << 28)
#define PP_PRISMTECH_PROCESS_ID ((uint64_t)1 << 29)
#define PP_PRISMTECH_SERVICE_TYPE ((uint64_t)1 << 30)
#define PP_PRISMTECH_WATCHDOG_SCHEDULING ((uint64_t)1 << 31)
#define PP_PRISMTECH_LISTENER_SCHEDULING ((uint64_t)1 << 32)
#define PP_PRISMTECH_BUILTIN_ENDPOINT_SET ((uint64_t)1 << 33)
#define PP_PRISMTECH_TYPE_DESCRIPTION ((uint64_t)1 << 34)
#define PP_COHERENT_SET ((uint64_t)1 << 37)
#define PP_PRISMTECH_EOTINFO ((uint64_t)1 << 38)
#ifdef DDSI_INCLUDE_SSM
#define PP_READER_FAVOURS_SSM ((uint64_t)1 << 39)
#endif
#define PP_RTI_TYPECODE ((uint64_t)1 << 40)
/* Security extensions. */
#define PP_IDENTITY_TOKEN ((uint64_t)1 << 41)
#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 42)
/* Set for unrecognized parameters that are in the reserved space or
in our own vendor-specific space that have the
PID_UNRECOGNIZED_INCOMPATIBLE_FLAG set (see DDSI 2.1 9.6.2.2.1) */
#define PP_INCOMPATIBLE ((uint64_t)1 << 63)
#define NN_PRISMTECH_PARTICIPANT_VERSION_INFO_FIXED_CDRSIZE (24)
#define NN_PRISMTECH_FL_KERNEL_SEQUENCE_NUMBER (1u << 0)
#define NN_PRISMTECH_FL_DISCOVERY_INCLUDES_GID (1u << 1)
#define NN_PRISMTECH_FL_PTBES_FIXED_0 (1u << 2)
#define NN_PRISMTECH_FL_DDSI2_PARTICIPANT_FLAG (1u << 3)
#define NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2 (1u << 4)
#define NN_PRISMTECH_FL_MINIMAL_BES_MODE (1u << 5)
#define NN_PRISMTECH_FL_SUPPORTS_STATUSINFOX (1u << 5)
/* SUPPORTS_STATUSINFOX: when set, also means any combination of
write/unregister/dispose supported */
/* For locators one could patch the received message data to create
singly-linked lists (parameter header -> offset of next entry in
list relative to current), allowing aliasing of the data. But that
requires modifying the data. For string sequences the length does
the same thing. */
struct nn_locators_one {
struct nn_locators_one *next;
nn_locator_t loc;
};
typedef struct nn_locators {
int n;
struct nn_locators_one *first;
struct nn_locators_one *last;
} nn_locators_t;
typedef unsigned nn_ipv4address_t;
typedef unsigned nn_port_t;
typedef struct nn_keyhash {
unsigned char value[16];
} nn_keyhash_t;
#ifdef DDSI_INCLUDE_SSM
typedef struct nn_reader_favours_ssm {
unsigned state; /* default is false */
} nn_reader_favours_ssm_t;
#endif
typedef struct nn_dataholder
{
char *class_id;
nn_propertyseq_t properties;
nn_binarypropertyseq_t binary_properties;
} nn_dataholder_t;
typedef nn_dataholder_t nn_token_t;
typedef struct nn_prismtech_participant_version_info
{
unsigned version;
unsigned flags;
unsigned unused[3];
char *internals;
} nn_prismtech_participant_version_info_t;
typedef struct nn_prismtech_eotgroup_tid {
nn_entityid_t writer_entityid;
uint32_t transactionId;
} nn_prismtech_eotgroup_tid_t;
typedef struct nn_prismtech_eotinfo {
uint32_t transactionId;
uint32_t n;
nn_prismtech_eotgroup_tid_t *tids;
} nn_prismtech_eotinfo_t;
typedef struct nn_plist {
uint64_t present;
uint64_t aliased;
int unalias_needs_bswap;
nn_xqos_t qos;
nn_protocol_version_t protocol_version;
nn_vendorid_t vendorid;
nn_locators_t unicast_locators;
nn_locators_t multicast_locators;
nn_locators_t default_unicast_locators;
nn_locators_t default_multicast_locators;
nn_locators_t metatraffic_unicast_locators;
nn_locators_t metatraffic_multicast_locators;
unsigned char expects_inline_qos;
nn_count_t participant_manual_liveliness_count;
unsigned participant_builtin_endpoints;
nn_duration_t participant_lease_duration;
/* nn_content_filter_property_t content_filter_property; */
nn_guid_t participant_guid;
nn_guid_t endpoint_guid;
nn_guid_t group_guid;
#if 0 /* reserved, rather than NIY */
nn_entityid_t participant_entityid;
nn_entityid_t group_entityid;
#endif
unsigned builtin_endpoint_set;
unsigned prismtech_builtin_endpoint_set;
/* int type_max_size_serialized; */
char *entity_name;
nn_keyhash_t keyhash;
unsigned statusinfo;
nn_prismtech_participant_version_info_t prismtech_participant_version_info;
char *node_name;
char *exec_name;
unsigned char is_service;
unsigned service_type;
unsigned process_id;
char *type_description;
nn_sequence_number_t coherent_set_seqno;
nn_prismtech_eotinfo_t eotinfo;
nn_token_t identity_token;
nn_token_t permissions_token;
#ifdef DDSI_INCLUDE_SSM
nn_reader_favours_ssm_t reader_favours_ssm;
#endif
} nn_plist_t;
/***/
typedef struct nn_plist_src {
nn_protocol_version_t protocol_version;
nn_vendorid_t vendorid;
int encoding;
unsigned char *buf;
size_t bufsz;
} nn_plist_src_t;
void nn_plist_init_empty (nn_plist_t *dest);
void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b);
void nn_plist_copy (nn_plist_t *dst, const nn_plist_t *src);
nn_plist_t *nn_plist_dup (const nn_plist_t *src);
int nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uint64_t pwanted, uint64_t qwanted, const nn_plist_src_t *src);
void nn_plist_fini (nn_plist_t *ps);
void nn_plist_addtomsg (struct nn_xmsg *m, const nn_plist_t *ps, uint64_t pwanted, uint64_t qwanted);
int nn_plist_init_default_participant (nn_plist_t *plist);
int validate_history_qospolicy (const nn_history_qospolicy_t *q);
int validate_durability_qospolicy (const nn_durability_qospolicy_t *q);
int validate_resource_limits_qospolicy (const nn_resource_limits_qospolicy_t *q);
int validate_history_and_resource_limits (const nn_history_qospolicy_t *qh, const nn_resource_limits_qospolicy_t *qr);
int validate_durability_service_qospolicy (const nn_durability_service_qospolicy_t *q);
int validate_liveliness_qospolicy (const nn_liveliness_qospolicy_t *q);
int validate_destination_order_qospolicy (const nn_destination_order_qospolicy_t *q);
int validate_ownership_qospolicy (const nn_ownership_qospolicy_t *q);
int validate_ownership_strength_qospolicy (const nn_ownership_strength_qospolicy_t *q);
int validate_presentation_qospolicy (const nn_presentation_qospolicy_t *q);
int validate_transport_priority_qospolicy (const nn_transport_priority_qospolicy_t *q);
int validate_reader_data_lifecycle (const nn_reader_data_lifecycle_qospolicy_t *q);
int validate_duration (const nn_duration_t *d);
struct nn_rmsg;
struct nn_rsample_info;
struct nn_rdata;
unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const nn_plist_src_t *src);
#if defined (__cplusplus)
}
#endif
#endif /* NN_PLIST_H */

View file

@ -0,0 +1,484 @@
/*
* 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 NN_PROTOCOL_H
#define NN_PROTOCOL_H
#include "os/os.h"
#include "ddsi/q_feature_check.h"
#if OS_ENDIANNESS == OS_LITTLE_ENDIAN
#define PLATFORM_IS_LITTLE_ENDIAN 1
#else
#define PLATFORM_IS_LITTLE_ENDIAN 0
#endif
#include "ddsi/q_rtps.h"
#include "ddsi/q_time.h"
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct {
unsigned char id[4];
} nn_protocolid_t;
typedef struct {
int high;
unsigned low;
} nn_sequence_number_t;
#define NN_SEQUENCE_NUMBER_UNKNOWN_HIGH -1
#define NN_SEQUENCE_NUMBER_UNKNOWN_LOW 0
#define NN_SEQUENCE_NUMBER_UNKNOWN ((seqno_t) (((uint64_t)NN_SEQUENCE_NUMBER_UNKNOWN_HIGH << 32) | NN_SEQUENCE_NUMBER_UNKNOWN_LOW))
typedef struct nn_sequence_number_set {
nn_sequence_number_t bitmap_base;
unsigned numbits;
unsigned bits[1];
} nn_sequence_number_set_t; /* Why strict C90? zero-length/flexible array members are far nicer */
/* SequenceNumberSet size is base (2 words) + numbits (1 word) +
bitmap ((numbits+31)/32 words), and this at 4 bytes/word */
#define NN_SEQUENCE_NUMBER_SET_BITS_SIZE(numbits) ((unsigned) (4 * (((numbits) + 31) / 32)))
#define NN_SEQUENCE_NUMBER_SET_SIZE(numbits) (offsetof (nn_sequence_number_set_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits))
typedef unsigned nn_fragment_number_t;
typedef struct nn_fragment_number_set {
nn_fragment_number_t bitmap_base;
unsigned numbits;
unsigned bits[1];
} nn_fragment_number_set_t;
/* FragmentNumberSet size is base (2 words) + numbits (1 word) +
bitmap ((numbits+31)/32 words), and this at 4 bytes/word */
#define NN_FRAGMENT_NUMBER_SET_BITS_SIZE(numbits) ((unsigned) (4 * (((numbits) + 31) / 32)))
#define NN_FRAGMENT_NUMBER_SET_SIZE(numbits) (offsetof (nn_fragment_number_set_t, bits) + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (numbits))
typedef int nn_count_t;
#define DDSI_COUNT_MIN (-2147483647 - 1)
#define DDSI_COUNT_MAX (2147483647)
/* address field in locator maintained in network byte order, the rest
in host (yes: that's a FIXME) */
typedef struct {
int32_t kind;
unsigned port;
unsigned char address[16];
} nn_locator_t;
typedef struct nn_udpv4mcgen_address {
/* base IPv4 MC address is ipv4, host bits are bits base .. base+count-1, this machine is bit idx */
struct in_addr ipv4;
unsigned char base;
unsigned char count;
unsigned char idx; /* must be last: then sorting will put them consecutively */
} nn_udpv4mcgen_address_t;
struct cdrstring {
unsigned length;
unsigned char contents[1]; /* C90 does not support flex. array members */
};
#define NN_STATUSINFO_DISPOSE 0x1u
#define NN_STATUSINFO_UNREGISTER 0x2u
#define NN_STATUSINFO_STANDARDIZED (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)
#define NN_STATUSINFO_OSPL_AUTO 0x10000000u /* OSPL extension, not on the wire */
#define NN_STATUSINFOX_OSPL_AUTO 0x1 /* statusinfo word 2, OSPL L_AUTO flag on the wire */
#define NN_GUID_PREFIX_UNKNOWN_INITIALIZER {{0,0,0,0, 0,0,0,0, 0,0,0,0}}
#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER (1u << 0)
#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR (1u << 1)
#define NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER (1u << 2)
#define NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_DETECTOR (1u << 3)
#define NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER (1u << 4)
#define NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_DETECTOR (1u << 5)
#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_PROXY_ANNOUNCER (1u << 6) /* undefined meaning */
#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_PROXY_DETECTOR (1u << 7) /* undefined meaning */
#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_STATE_ANNOUNCER (1u << 8) /* undefined meaning */
#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_STATE_DETECTOR (1u << 9) /* undefined meaning */
#define NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER (1u << 10)
#define NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER (1u << 11)
#define NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER (1u << 12)
#define NN_DISC_BUILTIN_ENDPOINT_TOPIC_DETECTOR (1u << 13)
/* PrismTech extensions: */
#define NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER (1u << 0)
#define NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_READER (1u << 1)
#define NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER (1u << 2)
#define NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_READER (1u << 3)
#define NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER (1u << 4)
#define NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_READER (1u << 5)
#define NN_LOCATOR_KIND_INVALID -1
#define NN_LOCATOR_KIND_RESERVED 0
#define NN_LOCATOR_KIND_UDPv4 1
#define NN_LOCATOR_KIND_UDPv6 2
#define NN_LOCATOR_KIND_TCPv4 4
#define NN_LOCATOR_KIND_TCPv6 8
#define NN_LOCATOR_KIND_UDPv4MCGEN 0x4fff0000
#define NN_LOCATOR_PORT_INVALID 0
#define NN_VENDORID_UNKNOWN {{ 0x00, 0x00 }}
#define NN_VENDORID_RTI {{ 0x01, 0x01 }}
#define NN_VENDORID_PRISMTECH_OSPL {{ 0x01, 0x02 }}
#define NN_VENDORID_OCI {{ 0x01, 0x03 }}
#define NN_VENDORID_MILSOFT {{ 0x01, 0x04 }}
#define NN_VENDORID_KONGSBERG {{ 0x01, 0x05 }}
#define NN_VENDORID_TWINOAKS {{ 0x01, 0x06 }}
#define NN_VENDORID_LAKOTA {{ 0x01, 0x07 }}
#define NN_VENDORID_ICOUP {{ 0x01, 0x08 }}
#define NN_VENDORID_ETRI {{ 0x01, 0x09 }}
#define NN_VENDORID_RTI_MICRO {{ 0x01, 0x0a }}
#define NN_VENDORID_PRISMTECH_JAVA {{ 0x01, 0x0b }}
#define NN_VENDORID_PRISMTECH_GATEWAY {{ 0x01, 0x0c }}
#define NN_VENDORID_PRISMTECH_LITE {{ 0x01, 0x0d }}
#define NN_VENDORID_TECHNICOLOR {{ 0x01, 0x0e }}
#define NN_VENDORID_EPROSIMA {{ 0x01, 0x0f }}
#define NN_VENDORID_PRISMTECH_CLOUD {{ 0x01, 0x20 }}
#define NN_VENDORID_ECLIPSE_CYCLONEDDS {{ 0x01, 0x0d }} // Since CYCLONEDDS has no owner yet, it uses the same VENDORID as LITE
#define MY_VENDOR_ID NN_VENDORID_ECLIPSE_CYCLONEDDS
/* Only one specific version is grokked */
#define RTPS_MAJOR 2
#define RTPS_MINOR 1
typedef struct Header {
nn_protocolid_t protocol;
nn_protocol_version_t version;
nn_vendorid_t vendorid;
nn_guid_prefix_t guid_prefix;
} Header_t;
#define NN_PROTOCOLID_INITIALIZER {{ 'R','T','P','S' }}
#define NN_PROTOCOL_VERSION_INITIALIZER { RTPS_MAJOR, RTPS_MINOR }
#define NN_VENDORID_INITIALIER MY_VENDOR_ID
#define NN_HEADER_INITIALIZER { NN_PROTOCOLID_INITIALIZER, NN_PROTOCOL_VERSION_INITIALIZER, NN_VENDORID_INITIALIER, NN_GUID_PREFIX_UNKNOWN_INITIALIZER }
#define RTPS_MESSAGE_HEADER_SIZE (sizeof (Header_t))
typedef struct SubmessageHeader {
unsigned char submessageId;
unsigned char flags;
unsigned short octetsToNextHeader;
} SubmessageHeader_t;
#define RTPS_SUBMESSAGE_HEADER_SIZE (sizeof (SubmessageHeader_t))
#define SMFLAG_ENDIANNESS 0x01u
typedef enum SubmessageKind {
SMID_PAD = 0x01,
SMID_ACKNACK = 0x06,
SMID_HEARTBEAT = 0x07,
SMID_GAP = 0x08,
SMID_INFO_TS = 0x09,
SMID_INFO_SRC = 0x0c,
SMID_INFO_REPLY_IP4 = 0x0d,
SMID_INFO_DST = 0x0e,
SMID_INFO_REPLY = 0x0f,
SMID_NACK_FRAG = 0x12,
SMID_HEARTBEAT_FRAG = 0x13,
SMID_DATA = 0x15,
SMID_DATA_FRAG = 0x16,
/* vendor-specific sub messages (0x80 .. 0xff) */
SMID_PT_INFO_CONTAINER = 0x80,
SMID_PT_MSG_LEN = 0x81,
SMID_PT_ENTITY_ID = 0x82
} SubmessageKind_t;
typedef struct InfoTimestamp {
SubmessageHeader_t smhdr;
nn_ddsi_time_t time;
} InfoTimestamp_t;
typedef struct EntityId {
SubmessageHeader_t smhdr;
nn_entityid_t entityid;
} EntityId_t;
typedef struct InfoDST {
SubmessageHeader_t smhdr;
nn_guid_prefix_t guid_prefix;
} InfoDST_t;
typedef struct InfoSRC {
SubmessageHeader_t smhdr;
unsigned unused;
nn_protocol_version_t version;
nn_vendorid_t vendorid;
nn_guid_prefix_t guid_prefix;
} InfoSRC_t;
#if PLATFORM_IS_LITTLE_ENDIAN
#define PL_CDR_BE 0x0200u
#define PL_CDR_LE 0x0300u
#else
#define PL_CDR_BE 0x0002u
#define PL_CDR_LE 0x0003u
#endif
typedef unsigned short nn_parameterid_t; /* spec says short */
typedef struct nn_parameter {
nn_parameterid_t parameterid;
unsigned short length; /* spec says short */
/* char value[]; O! how I long for C99 */
} nn_parameter_t;
typedef struct Data_DataFrag_common {
SubmessageHeader_t smhdr;
unsigned short extraFlags;
unsigned short octetsToInlineQos;
nn_entityid_t readerId;
nn_entityid_t writerId;
nn_sequence_number_t writerSN;
} Data_DataFrag_common_t;
typedef struct Data {
Data_DataFrag_common_t x;
} Data_t;
#define DATA_FLAG_INLINE_QOS 0x02u
#define DATA_FLAG_DATAFLAG 0x04u
#define DATA_FLAG_KEYFLAG 0x08u
typedef struct DataFrag {
Data_DataFrag_common_t x;
nn_fragment_number_t fragmentStartingNum;
unsigned short fragmentsInSubmessage;
unsigned short fragmentSize;
unsigned sampleSize;
} DataFrag_t;
#define DATAFRAG_FLAG_INLINE_QOS 0x02u
#define DATAFRAG_FLAG_KEYFLAG 0x04u
typedef struct MsgLen {
SubmessageHeader_t smhdr;
uint32_t length;
} MsgLen_t;
typedef struct AckNack {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
nn_sequence_number_set_t readerSNState;
/* nn_count_t count; */
} AckNack_t;
#define ACKNACK_FLAG_FINAL 0x02u
#define ACKNACK_SIZE(numbits) (offsetof (AckNack_t, readerSNState) + NN_SEQUENCE_NUMBER_SET_SIZE (numbits) + 4)
#define ACKNACK_SIZE_MAX ACKNACK_SIZE (256u)
typedef struct Gap {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
nn_sequence_number_t gapStart;
nn_sequence_number_set_t gapList;
} Gap_t;
#define GAP_SIZE(numbits) (offsetof (Gap_t, gapList) + NN_SEQUENCE_NUMBER_SET_SIZE (numbits))
#define GAP_SIZE_MAX GAP_SIZE (256u)
typedef struct InfoTS {
SubmessageHeader_t smhdr;
nn_ddsi_time_t time;
} InfoTS_t;
#define INFOTS_INVALIDATE_FLAG 0x2u
typedef struct Heartbeat {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
nn_sequence_number_t firstSN;
nn_sequence_number_t lastSN;
nn_count_t count;
} Heartbeat_t;
#define HEARTBEAT_FLAG_FINAL 0x02u
#define HEARTBEAT_FLAG_LIVELINESS 0x04u
typedef struct HeartbeatFrag {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
nn_sequence_number_t writerSN;
nn_fragment_number_t lastFragmentNum;
nn_count_t count;
} HeartbeatFrag_t;
typedef struct NackFrag {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
nn_sequence_number_t writerSN;
nn_fragment_number_set_t fragmentNumberState;
/* nn_count_t count; */
} NackFrag_t;
#define NACKFRAG_SIZE(numbits) (offsetof (NackFrag_t, fragmentNumberState) + NN_FRAGMENT_NUMBER_SET_SIZE (numbits) + 4)
#define NACKFRAG_SIZE_MAX NACKFRAG_SIZE (256u)
typedef struct PT_InfoContainer {
SubmessageHeader_t smhdr;
uint32_t id;
} PT_InfoContainer_t;
#define PTINFO_ID_ENCRYPT (0x01u)
typedef union Submessage {
SubmessageHeader_t smhdr;
AckNack_t acknack;
Data_t data;
DataFrag_t datafrag;
InfoTS_t infots;
InfoDST_t infodst;
InfoSRC_t infosrc;
Heartbeat_t heartbeat;
HeartbeatFrag_t heartbeatfrag;
Gap_t gap;
NackFrag_t nackfrag;
PT_InfoContainer_t pt_infocontainer;
} Submessage_t;
typedef struct ParticipantMessageData {
nn_guid_prefix_t participantGuidPrefix;
unsigned kind; /* really 4 octets */
unsigned length;
char value[1 /* length */];
} ParticipantMessageData_t;
#define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN 0x0u
#define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE 0x1u
#define PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE 0x2u
#define PARTICIPANT_MESSAGE_DATA_VENDER_SPECIFIC_KIND_FLAG 0x8000000u
#define PID_VENDORSPECIFIC_FLAG 0x8000u
#define PID_UNRECOGNIZED_INCOMPATIBLE_FLAG 0x4000u
#define PID_PAD 0x0u
#define PID_SENTINEL 0x1u
#define PID_USER_DATA 0x2cu
#define PID_TOPIC_NAME 0x5u
#define PID_TYPE_NAME 0x7u
#define PID_GROUP_DATA 0x2du
#define PID_TOPIC_DATA 0x2eu
#define PID_DURABILITY 0x1du
#define PID_DURABILITY_SERVICE 0x1eu
#define PID_DEADLINE 0x23u
#define PID_LATENCY_BUDGET 0x27u
#define PID_LIVELINESS 0x1bu
#define PID_RELIABILITY 0x1au
#define PID_LIFESPAN 0x2bu
#define PID_DESTINATION_ORDER 0x25u
#define PID_HISTORY 0x40u
#define PID_RESOURCE_LIMITS 0x41u
#define PID_OWNERSHIP 0x1fu
#define PID_OWNERSHIP_STRENGTH 0x6u
#define PID_PRESENTATION 0x21u
#define PID_PARTITION 0x29u
#define PID_TIME_BASED_FILTER 0x4u
#define PID_TRANSPORT_PRIORITY 0x49u
#define PID_PROTOCOL_VERSION 0x15u
#define PID_VENDORID 0x16u
#define PID_UNICAST_LOCATOR 0x2fu
#define PID_MULTICAST_LOCATOR 0x30u
#define PID_MULTICAST_IPADDRESS 0x11u
#define PID_DEFAULT_UNICAST_LOCATOR 0x31u
#define PID_DEFAULT_MULTICAST_LOCATOR 0x48u
#define PID_METATRAFFIC_UNICAST_LOCATOR 0x32u
#define PID_METATRAFFIC_MULTICAST_LOCATOR 0x33u
#define PID_DEFAULT_UNICAST_IPADDRESS 0xcu
#define PID_DEFAULT_UNICAST_PORT 0xeu
#define PID_METATRAFFIC_UNICAST_IPADDRESS 0x45u
#define PID_METATRAFFIC_UNICAST_PORT 0xdu
#define PID_METATRAFFIC_MULTICAST_IPADDRESS 0xbu
#define PID_METATRAFFIC_MULTICAST_PORT 0x46u
#define PID_EXPECTS_INLINE_QOS 0x43u
#define PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT 0x34u
#define PID_PARTICIPANT_BUILTIN_ENDPOINTS 0x44u
#define PID_PARTICIPANT_LEASE_DURATION 0x2u
#define PID_CONTENT_FILTER_PROPERTY 0x35u
#define PID_PARTICIPANT_GUID 0x50u
#define PID_PARTICIPANT_ENTITYID 0x51u
#define PID_GROUP_GUID 0x52u
#define PID_GROUP_ENTITYID 0x53u
#define PID_BUILTIN_ENDPOINT_SET 0x58u
#define PID_PROPERTY_LIST 0x59u
#define PID_TYPE_MAX_SIZE_SERIALIZED 0x60u
#define PID_ENTITY_NAME 0x62u
#define PID_KEYHASH 0x70u
#define PID_STATUSINFO 0x71u
#define PID_CONTENT_FILTER_INFO 0x55u
#define PID_COHERENT_SET 0x56u
#define PID_DIRECTED_WRITE 0x57u
#define PID_ORIGINAL_WRITER_INFO 0x61u
#define PID_ENDPOINT_GUID 0x5au /* !SPEC <=> PRISMTECH_ENDPOINT_GUID */
/* Security related PID values. */
#define PID_IDENTITY_TOKEN 0x1001u
#define PID_PERMISSIONS_TOKEN 0x1002u
#define PID_RTI_TYPECODE (PID_VENDORSPECIFIC_FLAG | 0x4u)
#ifdef DDSI_INCLUDE_SSM
/* To indicate whether a reader favours the use of SSM. Iff the
reader favours SSM, it will use SSM if available. */
#define PID_READER_FAVOURS_SSM 0x72u
#endif
#ifdef DDSI_INCLUDE_SSM
/* To indicate whether a reader favours the use of SSM. Iff the
reader favours SSM, it will use SSM if available. */
#define PID_READER_FAVOURS_SSM 0x72u
#endif
/* Deprecated parameter IDs (accepted but ignored) */
#define PID_PERSISTENCE 0x03u
#define PID_TYPE_CHECKSUM 0x08u
#define PID_TYPE2_NAME 0x09u
#define PID_TYPE2_CHECKSUM 0x0au
#define PID_EXPECTS_ACK 0x10u
#define PID_MANAGER_KEY 0x12u
#define PID_SEND_QUEUE_SIZE 0x13u
#define PID_RELIABILITY_ENABLED 0x14u
#define PID_VARGAPPS_SEQUENCE_NUMBER_LAST 0x17u
#define PID_RECV_QUEUE_SIZE 0x18u
#define PID_RELIABILITY_OFFERED 0x19u
#define PID_PRISMTECH_BUILTIN_ENDPOINT_SET (PID_VENDORSPECIFIC_FLAG | 0x0u)
/* parameter ids for READER_DATA_LIFECYCLE & WRITER_DATA_LIFECYCLE are
undefined, but let's publish them anyway */
#define PID_PRISMTECH_READER_DATA_LIFECYCLE (PID_VENDORSPECIFIC_FLAG | 0x2u)
#define PID_PRISMTECH_WRITER_DATA_LIFECYCLE (PID_VENDORSPECIFIC_FLAG | 0x3u)
/* ENDPOINT_GUID is formally undefined, so in strictly conforming
mode, we use our own */
#define PID_PRISMTECH_ENDPOINT_GUID (PID_VENDORSPECIFIC_FLAG | 0x4u)
#define PID_PRISMTECH_SYNCHRONOUS_ENDPOINT (PID_VENDORSPECIFIC_FLAG | 0x5u)
/* Relaxed QoS matching readers/writers are best ignored by
implementations that don't understand them. This also covers "old"
DDSI2's, although they may emit an error. */
#define PID_PRISMTECH_RELAXED_QOS_MATCHING (PID_VENDORSPECIFIC_FLAG | PID_UNRECOGNIZED_INCOMPATIBLE_FLAG | 0x6u)
#define PID_PRISMTECH_PARTICIPANT_VERSION_INFO (PID_VENDORSPECIFIC_FLAG | 0x7u)
/* See CMTopics protocol.doc (2013-12-09) */
#define PID_PRISMTECH_NODE_NAME (PID_VENDORSPECIFIC_FLAG | 0x8u)
#define PID_PRISMTECH_EXEC_NAME (PID_VENDORSPECIFIC_FLAG | 0x9u)
#define PID_PRISMTECH_PROCESS_ID (PID_VENDORSPECIFIC_FLAG | 0xau)
#define PID_PRISMTECH_SERVICE_TYPE (PID_VENDORSPECIFIC_FLAG | 0xbu)
#define PID_PRISMTECH_ENTITY_FACTORY (PID_VENDORSPECIFIC_FLAG | 0xcu)
#define PID_PRISMTECH_WATCHDOG_SCHEDULING (PID_VENDORSPECIFIC_FLAG | 0xdu)
#define PID_PRISMTECH_LISTENER_SCHEDULING (PID_VENDORSPECIFIC_FLAG | 0xeu)
#define PID_PRISMTECH_SUBSCRIPTION_KEYS (PID_VENDORSPECIFIC_FLAG | 0xfu)
#define PID_PRISMTECH_READER_LIFESPAN (PID_VENDORSPECIFIC_FLAG | 0x10u)
#define PID_PRISMTECH_TYPE_DESCRIPTION (PID_VENDORSPECIFIC_FLAG | 0x12u)
#define PID_PRISMTECH_LAN (PID_VENDORSPECIFIC_FLAG | 0x13u)
#define PID_PRISMTECH_ENDPOINT_GID (PID_VENDORSPECIFIC_FLAG | 0x14u)
#define PID_PRISMTECH_GROUP_GID (PID_VENDORSPECIFIC_FLAG | 0x15u)
#define PID_PRISMTECH_EOTINFO (PID_VENDORSPECIFIC_FLAG | 0x16u)
#define PID_PRISMTECH_PART_CERT_NAME (PID_VENDORSPECIFIC_FLAG | 0x17u);
#define PID_PRISMTECH_LAN_CERT_NAME (PID_VENDORSPECIFIC_FLAG | 0x18u);
#if defined (__cplusplus)
}
#endif
#endif /* NN_PROTOCOL_H */

View file

@ -0,0 +1,33 @@
/*
* 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 Q_QOSMATCH_H
#define Q_QOSMATCH_H
#if defined (__cplusplus)
extern "C" {
#endif
struct nn_xqos;
int partition_match_based_on_wildcard_in_left_operand (const struct nn_xqos *a, const struct nn_xqos *b, const char **realname);
int partitions_match_p (const struct nn_xqos *a, const struct nn_xqos *b);
int is_wildcard_partition (const char *str);
/* Returns -1 on success, or QoS id of first mismatch (>=0) */
int32_t qos_match_p (const struct nn_xqos *rd, const struct nn_xqos *wr);
#if defined (__cplusplus)
}
#endif
#endif /* Q_QOSMATCH_H */

View file

@ -0,0 +1,250 @@
/*
* 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 NN_RADMIN_H
#define NN_RADMIN_H
#include "os/os_thread.h"
#include "ddsi/q_rtps.h"
#include "ddsi/ddsi_tran.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct nn_rbufpool;
struct nn_rbuf;
struct nn_rmsg;
struct nn_rdata;
struct nn_rsample;
struct nn_rsample_chain;
struct nn_rsample_info;
struct nn_defrag;
struct nn_reorder;
struct nn_dqueue;
struct nn_guid;
struct proxy_writer;
struct nn_fragment_number_set;
struct nn_sequence_number_set;
typedef int (*nn_dqueue_handler_t) (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const struct nn_guid *rdguid, void *qarg);
struct nn_rmsg_chunk {
struct nn_rbuf *rbuf;
struct nn_rmsg_chunk *next;
/* Size is 0 after initial allocation, must be set with
nn_rmsg_setsize after receiving a packet from the kernel and
before processing it. */
uint32_t size;
union {
/* payload array stretched to whatever it really is */
unsigned char payload[1];
/* to ensure reasonable alignment of payload[] */
int64_t l;
double d;
void *p;
} u;
};
struct nn_rmsg {
/* Reference count: all references to rdatas of this message are
counted. The rdatas themselves do not have a reference count.
The refcount is biased by RMSG_REFCOUNT_UNCOMMITED_BIAS while
still being inserted to allow verifying it is still uncommitted
when allocating memory, increasing refcounts, &c.
Each rdata adds RMS_REFCOUNT_RDATA_BIAS when it leaves
defragmentation until it has been rejected by reordering or has
been scheduled for delivery. This allows delaying the
decrementing of refcounts until after a sample has been added to
all radmins even though be delivery of it may take place in
concurrently. */
os_atomic_uint32_t refcount;
/* Worst-case memory requirement is gigantic (64kB UDP packet, only
1-byte final fragments, each of one a new interval, or maybe 1
byte messages, destined for many readers and in each case
introducing a new interval, with receiver state changes in
between, &c.), so we can either:
- allocate a _lot_ and cover the worst case
- allocate enough for all "reasonable" cases, discarding data when that limit is hit
- dynamically add chunks of memory, and even entire receive buffers.
The latter seems the best approach, especially because it also
covers the second one. We treat the other chunks specially,
which is not strictly required but also not entirely
unreasonable, considering that the first chunk has the refcount &
the real packet. */
struct nn_rmsg_chunk *lastchunk;
struct nn_rmsg_chunk chunk;
};
#define NN_RMSG_PAYLOAD(m) ((m)->chunk.u.payload)
#define NN_RMSG_PAYLOADOFF(m, o) (NN_RMSG_PAYLOAD (m) + (o))
struct receiver_state {
nn_guid_prefix_t src_guid_prefix; /* 12 */
nn_guid_prefix_t dst_guid_prefix; /* 12 */
struct addrset *reply_locators; /* 4/8 */
int forme; /* 4 */
nn_vendorid_t vendor; /* 2 */
nn_protocol_version_t protocol_version; /* 2 => 44/48 */
ddsi_tran_conn_t conn; /* Connection for request */
};
struct proxy_writer_info
{
nn_guid_t guid;
bool auto_dispose;
int32_t ownership_strength;
uint64_t iid;
};
struct nn_rsample_info {
seqno_t seq;
struct receiver_state *rst;
struct proxy_writer *pwr;
uint32_t size;
uint32_t fragsize;
nn_ddsi_time_t timestamp;
nn_wctime_t reception_timestamp; /* OpenSplice extension -- but we get it essentially for free, so why not? */
unsigned statusinfo: 2; /* just the two defined bits from the status info */
unsigned pt_wr_info_zoff: 16; /* PrismTech writer info offset */
unsigned bswap: 1; /* so we can extract well formatted writer info quicker */
unsigned complex_qos: 1; /* includes QoS other than keyhash, 2-bit statusinfo, PT writer info */
unsigned hashash: 1; /* Do we have a key hash */
nn_keyhash_t keyhash; /* Key hash. Not currently used by OSPL */
struct proxy_writer_info pwr_info;
};
struct nn_rdata {
struct nn_rmsg *rmsg; /* received (and refcounted) in rmsg */
struct nn_rdata *nextfrag; /* fragment chain */
uint32_t min, maxp1; /* fragment as byte offsets */
uint16_t submsg_zoff; /* offset to submessage from packet start, or 0 */
uint16_t payload_zoff; /* offset to payload from packet start */
#ifndef NDEBUG
os_atomic_uint32_t refcount_bias_added;
#endif
};
/* All relative offsets in packets that we care about (submessage
header, payload, writer info) are at multiples of 4 bytes and
within 64kB, so technically we can make do with 14 bits instead of
16, in case we run out of space.
If we _really_ need to squeeze out every last bit, only the submsg
offset really requires 14 bits, the for the others we could use an
offset relative to the submessage header so that it is limited by
the maximum size of the inline QoS ... Defining the macros now, so
we have the option to do wild things. */
#ifndef NDEBUG
#define NN_ZOFF_TO_OFF(zoff) ((unsigned) (zoff))
#define NN_OFF_TO_ZOFF(off) (assert ((off) < 65536 && ((off) % 4) == 0), ((unsigned short) (off)))
#else
#define NN_ZOFF_TO_OFF(zoff) ((unsigned) (zoff))
#define NN_OFF_TO_ZOFF(off) ((unsigned short) (off))
#endif
#define NN_SAMPLEINFO_HAS_WRINFO(rsi) ((rsi)->pt_wr_info_zoff != NN_OFF_TO_ZOFF (0))
#define NN_SAMPLEINFO_WRINFO_OFF(rsi) NN_ZOFF_TO_OFF ((rsi)->pt_wr_info_zoff)
#define NN_RDATA_PAYLOAD_OFF(rdata) NN_ZOFF_TO_OFF ((rdata)->payload_zoff)
#define NN_RDATA_SUBMSG_OFF(rdata) NN_ZOFF_TO_OFF ((rdata)->submsg_zoff)
struct nn_rsample_chain_elem {
/* FIXME: evidently smaller than a defrag_iv, but maybe better to
merge it with defrag_iv in a union anyway. */
struct nn_rdata *fragchain;
struct nn_rsample_chain_elem *next;
/* Gaps have sampleinfo = NULL, but nonetheless a fragchain with 1
rdata with min=maxp1 (length 0) and valid rmsg pointer. And (see
DQUEUE) its lsb gets abused so we can queue "bubbles" in addition
to data). */
struct nn_rsample_info *sampleinfo;
};
struct nn_rsample_chain {
struct nn_rsample_chain_elem *first;
struct nn_rsample_chain_elem *last;
};
enum nn_reorder_mode {
NN_REORDER_MODE_NORMAL,
NN_REORDER_MODE_MONOTONICALLY_INCREASING,
NN_REORDER_MODE_ALWAYS_DELIVER
};
enum nn_defrag_drop_mode {
NN_DEFRAG_DROP_OLDEST, /* (believed to be) best for unreliable */
NN_DEFRAG_DROP_LATEST /* (...) best for reliable */
};
typedef int32_t nn_reorder_result_t;
/* typedef of reorder result serves as a warning that it is to be
interpreted as follows: */
/* REORDER_DELIVER > 0 -- number of samples in sample chain */
#define NN_REORDER_ACCEPT 0 /* accepted/stored (for gap: also adjusted next_expected) */
#define NN_REORDER_TOO_OLD -1 /* discarded because it was too old */
#define NN_REORDER_REJECT -2 /* caller may reuse memory ("real" reject for data, "fake" for gap) */
typedef void (*nn_dqueue_callback_t) (void *arg);
struct nn_rbufpool *nn_rbufpool_new (uint32_t rbuf_size, uint32_t max_rmsg_size);
void nn_rbufpool_setowner (struct nn_rbufpool *rbp, os_threadId tid);
void nn_rbufpool_free (struct nn_rbufpool *rbp);
struct nn_rmsg *nn_rmsg_new (struct nn_rbufpool *rbufpool);
void nn_rmsg_setsize (struct nn_rmsg *rmsg, uint32_t size);
void nn_rmsg_commit (struct nn_rmsg *rmsg);
void nn_rmsg_free (struct nn_rmsg *rmsg);
void *nn_rmsg_alloc (struct nn_rmsg *rmsg, uint32_t size);
struct nn_rdata *nn_rdata_new (struct nn_rmsg *rmsg, uint32_t start, uint32_t endp1, uint32_t submsg_offset, uint32_t payload_offset);
struct nn_rdata *nn_rdata_newgap (struct nn_rmsg *rmsg);
void nn_fragchain_adjust_refcount (struct nn_rdata *frag, int adjust);
void nn_fragchain_unref (struct nn_rdata *frag);
struct nn_defrag *nn_defrag_new (enum nn_defrag_drop_mode drop_mode, uint32_t max_samples);
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);
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 *map, uint32_t maxsz);
struct nn_reorder *nn_reorder_new (enum nn_reorder_mode mode, uint32_t max_samples);
void nn_reorder_free (struct nn_reorder *r);
struct nn_rsample *nn_reorder_rsample_dup (struct nn_rmsg *rmsg, struct nn_rsample *rsampleiv);
struct nn_rdata *nn_rsample_fragchain (struct nn_rsample *rsample);
nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_reorder *reorder, struct nn_rsample *rsampleiv, int *refcount_adjust, int delivery_queue_full_p);
nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reorder *reorder, struct nn_rdata *rdata, seqno_t min, seqno_t maxp1, int *refcount_adjust);
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 *map, uint32_t maxsz, int notail);
seqno_t nn_reorder_next_seq (const struct nn_reorder *reorder);
struct nn_dqueue *nn_dqueue_new (const char *name, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg);
void nn_dqueue_free (struct nn_dqueue *q);
void nn_dqueue_enqueue (struct nn_dqueue *q, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const nn_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
void nn_dqueue_enqueue_callback (struct nn_dqueue *q, nn_dqueue_callback_t cb, void *arg);
int nn_dqueue_is_full (struct nn_dqueue *q);
void nn_dqueue_wait_until_empty_if_full (struct nn_dqueue *q);
#if defined (__cplusplus)
}
#endif
#endif /* NN_RADMIN_H */

View file

@ -0,0 +1,32 @@
/*
* 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 Q_RECEIVE_H
#define Q_RECEIVE_H
#if defined (__cplusplus)
extern "C" {
#endif
struct nn_rbufpool;
struct nn_rsample_info;
struct nn_rdata;
struct ddsi_tran_listener;
uint32_t recv_thread (struct nn_rbufpool *rbpool);
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 nn_guid_t *rdguid, void *qarg);
#if defined (__cplusplus)
}
#endif
#endif /* Q_RECEIVE_H */

View file

@ -0,0 +1,90 @@
/*
* 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 NN_RTPS_H
#define NN_RTPS_H
#include "os/os_defs.h"
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct {
unsigned char id[2];
} nn_vendorid_t;
typedef struct {
unsigned char major, minor;
} nn_protocol_version_t;
typedef union nn_guid_prefix {
unsigned char s[12];
unsigned u[3];
} nn_guid_prefix_t;
typedef union nn_entityid {
unsigned u;
} nn_entityid_t;
typedef struct nn_guid {
nn_guid_prefix_t prefix;
nn_entityid_t entityid;
} nn_guid_t;
typedef int64_t seqno_t;
#define MAX_SEQ_NUMBER INT64_MAX
#define PGUIDPREFIX(gp) (gp).u[0], (gp).u[1], (gp).u[2]
#define PGUID(g) PGUIDPREFIX ((g).prefix), (g).entityid.u
/* predefined entity ids; here viewed as an unsigned int, on the
network as four bytes corresponding to the integer in network byte
order */
#define NN_ENTITYID_UNKNOWN 0x0
#define NN_ENTITYID_PARTICIPANT 0x1c1
#define NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER 0x2c2
#define NN_ENTITYID_SEDP_BUILTIN_TOPIC_READER 0x2c7
#define NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER 0x3c2
#define NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER 0x3c7
#define NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER 0x4c2
#define NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER 0x4c7
#define NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER 0x100c2
#define NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER 0x100c7
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER 0x200c2
#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER 0x200c7
#define NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER 0x142
#define NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER 0x147
#define NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER 0x242
#define NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER 0x247
#define NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER 0x342
#define NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER 0x347
#define NN_ENTITYID_SOURCE_MASK 0xc0
#define NN_ENTITYID_SOURCE_USER 0x00
#define NN_ENTITYID_SOURCE_BUILTIN 0xc0
#define NN_ENTITYID_SOURCE_VENDOR 0x40
#define NN_ENTITYID_KIND_MASK 0x3f
#define NN_ENTITYID_KIND_WRITER_WITH_KEY 0x02
#define NN_ENTITYID_KIND_WRITER_NO_KEY 0x03
#define NN_ENTITYID_KIND_READER_NO_KEY 0x04
#define NN_ENTITYID_KIND_READER_WITH_KEY 0x07
#define NN_ENTITYID_KIND_PRISMTECH_SUBSCRIBER 0x0a /* source = VENDOR */
#define NN_ENTITYID_KIND_PRISMTECH_PUBLISHER 0x0b /* source = VENDOR */
#define NN_ENTITYID_ALLOCSTEP 0x100
struct cfgst;
int rtps_config_prep (struct cfgst *cfgst);
int rtps_config_open (void);
int rtps_init (void);
void ddsi_plugin_init (void);
void rtps_term_prep (void);
void rtps_term (void);
#if defined (__cplusplus)
}
#endif
#endif /* NN_RTPS_H */

View file

@ -0,0 +1,46 @@
/*
* 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
*/
#ifdef DDSI_INCLUDE_ENCRYPTION
#ifndef Q_SECURITY_H
#define Q_SECURITY_H
#include "c_typebase.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* Generic class */
C_CLASS(q_securityEncoderSet);
C_CLASS(q_securityDecoderSet);
/* Set of supported ciphers */
typedef enum
{
Q_CIPHER_UNDEFINED,
Q_CIPHER_NULL,
Q_CIPHER_BLOWFISH,
Q_CIPHER_AES128,
Q_CIPHER_AES192,
Q_CIPHER_AES256,
Q_CIPHER_NONE,
Q_CIPHER_MAX
} q_cipherType;
void ddsi_security_plugin (void);
#if defined (__cplusplus)
}
#endif
#endif
#endif

View file

@ -0,0 +1,30 @@
/*
* 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 NN_SERVICELEASE_H
#define NN_SERVICELEASE_H
#if defined (__cplusplus)
extern "C" {
#endif
struct nn_servicelease;
struct nn_servicelease *nn_servicelease_new (void (*renew_cb) (void *arg), void *renew_arg);
int nn_servicelease_start_renewing (struct nn_servicelease *sl);
void nn_servicelease_free (struct nn_servicelease *sl);
void nn_servicelease_statechange_barrier (struct nn_servicelease *sl);
#if defined (__cplusplus)
}
#endif
#endif /* NN_SERVICELEASE_H */

View file

@ -0,0 +1,111 @@
/*
* 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 Q_SOCKWAITSET_H
#define Q_SOCKWAITSET_H
#include "os/os_defs.h"
#include "ddsi/sysdeps.h"
#if defined (__cplusplus)
extern "C" {
#endif
typedef struct os_sockWaitset * os_sockWaitset;
typedef struct os_sockWaitsetCtx * os_sockWaitsetCtx;
struct ddsi_tran_conn;
/*
Allocates a new connection waitset. The waitset is thread-safe in
that multiple threads may add and remove connections from the wait set
or trigger it. However only a single thread may process events from
the wait set using the Wait and NextEvent functions in a single handling
loop.
*/
os_sockWaitset os_sockWaitsetNew (void);
/*
Frees the waitset WS. Any connections associated with it will
be closed.
*/
void os_sockWaitsetFree (os_sockWaitset ws);
/*
Triggers the waitset, from any thread. It is level
triggered, when called while no thread is waiting in
os_sockWaitsetWait the trigger will cause an (early) wakeup on the
next call to os_sockWaitsetWait. Returns os_resultSuccess if
successfully triggered, os_resultInvalid if an error occurs.
Triggering a waitset may require resources and they may be counted.
Do not trigger a waitset arbitrarily often without ensuring
os_sockWaitsetWait is called often enough to let it release any
resources used.
Shared state updates preceding os_sockWaitsetTrigger are visible
following os_sockWaitsetWait.
*/
void os_sockWaitsetTrigger (os_sockWaitset ws);
/*
A connection may be associated with only one waitset at any time, and
may be added to the waitset only once. Failure to comply with this
restriction results in undefined behaviour.
Closing a connection associated with a waitset is handled gracefully: no
operations will signal errors because of it.
*/
void os_sockWaitsetAdd (os_sockWaitset ws, struct ddsi_tran_conn * conn);
/*
Drops all connections from the waitset from index onwards. Index
0 corresponds to the first connection added to the waitset, index 1 to
the second, etc. Behaviour is undefined when called after a successful wait
but before all events had been enumerated.
*/
void os_sockWaitsetPurge (os_sockWaitset ws, unsigned index);
/*
Waits until some of the connections in WS have data to be read.
Returns a new wait set context if one or more connections have data to read.
However, the return may be spurious (NULL) (i.e., no events)
If a context is returned it must be enumerated before os_sockWaitsetWait
may be called again.
Shared state updates preceding os_sockWaitsetTrigger are visible
following os_sockWaitsetWait.
*/
os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws);
/*
Returns the index of the next triggered connection in the
waitset contect ctx, or -1 if the set of available events has been
exhausted. Index 0 is the first connection added to the waitset, index
1 the second, &c.
Following a call to os_sockWaitsetWait on waitset that returned
a context, one MUST enumerate all available events before
os_sockWaitsetWait may be called again.
If the return value is >= 0, *conn contains the connection on which
data is available.
*/
int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, struct ddsi_tran_conn ** conn);
/* Remove connection */
void os_sockWaitsetRemove (os_sockWaitset ws, struct ddsi_tran_conn * conn);
#if defined (__cplusplus)
}
#endif
#endif /* Q_SOCKWAITSET_H */

View file

@ -0,0 +1,37 @@
/*
* 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 Q_STATIC_ASSERT_H
#define Q_STATIC_ASSERT_H
/* There are many tricks to use a constant expression to yield an
illegal type or expression at compile time, such as zero-sized
arrays and duplicate case or enum labels. So this is but one of the
many tricks. */
#ifndef _MSC_VER
#define Q_STATIC_ASSERT_CODE(pred) do { switch(0) { case 0: case pred: ; } } while (0)
#else
/* Temporarily disabling warning C6326: Potential comparison of a
constant with another constant. */
#define Q_STATIC_ASSERT_CODE(pred) do { \
__pragma (warning (push)) \
__pragma (warning (disable : 6326)) \
switch(0) { case 0: case pred: ; } \
__pragma (warning (pop)) \
} while (0)
#endif
#endif /* Q_STATIC_ASSERT_H */

View file

@ -0,0 +1,128 @@
/*
* 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 Q_THREAD_H
#define Q_THREAD_H
#include "os/os.h"
#include "ddsi/q_inline.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* Things don't go wrong if CACHE_LINE_SIZE is defined incorrectly,
they just run slower because of false cache-line sharing. It can be
discovered at run-time, but in practice it's 64 for most CPUs and
128 for some. */
#define CACHE_LINE_SIZE 64
typedef uint32_t vtime_t;
typedef int32_t svtime_t; /* signed version */
/* GCC has a nifty feature allowing the specification of the required
alignment: __attribute__ ((aligned (CACHE_LINE_SIZE))) in this
case. Many other compilers implement it as well, but it is by no
means a standard feature. So we do it the old-fashioned way. */
/* These strings are used to indicate the required scheduling class to the "create_thread()" */
#define Q_THREAD_SCHEDCLASS_REALTIME "Realtime"
#define Q_THREAD_SCHEDCLASS_TIMESHARE "Timeshare"
/* When this value is used, the platform default for scheduling priority will be used */
#define Q_THREAD_SCHEDPRIO_DEFAULT 0
enum thread_state {
THREAD_STATE_ZERO,
THREAD_STATE_ALIVE
};
struct logbuf;
/*
* watchdog indicates progress for the service lease liveliness mechsanism, while vtime
* indicates progress for the Garbage collection purposes.
* vtime even : thread awake
* vtime odd : thread asleep
*/
#define THREAD_BASE \
volatile vtime_t vtime; \
volatile vtime_t watchdog; \
os_threadId tid; \
os_threadId extTid; \
enum thread_state state; \
struct logbuf *lb; \
char *name /* note: no semicolon! */
struct thread_state_base {
THREAD_BASE;
};
struct thread_state1 {
THREAD_BASE;
char pad[CACHE_LINE_SIZE
* ((sizeof (struct thread_state_base) + CACHE_LINE_SIZE - 1)
/ CACHE_LINE_SIZE)
- sizeof (struct thread_state_base)];
};
#undef THREAD_BASE
struct thread_states {
os_mutex lock;
unsigned nthreads;
struct thread_state1 *ts; /* [nthreads] */
};
extern struct thread_states thread_states;
extern os_threadLocal struct thread_state1 *tsd_thread_state;
void thread_states_init (_In_ unsigned maxthreads);
void thread_states_fini (void);
void upgrade_main_thread (void);
void downgrade_main_thread (void);
const struct config_thread_properties_listelem *lookup_thread_properties (_In_z_ const char *name);
_Success_(return != NULL) _Ret_maybenull_ struct thread_state1 *create_thread (_In_z_ const char *name, _In_ uint32_t (*f) (void *arg), _In_opt_ void *arg);
_Ret_valid_ struct thread_state1 *lookup_thread_state (void);
_Success_(return != NULL) _Ret_maybenull_ struct thread_state1 *lookup_thread_state_real (void);
_Success_(return == 0) int join_thread (_Inout_ struct thread_state1 *ts1);
void log_stack_traces (void);
struct thread_state1 *get_thread_state (_In_ os_threadId id);
struct thread_state1 * init_thread_state (_In_z_ const char *tname);
void reset_thread_state (_Inout_opt_ struct thread_state1 *ts1);
int thread_exists (_In_z_ const char *name);
#if defined (__cplusplus)
}
#endif
#if NN_HAVE_C99_INLINE && !defined SUPPRESS_THREAD_INLINES
#include "q_thread_template.h"
#else
#if defined (__cplusplus)
extern "C" {
#endif
int vtime_awake_p (_In_ vtime_t vtime);
int vtime_asleep_p (_In_ vtime_t vtime);
int vtime_gt (_In_ vtime_t vtime1, _In_ vtime_t vtime0);
void thread_state_asleep (_Inout_ struct thread_state1 *ts1);
void thread_state_awake (_Inout_ struct thread_state1 *ts1);
void thread_state_blocked (_Inout_ struct thread_state1 *ts1);
void thread_state_unblocked (_Inout_ struct thread_state1 *ts1);
#if defined (__cplusplus)
}
#endif
#endif
#endif /* Q_THREAD_H */

View file

@ -0,0 +1,101 @@
/*
* 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
*/
/* -*- c -*- */
#include "ddsi/sysdeps.h"
#include "os/os_atomics.h"
#include "ddsi/q_static_assert.h"
#if defined SUPPRESS_THREAD_INLINES && defined NN_C99_INLINE
#undef NN_C99_INLINE
#define NN_C99_INLINE
#endif
NN_C99_INLINE int vtime_awake_p (_In_ vtime_t vtime)
{
return (vtime % 2) == 0;
}
NN_C99_INLINE int vtime_asleep_p (_In_ vtime_t vtime)
{
return (vtime % 2) == 1;
}
NN_C99_INLINE int vtime_gt (_In_ vtime_t vtime1, _In_ vtime_t vtime0)
{
Q_STATIC_ASSERT_CODE (sizeof (vtime_t) == sizeof (svtime_t));
return (svtime_t) (vtime1 - vtime0) > 0;
}
NN_C99_INLINE void thread_state_asleep (_Inout_ struct thread_state1 *ts1)
{
vtime_t vt = ts1->vtime;
vtime_t wd = ts1->watchdog;
if (vtime_awake_p (vt))
{
os_atomic_fence_rel ();
ts1->vtime = vt + 1;
}
else
{
os_atomic_fence_rel ();
ts1->vtime = vt + 2;
os_atomic_fence_acq ();
}
if ( wd % 2 ){
ts1->watchdog = wd + 2;
} else {
ts1->watchdog = wd + 1;
}
}
NN_C99_INLINE void thread_state_awake (_Inout_ struct thread_state1 *ts1)
{
vtime_t vt = ts1->vtime;
vtime_t wd = ts1->watchdog;
if (vtime_asleep_p (vt))
ts1->vtime = vt + 1;
else
{
os_atomic_fence_rel ();
ts1->vtime = vt + 2;
}
os_atomic_fence_acq ();
if ( wd % 2 ){
ts1->watchdog = wd + 1;
} else {
ts1->watchdog = wd + 2;
}
}
NN_C99_INLINE void thread_state_blocked (_Inout_ struct thread_state1 *ts1)
{
vtime_t wd = ts1->watchdog;
if ( wd % 2 ){
ts1->watchdog = wd + 2;
} else {
ts1->watchdog = wd + 1;
}
}
NN_C99_INLINE void thread_state_unblocked (_Inout_ struct thread_state1 *ts1)
{
vtime_t wd = ts1->watchdog;
if ( wd % 2 ){
ts1->watchdog = wd + 1;
} else {
ts1->watchdog = wd + 2;
}
}

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 NN_TIME_H
#define NN_TIME_H
#include "os/os.h"
#if defined (__cplusplus)
extern "C" {
#endif
#define T_NEVER 0x7fffffffffffffffll
#define T_MILLISECOND 1000000ll
#define T_SECOND (1000 * T_MILLISECOND)
#define T_MICROSECOND (T_MILLISECOND/1000)
typedef struct {
int seconds;
unsigned fraction;
} nn_ddsi_time_t;
#if DDSI_DURATION_ACCORDING_TO_SPEC /* what the spec says */
typedef struct { /* why different from ddsi_time_t? */
int sec;
int nanosec;
} nn_duration_t;
#else /* this is what I used to do & what wireshark does - probably right */
typedef nn_ddsi_time_t nn_duration_t;
#endif
typedef struct {
int64_t v;
} nn_mtime_t;
typedef struct {
int64_t v;
} nn_wctime_t;
typedef struct {
int64_t v;
} nn_etime_t;
extern const nn_ddsi_time_t invalid_ddsi_timestamp;
extern const nn_ddsi_time_t ddsi_time_infinite;
extern const nn_duration_t duration_infinite;
int valid_ddsi_timestamp (nn_ddsi_time_t t);
OSAPI_EXPORT nn_wctime_t now (void); /* wall clock time */
nn_mtime_t now_mt (void); /* monotonic time */
nn_etime_t now_et (void); /* elapsed time */
void mtime_to_sec_usec (_Out_ int * __restrict sec, _Out_ int * __restrict usec, _In_ nn_mtime_t t);
void wctime_to_sec_usec (_Out_ int * __restrict sec, _Out_ int * __restrict usec, _In_ nn_wctime_t t);
void etime_to_sec_usec (_Out_ int * __restrict sec, _Out_ int * __restrict usec, _In_ nn_etime_t t);
nn_mtime_t mtime_round_up (nn_mtime_t t, int64_t round);
nn_mtime_t add_duration_to_mtime (nn_mtime_t t, int64_t d);
nn_wctime_t add_duration_to_wctime (nn_wctime_t t, int64_t d);
nn_etime_t add_duration_to_etime (nn_etime_t t, int64_t d);
nn_ddsi_time_t nn_wctime_to_ddsi_time (nn_wctime_t t);
OSAPI_EXPORT nn_wctime_t nn_wctime_from_ddsi_time (nn_ddsi_time_t x);
OSAPI_EXPORT nn_duration_t nn_to_ddsi_duration (int64_t t);
OSAPI_EXPORT int64_t nn_from_ddsi_duration (nn_duration_t x);
#if defined (__cplusplus)
}
#endif
#endif /* NN_TIME_H */

View file

@ -0,0 +1,50 @@
/*
* 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 Q_TRANSMIT_H
#define Q_TRANSMIT_H
#include "os/os_defs.h"
#include "ddsi/q_rtps.h" /* for nn_entityid_t */
#if defined (__cplusplus)
extern "C" {
#endif
struct nn_xpack;
struct nn_xmsg;
struct writer;
struct proxy_reader;
struct serdata;
struct tkmap_instance;
/* Writing new data; serdata_twrite (serdata) is assumed to be really
recentish; serdata is unref'd. If xp == NULL, data is queued, else
packed.
"nogc": no GC may occur, so it may not block to throttle the writer if the high water mark of the WHC is reached, which implies true KEEP_LAST behaviour. This is true for all the DDSI built-in writers.
"gc": GC may occur, which means the writer history and watermarks can be anything. This must be used for all application data.
*/
int write_sample_gc (struct nn_xpack *xp, struct writer *wr, struct serdata *serdata, struct tkmap_instance *tk);
int write_sample_nogc (struct nn_xpack *xp, struct writer *wr, struct serdata *serdata, struct tkmap_instance *tk);
int write_sample_gc_notk (struct nn_xpack *xp, struct writer *wr, struct serdata *serdata);
int write_sample_nogc_notk (struct nn_xpack *xp, struct writer *wr, struct serdata *serdata);
/* When calling the following functions, wr->lock must be held */
int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct serdata *serdata, unsigned fragnum, struct proxy_reader *prd,struct nn_xmsg **msg, int isnew);
int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct serdata *serdata, struct proxy_reader *prd, int isnew);
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, int hbansreq, nn_entityid_t dst, int issync);
#if defined (__cplusplus)
}
#endif
#endif /* Q_TRANSMIT_H */

View file

@ -0,0 +1,27 @@
/*
* 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 NN_UNUSED_H
#define NN_UNUSED_H
#ifdef __GNUC__
#define UNUSED_ARG(x) x __attribute__ ((unused))
#else
#define UNUSED_ARG(x) x
#endif
#ifndef NDEBUG
#define UNUSED_ARG_NDEBUG(x) x
#else
#define UNUSED_ARG_NDEBUG(x) UNUSED_ARG (x)
#endif
#endif /* NN_UNUSED_H */

View file

@ -0,0 +1,122 @@
/*
* 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 Q_WHC_H
#define Q_WHC_H
#include "util/ut_avl.h"
#include "util/ut_hopscotch.h"
#include "ddsi/q_time.h"
#include "ddsi/q_rtps.h"
#include "ddsi/q_freelist.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct serdata;
struct nn_plist;
struct whc_idxnode;
#define USE_EHH 0
struct whc_node {
struct whc_node *next_seq; /* next in this interval */
struct whc_node *prev_seq; /* prev in this interval */
struct whc_idxnode *idxnode; /* NULL if not in index */
unsigned idxnode_pos; /* index in idxnode.hist */
seqno_t seq;
uint64_t total_bytes; /* cumulative number of bytes up to and including this node */
size_t size;
struct nn_plist *plist; /* 0 if nothing special */
unsigned unacked: 1; /* counted in whc::unacked_bytes iff 1 */
nn_mtime_t last_rexmit_ts;
unsigned rexmit_count;
struct serdata *serdata;
};
struct whc_intvnode {
ut_avlNode_t avlnode;
seqno_t min;
seqno_t maxp1;
struct whc_node *first; /* linked list of seqs with contiguous sequence numbers [min,maxp1) */
struct whc_node *last; /* valid iff first != NULL */
};
struct whc_idxnode {
int64_t iid;
seqno_t prune_seq;
struct tkmap_instance *tk;
unsigned headidx;
#if __STDC_VERSION__ >= 199901L
struct whc_node *hist[];
#else
struct whc_node *hist[1];
#endif
};
#if USE_EHH
struct whc_seq_entry {
seqno_t seq;
struct whc_node *whcn;
};
#endif
struct whc {
unsigned seq_size;
size_t unacked_bytes;
size_t sample_overhead;
uint64_t total_bytes; /* total number of bytes pushed in */
unsigned is_transient_local: 1;
unsigned hdepth; /* 0 = unlimited */
unsigned tldepth; /* 0 = disabled/unlimited (no need to maintain an index if KEEP_ALL <=> is_transient_local + tldepth=0) */
unsigned idxdepth; /* = max(hdepth, tldepth) */
seqno_t max_drop_seq; /* samples in whc with seq <= max_drop_seq => transient-local */
struct whc_intvnode *open_intv; /* interval where next sample will go (usually) */
struct whc_node *maxseq_node; /* NULL if empty; if not in open_intv, open_intv is empty */
struct nn_freelist freelist; /* struct whc_node *; linked via whc_node::next_seq */
#if USE_EHH
struct ut_ehh *seq_hash;
#else
struct ut_hh *seq_hash;
#endif
struct ut_hh *idx_hash;
ut_avlTree_t seq;
};
struct whc *whc_new (int is_transient_local, unsigned hdepth, unsigned tldepth, size_t sample_overhead);
void whc_free (struct whc *whc);
int whc_empty (const struct whc *whc);
seqno_t whc_min_seq (const struct whc *whc);
seqno_t whc_max_seq (const struct whc *whc);
seqno_t whc_next_seq (const struct whc *whc, seqno_t seq);
size_t whc_unacked_bytes (struct whc *whc);
struct whc_node *whc_findseq (const struct whc *whc, seqno_t seq);
struct whc_node *whc_findmax (const struct whc *whc);
struct whc_node *whc_findkey (const struct whc *whc, const struct serdata *serdata_key);
struct whc_node *whc_next_node (const struct whc *whc, seqno_t seq);
/* min_seq is lowest sequence number that must be retained because of
reliable readers that have not acknowledged all data */
/* max_drop_seq must go soon, it's way too ugly. */
/* plist may be NULL or os_malloc'd, WHC takes ownership of plist */
int whc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, struct nn_plist *plist, struct serdata *serdata, struct tkmap_instance *tk);
void whc_downgrade_to_volatile (struct whc *whc);
unsigned whc_remove_acked_messages (struct whc *whc, seqno_t max_drop_seq, struct whc_node **deferred_free_list);
void whc_free_deferred_free_list (struct whc *whc, struct whc_node *deferred_free_list);
#if defined (__cplusplus)
}
#endif
#endif /* Q_WHC_H */

View file

@ -0,0 +1,73 @@
/*
* 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 NN_XEVENT_H
#define NN_XEVENT_H
#if defined (__cplusplus)
extern "C" {
#endif
/* NOTE: xevents scheduled with the same tsched used to always be
executed in the order of scheduling, but that is no longer true.
With the messages now via the "untimed" path, that should not
introduce any issues. */
struct writer;
struct pwr_rd_match;
struct participant;
struct proxy_participant;
struct ddsi_tran_conn;
struct xevent;
struct xeventq;
struct proxy_writer;
struct proxy_reader;
struct xeventq *xeventq_new
(
struct ddsi_tran_conn * conn,
size_t max_queued_rexmit_bytes,
size_t max_queued_rexmit_msgs,
uint32_t auxiliary_bandwidth_limit
);
/* xeventq_free calls callback handlers with t = T_NEVER, at which point they are required to free
whatever memory is claimed for the argument and call delete_xevent. */
void xeventq_free (struct xeventq *evq);
int xeventq_start (struct xeventq *evq, const char *name); /* <0 => error, =0 => ok */
void xeventq_stop (struct xeventq *evq);
void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg);
void qxev_pwr_entityid (struct proxy_writer * pwr, nn_guid_prefix_t * id);
void qxev_prd_entityid (struct proxy_reader * prd, nn_guid_prefix_t * id);
/* Returns 1 if queued, 0 otherwise (no point in returning the
event, you can't do anything with it anyway) */
int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg *msg, int force);
/* All of the following lock EVQ for the duration of the operation */
void delete_xevent (struct xevent *ev);
int resched_xevent_if_earlier (struct xevent *ev, nn_mtime_t tsched);
struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *wr_guid);
struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pwr_guid, const nn_guid_t *rd_guid);
struct xevent *qxev_spdp (nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_guid_t *proxypp_guid);
struct xevent *qxev_pmd_update (nn_mtime_t tsched, const nn_guid_t *pp_guid);
struct xevent *qxev_end_startup_mode (nn_mtime_t tsched);
struct xevent *qxev_delete_writer (nn_mtime_t tsched, const nn_guid_t *guid);
/* cb will be called with now = T_NEVER if the event is still enqueued when when xeventq_free starts cleaning up */
struct xevent *qxev_callback (nn_mtime_t tsched, void (*cb) (struct xevent *xev, void *arg, nn_mtime_t now), void *arg);
#if defined (__cplusplus)
}
#endif
#endif /* NN_XEVENT_H */

View file

@ -0,0 +1,158 @@
/*
* 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 NN_XMSG_H
#define NN_XMSG_H
#include <stddef.h>
#include "ddsi/q_protocol.h" /* for, e.g., SubmessageKind_t */
#include "ddsi/q_xqos.h" /* for, e.g., octetseq, stringseq */
#include "ddsi/ddsi_tran.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct serdata;
struct addrset;
struct proxy_reader;
struct proxy_writer;
struct nn_prismtech_participant_version_info;
struct nn_prismtech_writer_info;
struct nn_xmsgpool;
struct nn_xmsg_data;
struct nn_xmsg;
struct nn_xpack;
struct nn_xmsg_marker {
size_t offset;
};
enum nn_xmsg_kind {
NN_XMSG_KIND_CONTROL,
NN_XMSG_KIND_DATA,
NN_XMSG_KIND_DATA_REXMIT
};
/* XMSGPOOL */
struct nn_xmsgpool *nn_xmsgpool_new (void);
void nn_xmsgpool_free (struct nn_xmsgpool *pool);
/* XMSG */
/* To allocate a new xmsg from the pool; if expected_size is NOT
exceeded, no reallocs will be performed, else the address of the
xmsg may change because of reallocing when appending to it. */
struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const nn_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind);
/* For sending to a particular destination (participant) */
void nn_xmsg_setdst1 (struct nn_xmsg *m, const nn_guid_prefix_t *gp, const nn_locator_t *addr);
/* For sending to a particular proxy reader; this is a convenience
routine that extracts a suitable address from the proxy reader's
address sets and calls setdst1. */
int nn_xmsg_setdstPRD (struct nn_xmsg *m, const struct proxy_reader *prd);
int nn_xmsg_setdstPWR (struct nn_xmsg *m, const struct proxy_writer *pwr);
/* For sending to all in the address set AS -- typically, the writer's
address set to multicast to all matched readers */
void nn_xmsg_setdstN (struct nn_xmsg *msg, struct addrset *as, struct addrset *as_group);
int nn_xmsg_setmaxdelay (struct nn_xmsg *msg, int64_t maxdelay);
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
int nn_xmsg_setencoderid (struct nn_xmsg *msg, uint32_t encoderid);
#endif
/* Sets the location of the destination readerId within the message
(address changes because of reallocations are handled correctly).
M must be a rexmit, and for all rexmits this must be called. It is
a separate function because the location may only become known at a
late-ish stage in the construction of the message. */
void nn_xmsg_set_data_readerId (struct nn_xmsg *m, nn_entityid_t *readerId);
/* If M and MADD are both xmsg's containing the same retransmit
message, this will merge the destination embedded in MADD into M.
Typically, this will cause the readerId of M to be cleared and the
destination to change to the writer's address set.
M and MADD *must* contain the same sample/fragment of a sample.
Returns 1 if merge was successful, else 0. On failure, neither
message will have been changed and both should be sent as if there
had been no merging. */
int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct nn_xmsg *m, const struct nn_xmsg *madd);
/* To set writer ids for updating last transmitted sequence number;
wrfragid is 0 based, unlike DDSI but like other places where
fragment numbers are handled internally. */
void nn_xmsg_setwriterseq (struct nn_xmsg *msg, const nn_guid_t *wrguid, seqno_t wrseq);
void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const nn_guid_t *wrguid, seqno_t wrseq, nn_fragment_number_t wrfragid);
/* Comparison function for retransmits: orders messages on writer
guid, sequence number and fragment id */
int nn_xmsg_compare_fragid (const struct nn_xmsg *a, const struct nn_xmsg *b);
void nn_xmsg_free (struct nn_xmsg *msg);
size_t nn_xmsg_size (const struct nn_xmsg *m);
void *nn_xmsg_payload (size_t *sz, struct nn_xmsg *m);
enum nn_xmsg_kind nn_xmsg_kind (const struct nn_xmsg *m);
void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, nn_guid_t *wrguid, seqno_t *wrseq, nn_fragment_number_t *wrfragid);
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_shrink (struct nn_xmsg *m, struct nn_xmsg_marker marker, size_t sz);
void nn_xmsg_serdata (struct nn_xmsg *m, struct serdata *serdata, unsigned off, unsigned len);
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_add_timestamp (struct nn_xmsg *m, nn_wctime_t t);
void nn_xmsg_add_entityid (struct nn_xmsg * m);
void *nn_xmsg_addpar (struct nn_xmsg *m, unsigned pid, size_t len);
void nn_xmsg_addpar_string (struct nn_xmsg *m, unsigned pid, const char *str);
void nn_xmsg_addpar_octetseq (struct nn_xmsg *m, unsigned pid, const nn_octetseq_t *oseq);
void nn_xmsg_addpar_stringseq (struct nn_xmsg *m, unsigned pid, const nn_stringseq_t *sseq);
void nn_xmsg_addpar_guid (struct nn_xmsg *m, unsigned pid, const nn_guid_t *guid);
void nn_xmsg_addpar_BE4u (struct nn_xmsg *m, unsigned pid, unsigned x);
void nn_xmsg_addpar_4u (struct nn_xmsg *m, unsigned pid, unsigned x);
void nn_xmsg_addpar_keyhash (struct nn_xmsg *m, const struct serdata *serdata);
void nn_xmsg_addpar_statusinfo (struct nn_xmsg *m, unsigned statusinfo);
void nn_xmsg_addpar_reliability (struct nn_xmsg *m, unsigned pid, const struct nn_reliability_qospolicy *rq);
void nn_xmsg_addpar_share (struct nn_xmsg *m, unsigned pid, const struct nn_share_qospolicy *rq);
void nn_xmsg_addpar_subscription_keys (struct nn_xmsg *m, unsigned pid, const struct nn_subscription_keys_qospolicy *rq);
void nn_xmsg_addpar_parvinfo (struct nn_xmsg *m, unsigned pid, const struct nn_prismtech_participant_version_info *pvi);
void nn_xmsg_addpar_eotinfo (struct nn_xmsg *m, unsigned pid, const struct nn_prismtech_eotinfo *txnid);
void nn_xmsg_addpar_dataholder (_In_ struct nn_xmsg *m, _In_ unsigned pid, _In_ const struct nn_dataholder *dh);
void nn_xmsg_addpar_sentinel (struct nn_xmsg *m);
int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg *m);
/* XPACK */
struct nn_xpack * nn_xpack_new (ddsi_tran_conn_t conn, uint32_t bw_limit, bool async_mode);
void nn_xpack_free (struct nn_xpack *xp);
void nn_xpack_send (struct nn_xpack *xp, bool immediately /* unused */);
int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flags);
int64_t nn_xpack_maxdelay (const struct nn_xpack *xp);
unsigned nn_xpack_packetid (const struct nn_xpack *xp);
/* SENDQ */
void nn_xpack_sendq_init (void);
void nn_xpack_sendq_start (void);
void nn_xpack_sendq_stop (void);
void nn_xpack_sendq_fini (void);
#if defined (__cplusplus)
}
#endif
#endif /* NN_XMSG_H */

View file

@ -0,0 +1,349 @@
/*
* 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 NN_XQOS_H
#define NN_XQOS_H
/*XXX*/
#include "ddsi/q_protocol.h"
#include "ddsi/q_rtps.h"
/*XXX*/
#include "ddsi/q_log.h"
#if defined (__cplusplus)
extern "C" {
#endif
#define NN_DDS_LENGTH_UNLIMITED -1
typedef struct nn_octetseq {
unsigned length;
unsigned char *value;
} nn_octetseq_t;
typedef nn_octetseq_t nn_userdata_qospolicy_t;
typedef nn_octetseq_t nn_topicdata_qospolicy_t;
typedef nn_octetseq_t nn_groupdata_qospolicy_t;
typedef struct nn_property {
char *name;
char *value;
bool propagate;
} nn_property_t;
typedef struct nn_propertyseq {
unsigned n;
nn_property_t *props;
} nn_propertyseq_t;
typedef struct nn_binaryproperty {
char *name;
nn_octetseq_t value;
bool propagate;
} nn_binaryproperty_t;
typedef struct nn_binarypropertyseq {
unsigned n;
nn_binaryproperty_t *props;
} nn_binarypropertyseq_t;
typedef struct nn_property_qospolicy {
nn_propertyseq_t value;
nn_binarypropertyseq_t binary_value;
} nn_property_qospolicy_t;
typedef enum nn_durability_kind {
NN_VOLATILE_DURABILITY_QOS,
NN_TRANSIENT_LOCAL_DURABILITY_QOS,
NN_TRANSIENT_DURABILITY_QOS,
NN_PERSISTENT_DURABILITY_QOS
} nn_durability_kind_t;
typedef struct nn_durability_qospolicy {
nn_durability_kind_t kind;
} nn_durability_qospolicy_t;
typedef enum nn_history_kind {
NN_KEEP_LAST_HISTORY_QOS,
NN_KEEP_ALL_HISTORY_QOS
} nn_history_kind_t;
typedef struct nn_history_qospolicy {
nn_history_kind_t kind;
int depth;
} nn_history_qospolicy_t;
typedef struct nn_resource_limits_qospolicy {
int max_samples;
int max_instances;
int max_samples_per_instance;
} nn_resource_limits_qospolicy_t;
typedef struct nn_durability_service_qospolicy {
nn_duration_t service_cleanup_delay;
nn_history_qospolicy_t history;
nn_resource_limits_qospolicy_t resource_limits;
} nn_durability_service_qospolicy_t;
typedef enum nn_presentation_access_scope_kind {
NN_INSTANCE_PRESENTATION_QOS,
NN_TOPIC_PRESENTATION_QOS,
NN_GROUP_PRESENTATION_QOS
} nn_presentation_access_scope_kind_t;
typedef struct nn_presentation_qospolicy {
nn_presentation_access_scope_kind_t access_scope;
unsigned char coherent_access;
unsigned char ordered_access;
} nn_presentation_qospolicy_t;
typedef struct nn_deadline_qospolicy {
nn_duration_t deadline;
} nn_deadline_qospolicy_t;
typedef struct nn_latency_budget_qospolicy {
nn_duration_t duration;
} nn_latency_budget_qospolicy_t;
typedef enum nn_ownership_kind {
NN_SHARED_OWNERSHIP_QOS,
NN_EXCLUSIVE_OWNERSHIP_QOS
} nn_ownership_kind_t;
typedef struct nn_ownership_qospolicy {
nn_ownership_kind_t kind;
} nn_ownership_qospolicy_t;
typedef struct nn_ownership_strength_qospolicy {
int value;
} nn_ownership_strength_qospolicy_t;
typedef enum nn_liveliness_kind {
NN_AUTOMATIC_LIVELINESS_QOS,
NN_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS,
NN_MANUAL_BY_TOPIC_LIVELINESS_QOS
} nn_liveliness_kind_t;
typedef struct nn_liveliness_qospolicy {
nn_liveliness_kind_t kind;
nn_duration_t lease_duration;
} nn_liveliness_qospolicy_t;
typedef struct nn_time_based_filter_qospolicy {
nn_duration_t minimum_separation;
} nn_time_based_filter_qospolicy_t;
typedef struct nn_stringseq {
unsigned n;
char **strs;
} nn_stringseq_t;
typedef nn_stringseq_t nn_partition_qospolicy_t;
typedef enum nn_reliability_kind {
NN_BEST_EFFORT_RELIABILITY_QOS,
NN_RELIABLE_RELIABILITY_QOS
} nn_reliability_kind_t;
typedef struct nn_reliability_qospolicy {
nn_reliability_kind_t kind;
nn_duration_t max_blocking_time;
} nn_reliability_qospolicy_t;
typedef struct nn_external_reliability_qospolicy {
int kind;
nn_duration_t max_blocking_time;
} nn_external_reliability_qospolicy_t;
#define NN_PEDANTIC_BEST_EFFORT_RELIABILITY_QOS 1
#define NN_PEDANTIC_RELIABLE_RELIABILITY_QOS 3 /* <= see DDSI 2.1, table 9.4 */
#define NN_INTEROP_BEST_EFFORT_RELIABILITY_QOS 1
#define NN_INTEROP_RELIABLE_RELIABILITY_QOS 2
typedef struct nn_transport_priority_qospolicy {
int value;
} nn_transport_priority_qospolicy_t;
typedef struct nn_lifespan_qospolicy {
nn_duration_t duration;
} nn_lifespan_qospolicy_t;
typedef enum nn_destination_order_kind {
NN_BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS,
NN_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS
} nn_destination_order_kind_t;
typedef struct nn_destination_order_qospolicy {
nn_destination_order_kind_t kind;
} nn_destination_order_qospolicy_t;
typedef struct nn_entity_factory_qospolicy {
unsigned char autoenable_created_entities;
} nn_entity_factory_qospolicy_t;
typedef struct nn_writer_data_lifecycle_qospolicy {
unsigned char autodispose_unregistered_instances;
nn_duration_t autopurge_suspended_samples_delay; /* OpenSplice extension */
nn_duration_t autounregister_instance_delay; /* OpenSplice extension */
} nn_writer_data_lifecycle_qospolicy_t;
typedef enum nn_invalid_sample_visibility_kind {
NN_NO_INVALID_SAMPLE_VISIBILITY_QOS,
NN_MINIMUM_INVALID_SAMPLE_VISIBILITY_QOS,
NN_ALL_INVALID_SAMPLE_VISIBILITY_QOS
} nn_invalid_sample_visibility_kind_t;
typedef struct nn_reader_data_lifecycle_qospolicy {
nn_duration_t autopurge_nowriter_samples_delay;
nn_duration_t autopurge_disposed_samples_delay;
unsigned char autopurge_dispose_all; /* OpenSplice extension */
unsigned char enable_invalid_samples; /* OpenSplice extension */
nn_invalid_sample_visibility_kind_t invalid_sample_visibility; /* OpenSplice extension */
} nn_reader_data_lifecycle_qospolicy_t;
typedef struct nn_synchronous_endpoint_qospolicy {
unsigned char value;
} nn_synchronous_endpoint_qospolicy_t;
typedef struct nn_relaxed_qos_matching_qospolicy {
unsigned char value;
} nn_relaxed_qos_matching_qospolicy_t;
typedef struct nn_subscription_keys_qospolicy {
unsigned char use_key_list;
nn_stringseq_t key_list;
} nn_subscription_keys_qospolicy_t;
typedef struct nn_reader_lifespan_qospolicy {
unsigned char use_lifespan;
nn_duration_t duration;
} nn_reader_lifespan_qospolicy_t;
typedef struct nn_share_qospolicy {
unsigned char enable;
char *name;
} nn_share_qospolicy_t;
/***/
/* Qos Present bit indices */
#define QP_TOPIC_NAME ((uint64_t)1 << 0)
#define QP_TYPE_NAME ((uint64_t)1 << 1)
#define QP_PRESENTATION ((uint64_t)1 << 2)
#define QP_PARTITION ((uint64_t)1 << 3)
#define QP_GROUP_DATA ((uint64_t)1 << 4)
#define QP_TOPIC_DATA ((uint64_t)1 << 5)
#define QP_DURABILITY ((uint64_t)1 << 6)
#define QP_DURABILITY_SERVICE ((uint64_t)1 << 7)
#define QP_DEADLINE ((uint64_t)1 << 8)
#define QP_LATENCY_BUDGET ((uint64_t)1 << 9)
#define QP_LIVELINESS ((uint64_t)1 << 10)
#define QP_RELIABILITY ((uint64_t)1 << 11)
#define QP_DESTINATION_ORDER ((uint64_t)1 << 12)
#define QP_HISTORY ((uint64_t)1 << 13)
#define QP_RESOURCE_LIMITS ((uint64_t)1 << 14)
#define QP_TRANSPORT_PRIORITY ((uint64_t)1 << 15)
#define QP_LIFESPAN ((uint64_t)1 << 16)
#define QP_USER_DATA ((uint64_t)1 << 17)
#define QP_OWNERSHIP ((uint64_t)1 << 18)
#define QP_OWNERSHIP_STRENGTH ((uint64_t)1 << 19)
#define QP_TIME_BASED_FILTER ((uint64_t)1 << 20)
#define QP_PRISMTECH_WRITER_DATA_LIFECYCLE ((uint64_t)1 << 21)
#define QP_PRISMTECH_READER_DATA_LIFECYCLE ((uint64_t)1 << 22)
#define QP_PRISMTECH_RELAXED_QOS_MATCHING ((uint64_t)1 << 23)
#define QP_PRISMTECH_READER_LIFESPAN ((uint64_t)1 << 24)
#define QP_PRISMTECH_SUBSCRIPTION_KEYS ((uint64_t)1 << 25)
#define QP_PRISMTECH_ENTITY_FACTORY ((uint64_t)1 << 27)
#define QP_PRISMTECH_SYNCHRONOUS_ENDPOINT ((uint64_t)1 << 28)
#define QP_RTI_TYPECODE ((uint64_t)1 << 29)
#define QP_PROPERTY ((uint64_t)1 << 30)
/* Partition QoS is not RxO according to the specification (DDS 1.2,
section 7.1.3), but communication will not take place unless it
matches. Same for topic and type. Relaxed qos matching is a bit of
a weird one, but it affects matching, so ... */
#define QP_RXO_MASK (QP_DURABILITY | QP_PRESENTATION | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_LIVELINESS | QP_RELIABILITY | QP_DESTINATION_ORDER | QP_PRISMTECH_RELAXED_QOS_MATCHING | QP_PRISMTECH_SYNCHRONOUS_ENDPOINT)
#define QP_CHANGEABLE_MASK (QP_USER_DATA | QP_TOPIC_DATA | QP_GROUP_DATA | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP_STRENGTH | QP_TIME_BASED_FILTER | QP_PARTITION | QP_TRANSPORT_PRIORITY | QP_LIFESPAN | QP_PRISMTECH_ENTITY_FACTORY | QP_PRISMTECH_WRITER_DATA_LIFECYCLE | QP_PRISMTECH_READER_DATA_LIFECYCLE)
#define QP_UNRECOGNIZED_INCOMPATIBLE_MASK (QP_PRISMTECH_RELAXED_QOS_MATCHING)
/* readers & writers have an extended qos, hence why it is a separate
type */
typedef struct nn_xqos {
/* Entries present, for sparse QoS */
uint64_t present;
uint64_t aliased;
/*v---- in ...Qos
v--- in ...BuiltinTopicData
v-- mapped in DDSI
v- reader/writer/publisher/subscriber/participant specific */
/* Extras: */
/* xx */char *topic_name;
/* xx */char *type_name;
/* PublisherQos, SubscriberQos: */
/*xxx */nn_presentation_qospolicy_t presentation;
/*xxx */nn_partition_qospolicy_t partition;
/*xxx */nn_groupdata_qospolicy_t group_data;
/*x xX*/nn_entity_factory_qospolicy_t entity_factory;
/* TopicQos: */
/*xxx */nn_topicdata_qospolicy_t topic_data;
/* DataWriterQos, DataReaderQos: */
/*xxx */nn_durability_qospolicy_t durability;
/*xxx */nn_durability_service_qospolicy_t durability_service;
/*xxx */nn_deadline_qospolicy_t deadline;
/*xxx */nn_latency_budget_qospolicy_t latency_budget;
/*xxx */nn_liveliness_qospolicy_t liveliness;
/*xxx */nn_reliability_qospolicy_t reliability;
/*xxx */nn_destination_order_qospolicy_t destination_order;
/*x x */nn_history_qospolicy_t history;
/*x x */nn_resource_limits_qospolicy_t resource_limits;
/*x x */nn_transport_priority_qospolicy_t transport_priority;
/*xxx */nn_lifespan_qospolicy_t lifespan;
/*xxx */nn_userdata_qospolicy_t user_data;
/*xxx */nn_ownership_qospolicy_t ownership;
/*xxxW*/nn_ownership_strength_qospolicy_t ownership_strength;
/*xxxR*/nn_time_based_filter_qospolicy_t time_based_filter;
/*x W*/nn_writer_data_lifecycle_qospolicy_t writer_data_lifecycle;
/*x xR*/nn_reader_data_lifecycle_qospolicy_t reader_data_lifecycle;
/*x x */nn_relaxed_qos_matching_qospolicy_t relaxed_qos_matching;
/*x xR*/nn_subscription_keys_qospolicy_t subscription_keys;
/*x xR*/nn_reader_lifespan_qospolicy_t reader_lifespan;
/*x xR*/nn_share_qospolicy_t share;
/*xxx */nn_synchronous_endpoint_qospolicy_t synchronous_endpoint;
/*xxx */nn_property_qospolicy_t property;
/* X*/nn_octetseq_t rti_typecode;
} nn_xqos_t;
struct nn_xmsg;
void nn_xqos_init_empty (nn_xqos_t *xqos);
void nn_xqos_init_default_reader (nn_xqos_t *xqos);
void nn_xqos_init_default_writer (nn_xqos_t *xqos);
void nn_xqos_init_default_writer_noautodispose (nn_xqos_t *xqos);
void nn_xqos_init_default_subscriber (nn_xqos_t *xqos);
void nn_xqos_init_default_publisher (nn_xqos_t *xqos);
void nn_xqos_init_default_topic (nn_xqos_t *xqos);
void nn_xqos_copy (nn_xqos_t *dst, const nn_xqos_t *src);
void nn_xqos_unalias (nn_xqos_t *xqos);
void nn_xqos_fini (nn_xqos_t *xqos);
void nn_xqos_mergein_missing (nn_xqos_t *a, const nn_xqos_t *b);
uint64_t nn_xqos_delta (const nn_xqos_t *a, const nn_xqos_t *b, uint64_t mask);
void nn_xqos_addtomsg (struct nn_xmsg *m, const nn_xqos_t *xqos, uint64_t wanted);
void nn_log_xqos (logcat_t cat, const nn_xqos_t *xqos);
nn_xqos_t *nn_xqos_dup (const nn_xqos_t *src);
#if defined (__cplusplus)
}
#endif
#endif /* NN_XQOS_H */

View file

@ -0,0 +1,195 @@
/*
* 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 SYSDEPS_H
#define SYSDEPS_H
#include "os/os.h"
#include "ddsi/q_inline.h"
#ifndef os_sockECONNRESET
#ifdef WSAECONNRESET
#define os_sockECONNRESET WSAECONNRESET
#else
#define os_sockECONNRESET ECONNRESET
#endif
#endif
#ifndef os_sockEPERM
#ifdef WSAEACCES
#define os_sockEPERM WSAEACCES
#else
#define os_sockEPERM EPERM
#endif
#endif
#if defined (__linux) || defined (__sun) || defined (__APPLE__) || defined (INTEGRITY) || defined (AIX) || defined (OS_RTEMS_DEFS_H) || defined (__VXWORKS__) || defined (__Lynx__) || defined (__linux__) || defined (OS_QNX_DEFS_H)
#define SYSDEPS_HAVE_MSGHDR 1
#define SYSDEPS_HAVE_RECVMSG 1
#define SYSDEPS_HAVE_SENDMSG 1
#endif
#if defined (__linux) || defined (__sun) || defined (__APPLE__) || defined (INTEGRITY) || defined (AIX) || defined (OS_RTEMS_DEFS_H) || defined (__VXWORKS__) || defined (__linux__) || defined (OS_QNX_DEFS_H)
#define SYSDEPS_HAVE_IOVEC 1
#endif
#if defined (__linux) || defined (__sun) || defined (__APPLE__) || defined (AIX) || defined (__Lynx__) || defined (OS_QNX_DEFS_H)
#define SYSDEPS_HAVE_RANDOM 1
#include <unistd.h>
#endif
#if defined (__linux) || defined (__sun) || defined (__APPLE__) || defined (AIX) || defined (OS_QNX_DEFS_H)
#define SYSDEPS_HAVE_GETRUSAGE 1
#include <sys/time.h> /* needed for Linux, exists on all four */
#include <sys/times.h> /* needed for AIX, exists on all four */
#include <sys/resource.h>
#endif
#if defined (__linux) && defined (CLOCK_THREAD_CPUTIME_ID)
#define SYSDEPS_HAVE_CLOCK_THREAD_CPUTIME 1
#endif
#if defined (INTEGRITY)
#include <sys/uio.h>
#include <limits.h>
#endif
#if defined (VXWORKS_RTP)
#include <net/uio.h>
#endif
#if defined (_WIN32)
typedef SOCKET os_handle;
#define Q_VALID_SOCKET(s) ((s) != INVALID_SOCKET)
#define Q_INVALID_SOCKET INVALID_SOCKET
#else /* All Unixes have socket() return -1 on error */
typedef int os_handle;
#define Q_VALID_SOCKET(s) ((s) != -1)
#define Q_INVALID_SOCKET -1
#endif
/* From MSDN: from Vista & 2k3 onwards, a macro named MemoryBarrier is
defined, XP needs inline assembly. Unfortunately, MemoryBarrier()
is a function on x86 ...
Definition below is taken from the MSDN page on MemoryBarrier() */
#ifndef MemoryBarrier
#if NTDDI_VERSION >= NTDDI_WS03 && defined _M_IX86
#define MemoryBarrier() do { \
LONG Barrier; \
__asm { \
xchg Barrier, eax \
} \
} while (0)
#endif /* x86 */
/* Don't try interworking with thumb - one thing at a time. Do a DMB
SY if supported, else no need for a memory barrier. (I think.) */
#if defined _M_ARM && ! defined _M_ARMT
#define MemoryBarrierARM __emit (0xf57ff05f) /* 0xf57ff05f or 0x5ff07ff5 */
#if _M_ARM > 7
/* if targetting ARMv7 the dmb instruction is available */
#define MemoryBarrier() MemoryBarrierARM
#else
/* else conditional on actual hardware platform */
extern void (*q_maybe_membar) (void);
#define MemoryBarrier() q_maybe_membar ()
#define NEED_ARM_MEMBAR_SUPPORT 1
#endif /* ARM version */
#endif /* ARM */
#endif /* !def MemoryBarrier */
#if defined (__sun) && !defined (_XPG4_2)
#define SYSDEPS_MSGHDR_ACCRIGHTS 1
#else
#define SYSDEPS_MSGHDR_ACCRIGHTS 0
#endif
#if SYSDEPS_MSGHDR_ACCRIGHTS
#define SYSDEPS_MSGHDR_FLAGS 0
#else
#define SYSDEPS_MSGHDR_FLAGS 1
#endif
#if defined (__cplusplus)
}
#endif
#if defined (__cplusplus)
extern "C" {
#endif
#define ASSERT_RDLOCK_HELD(x) ((void) 0)
#define ASSERT_WRLOCK_HELD(x) ((void) 0)
#define ASSERT_MUTEX_HELD(x) ((void) 0)
#if ! SYSDEPS_HAVE_IOVEC
struct iovec {
void *iov_base;
size_t iov_len;
};
#endif
#if ! SYSDEPS_HAVE_MSGHDR
struct msghdr
{
void *msg_name;
socklen_t msg_namelen;
struct iovec *msg_iov;
size_t msg_iovlen;
void *msg_control;
size_t msg_controllen;
int msg_flags;
};
#endif
#ifndef MSG_TRUNC
#define MSG_TRUNC 1
#endif
#if ! SYSDEPS_HAVE_RECVMSG
/* Only implements iovec of length 1, no control */
ssize_t recvmsg (os_handle fd, struct msghdr *message, int flags);
#endif
#if ! SYSDEPS_HAVE_SENDMSG
ssize_t sendmsg (os_handle fd, const struct msghdr *message, int flags);
#endif
#if ! SYSDEPS_HAVE_RANDOM
long random (void);
#endif
int64_t get_thread_cputime (void);
int os_threadEqual (os_threadId a, os_threadId b);
void log_stacktrace (const char *name, os_threadId tid);
#if (_LP64 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) || (!_LP64 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
#define HAVE_ATOMIC_LIFO 1
#if _LP64
typedef union { __int128 x; struct { uintptr_t a, b; } s; } os_atomic_uintptr2_t;
#else
typedef union { uint64_t x; struct { uintptr_t a, b; } s; } os_atomic_uintptr2_t;
#endif
typedef struct os_atomic_lifo {
os_atomic_uintptr2_t aba_head;
} os_atomic_lifo_t;
void os_atomic_lifo_init (os_atomic_lifo_t *head);
void os_atomic_lifo_push (os_atomic_lifo_t *head, void *elem, size_t linkoff);
void os_atomic_lifo_pushmany (os_atomic_lifo_t *head, void *first, void *last, size_t linkoff);
void *os_atomic_lifo_pop (os_atomic_lifo_t *head, size_t linkoff);
#endif
#if defined (__cplusplus)
}
#endif
#endif /* SYSDEPS_H */

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
*/
#include "ddsi/ddsi_ser.h"
#include <stddef.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include "os/os_stdlib.h"
#include "os/os_defs.h"
#include "os/os_thread.h"
#include "os/os_heap.h"
#include "os/os_atomics.h"
#include "ddsi/sysdeps.h"
#include "ddsi/q_md5.h"
#include "ddsi/q_bswap.h"
#include "ddsi/q_config.h"
#include "ddsi/q_freelist.h"
#include "q__osplser.h"
#define MAX_POOL_SIZE 16384
#ifndef NDEBUG
static int ispowerof2_size (size_t x)
{
return x > 0 && !(x & (x-1));
}
#endif
static size_t alignup_size (size_t x, size_t a);
static serstate_t serstate_allocnew (serstatepool_t pool, const struct sertopic * topic);
serstatepool_t ddsi_serstatepool_new (void)
{
serstatepool_t pool;
pool = os_malloc (sizeof (*pool));
nn_freelist_init (&pool->freelist, MAX_POOL_SIZE, offsetof (struct serstate, next));
return pool;
}
static void serstate_free_wrap (void *elem)
{
serstate_free (elem);
}
void ddsi_serstatepool_free (serstatepool_t pool)
{
nn_freelist_fini (&pool->freelist, serstate_free_wrap);
TRACE (("ddsi_serstatepool_free(%p)\n", pool));
os_free (pool);
}
int ddsi_serdata_refcount_is_1 (serdata_t serdata)
{
return (os_atomic_ld32 (&serdata->v.st->refcount) == 1);
}
serdata_t ddsi_serdata_ref (serdata_t serdata)
{
os_atomic_inc32 (&serdata->v.st->refcount);
return serdata;
}
void ddsi_serdata_unref (serdata_t serdata)
{
ddsi_serstate_release (serdata->v.st);
}
nn_mtime_t ddsi_serdata_twrite (const struct serdata *serdata)
{
return ddsi_serstate_twrite (serdata->v.st);
}
void ddsi_serdata_set_twrite (serdata_t serdata, nn_mtime_t twrite)
{
ddsi_serstate_set_twrite (serdata->v.st, twrite);
}
serstate_t ddsi_serstate_new (serstatepool_t pool, const struct sertopic * topic)
{
serstate_t st;
if ((st = nn_freelist_pop (&pool->freelist)) != NULL)
serstate_init (st, topic);
else
st = serstate_allocnew (pool, topic);
return st;
}
serdata_t ddsi_serstate_fix (serstate_t st)
{
/* see serialize_raw_private() */
ddsi_serstate_append_aligned (st, 0, 4);
return st->data;
}
nn_mtime_t ddsi_serstate_twrite (const struct serstate *serstate)
{
assert (serstate->twrite.v >= 0);
return serstate->twrite;
}
void ddsi_serstate_set_twrite (serstate_t st, nn_mtime_t twrite)
{
st->twrite = twrite;
}
void ddsi_serstate_append_blob (serstate_t st, size_t align, size_t sz, const void *data)
{
char *p = ddsi_serstate_append_aligned (st, sz, align);
memcpy (p, data, sz);
}
void ddsi_serstate_set_msginfo
(
serstate_t st, unsigned statusinfo, nn_wctime_t timestamp,
void * dummy
)
{
serdata_t d = st->data;
d->v.msginfo.statusinfo = statusinfo;
d->v.msginfo.timestamp = timestamp;
}
uint32_t ddsi_serdata_size (const struct serdata *serdata)
{
const struct serstate *st = serdata->v.st;
if (serdata->v.st->kind == STK_EMPTY)
return 0;
else
return (uint32_t) (sizeof (struct CDRHeader) + st->pos);
}
int ddsi_serdata_is_key (const struct serdata * serdata)
{
return serdata->v.st->kind == STK_KEY;
}
int ddsi_serdata_is_empty (const struct serdata * serdata)
{
return serdata->v.st->kind == STK_EMPTY;
}
/* Internal static functions */
static serstate_t serstate_allocnew (serstatepool_t pool, const struct sertopic * topic)
{
serstate_t st = os_malloc (sizeof (*st));
size_t size;
memset (st, 0, sizeof (*st));
st->size = 128;
st->pool = pool;
size = offsetof (struct serdata, data) + st->size;
st->data = os_malloc (size);
memset (st->data, 0, size);
st->data->v.st = st;
serstate_init (st, topic);
return st;
}
void * ddsi_serstate_append (serstate_t st, size_t n)
{
char *p;
if (st->pos + n > st->size)
{
size_t size1 = alignup_size (st->pos + n, 128);
serdata_t data1 = os_realloc (st->data, offsetof (struct serdata, data) + size1);
st->data = data1;
st->size = size1;
}
assert (st->pos + n <= st->size);
p = st->data->data + st->pos;
st->pos += n;
return p;
}
void ddsi_serstate_release (serstate_t st)
{
if (os_atomic_dec32_ov (&st->refcount) == 1)
{
serstatepool_t pool = st->pool;
sertopic_free ((sertopic_t) st->topic);
if (!nn_freelist_push (&pool->freelist, st))
serstate_free (st);
}
}
void * ddsi_serstate_append_align (serstate_t st, size_t sz)
{
return ddsi_serstate_append_aligned (st, sz, sz);
}
void * ddsi_serstate_append_aligned (serstate_t st, size_t n, size_t a)
{
/* Simply align st->pos, without verifying it fits in the allocated
buffer: ddsi_serstate_append() is called immediately afterward and will
grow the buffer as soon as the end of the requested space no
longer fits. */
size_t pos0 = st->pos;
char *p;
assert (ispowerof2_size (a));
st->pos = alignup_size (st->pos, a);
p = ddsi_serstate_append (st, n);
if (p && st->pos > pos0)
memset (st->data->data + pos0, 0, st->pos - pos0);
return p;
}
static size_t alignup_size (size_t x, size_t a)
{
size_t m = a-1;
assert (ispowerof2_size (a));
return (x+m) & ~m;
}

View file

@ -0,0 +1,437 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "ddsi/ddsi_ssl.h"
#include "ddsi/q_config.h"
#include "ddsi/q_log.h"
#include "os/os_heap.h"
#include "ddsi/ddsi_tcp.h"
#ifdef DDSI_INCLUDE_SSL
#include <openssl/rand.h>
#include <openssl/err.h>
static SSL_CTX * ddsi_ssl_ctx = NULL;
static SSL * ddsi_ssl_new (void)
{
return SSL_new (ddsi_ssl_ctx);
}
static void ddsi_ssl_error (SSL * ssl, const char * str, int err)
{
char buff [128];
ERR_error_string ((unsigned) SSL_get_error (ssl, err), buff);
nn_log (LC_ERROR, "tcp/ssl %s %s %d\n", str, buff, err);
}
static int ddsi_ssl_verify (int ok, X509_STORE_CTX * store)
{
if (!ok)
{
char issuer[256];
X509 * cert = X509_STORE_CTX_get_current_cert (store);
int err = X509_STORE_CTX_get_error (store);
/* Check if allowing self-signed certificates */
if
(
config.ssl_self_signed &&
((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ||
(err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN))
)
{
ok = 1;
}
else
{
X509_NAME_oneline (X509_get_issuer_name (cert), issuer, sizeof (issuer));
nn_log
(
LC_ERROR,
"tcp/ssl failed to verify certificate from %s : %s\n",
issuer,
X509_verify_cert_error_string (err)
);
}
}
return ok;
}
static os_ssize_t ddsi_ssl_read (SSL * ssl, void * buf, os_size_t len, int * err)
{
int ret;
assert (len <= INT32_MAX);
if (SSL_get_shutdown (ssl) != 0)
{
return -1;
}
/* Returns -1 on error or 0 on shutdown */
ret = SSL_read (ssl, buf, (int) len);
switch (SSL_get_error (ssl, ret))
{
case SSL_ERROR_NONE:
{
/* Success */
break;
}
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
*err = os_sockEAGAIN;
ret = -1;
break;
}
case SSL_ERROR_ZERO_RETURN:
default:
{
/* Connection closed or error */
*err = os_getErrno ();
ret = -1;
break;
}
}
return ret;
}
static os_ssize_t ddsi_ssl_write (SSL * ssl, const void * buf, os_size_t len, int * err)
{
int ret;
assert(len <= INT32_MAX);
if (SSL_get_shutdown (ssl) != 0)
{
return -1;
}
/* Returns -1 on error or 0 on shutdown */
ret = SSL_write (ssl, buf, (int) len);
switch (SSL_get_error (ssl, ret))
{
case SSL_ERROR_NONE:
{
/* Success */
break;
}
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
*err = os_sockEAGAIN;
ret = -1;
break;
}
case SSL_ERROR_ZERO_RETURN:
default:
{
/* Connection closed or error */
*err = os_getErrno ();
ret = -1;
break;
}
}
return ret;
}
/* Standard OpenSSL init and thread support routines. See O'Reilly. */
static unsigned long ddsi_ssl_id (void)
{
return os_threadIdToInteger (os_threadIdSelf ());
}
typedef struct CRYPTO_dynlock_value
{
os_mutex m_mutex;
}
CRYPTO_dynlock_value;
static CRYPTO_dynlock_value * ddsi_ssl_locks = NULL;
static void ddsi_ssl_dynlock_lock (int mode, CRYPTO_dynlock_value * lock, const char * file, int line)
{
(void) file;
(void) line;
if (mode & CRYPTO_LOCK)
{
os_mutexLock (&lock->m_mutex);
}
else
{
os_mutexUnlock (&lock->m_mutex);
}
}
static void ddsi_ssl_lock (int mode, int n, const char * file, int line)
{
ddsi_ssl_dynlock_lock (mode, &ddsi_ssl_locks[n], file, line);
}
static CRYPTO_dynlock_value * ddsi_ssl_dynlock_create (const char * file, int line)
{
CRYPTO_dynlock_value * val = os_malloc (sizeof (*val));
(void) file;
(void) line;
os_mutexInit (&val->m_mutex);
return val;
}
static void ddsi_ssl_dynlock_destroy (CRYPTO_dynlock_value * lock, const char * file, int line)
{
(void) file;
(void) line;
os_mutexDestroy (&lock->m_mutex);
os_free (lock);
}
static int ddsi_ssl_password (char * buf, int num, int rwflag, void * udata)
{
(void) rwflag;
(void) udata;
if ((unsigned int) num < strlen (config.ssl_key_pass) + 1)
{
return (0);
}
strcpy (buf, config.ssl_key_pass);
return (int) strlen (config.ssl_key_pass);
}
static SSL_CTX * ddsi_ssl_ctx_init (void)
{
int i;
SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
/* Load certificates */
if (! SSL_CTX_use_certificate_file (ctx, config.ssl_keystore, SSL_FILETYPE_PEM))
{
nn_log
(
LC_ERROR | LC_CONFIG,
"tcp/ssl failed to load certificate from file: %s\n",
config.ssl_keystore
);
goto fail;
}
/* Set password and callback */
SSL_CTX_set_default_passwd_cb (ctx, ddsi_ssl_password);
/* Get private key */
if (! SSL_CTX_use_PrivateKey_file (ctx, config.ssl_keystore, SSL_FILETYPE_PEM))
{
nn_log
(
LC_ERROR | LC_CONFIG,
"tcp/ssl failed to load private key from file: %s\n",
config.ssl_keystore
);
goto fail;
}
/* Load CAs */
if (! SSL_CTX_load_verify_locations (ctx, config.ssl_keystore, 0))
{
nn_log
(
LC_ERROR | LC_CONFIG,
"tcp/ssl failed to load CA from file: %s\n",
config.ssl_keystore
);
goto fail;
}
/* Set ciphers */
if (! SSL_CTX_set_cipher_list (ctx, config.ssl_ciphers))
{
nn_log
(
LC_ERROR | LC_CONFIG,
"tcp/ssl failed to set ciphers: %s\n",
config.ssl_ciphers
);
goto fail;
}
/* Load randomness from file (optional) */
if (config.ssl_rand_file[0] != '\0')
{
if (! RAND_load_file (config.ssl_rand_file, 4096))
{
nn_log
(
LC_ERROR | LC_CONFIG,
"tcp/ssl failed to load random seed from file: %s\n",
config.ssl_rand_file
);
goto fail;
}
}
/* Set certificate verification policy from configuration */
if (config.ssl_verify)
{
i = SSL_VERIFY_PEER;
if (config.ssl_verify_client)
{
i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
}
SSL_CTX_set_verify (ctx, i, ddsi_ssl_verify);
}
else
{
SSL_CTX_set_verify (ctx, SSL_VERIFY_NONE, NULL);
}
SSL_CTX_set_options (ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
return ctx;
fail:
SSL_CTX_free (ctx);
return NULL;
}
static SSL * ddsi_ssl_connect (os_socket sock)
{
SSL * ssl;
int err;
/* Connect SSL over connected socket */
ssl = ddsi_ssl_new ();
SSL_set_fd (ssl, sock);
err = SSL_connect (ssl);
if (err != 1)
{
ddsi_ssl_error (ssl, "connect failed", err);
SSL_free (ssl);
ssl = NULL;
}
return ssl;
}
static BIO * ddsi_ssl_listen (os_socket sock)
{
BIO * bio = BIO_new (BIO_s_accept ());
BIO_set_fd (bio, sock, BIO_NOCLOSE);
return bio;
}
static SSL * ddsi_ssl_accept (BIO * bio, os_socket * sock)
{
SSL * ssl = NULL;
BIO * nbio;
int err;
if (BIO_do_accept (bio) > 0)
{
nbio = BIO_pop (bio);
*sock = (os_socket) BIO_get_fd (nbio, NULL);
ssl = ddsi_ssl_new ();
SSL_set_bio (ssl, nbio, nbio);
err = SSL_accept (ssl);
if (err <= 0)
{
SSL_free (ssl);
*sock = Q_INVALID_SOCKET;
ssl = NULL;
}
}
return ssl;
}
static c_bool ddsi_ssl_init (void)
{
unsigned locks = (unsigned) CRYPTO_num_locks ();
unsigned i;
ddsi_ssl_locks = os_malloc (sizeof (CRYPTO_dynlock_value) * locks);
for (i = 0; i < locks; i++)
{
os_mutexInit (&ddsi_ssl_locks[i].m_mutex);
}
ERR_load_BIO_strings ();
SSL_load_error_strings ();
SSL_library_init ();
OpenSSL_add_all_algorithms ();
CRYPTO_set_id_callback (ddsi_ssl_id);
CRYPTO_set_locking_callback (ddsi_ssl_lock);
CRYPTO_set_dynlock_create_callback (ddsi_ssl_dynlock_create);
CRYPTO_set_dynlock_lock_callback (ddsi_ssl_dynlock_lock);
CRYPTO_set_dynlock_destroy_callback (ddsi_ssl_dynlock_destroy);
ddsi_ssl_ctx = ddsi_ssl_ctx_init ();
return (ddsi_ssl_ctx != NULL);
}
static void ddsi_ssl_fini (void)
{
unsigned locks = (unsigned) CRYPTO_num_locks ();
unsigned i;
SSL_CTX_free (ddsi_ssl_ctx);
CRYPTO_set_id_callback (NULL);
CRYPTO_set_locking_callback (NULL);
CRYPTO_set_dynlock_create_callback (NULL);
CRYPTO_set_dynlock_lock_callback (NULL);
CRYPTO_set_dynlock_destroy_callback (NULL);
ERR_free_strings ();
EVP_cleanup ();
for (i = 0; i < locks; i++)
{
os_mutexDestroy (&ddsi_ssl_locks[i].m_mutex);
}
os_free (ddsi_ssl_locks);
}
static void ddsi_ssl_config (void)
{
if (config.ssl_enable)
{
ddsi_tcp_ssl_plugin.init = ddsi_ssl_init;
ddsi_tcp_ssl_plugin.fini = ddsi_ssl_fini;
ddsi_tcp_ssl_plugin.ssl_free = SSL_free;
ddsi_tcp_ssl_plugin.bio_vfree = BIO_vfree;
ddsi_tcp_ssl_plugin.read = ddsi_ssl_read;
ddsi_tcp_ssl_plugin.write = ddsi_ssl_write;
ddsi_tcp_ssl_plugin.connect = ddsi_ssl_connect;
ddsi_tcp_ssl_plugin.listen = ddsi_ssl_listen;
ddsi_tcp_ssl_plugin.accept = ddsi_ssl_accept;
}
}
void ddsi_ssl_plugin (void)
{
ddsi_tcp_ssl_plugin.config = ddsi_ssl_config;
}
#endif /* DDSI_INCLUDE_SSL */

1068
src/core/ddsi/src/ddsi_tcp.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,206 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include "os/os.h"
#include "ddsi/ddsi_tran.h"
#include "ddsi/q_config.h"
#include "ddsi/q_log.h"
static ddsi_tran_factory_t ddsi_tran_factories = NULL;
void ddsi_factory_add (ddsi_tran_factory_t factory)
{
factory->m_factory = ddsi_tran_factories;
ddsi_tran_factories = factory;
}
ddsi_tran_factory_t ddsi_factory_find (const char * type)
{
ddsi_tran_factory_t factory = ddsi_tran_factories;
while (factory)
{
if (strcmp (factory->m_typename, type) == 0)
{
break;
}
factory = factory->m_factory;
}
return factory;
}
void ddsi_tran_factories_fini (void)
{
ddsi_tran_factory_t factory;
while ((factory = ddsi_tran_factories) != NULL) {
ddsi_tran_factories = ddsi_tran_factories->m_factory;
ddsi_factory_free(factory);
}
}
void ddsi_factory_free (ddsi_tran_factory_t factory)
{
if (factory && factory->m_free_fn)
{
(factory->m_free_fn) ();
}
}
void ddsi_conn_free (ddsi_tran_conn_t conn)
{
if (conn)
{
if (! conn->m_closed)
{
conn->m_closed = true;
if (conn->m_factory->m_close_conn_fn)
{
(conn->m_factory->m_close_conn_fn) (conn);
}
}
if (os_atomic_dec32_ov (&conn->m_count) == 1)
{
(conn->m_factory->m_release_conn_fn) (conn);
}
}
}
void ddsi_conn_add_ref (ddsi_tran_conn_t conn)
{
os_atomic_inc32 (&conn->m_count);
}
extern void ddsi_factory_conn_init (ddsi_tran_factory_t factory, ddsi_tran_conn_t conn)
{
os_atomic_st32 (&conn->m_count, 1);
conn->m_connless = factory->m_connless;
conn->m_stream = factory->m_stream;
conn->m_factory = factory;
}
ssize_t ddsi_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len)
{
return (conn->m_closed) ? -1 : (conn->m_read_fn) (conn, buf, len);
}
ssize_t ddsi_conn_write (ddsi_tran_conn_t conn, const struct msghdr * msg, size_t len, uint32_t flags)
{
ssize_t ret = -1;
if (! conn->m_closed)
{
ret = (conn->m_write_fn) (conn, msg, len, flags);
}
/* Check that write function is atomic (all or nothing) */
assert (ret == -1 || (size_t) ret == len);
return ret;
}
bool ddsi_conn_peer_locator (ddsi_tran_conn_t conn, nn_locator_t * loc)
{
if (conn->m_peer_locator_fn)
{
(conn->m_peer_locator_fn) (conn, loc);
return true;
}
return false;
}
void ddsi_tran_free_qos (ddsi_tran_qos_t qos)
{
os_free (qos);
}
int ddsi_conn_join_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcloc, const nn_locator_t *mcloc)
{
return conn->m_factory->m_join_mc_fn (conn, srcloc, mcloc);
}
int ddsi_conn_leave_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcloc, const nn_locator_t *mcloc)
{
return conn->m_factory->m_leave_mc_fn (conn, srcloc, mcloc);
}
os_handle ddsi_tran_handle (ddsi_tran_base_t base)
{
return (base->m_handle_fn) (base);
}
ddsi_tran_qos_t ddsi_tran_create_qos (void)
{
ddsi_tran_qos_t qos;
qos = (ddsi_tran_qos_t) os_malloc (sizeof (*qos));
memset (qos, 0, sizeof (*qos));
return qos;
}
ddsi_tran_conn_t ddsi_factory_create_conn
(
ddsi_tran_factory_t factory,
uint32_t port,
ddsi_tran_qos_t qos
)
{
return factory->m_create_conn_fn (port, qos);
}
int ddsi_tran_locator (ddsi_tran_base_t base, nn_locator_t * loc)
{
return (base->m_locator_fn) (base, loc);
}
int ddsi_listener_listen (ddsi_tran_listener_t listener)
{
return (listener->m_listen_fn) (listener);
}
ddsi_tran_conn_t ddsi_listener_accept (ddsi_tran_listener_t listener)
{
return (listener->m_accept_fn) (listener);
}
void ddsi_tran_free (ddsi_tran_base_t base)
{
if (base)
{
if (base->m_trantype == DDSI_TRAN_CONN)
{
ddsi_conn_free ((ddsi_tran_conn_t) base);
}
else
{
ddsi_listener_unblock ((ddsi_tran_listener_t) base);
ddsi_listener_free ((ddsi_tran_listener_t) base);
}
}
}
void ddsi_listener_unblock (ddsi_tran_listener_t listener)
{
if (listener)
{
(listener->m_factory->m_unblock_listener_fn) (listener);
}
}
void ddsi_listener_free (ddsi_tran_listener_t listener)
{
if (listener)
{
(listener->m_factory->m_release_listener_fn) (listener);
}
}

View file

@ -0,0 +1,337 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include "os/os.h"
#include "ddsi/ddsi_tran.h"
#include "ddsi/ddsi_udp.h"
#include "ddsi/q_nwif.h"
#include "ddsi/q_config.h"
#include "ddsi/q_log.h"
#include "ddsi/q_pcap.h"
extern void ddsi_factory_conn_init (ddsi_tran_factory_t factory, ddsi_tran_conn_t conn);
typedef struct ddsi_tran_factory * ddsi_udp_factory_t;
typedef struct ddsi_udp_config
{
struct nn_group_membership *mship;
}
* ddsi_udp_config_t;
typedef struct ddsi_udp_conn
{
struct ddsi_tran_conn m_base;
os_socket m_sock;
#if defined _WIN32 && !defined WINCE
WSAEVENT m_sockEvent;
#endif
int m_diffserv;
}
* ddsi_udp_conn_t;
static struct ddsi_udp_config ddsi_udp_config_g;
static struct ddsi_tran_factory ddsi_udp_factory_g;
static os_atomic_uint32_t ddsi_udp_init_g = OS_ATOMIC_UINT32_INIT(0);
static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len)
{
int err;
ssize_t ret;
struct msghdr msghdr;
os_sockaddr_storage src;
struct iovec msg_iov;
socklen_t srclen = (socklen_t) sizeof (src);
msg_iov.iov_base = (void*) buf;
msg_iov.iov_len = len;
memset (&msghdr, 0, sizeof (msghdr));
msghdr.msg_name = &src;
msghdr.msg_namelen = srclen;
msghdr.msg_iov = &msg_iov;
msghdr.msg_iovlen = 1;
do {
ret = recvmsg(((ddsi_udp_conn_t) conn)->m_sock, &msghdr, 0);
err = (ret == -1) ? os_getErrno() : 0;
} while (err == os_sockEINTR);
if (ret > 0)
{
/* Check for udp packet truncation */
if ((((size_t) ret) > len)
#if SYSDEPS_MSGHDR_FLAGS
|| (msghdr.msg_flags & MSG_TRUNC)
#endif
)
{
char addrbuf[INET6_ADDRSTRLEN_EXTENDED];
sockaddr_to_string_with_port (addrbuf, &src);
NN_WARNING ("%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len);
}
}
else if (err != os_sockENOTSOCK && err != os_sockECONNRESET)
{
NN_ERROR ("UDP recvmsg sock %d: ret %d errno %d\n", (int) ((ddsi_udp_conn_t) conn)->m_sock, (int) ret, err);
}
return ret;
}
static ssize_t ddsi_udp_conn_write (ddsi_tran_conn_t conn, const struct msghdr * msg, size_t len, uint32_t flags)
{
int err;
ssize_t ret;
unsigned retry = 2;
int sendflags = 0;
(void) flags;
(void) len;
#ifdef MSG_NOSIGNAL
sendflags |= MSG_NOSIGNAL;
#endif
do {
ddsi_udp_conn_t uc = (ddsi_udp_conn_t) conn;
ret = sendmsg (uc->m_sock, msg, sendflags);
err = (ret == -1) ? os_getErrno() : 0;
#if defined _WIN32 && !defined WINCE
if (err == os_sockEWOULDBLOCK) {
WSANETWORKEVENTS ev;
WaitForSingleObject(uc->m_sockEvent, INFINITE);
WSAEnumNetworkEvents(uc->m_sock, uc->m_sockEvent, &ev);
}
#endif
} while (err == os_sockEINTR || err == os_sockEWOULDBLOCK || (err == os_sockEPERM && retry-- > 0));
if (ret > 0 && gv.pcap_fp)
{
os_sockaddr_storage sa;
socklen_t alen = sizeof (sa);
if (getsockname (((ddsi_udp_conn_t) conn)->m_sock, (struct sockaddr *) &sa, &alen) == -1)
memset(&sa, 0, sizeof(sa));
write_pcap_sent (gv.pcap_fp, now (), &sa, msg, (size_t) ret);
}
else if (ret == -1)
{
switch (err)
{
case os_sockEPERM:
case os_sockECONNRESET:
#ifdef os_sockENETUNREACH
case os_sockENETUNREACH:
#endif
#ifdef os_sockEHOSTUNREACH
case os_sockEHOSTUNREACH:
#endif
break;
default:
NN_ERROR("ddsi_udp_conn_write failed with error code %d", err);
}
}
return ret;
}
static os_handle ddsi_udp_conn_handle (ddsi_tran_base_t base)
{
return ((ddsi_udp_conn_t) base)->m_sock;
}
static bool ddsi_udp_supports (int32_t kind)
{
return
(
(!config.useIpv6 && (kind == NN_LOCATOR_KIND_UDPv4))
#if OS_SOCKET_HAS_IPV6
|| (config.useIpv6 && (kind == NN_LOCATOR_KIND_UDPv6))
#endif
);
}
static int ddsi_udp_conn_locator (ddsi_tran_base_t base, nn_locator_t *loc)
{
int ret = -1;
ddsi_udp_conn_t uc = (ddsi_udp_conn_t) base;
os_sockaddr_storage * addr = &gv.extip;
memset (loc, 0, sizeof (*loc));
if (uc->m_sock != Q_INVALID_SOCKET)
{
loc->kind = ddsi_udp_factory_g.m_kind;
loc->port = uc->m_base.m_base.m_port;
if (loc->kind == NN_LOCATOR_KIND_UDPv4)
{
memcpy (loc->address + 12, &((os_sockaddr_in*) addr)->sin_addr, 4);
}
else
{
memcpy (loc->address, &((os_sockaddr_in6*) addr)->sin6_addr, 16);
}
ret = 0;
}
return ret;
}
static ddsi_tran_conn_t ddsi_udp_create_conn
(
uint32_t port,
ddsi_tran_qos_t qos
)
{
int ret;
os_socket sock;
ddsi_udp_conn_t uc = NULL;
bool mcast = (bool) (qos ? qos->m_multicast : false);
/* If port is zero, need to create dynamic port */
ret = make_socket
(
&sock,
(unsigned short) port,
false,
mcast
);
if (ret == 0)
{
uc = (ddsi_udp_conn_t) os_malloc (sizeof (*uc));
memset (uc, 0, sizeof (*uc));
uc->m_sock = sock;
uc->m_diffserv = qos ? qos->m_diffserv : 0;
#if defined _WIN32 && !defined WINCE
uc->m_sockEvent = WSACreateEvent();
WSAEventSelect(uc->m_sock, uc->m_sockEvent, FD_WRITE);
#endif
ddsi_factory_conn_init (&ddsi_udp_factory_g, &uc->m_base);
uc->m_base.m_base.m_port = get_socket_port (sock);
uc->m_base.m_base.m_trantype = DDSI_TRAN_CONN;
uc->m_base.m_base.m_multicast = mcast;
uc->m_base.m_base.m_handle_fn = ddsi_udp_conn_handle;
uc->m_base.m_base.m_locator_fn = ddsi_udp_conn_locator;
uc->m_base.m_read_fn = ddsi_udp_conn_read;
uc->m_base.m_write_fn = ddsi_udp_conn_write;
nn_log
(
LC_INFO,
"ddsi_udp_create_conn %s socket %"PRIsock" port %u\n",
mcast ? "multicast" : "unicast",
uc->m_sock,
uc->m_base.m_base.m_port
);
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
if ((uc->m_diffserv != 0) && (ddsi_udp_factory_g.m_kind == NN_LOCATOR_KIND_UDPv4))
{
set_socket_diffserv (uc->m_sock, uc->m_diffserv);
}
#endif
}
else
{
if (config.participantIndex != PARTICIPANT_INDEX_AUTO)
{
NN_ERROR
(
"UDP make_socket failed for %s port %u\n",
mcast ? "multicast" : "unicast",
port
);
}
}
return uc ? &uc->m_base : NULL;
}
static int ddsi_udp_join_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcloc, const nn_locator_t *mcloc)
{
ddsi_udp_conn_t uc = (ddsi_udp_conn_t) conn;
os_sockaddr_storage mcip, srcip;
nn_loc_to_address (&mcip, mcloc);
if (srcloc)
nn_loc_to_address (&srcip, srcloc);
return join_mcgroups (ddsi_udp_config_g.mship, uc->m_sock, srcloc ? &srcip : NULL, &mcip);
}
static int ddsi_udp_leave_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcloc, const nn_locator_t *mcloc)
{
ddsi_udp_conn_t uc = (ddsi_udp_conn_t) conn;
os_sockaddr_storage mcip, srcip;
nn_loc_to_address (&mcip, mcloc);
if (srcloc)
nn_loc_to_address (&srcip, srcloc);
return leave_mcgroups (ddsi_udp_config_g.mship, uc->m_sock, srcloc ? &srcip : NULL, &mcip);
}
static void ddsi_udp_release_conn (ddsi_tran_conn_t conn)
{
ddsi_udp_conn_t uc = (ddsi_udp_conn_t) conn;
nn_log
(
LC_INFO,
"ddsi_udp_release_conn %s socket %"PRIsock" port %u\n",
conn->m_base.m_multicast ? "multicast" : "unicast",
uc->m_sock,
uc->m_base.m_base.m_port
);
os_sockFree (uc->m_sock);
#if defined _WIN32 && !defined WINCE
WSACloseEvent(uc->m_sockEvent);
#endif
os_free (conn);
}
void ddsi_udp_fini (void)
{
if(os_atomic_dec32_nv (&ddsi_udp_init_g) == 0) {
free_group_membership(ddsi_udp_config_g.mship);
memset (&ddsi_udp_factory_g, 0, sizeof (ddsi_udp_factory_g));
nn_log (LC_INFO | LC_CONFIG, "udp finalized\n");
}
}
int ddsi_udp_init (void)
{
/* TODO: proper init_once. Either the call doesn't need it, in which case
* this can be removed. Or the call does, in which case it should be done right.
* The lack of locking suggests it isn't needed.
*/
if (os_atomic_inc32_nv (&ddsi_udp_init_g) == 1)
{
memset (&ddsi_udp_factory_g, 0, sizeof (ddsi_udp_factory_g));
ddsi_udp_factory_g.m_kind = NN_LOCATOR_KIND_UDPv4;
ddsi_udp_factory_g.m_typename = "udp";
ddsi_udp_factory_g.m_connless = true;
ddsi_udp_factory_g.m_supports_fn = ddsi_udp_supports;
ddsi_udp_factory_g.m_create_conn_fn = ddsi_udp_create_conn;
ddsi_udp_factory_g.m_release_conn_fn = ddsi_udp_release_conn;
ddsi_udp_factory_g.m_free_fn = ddsi_udp_fini;
ddsi_udp_factory_g.m_join_mc_fn = ddsi_udp_join_mc;
ddsi_udp_factory_g.m_leave_mc_fn = ddsi_udp_leave_mc;
#if OS_SOCKET_HAS_IPV6
if (config.useIpv6)
{
ddsi_udp_factory_g.m_kind = NN_LOCATOR_KIND_UDPv6;
}
#endif
ddsi_udp_config_g.mship = new_group_membership();
ddsi_factory_add (&ddsi_udp_factory_g);
nn_log (LC_INFO | LC_CONFIG, "udp initialized\n");
}
return 0;
}

View file

@ -0,0 +1,681 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <string.h>
#include <stddef.h>
#include <assert.h>
#include "os/os.h"
#include "util/ut_avl.h"
#include "ddsi/q_log.h"
#include "ddsi/q_misc.h"
#include "ddsi/q_config.h"
#include "ddsi/q_addrset.h"
#include "ddsi/q_globals.h" /* gv.mattr */
/* So what does one do with const & mutexes? I need to take lock in a
pure function just in case some other thread is trying to change
something. Arguably, that means the thing isn't const; but one
could just as easily argue that "const" means "this call won't
change it". If it is globally visible before the call, it may
change anyway.
Today, I'm taking the latter interpretation. But all the
const-discarding casts get moved into LOCK/UNLOCK macros. */
#define LOCK(as) (os_mutexLock (&((struct addrset *) (as))->lock))
#define TRYLOCK(as) (os_mutexTryLock (&((struct addrset *) (as))->lock))
#define UNLOCK(as) (os_mutexUnlock (&((struct addrset *) (as))->lock))
static int compare_locators_vwrap (const void *va, const void *vb);
static const ut_avlCTreedef_t addrset_treedef =
UT_AVL_CTREEDEF_INITIALIZER (offsetof (struct addrset_node, avlnode), offsetof (struct addrset_node, loc), compare_locators_vwrap, 0);
static int add_addresses_to_addrset_1 (struct addrset *as, const char *ip, int port_mode, const char *msgtag, int req_mc, int mcgen_base, int mcgen_count, int mcgen_idx)
{
char buf[INET6_ADDRSTRLEN_EXTENDED];
os_sockaddr_storage tmpaddr;
nn_locator_t loc;
int32_t kind;
if (config.useIpv6)
kind = config.tcp_enable ? NN_LOCATOR_KIND_TCPv6 : NN_LOCATOR_KIND_UDPv6;
else
kind = config.tcp_enable ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_UDPv4;
if (!os_sockaddrStringToAddress (ip, (os_sockaddr *) &tmpaddr, !config.useIpv6))
{
NN_ERROR ("%s: %s: not a valid address\n", msgtag, ip);
return -1;
}
if ((config.useIpv6 && tmpaddr.ss_family != AF_INET6) || (!config.useIpv6 && tmpaddr.ss_family != AF_INET))
{
NN_ERROR ("%s: %s: not a valid IPv%d address\n", msgtag, ip, config.useIpv6 ? 6 : 4);
return -1;
}
nn_address_to_loc (&loc, &tmpaddr, kind);
if (req_mc && !is_mcaddr (&loc))
{
NN_ERROR ("%s: %s: not a multicast address\n", msgtag, ip);
return -1;
}
if (mcgen_base == -1 && mcgen_count == -1 && mcgen_idx == -1)
;
else if (kind == NN_LOCATOR_KIND_UDPv4 && is_mcaddr(&loc) && mcgen_base >= 0 && mcgen_count > 0 && mcgen_base + mcgen_count < 28 && mcgen_idx >= 0 && mcgen_idx < mcgen_count)
{
nn_udpv4mcgen_address_t x;
memset(&x, 0, sizeof(x));
memcpy(&x.ipv4, loc.address + 12, 4);
x.base = (unsigned char) mcgen_base;
x.count = (unsigned char) mcgen_count;
x.idx = (unsigned char) mcgen_idx;
memset(loc.address, 0, sizeof(loc.address));
memcpy(loc.address, &x, sizeof(x));
loc.kind = NN_LOCATOR_KIND_UDPv4MCGEN;
}
else
{
NN_ERROR ("%s: %s,%d,%d,%d: IPv4 multicast address generator invalid or out of place\n",
msgtag, ip, mcgen_base, mcgen_count, mcgen_idx);
return -1;
}
if (port_mode >= 0)
{
loc.port = (unsigned) port_mode;
nn_log (LC_CONFIG, "%s: add %s", msgtag, locator_to_string_with_port (buf, &loc));
add_to_addrset (as, &loc);
}
else
{
nn_log (LC_CONFIG, "%s: add ", msgtag);
if (!is_mcaddr (&loc))
{
int i;
for (i = 0; i <= config.maxAutoParticipantIndex; i++)
{
int port = config.port_base + config.port_dg * config.domainId + i * config.port_pg + config.port_d1;
loc.port = (unsigned) port;
if (i == 0)
nn_log (LC_CONFIG, "%s", locator_to_string_with_port (buf, &loc));
else
nn_log (LC_CONFIG, ", :%d", port);
add_to_addrset (as, &loc);
}
}
else
{
int port = port_mode;
if (port == -1)
port = config.port_base + config.port_dg * config.domainId + config.port_d0;
loc.port = (unsigned) port;
nn_log (LC_CONFIG, "%s", locator_to_string_with_port (buf, &loc));
add_to_addrset (as, &loc);
}
}
nn_log (LC_CONFIG, "\n");
return 0;
}
int add_addresses_to_addrset (struct addrset *as, const char *addrs, int port_mode, const char *msgtag, int req_mc)
{
/* port_mode: -1 => take from string, if 0 & unicast, add for a range of participant indices;
port_mode >= 0 => always set port to port_mode
*/
char *addrs_copy, *ip, *cursor, *a;
int retval = -1;
addrs_copy = os_strdup (addrs);
ip = os_malloc (strlen (addrs) + 1);
cursor = addrs_copy;
while ((a = os_strsep (&cursor, ",")) != NULL)
{
int port = 0, pos;
int mcgen_base = -1, mcgen_count = -1, mcgen_idx = -1;
if (!config.useIpv6)
{
if (port_mode == -1 && sscanf (a, "%[^:]:%d%n", ip, &port, &pos) == 2 && a[pos] == 0)
; /* XYZ:PORT */
else if (sscanf (a, "%[^;];%d;%d;%d%n", ip, &mcgen_base, &mcgen_count, &mcgen_idx, &pos) == 4 && a[pos] == 0)
port = port_mode; /* XYZ;BASE;COUNT;IDX for IPv4 MC address generators */
else if (sscanf (a, "%[^:]%n", ip, &pos) == 1 && a[pos] == 0)
port = port_mode; /* XYZ */
else { /* XY:Z -- illegal, but conversion routine should flag it */
strcpy (ip, a);
port = 0;
}
}
else
{
if (port_mode == -1 && sscanf (a, "[%[^]]]:%d%n", ip, &port, &pos) == 2 && a[pos] == 0)
; /* [XYZ]:PORT */
else if (sscanf (a, "[%[^]]]%n", ip, &pos) == 1 && a[pos] == 0)
port = port_mode; /* [XYZ] */
else { /* XYZ -- let conversion routines handle errors */
strcpy (ip, a);
port = 0;
}
}
if ((port > 0 && port <= 65535) || (port_mode == -1 && port == -1)) {
if (add_addresses_to_addrset_1 (as, ip, port, msgtag, req_mc, mcgen_base, mcgen_count, mcgen_idx) < 0)
goto error;
} else {
NN_ERROR ("%s: %s: port %d invalid\n", msgtag, a, port);
}
}
retval = 0;
error:
os_free (ip);
os_free (addrs_copy);
return retval;
}
int compare_locators (const nn_locator_t *a, const nn_locator_t *b)
{
int c;
if (a->kind != b->kind)
return (int) (a->kind - b->kind);
else if ((c = memcmp (a->address, b->address, sizeof (a->address))) != 0)
return c;
else
return (int) (a->port - b->port);
}
static int compare_locators_vwrap (const void *va, const void *vb)
{
return compare_locators (va, vb);
}
struct addrset *new_addrset (void)
{
struct addrset *as = os_malloc (sizeof (*as));
os_atomic_st32 (&as->refc, 1);
os_mutexInit (&as->lock);
ut_avlCInit (&addrset_treedef, &as->ucaddrs);
ut_avlCInit (&addrset_treedef, &as->mcaddrs);
return as;
}
struct addrset *ref_addrset (struct addrset *as)
{
if (as != NULL)
{
os_atomic_inc32 (&as->refc);
}
return as;
}
void unref_addrset (struct addrset *as)
{
if ((as != NULL) && (os_atomic_dec32_ov (&as->refc) == 1))
{
ut_avlCFree (&addrset_treedef, &as->ucaddrs, os_free);
ut_avlCFree (&addrset_treedef, &as->mcaddrs, os_free);
os_mutexDestroy (&as->lock);
os_free (as);
}
}
int is_mcaddr (const nn_locator_t *loc)
{
os_sockaddr_storage tmp;
switch (loc->kind)
{
case NN_LOCATOR_KIND_UDPv4: {
const os_sockaddr_in *x;
nn_loc_to_address (&tmp, loc);
x = (const os_sockaddr_in *) &tmp;
return IN_MULTICAST (ntohl (x->sin_addr.s_addr));
}
#if OS_SOCKET_HAS_IPV6
case NN_LOCATOR_KIND_UDPv6: {
const os_sockaddr_in6 *x;
nn_loc_to_address (&tmp, loc);
x = (const os_sockaddr_in6 *) &tmp;
return IN6_IS_ADDR_MULTICAST (&x->sin6_addr);
}
#endif
case NN_LOCATOR_KIND_UDPv4MCGEN:
return 1;
default: {
return 0;
}
}
}
void set_unspec_locator (nn_locator_t *loc)
{
loc->kind = NN_LOCATOR_KIND_INVALID;
loc->port = NN_LOCATOR_PORT_INVALID;
memset (loc->address, 0, sizeof (loc->address));
}
int is_unspec_locator (const nn_locator_t *loc)
{
static const nn_locator_t zloc;
return (loc->kind == NN_LOCATOR_KIND_INVALID &&
loc->port == NN_LOCATOR_PORT_INVALID &&
memcmp (&zloc.address, loc->address, sizeof (zloc.address)) == 0);
}
#ifdef DDSI_INCLUDE_SSM
int is_ssm_mcaddr (const nn_locator_t *loc)
{
os_sockaddr_storage tmp;
switch (loc->kind)
{
case NN_LOCATOR_KIND_UDPv4: {
const os_sockaddr_in *x;
nn_loc_to_address (&tmp, loc);
x = (const os_sockaddr_in *) &tmp;
return (((uint32_t) ntohl (x->sin_addr.s_addr)) >> 24) == 232;
}
#if OS_SOCKET_HAS_IPV6
case NN_LOCATOR_KIND_UDPv6: {
const os_sockaddr_in6 *x;
nn_loc_to_address (&tmp, loc);
x = (const os_sockaddr_in6 *) &tmp;
return x->sin6_addr.s6_addr[0] == 0xff && (x->sin6_addr.s6_addr[1] & 0xf0) == 0x30;
}
#endif
default: {
return 0;
}
}
}
int addrset_contains_ssm (const struct addrset *as)
{
struct addrset_node *n;
ut_avlCIter_t it;
LOCK (as);
for (n = ut_avlCIterFirst (&addrset_treedef, &as->mcaddrs, &it); n; n = ut_avlCIterNext (&it))
{
if (is_ssm_mcaddr (&n->loc))
{
UNLOCK (as);
return 1;
}
}
UNLOCK (as);
return 0;
}
int addrset_any_ssm (const struct addrset *as, nn_locator_t *dst)
{
struct addrset_node *n;
ut_avlCIter_t it;
LOCK (as);
for (n = ut_avlCIterFirst (&addrset_treedef, &as->mcaddrs, &it); n; n = ut_avlCIterNext (&it))
{
if (is_ssm_mcaddr (&n->loc))
{
*dst = n->loc;
UNLOCK (as);
return 1;
}
}
UNLOCK (as);
return 0;
}
int addrset_any_non_ssm_mc (const struct addrset *as, nn_locator_t *dst)
{
struct addrset_node *n;
ut_avlCIter_t it;
LOCK (as);
for (n = ut_avlCIterFirst (&addrset_treedef, &as->mcaddrs, &it); n; n = ut_avlCIterNext (&it))
{
if (!is_ssm_mcaddr (&n->loc))
{
*dst = n->loc;
UNLOCK (as);
return 1;
}
}
UNLOCK (as);
return 0;
}
#endif
int addrset_purge (struct addrset *as)
{
LOCK (as);
ut_avlCFree (&addrset_treedef, &as->ucaddrs, os_free);
ut_avlCFree (&addrset_treedef, &as->mcaddrs, os_free);
UNLOCK (as);
return 0;
}
void add_to_addrset (struct addrset *as, const nn_locator_t *loc)
{
if (!is_unspec_locator (loc))
{
ut_avlIPath_t path;
ut_avlCTree_t *tree = is_mcaddr (loc) ? &as->mcaddrs : &as->ucaddrs;
LOCK (as);
if (ut_avlCLookupIPath (&addrset_treedef, tree, loc, &path) == NULL)
{
struct addrset_node *n = os_malloc (sizeof (*n));
n->loc = *loc;
ut_avlCInsertIPath (&addrset_treedef, tree, n, &path);
}
UNLOCK (as);
}
}
void remove_from_addrset (struct addrset *as, const nn_locator_t *loc)
{
ut_avlDPath_t path;
ut_avlCTree_t *tree = is_mcaddr (loc) ? &as->mcaddrs : &as->ucaddrs;
struct addrset_node *n;
LOCK (as);
if ((n = ut_avlCLookupDPath (&addrset_treedef, tree, loc, &path)) != NULL)
{
ut_avlCDeleteDPath (&addrset_treedef, tree, n, &path);
os_free (n);
}
UNLOCK (as);
}
void copy_addrset_into_addrset_uc (struct addrset *as, const struct addrset *asadd)
{
struct addrset_node *n;
ut_avlCIter_t it;
LOCK (asadd);
for (n = ut_avlCIterFirst (&addrset_treedef, &asadd->ucaddrs, &it); n; n = ut_avlCIterNext (&it))
add_to_addrset (as, &n->loc);
UNLOCK (asadd);
}
void copy_addrset_into_addrset_mc (struct addrset *as, const struct addrset *asadd)
{
struct addrset_node *n;
ut_avlCIter_t it;
LOCK (asadd);
for (n = ut_avlCIterFirst (&addrset_treedef, &asadd->mcaddrs, &it); n; n = ut_avlCIterNext (&it))
add_to_addrset (as, &n->loc);
UNLOCK (asadd);
}
void copy_addrset_into_addrset (struct addrset *as, const struct addrset *asadd)
{
copy_addrset_into_addrset_uc (as, asadd);
copy_addrset_into_addrset_mc (as, asadd);
}
#ifdef DDSI_INCLUDE_SSM
void copy_addrset_into_addrset_no_ssm_mc (struct addrset *as, const struct addrset *asadd)
{
struct addrset_node *n;
ut_avlCIter_t it;
LOCK (asadd);
for (n = ut_avlCIterFirst (&addrset_treedef, &asadd->mcaddrs, &it); n; n = ut_avlCIterNext (&it))
{
if (!is_ssm_mcaddr (&n->loc))
add_to_addrset (as, &n->loc);
}
UNLOCK (asadd);
}
void copy_addrset_into_addrset_no_ssm (struct addrset *as, const struct addrset *asadd)
{
copy_addrset_into_addrset_uc (as, asadd);
copy_addrset_into_addrset_no_ssm_mc (as, asadd);
}
void addrset_purge_ssm (struct addrset *as)
{
struct addrset_node *n;
LOCK (as);
n = ut_avlCFindMin (&addrset_treedef, &as->mcaddrs);
while (n)
{
struct addrset_node *n1 = n;
n = ut_avlCFindSucc (&addrset_treedef, &as->mcaddrs, n);
if (is_ssm_mcaddr (&n1->loc))
{
ut_avlCDelete (&addrset_treedef, &as->mcaddrs, n1);
os_free (n1);
}
}
UNLOCK (as);
}
#endif
size_t addrset_count (const struct addrset *as)
{
if (as == NULL)
return 0;
else
{
size_t count;
LOCK (as);
count = ut_avlCCount (&as->ucaddrs) + ut_avlCCount (&as->mcaddrs);
UNLOCK (as);
return count;
}
}
size_t addrset_count_uc (const struct addrset *as)
{
if (as == NULL)
return 0;
else
{
size_t count;
LOCK (as);
count = ut_avlCCount (&as->ucaddrs);
UNLOCK (as);
return count;
}
}
size_t addrset_count_mc (const struct addrset *as)
{
if (as == NULL)
return 0;
else
{
size_t count;
LOCK (as);
count = ut_avlCCount (&as->mcaddrs);
UNLOCK (as);
return count;
}
}
int addrset_empty_uc (const struct addrset *as)
{
int isempty;
LOCK (as);
isempty = ut_avlCIsEmpty (&as->ucaddrs);
UNLOCK (as);
return isempty;
}
int addrset_empty_mc (const struct addrset *as)
{
int isempty;
LOCK (as);
isempty = ut_avlCIsEmpty (&as->mcaddrs);
UNLOCK (as);
return isempty;
}
int addrset_empty (const struct addrset *as)
{
int isempty;
LOCK (as);
isempty = ut_avlCIsEmpty (&as->ucaddrs) && ut_avlCIsEmpty (&as->mcaddrs);
UNLOCK (as);
return isempty;
}
int addrset_any_uc (const struct addrset *as, nn_locator_t *dst)
{
LOCK (as);
if (ut_avlCIsEmpty (&as->ucaddrs))
{
UNLOCK (as);
return 0;
}
else
{
const struct addrset_node *n = ut_avlCRootNonEmpty (&addrset_treedef, &as->ucaddrs);
*dst = n->loc;
UNLOCK (as);
return 1;
}
}
int addrset_any_mc (const struct addrset *as, nn_locator_t *dst)
{
LOCK (as);
if (ut_avlCIsEmpty (&as->mcaddrs))
{
UNLOCK (as);
return 0;
}
else
{
const struct addrset_node *n = ut_avlCRootNonEmpty (&addrset_treedef, &as->mcaddrs);
*dst = n->loc;
UNLOCK (as);
return 1;
}
}
struct addrset_forall_helper_arg
{
addrset_forall_fun_t f;
void * arg;
};
static void addrset_forall_helper (void *vnode, void *varg)
{
const struct addrset_node *n = vnode;
struct addrset_forall_helper_arg *arg = varg;
arg->f (&n->loc, arg->arg);
}
size_t addrset_forall_count (struct addrset *as, addrset_forall_fun_t f, void *arg)
{
struct addrset_forall_helper_arg arg1;
size_t count;
arg1.f = f;
arg1.arg = arg;
LOCK (as);
ut_avlCWalk (&addrset_treedef, &as->mcaddrs, addrset_forall_helper, &arg1);
ut_avlCWalk (&addrset_treedef, &as->ucaddrs, addrset_forall_helper, &arg1);
count = ut_avlCCount (&as->ucaddrs) + ut_avlCCount (&as->mcaddrs);
UNLOCK (as);
return count;
}
void addrset_forall (struct addrset *as, addrset_forall_fun_t f, void *arg)
{
(void) addrset_forall_count (as, f, arg);
}
int addrset_forone (struct addrset *as, addrset_forone_fun_t f, void *arg)
{
unsigned i;
addrset_node_t n;
ut_avlCTree_t *trees[2];
ut_avlCIter_t iter;
trees[0] = &as->mcaddrs;
trees[1] = &as->ucaddrs;
for (i = 0; i < 2u; i++)
{
n = (addrset_node_t) ut_avlCIterFirst (&addrset_treedef, trees[i], &iter);
while (n)
{
if ((f) (&n->loc, arg) > 0)
{
return 0;
}
n = (addrset_node_t) ut_avlCIterNext (&iter);
}
}
return -1;
}
struct log_addrset_helper_arg
{
logcat_t tf;
};
static void log_addrset_helper (const nn_locator_t *n, void *varg)
{
const struct log_addrset_helper_arg *arg = varg;
char buf[INET6_ADDRSTRLEN_EXTENDED];
if (config.enabled_logcats & arg->tf)
nn_log (arg->tf, " %s", locator_to_string_with_port (buf, n));
}
void nn_log_addrset (logcat_t tf, const char *prefix, const struct addrset *as)
{
if (config.enabled_logcats & tf)
{
struct log_addrset_helper_arg arg;
arg.tf = tf;
nn_log (tf, "%s", prefix);
addrset_forall ((struct addrset *) as, log_addrset_helper, &arg); /* drop const, we know it is */
}
}
static int addrset_eq_onesidederr1 (const ut_avlCTree_t *at, const ut_avlCTree_t *bt)
{
/* Just checking the root */
if (ut_avlCIsEmpty (at) && ut_avlCIsEmpty (bt)) {
return 1;
} else if (ut_avlCIsSingleton (at) && ut_avlCIsSingleton (bt)) {
const struct addrset_node *a = ut_avlCRootNonEmpty (&addrset_treedef, at);
const struct addrset_node *b = ut_avlCRootNonEmpty (&addrset_treedef, bt);
return compare_locators (&a->loc, &b->loc) == 0;
} else {
return 0;
}
}
int addrset_eq_onesidederr (const struct addrset *a, const struct addrset *b)
{
int iseq;
if (a == b)
return 1;
if (a == NULL || b == NULL)
return 0;
LOCK (a);
if (TRYLOCK (b) == os_resultSuccess)
{
iseq =
addrset_eq_onesidederr1 (&a->ucaddrs, &b->ucaddrs) &&
addrset_eq_onesidederr1 (&a->mcaddrs, &b->mcaddrs);
UNLOCK (b);
}
else
{
/* We could try <lock b ; trylock(a)>, in a loop, &c. Or we can
just decide it isn't worth the bother. Which it isn't because
it doesn't have to be an exact check on equality. A possible
improvement would be to use an rwlock. */
iseq = 0;
}
UNLOCK (a);
return iseq;
}

View file

@ -0,0 +1,16 @@
/*
* 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
*/
#define SUPPRESS_BITSET_INLINES
#include "ddsi/q_bitset.h"
#include "ddsi/q_bitset_template.h"

View file

@ -0,0 +1,80 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "ddsi/q_bswap.h"
nn_guid_prefix_t nn_hton_guid_prefix (nn_guid_prefix_t p)
{
int i;
for (i = 0; i < 3; i++)
p.u[i] = toBE4u (p.u[i]);
return p;
}
nn_guid_prefix_t nn_ntoh_guid_prefix (nn_guid_prefix_t p)
{
int i;
for (i = 0; i < 3; i++)
p.u[i] = fromBE4u (p.u[i]);
return p;
}
nn_entityid_t nn_hton_entityid (nn_entityid_t e)
{
e.u = toBE4u (e.u);
return e;
}
nn_entityid_t nn_ntoh_entityid (nn_entityid_t e)
{
e.u = fromBE4u (e.u);
return e;
}
nn_guid_t nn_hton_guid (nn_guid_t g)
{
g.prefix = nn_hton_guid_prefix (g.prefix);
g.entityid = nn_hton_entityid (g.entityid);
return g;
}
nn_guid_t nn_ntoh_guid (nn_guid_t g)
{
g.prefix = nn_ntoh_guid_prefix (g.prefix);
g.entityid = nn_ntoh_entityid (g.entityid);
return g;
}
void bswap_sequence_number_set_hdr (nn_sequence_number_set_t *snset)
{
bswapSN (&snset->bitmap_base);
snset->numbits = bswap4u (snset->numbits);
}
void bswap_sequence_number_set_bitmap (nn_sequence_number_set_t *snset)
{
unsigned i, n = (snset->numbits + 31) / 32;
for (i = 0; i < n; i++)
snset->bits[i] = bswap4u (snset->bits[i]);
}
void bswap_fragment_number_set_hdr (nn_fragment_number_set_t *fnset)
{
fnset->bitmap_base = bswap4u (fnset->bitmap_base);
fnset->numbits = bswap4u (fnset->numbits);
}
void bswap_fragment_number_set_bitmap (nn_fragment_number_set_t *fnset)
{
unsigned i, n = (fnset->numbits + 31) / 32;
for (i = 0; i < n; i++)
fnset->bits[i] = bswap4u (fnset->bits[i]);
}

View file

@ -0,0 +1,15 @@
/*
* 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
*/
#define SUPPRESS_BSWAP_INLINES
#include "ddsi/q_bswap.h"
#include "ddsi/q_bswap_template.h"

View file

@ -0,0 +1,183 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include "ddsi/q_misc.h"
#include "ddsi/q_config.h"
#include "ddsi/q_entity.h"
#include "ddsi/q_builtin_topic.h"
#include "dds_builtinTopics.h"
static void generate_user_data (_Out_ DDS_UserDataQosPolicy *a, _In_ const nn_xqos_t *xqos)
{
if (!(xqos->present & QP_USER_DATA) || (xqos->user_data.length == 0))
{
a->value._maximum = 0;
a->value._length = 0;
a->value._buffer = NULL;
a->value._release = false;
} else {
a->value._maximum = xqos->user_data.length;
a->value._length = xqos->user_data.length;
a->value._buffer = xqos->user_data.value;
a->value._release = false;
}
}
static void
generate_product_data(
_Out_ DDS_ProductDataQosPolicy *a,
_In_ const struct entity_common *participant,
_In_ const nn_plist_t *plist)
{
/* replicate format generated in v_builtinCreateCMParticipantInfo() */
static const char product_tag[] = "Product";
static const char exec_name_tag[] = "ExecName";
static const char participant_name_tag[] = "ParticipantName";
static const char process_id_tag[] = "PID";
static const char node_name_tag[] = "NodeName";
static const char federation_id_tag[] = "FederationId";
static const char vendor_id_tag[] = "VendorId";
static const char service_type_tag[] = "ServiceType";
const size_t cdata_overhead = 12; /* <![CDATA[ and ]]> */
const size_t tag_overhead = 5; /* <> and </> */
char pidstr[11]; /* unsigned 32-bits, so max < 5e9, or 10 chars + terminator */
char federationidstr[20]; /* max 2 * unsigned 32-bits hex + separator, terminator */
char vendoridstr[22]; /* max 2 * unsigned 32-bits + seperator, terminator */
char servicetypestr[11]; /* unsigned 32-bits */
unsigned servicetype;
size_t len = 1 + 2*(sizeof(product_tag)-1) + tag_overhead;
if (plist->present & PP_PRISMTECH_EXEC_NAME)
len += 2*(sizeof(exec_name_tag)-1) + cdata_overhead + tag_overhead + strlen(plist->exec_name);
if (plist->present & PP_ENTITY_NAME)
len += 2*(sizeof(participant_name_tag)-1) + cdata_overhead + tag_overhead + strlen(plist->entity_name);
if (plist->present & PP_PRISMTECH_PROCESS_ID)
{
int n = snprintf (pidstr, sizeof (pidstr), "%u", plist->process_id);
assert (n > 0 && (size_t) n < sizeof (pidstr));
len += 2*(sizeof(process_id_tag)-1) + tag_overhead + (size_t) n;
}
if (plist->present & PP_PRISMTECH_NODE_NAME)
len += 2*(sizeof(node_name_tag)-1) + cdata_overhead + tag_overhead + strlen(plist->node_name);
{
int n = snprintf (vendoridstr, sizeof (vendoridstr), "%u.%u", plist->vendorid.id[0], plist->vendorid.id[1]);
assert (n > 0 && (size_t) n < sizeof (vendoridstr));
len += 2*(sizeof(vendor_id_tag)-1) + tag_overhead + (size_t) n;
}
{
int n;
if (vendor_is_opensplice (plist->vendorid))
n = snprintf (federationidstr, sizeof (federationidstr), "%x", participant->guid.prefix.u[0]);
else
n = snprintf (federationidstr, sizeof (federationidstr), "%x:%x", participant->guid.prefix.u[0], participant->guid.prefix.u[1]);
assert (n > 0 && (size_t) n < sizeof (federationidstr));
len += 2*(sizeof(federation_id_tag)-1) + tag_overhead + (size_t) n;
}
if (plist->present & PP_PRISMTECH_SERVICE_TYPE)
servicetype = plist->service_type;
else
servicetype = 0;
{
int n = snprintf (servicetypestr, sizeof (servicetypestr), "%u", (unsigned) servicetype);
assert (n > 0 && (size_t) n < sizeof (servicetypestr));
len += 2*(sizeof(service_type_tag)-1) + tag_overhead + (size_t) n;
}
a->value = os_malloc(len);
{
char *p = a->value;
int n;
n = snprintf (p, len, "<%s>", product_tag); assert (n >= 0 && (size_t) n < len); p += n; len -= (size_t) n;
if (plist->present & PP_PRISMTECH_EXEC_NAME)
{
n = snprintf (p, len, "<%s><![CDATA[%s]]></%s>", exec_name_tag, plist->exec_name, exec_name_tag);
assert (n >= 0 && (size_t) n < len);
p += n; len -= (size_t) n;
}
if (plist->present & PP_ENTITY_NAME)
{
n = snprintf (p, len, "<%s><![CDATA[%s]]></%s>", participant_name_tag, plist->entity_name, participant_name_tag);
assert (n >= 0 && (size_t) n < len);
p += n; len -= (size_t) n;
}
if (plist->present & PP_PRISMTECH_PROCESS_ID)
{
n = snprintf (p, len, "<%s>%s</%s>", process_id_tag, pidstr, process_id_tag);
assert (n >= 0 && (size_t) n < len);
p += n; len -= (size_t) n;
}
if (plist->present & PP_PRISMTECH_NODE_NAME)
{
n = snprintf (p, len, "<%s><![CDATA[%s]]></%s>", node_name_tag, plist->node_name, node_name_tag);
assert (n >= 0 && (size_t) n < len);
p += n; len -= (size_t) n;
}
n = snprintf (p, len, "<%s>%s</%s>", federation_id_tag, federationidstr, federation_id_tag);
assert (n >= 0 && (size_t) n < len);
p += n; len -= (size_t) n;
n = snprintf (p, len, "<%s>%s</%s>", vendor_id_tag, vendoridstr, vendor_id_tag);
assert (n >= 0 && (size_t) n < len);
p += n; len -= (size_t) n;
{
n = snprintf (p, len, "<%s>%s</%s>", service_type_tag, servicetypestr, service_type_tag);
assert (n >= 0 && (size_t) n < len);
p += n; len -= (size_t) n;
}
n = snprintf (p, len, "</%s>", product_tag);
assert (n >= 0 && (size_t) n == len-1);
(void) n;
}
}
static void generate_key (_Out_ DDS_BuiltinTopicKey_t *a, _In_ const nn_guid_prefix_t *gid)
{
(*a)[0] = gid->u[0];
(*a)[1] = gid->u[1];
(*a)[2] = gid->u[2];
}
void
propagate_builtin_topic_participant(
_In_ const struct entity_common *participant,
_In_ const nn_plist_t *plist,
_In_ nn_wctime_t timestamp,
_In_ int alive)
{
DDS_ParticipantBuiltinTopicData data;
generate_key(&(data.key), &(participant->guid.prefix));
generate_user_data(&(data.user_data), &(plist->qos));
forward_builtin_participant(&data, timestamp, alive);
}
void
propagate_builtin_topic_cmparticipant(
_In_ const struct entity_common *participant,
_In_ const nn_plist_t *plist,
_In_ nn_wctime_t timestamp,
_In_ int alive)
{
DDS_CMParticipantBuiltinTopicData data;
generate_key(&(data.key), &(participant->guid.prefix));
generate_product_data(&(data.product), participant, plist);
forward_builtin_cmparticipant(&data, timestamp, alive);
os_free(data.product.value);
}

2817
src/core/ddsi/src/q_config.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,433 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "os/os.h"
#include "util/ut_avl.h"
#include "ddsi/q_entity.h"
#include "ddsi/q_config.h"
#include "ddsi/q_time.h"
#include "ddsi/q_misc.h"
#include "ddsi/q_log.h"
#include "ddsi/q_whc.h"
#include "ddsi/q_plist.h"
#include "q__osplser.h"
#include "ddsi/q_ephash.h"
#include "ddsi/q_globals.h"
#include "ddsi/q_addrset.h"
#include "ddsi/q_radmin.h"
#include "ddsi/q_ddsi_discovery.h"
#include "ddsi/q_protocol.h" /* NN_ENTITYID_... */
#include "ddsi/q_unused.h"
#include "ddsi/q_error.h"
#include "ddsi/q_debmon.h"
#include "ddsi/ddsi_ser.h"
#include "ddsi/ddsi_tran.h"
#include "ddsi/ddsi_tcp.h"
#include "ddsi/sysdeps.h"
struct plugin {
debug_monitor_plugin_t fn;
void *arg;
struct plugin *next;
};
struct debug_monitor {
struct thread_state1 *servts;
ddsi_tran_factory_t tran_factory;
ddsi_tran_listener_t servsock;
os_mutex lock;
os_cond cond;
struct plugin *plugins;
int stop;
};
static int cpf (ddsi_tran_conn_t conn, const char *fmt, ...)
{
nn_locator_t loc;
if (!ddsi_conn_peer_locator (conn, &loc))
return 0;
else
{
os_sockaddr_storage addr;
va_list ap;
struct msghdr msg;
struct iovec iov;
char buf[4096];
int n;
nn_loc_to_address(&addr, &loc);
va_start (ap, fmt);
n = os_vsnprintf (buf, sizeof (buf), fmt, ap);
va_end (ap);
iov.iov_base = buf;
iov.iov_len = (size_t) n;
memset (&msg, 0, sizeof (msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_name = &addr;
msg.msg_namelen = (socklen_t) os_sockaddrSizeof ((os_sockaddr*) &addr);
return ddsi_conn_write (conn, &msg, iov.iov_len, 0) < 0 ? -1 : 0;
}
}
struct print_address_arg {
ddsi_tran_conn_t conn;
int count;
};
static void print_address (const nn_locator_t *n, void *varg)
{
struct print_address_arg *arg = varg;
char buf[INET6_ADDRSTRLEN_EXTENDED];
arg->count += cpf (arg->conn, " %s", locator_to_string_with_port (buf, n));
}
static int print_addrset (ddsi_tran_conn_t conn, const char *prefix, struct addrset *as, const char *suffix)
{
struct print_address_arg pa_arg;
pa_arg.conn = conn;
pa_arg.count = cpf (conn, "%s", prefix);
addrset_forall(as, print_address, &pa_arg);
pa_arg.count += cpf (conn, "%s", suffix);
return pa_arg.count;
}
static int print_addrset_if_notempty (ddsi_tran_conn_t conn, const char *prefix, struct addrset *as, const char *suffix)
{
if (addrset_empty(as))
return 0;
else
return print_addrset (conn, prefix, as, suffix);
}
static int print_any_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e,
const struct nn_xqos *xqos, const struct sertopic *topic)
{
int x = 0;
x += cpf (conn, " %s %x:%x:%x:%x ", label, PGUID (e->guid));
if (xqos->present & QP_PARTITION)
{
unsigned i;
if (xqos->partition.n > 1) cpf (conn, "{");
for (i = 0; i < xqos->partition.n; i++)
x += cpf (conn, "%s%s", i == 0 ? "" : ",", xqos->partition.strs[i]);
if (xqos->partition.n > 1) cpf (conn, "}");
x += cpf (conn, ".%s/%s",
topic && topic->name ? topic->name : (xqos->present & QP_TOPIC_NAME) ? xqos->topic_name : "(null)",
topic && topic->typename ? topic->typename : (xqos->present & QP_TYPE_NAME) ? xqos->type_name : "(null)");
}
cpf (conn, "\n");
return x;
}
static int print_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct endpoint_common *c, const struct nn_xqos *xqos, const struct sertopic *topic)
{
OS_UNUSED_ARG (c);
return print_any_endpoint_common (conn, label, e, xqos, topic);
}
static int print_proxy_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct proxy_endpoint_common *c)
{
int x = 0;
x += print_any_endpoint_common (conn, label, e, c->xqos, c->topic);
x += print_addrset_if_notempty (conn, " as", c->as, "\n");
return x;
}
static int print_participants (struct thread_state1 *self, ddsi_tran_conn_t conn)
{
struct ephash_enum_participant e;
struct participant *p;
int x = 0;
thread_state_awake (self);
ephash_enum_participant_init (&e);
while ((p = ephash_enum_participant_next (&e)) != NULL)
{
os_mutexLock (&p->e.lock);
x += cpf (conn, "pp %x:%x:%x:%x %s%s\n", PGUID (p->e.guid), p->e.name, p->is_ddsi2_pp ? " [ddsi2]" : "");
os_mutexUnlock (&p->e.lock);
{
struct ephash_enum_reader er;
struct reader *r;
ephash_enum_reader_init (&er);
while ((r = ephash_enum_reader_next (&er)) != NULL)
{
ut_avlIter_t writ;
struct rd_pwr_match *m;
if (r->c.pp != p)
continue;
os_mutexLock (&r->e.lock);
print_endpoint_common (conn, "rd", &r->e, &r->c, r->xqos, r->topic);
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
x += print_addrset_if_notempty (conn, " as", r->as, "\n");
#endif
for (m = ut_avlIterFirst (&rd_writers_treedef, &r->writers, &writ); m; m = ut_avlIterNext (&writ))
x += cpf (conn, " pwr %x:%x:%x:%x\n", PGUID (m->pwr_guid));
os_mutexUnlock (&r->e.lock);
}
ephash_enum_reader_fini (&er);
}
{
struct ephash_enum_writer ew;
struct writer *w;
ephash_enum_writer_init (&ew);
while ((w = ephash_enum_writer_next (&ew)) != NULL)
{
ut_avlIter_t rdit;
struct wr_prd_match *m;
if (w->c.pp != p)
continue;
os_mutexLock (&w->e.lock);
print_endpoint_common (conn, "wr", &w->e, &w->c, w->xqos, w->topic);
x += cpf (conn, " whc [%lld,%lld] unacked %"PRIuSIZE"%s [%u,%u] seq %lld seq_xmit %lld cs_seq %lld\n",
whc_empty (w->whc) ? -1 : whc_min_seq (w->whc),
whc_empty (w->whc) ? -1 : whc_max_seq (w->whc),
whc_unacked_bytes (w->whc),
w->throttling ? " THROTTLING" : "",
w->whc_low, w->whc_high,
w->seq, READ_SEQ_XMIT(w), w->cs_seq);
if (w->reliable)
{
x += cpf (conn, " hb %u ackhb %lld hb %lld wr %lld sched %lld #rel %d\n",
w->hbcontrol.hbs_since_last_write, w->hbcontrol.t_of_last_ackhb,
w->hbcontrol.t_of_last_hb, w->hbcontrol.t_of_last_write,
w->hbcontrol.tsched, w->num_reliable_readers);
x += cpf (conn, " #acks %u #nacks %u #rexmit %u #lost %u #throttle %u\n",
w->num_acks_received, w->num_nacks_received, w->rexmit_count, w->rexmit_lost_count, w->throttle_count);
x += cpf (conn, " max-drop-seq %lld\n", writer_max_drop_seq (w));
}
x += print_addrset_if_notempty (conn, " as", w->as, "\n");
for (m = ut_avlIterFirst (&wr_readers_treedef, &w->readers, &rdit); m; m = ut_avlIterNext (&rdit))
{
char wr_prd_flags[4];
wr_prd_flags[0] = m->is_reliable ? 'R' : 'U';
wr_prd_flags[1] = m->assumed_in_sync ? 's' : '.';
wr_prd_flags[2] = m->has_replied_to_hb ? 'a' : '.'; /* a = ack seen */
wr_prd_flags[3] = 0;
x += cpf (conn, " prd %x:%x:%x:%x %s @ %lld [%lld,%lld] #nacks %u\n",
PGUID (m->prd_guid), wr_prd_flags, m->seq, m->min_seq, m->max_seq, m->rexmit_requests);
}
os_mutexUnlock (&w->e.lock);
}
ephash_enum_writer_fini (&ew);
}
}
ephash_enum_participant_fini (&e);
thread_state_asleep (self);
return x;
}
static int print_proxy_participants (struct thread_state1 *self, ddsi_tran_conn_t conn)
{
struct ephash_enum_proxy_participant e;
struct proxy_participant *p;
int x = 0;
thread_state_awake (self);
ephash_enum_proxy_participant_init (&e);
while ((p = ephash_enum_proxy_participant_next (&e)) != NULL)
{
os_mutexLock (&p->e.lock);
x += cpf (conn, "proxypp %x:%x:%x:%x%s\n", PGUID (p->e.guid), p->is_ddsi2_pp ? " [ddsi2]" : "");
os_mutexUnlock (&p->e.lock);
x += print_addrset (conn, " as data", p->as_default, "");
x += print_addrset (conn, " meta", p->as_default, "\n");
{
struct ephash_enum_proxy_reader er;
struct proxy_reader *r;
ephash_enum_proxy_reader_init (&er);
while ((r = ephash_enum_proxy_reader_next (&er)) != NULL)
{
ut_avlIter_t writ;
struct prd_wr_match *m;
if (r->c.proxypp != p)
continue;
os_mutexLock (&r->e.lock);
print_proxy_endpoint_common (conn, "prd", &r->e, &r->c);
for (m = ut_avlIterFirst (&rd_writers_treedef, &r->writers, &writ); m; m = ut_avlIterNext (&writ))
x += cpf (conn, " wr %x:%x:%x:%x\n", PGUID (m->wr_guid));
os_mutexUnlock (&r->e.lock);
}
ephash_enum_proxy_reader_fini (&er);
}
{
struct ephash_enum_proxy_writer ew;
struct proxy_writer *w;
ephash_enum_proxy_writer_init (&ew);
while ((w = ephash_enum_proxy_writer_next (&ew)) != NULL)
{
ut_avlIter_t rdit;
struct pwr_rd_match *m;
if (w->c.proxypp != p)
continue;
os_mutexLock (&w->e.lock);
print_proxy_endpoint_common (conn, "pwr", &w->e, &w->c);
x += cpf (conn, " last_seq %lld last_fragnum %u\n", w->last_seq, w->last_fragnum);
for (m = ut_avlIterFirst (&wr_readers_treedef, &w->readers, &rdit); m; m = ut_avlIterNext (&rdit))
{
x += cpf (conn, " rd %x:%x:%x:%x (nack %lld %lld)\n",
PGUID (m->rd_guid), m->seq_last_nack, m->t_last_nack);
switch (m->in_sync)
{
case PRMSS_SYNC:
break;
case PRMSS_TLCATCHUP:
x += cpf (conn, " tl-catchup end_of_tl_seq %lld\n", m->u.not_in_sync.end_of_tl_seq);
break;
case PRMSS_OUT_OF_SYNC:
x += cpf (conn, " out-of-sync end_of_tl_seq %lld end_of_out_of_sync_seq %lld\n", m->u.not_in_sync.end_of_tl_seq, m->u.not_in_sync.end_of_out_of_sync_seq);
break;
}
}
os_mutexUnlock (&w->e.lock);
}
ephash_enum_proxy_writer_fini (&ew);
}
}
ephash_enum_proxy_participant_fini (&e);
thread_state_asleep (self);
return x;
}
static uint32_t debmon_main (void *vdm)
{
struct debug_monitor *dm = vdm;
os_mutexLock (&dm->lock);
while (!dm->stop)
{
ddsi_tran_conn_t conn;
os_mutexUnlock (&dm->lock);
if ((conn = ddsi_listener_accept (dm->servsock)) != NULL)
{
struct plugin *p;
int r = 0;
r += print_participants (dm->servts, conn);
if (r == 0)
r += print_proxy_participants (dm->servts, conn);
/* Note: can only add plugins (at the tail) */
os_mutexLock (&dm->lock);
p = dm->plugins;
while (r == 0 && p != NULL)
{
os_mutexUnlock (&dm->lock);
r += p->fn (conn, cpf, p->arg);
os_mutexLock (&dm->lock);
p = p->next;
}
os_mutexUnlock (&dm->lock);
ddsi_conn_free (conn);
}
os_mutexLock (&dm->lock);
}
os_mutexUnlock (&dm->lock);
return 0;
}
struct debug_monitor *new_debug_monitor (int port)
{
struct debug_monitor *dm;
if (config.monitor_port < 0)
return NULL;
if (ddsi_tcp_init () < 0)
return NULL;
dm = os_malloc (sizeof (*dm));
dm->plugins = NULL;
dm->tran_factory = ddsi_factory_find ("tcp");
dm->servsock = ddsi_factory_create_listener (dm->tran_factory, port, NULL);
if (dm->servsock == NULL)
{
NN_WARNING ("debmon: can't create socket\n");
goto err_servsock;
}
{
nn_locator_t loc;
os_sockaddr_storage addr;
char buf[INET6_ADDRSTRLEN_EXTENDED];
(void) ddsi_listener_locator(dm->servsock, &loc);
nn_loc_to_address (&addr, &loc);
nn_log (LC_CONFIG, "debmon at %s\n", sockaddr_to_string_with_port (buf, &addr));
}
os_mutexInit (&dm->lock);
os_condInit (&dm->cond, &dm->lock);
if (ddsi_listener_listen (dm->servsock) < 0)
goto err_listen;
dm->stop = 0;
dm->servts = create_thread("debmon", debmon_main, dm);
return dm;
err_listen:
os_condDestroy(&dm->cond);
os_mutexDestroy(&dm->lock);
ddsi_listener_free(dm->servsock);
err_servsock:
os_free(dm);
return NULL;
}
void add_debug_monitor_plugin (struct debug_monitor *dm, debug_monitor_plugin_t fn, void *arg)
{
struct plugin *p, **pp;
if (dm != NULL && (p = os_malloc (sizeof (*p))) != NULL)
{
p->fn = fn;
p->arg = arg;
p->next = NULL;
os_mutexLock (&dm->lock);
pp = &dm->plugins;
while (*pp)
pp = &(*pp)->next;
*pp = p;
os_mutexUnlock (&dm->lock);
}
}
void free_debug_monitor (struct debug_monitor *dm)
{
if (dm == NULL)
return;
os_mutexLock (&dm->lock);
dm->stop = 1;
os_condBroadcast (&dm->cond);
os_mutexUnlock (&dm->lock);
ddsi_listener_unblock (dm->servsock);
join_thread (dm->servts);
ddsi_listener_free (dm->servsock);
os_condDestroy (&dm->cond);
os_mutexDestroy (&dm->lock);
while (dm->plugins) {
struct plugin *p = dm->plugins;
dm->plugins = p->next;
os_free (p);
}
os_free (dm);
}

4480
src/core/ddsi/src/q_entity.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,365 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stddef.h>
#include <assert.h>
#include "os/os.h"
#include "ddsi/sysdeps.h"
#include "util/ut_hopscotch.h"
#include "ddsi/q_ephash.h"
#include "ddsi/q_config.h"
#include "ddsi/q_globals.h"
#include "ddsi/q_entity.h"
#include "ddsi/q_gc.h"
#include "ddsi/q_rtps.h" /* guid_t */
#include "ddsi/q_thread.h" /* for assert(thread is awake) */
struct ephash {
struct ut_chh *hash;
};
static const uint64_t unihashconsts[] = {
UINT64_C (16292676669999574021),
UINT64_C (10242350189706880077),
UINT64_C (12844332200329132887),
UINT64_C (16728792139623414127)
};
static uint32_t hash_entity_guid (const struct entity_common *c)
{
return
(int) (((((uint32_t) c->guid.prefix.u[0] + unihashconsts[0]) *
((uint32_t) c->guid.prefix.u[1] + unihashconsts[1])) +
(((uint32_t) c->guid.prefix.u[2] + unihashconsts[2]) *
((uint32_t) c->guid.entityid.u + unihashconsts[3])))
>> 32);
}
static uint32_t hash_entity_guid_wrapper (const void *c)
{
return hash_entity_guid (c);
}
static int entity_guid_eq (const struct entity_common *a, const struct entity_common *b)
{
return
a->guid.prefix.u[0] == b->guid.prefix.u[0] && a->guid.prefix.u[1] == b->guid.prefix.u[1] &&
a->guid.prefix.u[2] == b->guid.prefix.u[2] && a->guid.entityid.u == b->guid.entityid.u;
}
static int entity_guid_eq_wrapper (const void *a, const void *b)
{
return entity_guid_eq (a, b);
}
static void gc_buckets_cb (struct gcreq *gcreq)
{
void *bs = gcreq->arg;
gcreq_free (gcreq);
os_free (bs);
}
static void gc_buckets (void *bs)
{
struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_buckets_cb);
gcreq->arg = bs;
gcreq_enqueue (gcreq);
}
struct ephash *ephash_new (void)
{
struct ephash *ephash;
ephash = os_malloc (sizeof (*ephash));
ephash->hash = ut_chhNew (32, hash_entity_guid_wrapper, entity_guid_eq_wrapper, gc_buckets);
if (ephash->hash == NULL) {
os_free (ephash);
return NULL;
} else {
return ephash;
}
}
void ephash_free (struct ephash *ephash)
{
ut_chhFree (ephash->hash);
ephash->hash = NULL;
os_free (ephash);
}
static void ephash_guid_insert (struct entity_common *e)
{
int x;
assert(gv.guid_hash);
assert(gv.guid_hash->hash);
x = ut_chhAdd (gv.guid_hash->hash, e);
(void)x;
assert (x);
}
static void ephash_guid_remove (struct entity_common *e)
{
int x;
assert(gv.guid_hash);
assert(gv.guid_hash->hash);
x = ut_chhRemove (gv.guid_hash->hash, e);
(void)x;
assert (x);
}
static void *ephash_lookup_guid_int (const struct ephash *ephash, const struct nn_guid *guid, enum entity_kind kind)
{
/* FIXME: could (now) require guid to be first in entity_common; entity_common already is first in entity */
struct entity_common e;
struct entity_common *res;
e.guid = *guid;
res = ut_chhLookup (gv.guid_hash->hash, &e);
if (res && res->kind == kind)
return res;
else
return NULL;
}
void *ephash_lookup_guid (const struct nn_guid *guid, enum entity_kind kind)
{
return ephash_lookup_guid_int (gv.guid_hash, guid, kind);
}
void ephash_insert_participant_guid (struct participant *pp)
{
ephash_guid_insert (&pp->e);
}
void ephash_insert_proxy_participant_guid (struct proxy_participant *proxypp)
{
ephash_guid_insert (&proxypp->e);
}
void ephash_insert_writer_guid (struct writer *wr)
{
ephash_guid_insert (&wr->e);
}
void ephash_insert_reader_guid (struct reader *rd)
{
ephash_guid_insert (&rd->e);
}
void ephash_insert_proxy_writer_guid (struct proxy_writer *pwr)
{
ephash_guid_insert (&pwr->e);
}
void ephash_insert_proxy_reader_guid (struct proxy_reader *prd)
{
ephash_guid_insert (&prd->e);
}
void ephash_remove_participant_guid (struct participant *pp)
{
ephash_guid_remove (&pp->e);
}
void ephash_remove_proxy_participant_guid (struct proxy_participant *proxypp)
{
ephash_guid_remove (&proxypp->e);
}
void ephash_remove_writer_guid (struct writer *wr)
{
ephash_guid_remove (&wr->e);
}
void ephash_remove_reader_guid (struct reader *rd)
{
ephash_guid_remove (&rd->e);
}
void ephash_remove_proxy_writer_guid (struct proxy_writer *pwr)
{
ephash_guid_remove (&pwr->e);
}
void ephash_remove_proxy_reader_guid (struct proxy_reader *prd)
{
ephash_guid_remove (&prd->e);
}
struct participant *ephash_lookup_participant_guid (const struct nn_guid *guid)
{
assert (guid->entityid.u == NN_ENTITYID_PARTICIPANT);
assert (offsetof (struct participant, e) == 0);
return ephash_lookup_guid_int (gv.guid_hash, guid, EK_PARTICIPANT);
}
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct nn_guid *guid)
{
assert (guid->entityid.u == NN_ENTITYID_PARTICIPANT);
assert (offsetof (struct proxy_participant, e) == 0);
return ephash_lookup_guid_int (gv.guid_hash, guid, EK_PROXY_PARTICIPANT);
}
struct writer *ephash_lookup_writer_guid (const struct nn_guid *guid)
{
assert (is_writer_entityid (guid->entityid));
assert (offsetof (struct writer, e) == 0);
return ephash_lookup_guid_int (gv.guid_hash, guid, EK_WRITER);
}
struct reader *ephash_lookup_reader_guid (const struct nn_guid *guid)
{
assert (is_reader_entityid (guid->entityid));
assert (offsetof (struct reader, e) == 0);
return ephash_lookup_guid_int (gv.guid_hash, guid, EK_READER);
}
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct nn_guid *guid)
{
assert (is_writer_entityid (guid->entityid));
assert (offsetof (struct proxy_writer, e) == 0);
return ephash_lookup_guid_int (gv.guid_hash, guid, EK_PROXY_WRITER);
}
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct nn_guid *guid)
{
assert (is_reader_entityid (guid->entityid));
assert (offsetof (struct proxy_reader, e) == 0);
return ephash_lookup_guid_int (gv.guid_hash, guid, EK_PROXY_READER);
}
/* Enumeration */
static void ephash_enum_init_int (struct ephash_enum *st, struct ephash *ephash, enum entity_kind kind)
{
st->kind = kind;
st->cur = ut_chhIterFirst (ephash->hash, &st->it);
while (st->cur && st->cur->kind != st->kind)
st->cur = ut_chhIterNext (&st->it);
}
void ephash_enum_init (struct ephash_enum *st, enum entity_kind kind)
{
ephash_enum_init_int(st, gv.guid_hash, kind);
}
void ephash_enum_writer_init (struct ephash_enum_writer *st)
{
ephash_enum_init (&st->st, EK_WRITER);
}
void ephash_enum_reader_init (struct ephash_enum_reader *st)
{
ephash_enum_init (&st->st, EK_READER);
}
void ephash_enum_proxy_writer_init (struct ephash_enum_proxy_writer *st)
{
ephash_enum_init (&st->st, EK_PROXY_WRITER);
}
void ephash_enum_proxy_reader_init (struct ephash_enum_proxy_reader *st)
{
ephash_enum_init (&st->st, EK_PROXY_READER);
}
void ephash_enum_participant_init (struct ephash_enum_participant *st)
{
ephash_enum_init (&st->st, EK_PARTICIPANT);
}
void ephash_enum_proxy_participant_init (struct ephash_enum_proxy_participant *st)
{
ephash_enum_init (&st->st, EK_PROXY_PARTICIPANT);
}
void *ephash_enum_next (struct ephash_enum *st)
{
void *res = st->cur;
if (st->cur)
{
st->cur = ut_chhIterNext (&st->it);
while (st->cur && (int)st->cur->kind != st->kind)
st->cur = ut_chhIterNext (&st->it);
}
return res;
}
struct writer *ephash_enum_writer_next (struct ephash_enum_writer *st)
{
assert (offsetof (struct writer, e) == 0);
return ephash_enum_next (&st->st);
}
struct reader *ephash_enum_reader_next (struct ephash_enum_reader *st)
{
assert (offsetof (struct reader, e) == 0);
return ephash_enum_next (&st->st);
}
struct proxy_writer *ephash_enum_proxy_writer_next (struct ephash_enum_proxy_writer *st)
{
assert (offsetof (struct proxy_writer, e) == 0);
return ephash_enum_next (&st->st);
}
struct proxy_reader *ephash_enum_proxy_reader_next (struct ephash_enum_proxy_reader *st)
{
assert (offsetof (struct proxy_reader, e) == 0);
return ephash_enum_next (&st->st);
}
struct participant *ephash_enum_participant_next (struct ephash_enum_participant *st)
{
assert (offsetof (struct participant, e) == 0);
return ephash_enum_next (&st->st);
}
struct proxy_participant *ephash_enum_proxy_participant_next (struct ephash_enum_proxy_participant *st)
{
assert (offsetof (struct proxy_participant, e) == 0);
return ephash_enum_next (&st->st);
}
void ephash_enum_fini (struct ephash_enum *st)
{
OS_UNUSED_ARG(st);
}
void ephash_enum_writer_fini (struct ephash_enum_writer *st)
{
ephash_enum_fini (&st->st);
}
void ephash_enum_reader_fini (struct ephash_enum_reader *st)
{
ephash_enum_fini (&st->st);
}
void ephash_enum_proxy_writer_fini (struct ephash_enum_proxy_writer *st)
{
ephash_enum_fini (&st->st);
}
void ephash_enum_proxy_reader_fini (struct ephash_enum_proxy_reader *st)
{
ephash_enum_fini (&st->st);
}
void ephash_enum_participant_fini (struct ephash_enum_participant *st)
{
ephash_enum_fini (&st->st);
}
void ephash_enum_proxy_participant_fini (struct ephash_enum_proxy_participant *st)
{
ephash_enum_fini (&st->st);
}

View file

@ -0,0 +1,248 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stddef.h>
#include "os/os.h"
#include "ddsi/sysdeps.h"
#include "ddsi/q_freelist.h"
#if FREELIST_TYPE == FREELIST_ATOMIC_LIFO
void nn_freelist_init (_Out_ struct nn_freelist *fl, uint32_t max, off_t linkoff)
{
os_atomic_lifo_init (&fl->x);
os_atomic_st32(&fl->count, 0);
fl->max = (max == UINT32_MAX) ? max-1 : max;
fl->linkoff = linkoff;
}
void nn_freelist_fini (_Inout_ _Post_invalid_ struct nn_freelist *fl, _In_ void (*free) (void *elem))
{
void *e;
while ((e = os_atomic_lifo_pop (&fl->x, fl->linkoff)) != NULL)
free (e);
}
_Check_return_ bool nn_freelist_push (_Inout_ struct nn_freelist *fl, _Inout_ _When_ (return != 0, _Post_invalid_) void *elem)
{
if (os_atomic_inc32_nv (&fl->count) <= fl->max)
{
os_atomic_lifo_push (&fl->x, elem, fl->linkoff);
return true;
}
else
{
os_atomic_dec32 (&fl->count);
return false;
}
}
_Check_return_ _Ret_maybenull_ void *nn_freelist_pushmany (_Inout_ struct nn_freelist *fl, _Inout_opt_ _When_ (return != 0, _Post_invalid_) void *first, _Inout_opt_ _When_ (return != 0, _Post_invalid_) void *last, uint32_t n)
{
os_atomic_add32 (&fl->count, n);
os_atomic_lifo_pushmany (&fl->x, first, last, fl->linkoff);
return NULL;
}
_Check_return_ _Ret_maybenull_ void *nn_freelist_pop (_Inout_ struct nn_freelist *fl)
{
void *e;
if ((e = os_atomic_lifo_pop (&fl->x, fl->linkoff)) != NULL)
{
os_atomic_dec32(&fl->count);
return e;
}
else
{
return NULL;
}
}
#elif FREELIST_TYPE == FREELIST_DOUBLE
static os_threadLocal int freelist_inner_idx = -1;
void nn_freelist_init (_Out_ struct nn_freelist *fl, uint32_t max, off_t linkoff)
{
int i;
os_mutexInit (&fl->lock);
for (i = 0; i < NN_FREELIST_NPAR; i++)
{
os_mutexInit (&fl->inner[i].lock);
fl->inner[i].count = 0;
fl->inner[i].m = os_malloc (sizeof (*fl->inner[i].m));
}
os_atomic_st32 (&fl->cc, 0);
fl->mlist = NULL;
fl->emlist = NULL;
fl->count = 0;
fl->max = (max == UINT32_MAX) ? max-1 : max;
fl->linkoff = linkoff;
}
static void *get_next (const struct nn_freelist *fl, const void *e)
{
return *((void **) ((char *)e + fl->linkoff));
}
void nn_freelist_fini (_Inout_ _Post_invalid_ struct nn_freelist *fl, _In_ void (*xfree) (void *))
{
int i;
uint32_t j;
struct nn_freelistM *m;
os_mutexDestroy (&fl->lock);
for (i = 0; i < NN_FREELIST_NPAR; i++)
{
os_mutexDestroy (&fl->inner[i].lock);
for (j = 0; j < fl->inner[i].count; j++)
xfree (fl->inner[i].m->x[j]);
os_free(fl->inner[i].m);
}
/* The compiler can't make sense of all these linked lists and doesn't
* realize that the next pointers are always initialized here. */
OS_WARNING_MSVC_OFF(6001);
while ((m = fl->mlist) != NULL)
{
fl->mlist = m->next;
for (j = 0; j < NN_FREELIST_MAGSIZE; j++)
xfree (m->x[j]);
os_free (m);
}
while ((m = fl->emlist) != NULL)
{
fl->emlist = m->next;
os_free (m);
}
OS_WARNING_MSVC_ON(6001);
}
static os_atomic_uint32_t freelist_inner_idx_off = OS_ATOMIC_UINT32_INIT(0);
static int get_freelist_inner_idx (void)
{
if (freelist_inner_idx == -1)
{
static const uint64_t unihashconsts[] = {
UINT64_C (16292676669999574021),
UINT64_C (10242350189706880077),
};
uintptr_t addr;
uint64_t t = (uint64_t) ((uintptr_t) &addr) + os_atomic_ld32 (&freelist_inner_idx_off);
freelist_inner_idx = (int) (((((uint32_t) t + unihashconsts[0]) * ((uint32_t) (t >> 32) + unihashconsts[1]))) >> (64 - NN_FREELIST_NPAR_LG2));
}
return freelist_inner_idx;
}
static int lock_inner (struct nn_freelist *fl)
{
int k = get_freelist_inner_idx();
if (os_mutexTryLock (&fl->inner[k].lock) != os_resultSuccess)
{
os_mutexLock (&fl->inner[k].lock);
if (os_atomic_inc32_nv (&fl->cc) == 100)
{
os_atomic_st32(&fl->cc, 0);
os_atomic_inc32(&freelist_inner_idx_off);
freelist_inner_idx = -1;
}
}
return k;
}
_Check_return_ bool nn_freelist_push (_Inout_ struct nn_freelist *fl, _Inout_ _When_ (return != 0, _Post_invalid_) void *elem)
{
int k = lock_inner (fl);
if (fl->inner[k].count < NN_FREELIST_MAGSIZE)
{
fl->inner[k].m->x[fl->inner[k].count++] = elem;
os_mutexUnlock (&fl->inner[k].lock);
return true;
}
else
{
struct nn_freelistM *m;
os_mutexLock (&fl->lock);
if (fl->count + NN_FREELIST_MAGSIZE >= fl->max)
{
os_mutexUnlock (&fl->lock);
os_mutexUnlock (&fl->inner[k].lock);
return false;
}
m = fl->inner[k].m;
m->next = fl->mlist;
fl->mlist = m;
fl->count += NN_FREELIST_MAGSIZE;
fl->inner[k].count = 0;
if (fl->emlist == NULL)
fl->inner[k].m = os_malloc (sizeof (*fl->inner[k].m));
else
{
fl->inner[k].m = fl->emlist;
fl->emlist = fl->emlist->next;
}
os_mutexUnlock (&fl->lock);
fl->inner[k].m->x[fl->inner[k].count++] = elem;
os_mutexUnlock (&fl->inner[k].lock);
return true;
}
}
_Check_return_ _Ret_maybenull_ void *nn_freelist_pushmany (_Inout_ struct nn_freelist *fl, _Inout_opt_ _When_ (return != 0, _Post_invalid_) void *first, _Inout_opt_ _When_ (return != 0, _Post_invalid_) void *last, uint32_t n)
{
void *m = first;
while (m)
{
void *mnext = get_next (fl, m);
if (!nn_freelist_push (fl, m)) {
return m;
}
m = mnext;
}
return NULL;
}
_Check_return_ _Ret_maybenull_ void *nn_freelist_pop (_Inout_ struct nn_freelist *fl)
{
int k = lock_inner (fl);
if (fl->inner[k].count > 0)
{
void *e = fl->inner[k].m->x[--fl->inner[k].count];
os_mutexUnlock (&fl->inner[k].lock);
return e;
}
else
{
os_mutexLock (&fl->lock);
if (fl->mlist == NULL)
{
os_mutexUnlock (&fl->lock);
os_mutexUnlock (&fl->inner[k].lock);
return NULL;
}
else
{
void *e;
fl->inner[k].m->next = fl->emlist;
fl->emlist = fl->inner[k].m;
fl->inner[k].m = fl->mlist;
fl->mlist = fl->mlist->next;
fl->count -= NN_FREELIST_MAGSIZE;
os_mutexUnlock (&fl->lock);
fl->inner[k].count = NN_FREELIST_MAGSIZE;
e = fl->inner[k].m->x[--fl->inner[k].count];
os_mutexUnlock (&fl->inner[k].lock);
return e;
}
}
}
#endif

254
src/core/ddsi/src/q_gc.c Normal file
View file

@ -0,0 +1,254 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <stdlib.h>
#include <stddef.h>
#include "os/os.h"
#include "ddsi/q_gc.h"
#include "ddsi/q_log.h"
#include "ddsi/q_config.h"
#include "ddsi/q_time.h"
#include "ddsi/q_thread.h"
#include "ddsi/q_ephash.h"
#include "ddsi/q_unused.h"
#include "ddsi/q_lease.h"
#include "ddsi/q_globals.h" /* for mattr, cattr */
#include "ddsi/q_rtps.h" /* for guid_hash */
struct gcreq_queue {
struct gcreq *first;
struct gcreq *last;
os_mutex lock;
os_cond cond;
int terminate;
int32_t count;
struct thread_state1 *ts;
};
static void threads_vtime_gather_for_wait (unsigned *nivs, struct idx_vtime *ivs)
{
/* copy vtimes of threads, skipping those that are sleeping */
unsigned i, j;
for (i = j = 0; i < thread_states.nthreads; i++)
{
vtime_t vtime = thread_states.ts[i].vtime;
if (vtime_awake_p (vtime))
{
ivs[j].idx = i;
ivs[j].vtime = vtime;
++j;
}
}
*nivs = j;
}
static int threads_vtime_check (unsigned *nivs, struct idx_vtime *ivs)
{
/* check all threads in ts have made progress those that have are
removed from the set */
unsigned i = 0;
while (i < *nivs)
{
unsigned thridx = ivs[i].idx;
vtime_t vtime = thread_states.ts[thridx].vtime;
assert (vtime_awake_p (ivs[i].vtime));
if (!vtime_gt (vtime, ivs[i].vtime))
++i;
else
{
if (i + 1 < *nivs)
ivs[i] = ivs[*nivs - 1];
--(*nivs);
}
}
return *nivs == 0;
}
static uint32_t gcreq_queue_thread (struct gcreq_queue *q)
{
struct thread_state1 *self = lookup_thread_state ();
nn_mtime_t next_thread_cputime = { 0 };
struct os_time to = { 0, 100 * T_MILLISECOND };
struct os_time shortsleep = { 0, 1 * T_MILLISECOND };
struct gcreq *gcreq = NULL;
int trace_shortsleep = 1;
os_mutexLock (&q->lock);
while (!(q->terminate && q->count == 0))
{
LOG_THREAD_CPUTIME (next_thread_cputime);
/* If we are waiting for a gcreq to become ready, don't bother
looking at the queue; if we aren't, wait for a request to come
in. We can't really wait until something came in because we're
also checking lease expirations. */
if (gcreq == NULL)
{
if (q->first == NULL)
os_condTimedWait (&q->cond, &q->lock, &to);
if (q->first)
{
gcreq = q->first;
q->first = q->first->next;
}
}
os_mutexUnlock (&q->lock);
/* Cleanup dead proxy entities. One can argue this should be an
independent thread, but one can also easily argue that an
expired lease is just another form of a request for
deletion. In any event, letting this thread do this should have
very little impact on its primary purpose and be less of a
burden on the system than having a separate thread or adding it
to the workload of the data handling threads. */
thread_state_awake (self);
check_and_handle_lease_expiration (self, now_et ());
thread_state_asleep (self);
if (gcreq)
{
if (!threads_vtime_check (&gcreq->nvtimes, gcreq->vtimes))
{
/* Not all threads made enough progress => gcreq is not ready
yet => sleep for a bit and rety. Note that we can't even
terminate while this gcreq is waiting and that there is no
condition on which to wait, so a plain sleep is quite
reasonable. */
if (trace_shortsleep)
{
TRACE (("gc %p: not yet, shortsleep\n", (void*)gcreq));
trace_shortsleep = 0;
}
os_nanoSleep (shortsleep);
}
else
{
/* Sufficent progress has been made: may now continue deleting
it; the callback is responsible for requeueing (if complex
multi-phase delete) or freeing the delete request. Reset
the current gcreq as this one obviously is no more. */
TRACE (("gc %p: deleting\n", (void*)gcreq));
thread_state_awake (self);
gcreq->cb (gcreq);
thread_state_asleep (self);
gcreq = NULL;
trace_shortsleep = 1;
}
}
os_mutexLock (&q->lock);
}
os_mutexUnlock (&q->lock);
return 0;
}
struct gcreq_queue *gcreq_queue_new (void)
{
struct gcreq_queue *q = os_malloc (sizeof (*q));
q->first = q->last = NULL;
q->terminate = 0;
q->count = 0;
os_mutexInit (&q->lock);
os_condInit (&q->cond, &q->lock);
q->ts = create_thread ("gc", (uint32_t (*) (void *)) gcreq_queue_thread, q);
assert (q->ts);
return q;
}
void gcreq_queue_free (struct gcreq_queue *q)
{
struct gcreq *gcreq;
/* Create a no-op not dependent on any thread */
gcreq = gcreq_new (q, gcreq_free);
gcreq->nvtimes = 0;
os_mutexLock (&q->lock);
q->terminate = 1;
/* Wait until there is only request in existence, the one we just
allocated. Then we know the gc system is quiet. */
while (q->count != 1)
os_condWait (&q->cond, &q->lock);
os_mutexUnlock (&q->lock);
/* Force the gc thread to wake up by enqueueing our no-op. The
callback, gcreq_free, will be called immediately, which causes
q->count to 0 before the loop condition is evaluated again, at
which point the thread terminates. */
gcreq_enqueue (gcreq);
join_thread (q->ts);
assert (q->first == NULL);
os_condDestroy (&q->cond);
os_mutexDestroy (&q->lock);
os_free (q);
}
struct gcreq *gcreq_new (struct gcreq_queue *q, gcreq_cb_t cb)
{
struct gcreq *gcreq;
gcreq = os_malloc (offsetof (struct gcreq, vtimes) + thread_states.nthreads * sizeof (*gcreq->vtimes));
gcreq->cb = cb;
gcreq->queue = q;
threads_vtime_gather_for_wait (&gcreq->nvtimes, gcreq->vtimes);
os_mutexLock (&q->lock);
q->count++;
os_mutexUnlock (&q->lock);
return gcreq;
}
void gcreq_free (struct gcreq *gcreq)
{
struct gcreq_queue *gcreq_queue = gcreq->queue;
os_mutexLock (&gcreq_queue->lock);
--gcreq_queue->count;
if (gcreq_queue->terminate && gcreq_queue->count <= 1)
os_condBroadcast (&gcreq_queue->cond);
os_mutexUnlock (&gcreq_queue->lock);
os_free (gcreq);
}
static int gcreq_enqueue_common (struct gcreq *gcreq)
{
struct gcreq_queue *gcreq_queue = gcreq->queue;
int isfirst;
os_mutexLock (&gcreq_queue->lock);
gcreq->next = NULL;
if (gcreq_queue->first)
{
gcreq_queue->last->next = gcreq;
isfirst = 0;
}
else
{
gcreq_queue->first = gcreq;
isfirst = 1;
}
gcreq_queue->last = gcreq;
if (isfirst)
os_condBroadcast (&gcreq_queue->cond);
os_mutexUnlock (&gcreq_queue->lock);
return isfirst;
}
void gcreq_enqueue (struct gcreq *gcreq)
{
gcreq_enqueue_common (gcreq);
}
int gcreq_requeue (struct gcreq *gcreq, gcreq_cb_t cb)
{
gcreq->cb = cb;
return gcreq_enqueue_common (gcreq);
}

1465
src/core/ddsi/src/q_init.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,84 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <ctype.h>
#include <stddef.h>
#include "ddsi/q_log.h"
#include "ddsi/q_unused.h"
#include "ddsi/q_lat_estim.h"
#include <stdlib.h>
#include <string.h>
void nn_lat_estim_init (struct nn_lat_estim *le)
{
int i;
le->index = 0;
for (i = 0; i < NN_LAT_ESTIM_MEDIAN_WINSZ; i++)
le->window[i] = 0;
le->smoothed = 0;
}
void nn_lat_estim_fini (UNUSED_ARG (struct nn_lat_estim *le))
{
}
static int cmpfloat (const float *a, const float *b)
{
return (*a < *b) ? -1 : (*a > *b) ? 1 : 0;
}
void nn_lat_estim_update (struct nn_lat_estim *le, int64_t est)
{
const float alpha = 0.01f;
float fest, med;
float tmp[NN_LAT_ESTIM_MEDIAN_WINSZ];
if (est <= 0)
return;
fest = (float) est / 1e3f; /* we do latencies in microseconds */
le->window[le->index] = fest;
if (++le->index == NN_LAT_ESTIM_MEDIAN_WINSZ)
le->index = 0;
memcpy (tmp, le->window, sizeof (tmp));
qsort (tmp, NN_LAT_ESTIM_MEDIAN_WINSZ, sizeof (tmp[0]), (int (*) (const void *, const void *)) cmpfloat);
med = tmp[NN_LAT_ESTIM_MEDIAN_WINSZ / 2];
if (le->smoothed == 0 && le->index == 0)
le->smoothed = med;
else if (le->smoothed != 0)
le->smoothed = (1.0f - alpha) * le->smoothed + alpha * med;
}
int nn_lat_estim_log (logcat_t logcat, const char *tag, const struct nn_lat_estim *le)
{
if (le->smoothed == 0.0f)
return 0;
else
{
float tmp[NN_LAT_ESTIM_MEDIAN_WINSZ];
int i;
memcpy (tmp, le->window, sizeof (tmp));
qsort (tmp, NN_LAT_ESTIM_MEDIAN_WINSZ, sizeof (tmp[0]), (int (*) (const void *, const void *)) cmpfloat);
if (tag)
nn_log (logcat, " LAT(%s: %e {", tag, le->smoothed);
else
nn_log (logcat, " LAT(%e {", le->smoothed);
for (i = 0; i < NN_LAT_ESTIM_MEDIAN_WINSZ; i++)
nn_log (logcat, "%s%e", (i > 0) ? "," : "", tmp[i]);
nn_log (logcat, "})");
return 1;
}
}
#if 0 /* not implemented yet */
double nn_lat_estim_current (const struct nn_lat_estim *le)
{
}
#endif

370
src/core/ddsi/src/q_lease.c Normal file
View file

@ -0,0 +1,370 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <ctype.h>
#include <stddef.h>
#include <assert.h>
#include "os/os.h"
#include "util/ut_fibheap.h"
#include "ddsi/ddsi_ser.h"
#include "ddsi/q_protocol.h"
#include "ddsi/q_rtps.h"
#include "ddsi/q_misc.h"
#include "ddsi/q_config.h"
#include "ddsi/q_log.h"
#include "ddsi/q_plist.h"
#include "ddsi/q_unused.h"
#include "ddsi/q_xevent.h"
#include "ddsi/q_addrset.h"
#include "ddsi/q_ddsi_discovery.h"
#include "ddsi/q_radmin.h"
#include "ddsi/q_ephash.h"
#include "ddsi/q_entity.h"
#include "ddsi/q_globals.h"
#include "ddsi/q_xmsg.h"
#include "ddsi/q_bswap.h"
#include "ddsi/q_transmit.h"
#include "ddsi/q_lease.h"
#include "ddsi/sysdeps.h"
/* This is absolute bottom for signed integers, where -x = x and yet x
!= 0 -- and note that it had better be 2's complement machine! */
#define TSCHED_NOT_ON_HEAP INT64_MIN
struct lease {
ut_fibheapNode_t heapnode;
nn_etime_t tsched; /* access guarded by leaseheap_lock */
nn_etime_t tend; /* access guarded by lock_lease/unlock_lease */
int64_t tdur; /* constant (renew depends on it) */
struct entity_common *entity; /* constant */
};
static int compare_lease_tsched (const void *va, const void *vb);
static const ut_fibheapDef_t lease_fhdef = UT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, heapnode), compare_lease_tsched);
static int compare_lease_tsched (const void *va, const void *vb)
{
const struct lease *a = va;
const struct lease *b = vb;
return (a->tsched.v == b->tsched.v) ? 0 : (a->tsched.v < b->tsched.v) ? -1 : 1;
}
void lease_management_init (void)
{
int i;
os_mutexInit (&gv.leaseheap_lock);
for (i = 0; i < N_LEASE_LOCKS; i++)
os_mutexInit (&gv.lease_locks[i]);
ut_fibheapInit (&lease_fhdef, &gv.leaseheap);
}
void lease_management_term (void)
{
int i;
assert (ut_fibheapMin (&lease_fhdef, &gv.leaseheap) == NULL);
for (i = 0; i < N_LEASE_LOCKS; i++)
os_mutexDestroy (&gv.lease_locks[i]);
os_mutexDestroy (&gv.leaseheap_lock);
}
static os_mutex *lock_lease_addr (struct lease const * const l)
{
uint32_t u = (uint16_t) ((uintptr_t) l >> 3);
uint32_t v = u * 0xb4817365;
unsigned idx = v >> (32 - N_LEASE_LOCKS_LG2);
return &gv.lease_locks[idx];
}
static void lock_lease (const struct lease *l)
{
os_mutexLock (lock_lease_addr (l));
}
static void unlock_lease (const struct lease *l)
{
os_mutexUnlock (lock_lease_addr (l));
}
struct lease *lease_new (nn_etime_t texpire, int64_t tdur, struct entity_common *e)
{
struct lease *l;
if ((l = os_malloc (sizeof (*l))) == NULL)
return NULL;
TRACE (("lease_new(tdur %"PRId64" guid %x:%x:%x:%x) @ %p\n", tdur, PGUID (e->guid), (void *) l));
l->tdur = tdur;
l->tend = texpire;
l->tsched.v = TSCHED_NOT_ON_HEAP;
l->entity = e;
return l;
}
void lease_register (struct lease *l)
{
TRACE (("lease_register(l %p guid %x:%x:%x:%x)\n", (void *) l, PGUID (l->entity->guid)));
os_mutexLock (&gv.leaseheap_lock);
lock_lease (l);
assert (l->tsched.v == TSCHED_NOT_ON_HEAP);
if (l->tend.v != T_NEVER)
{
l->tsched = l->tend;
ut_fibheapInsert (&lease_fhdef, &gv.leaseheap, l);
}
unlock_lease (l);
os_mutexUnlock (&gv.leaseheap_lock);
}
void lease_free (struct lease *l)
{
TRACE (("lease_free(l %p guid %x:%x:%x:%x)\n", (void *) l, PGUID (l->entity->guid)));
os_mutexLock (&gv.leaseheap_lock);
if (l->tsched.v != TSCHED_NOT_ON_HEAP)
ut_fibheapDelete (&lease_fhdef, &gv.leaseheap, l);
os_mutexUnlock (&gv.leaseheap_lock);
os_free (l);
}
void lease_renew (struct lease *l, nn_etime_t tnowE)
{
nn_etime_t tend_new = add_duration_to_etime (tnowE, l->tdur);
int did_update;
lock_lease (l);
/* do not touch tend if moving forward or if already expired */
if (tend_new.v <= l->tend.v || tnowE.v >= l->tend.v)
did_update = 0;
else
{
l->tend = tend_new;
did_update = 1;
}
unlock_lease (l);
if (did_update && (config.enabled_logcats & LC_TRACE))
{
int tsec, tusec;
TRACE ((" L("));
if (l->entity->guid.entityid.u == NN_ENTITYID_PARTICIPANT)
TRACE ((":%x", l->entity->guid.entityid.u));
else
TRACE (("%x:%x:%x:%x", PGUID (l->entity->guid)));
etime_to_sec_usec (&tsec, &tusec, tend_new);
TRACE ((" %d.%06d)", tsec, tusec));
}
}
void lease_set_expiry (struct lease *l, nn_etime_t when)
{
assert (when.v >= 0);
os_mutexLock (&gv.leaseheap_lock);
lock_lease (l);
l->tend = when;
if (l->tend.v < l->tsched.v)
{
/* moved forward and currently scheduled (by virtue of
TSCHED_NOT_ON_HEAP == INT64_MIN) */
l->tsched = l->tend;
ut_fibheapDecreaseKey (&lease_fhdef, &gv.leaseheap, l);
}
else if (l->tsched.v == TSCHED_NOT_ON_HEAP && l->tend.v < T_NEVER)
{
/* not currently scheduled, with a finite new expiry time */
l->tsched = l->tend;
ut_fibheapInsert (&lease_fhdef, &gv.leaseheap, l);
}
unlock_lease (l);
os_mutexUnlock (&gv.leaseheap_lock);
}
void check_and_handle_lease_expiration (UNUSED_ARG (struct thread_state1 *self), nn_etime_t tnowE)
{
struct lease *l;
const nn_wctime_t tnow = now();
os_mutexLock (&gv.leaseheap_lock);
while ((l = ut_fibheapMin (&lease_fhdef, &gv.leaseheap)) != NULL && l->tsched.v <= tnowE.v)
{
nn_guid_t g = l->entity->guid;
enum entity_kind k = l->entity->kind;
assert (l->tsched.v != TSCHED_NOT_ON_HEAP);
ut_fibheapExtractMin (&lease_fhdef, &gv.leaseheap);
lock_lease (l);
if (tnowE.v < l->tend.v)
{
if (l->tend.v == T_NEVER) {
/* don't reinsert if it won't expire */
l->tsched.v = TSCHED_NOT_ON_HEAP;
unlock_lease (l);
} else {
l->tsched = l->tend;
unlock_lease (l);
ut_fibheapInsert (&lease_fhdef, &gv.leaseheap, l);
}
continue;
}
nn_log (LC_DISCOVERY, "lease expired: l %p guid %x:%x:%x:%x tend %"PRId64" < now %"PRId64"\n", (void *) l, PGUID (g), l->tend.v, tnowE.v);
/* If the proxy participant is relying on another participant for
writing its discovery data (on the privileged participant,
i.e., its ddsi2 instance), we can't afford to drop it while the
privileged one is still considered live. If we do and it was a
temporary asymmetrical thing and the ddsi2 instance never lost
its liveliness, we will not rediscover the endpoints of this
participant because we will not rediscover the ddsi2
participant.
So IF it is dependent on another one, we renew the lease for a
very short while if the other one is still alive. If it is a
real case of lost liveliness, the other one will be gone soon
enough; if not, we should get a sign of life soon enough.
In this case, we simply abort the current iteration of the loop
after renewing the lease and continue with the next one.
This trick would fail if the ddsi2 participant can lose its
liveliness and regain it before we re-check the liveliness of
the dependent participants, and so the interval here must
significantly less than the pruning time for the
deleted_participants admin.
I guess that means there is a really good argument for the SPDP
and SEDP writers to be per-participant! */
if (k == EK_PROXY_PARTICIPANT)
{
struct proxy_participant *proxypp;
if ((proxypp = ephash_lookup_proxy_participant_guid (&g)) != NULL &&
ephash_lookup_proxy_participant_guid (&proxypp->privileged_pp_guid) != NULL)
{
nn_log (LC_DISCOVERY, "but postponing because privileged pp %x:%x:%x:%x is still live\n",
PGUID (proxypp->privileged_pp_guid));
l->tsched = l->tend = add_duration_to_etime (tnowE, 200 * T_MILLISECOND);
unlock_lease (l);
ut_fibheapInsert (&lease_fhdef, &gv.leaseheap, l);
continue;
}
}
unlock_lease (l);
l->tsched.v = TSCHED_NOT_ON_HEAP;
os_mutexUnlock (&gv.leaseheap_lock);
switch (k)
{
case EK_PARTICIPANT:
delete_participant (&g);
break;
case EK_PROXY_PARTICIPANT:
delete_proxy_participant_by_guid (&g, tnow, 1);
break;
case EK_WRITER:
delete_writer_nolinger (&g);
break;
case EK_PROXY_WRITER:
delete_proxy_writer (&g, tnow, 1);
break;
case EK_READER:
(void)delete_reader (&g);
break;
case EK_PROXY_READER:
delete_proxy_reader (&g, tnow, 1);
break;
}
os_mutexLock (&gv.leaseheap_lock);
}
os_mutexUnlock (&gv.leaseheap_lock);
}
/******/
static void debug_print_rawdata (const char *msg, const void *data, size_t len)
{
const unsigned char *c = data;
size_t i;
TRACE (("%s<", msg));
for (i = 0; i < len; i++)
{
if (32 < c[i] && c[i] <= 127)
TRACE (("%s%c", (i > 0 && (i%4) == 0) ? " " : "", c[i]));
else
TRACE (("%s\\x%02x", (i > 0 && (i%4) == 0) ? " " : "", c[i]));
}
TRACE ((">"));
}
void handle_PMD (UNUSED_ARG (const struct receiver_state *rst), nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len)
{
const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
const int bswap = (data->identifier == CDR_LE) ^ PLATFORM_IS_LITTLE_ENDIAN;
struct proxy_participant *pp;
nn_guid_t ppguid;
TRACE ((" PMD ST%x", statusinfo));
if (data->identifier != CDR_LE && data->identifier != CDR_BE)
{
TRACE ((" PMD data->identifier %u !?\n", ntohs (data->identifier)));
return;
}
switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER))
{
case 0:
if (offsetof (ParticipantMessageData_t, value) > len - sizeof (struct CDRHeader))
debug_print_rawdata (" SHORT1", data, len);
else
{
const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1);
nn_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
unsigned kind = ntohl (pmd->kind);
unsigned length = bswap ? bswap4u (pmd->length) : pmd->length;
TRACE ((" pp %x:%x:%x kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length));
if (len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value) < length)
debug_print_rawdata (" SHORT2", pmd->value, len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value));
else
debug_print_rawdata ("", pmd->value, length);
ppguid.prefix = p;
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
if ((pp = ephash_lookup_proxy_participant_guid (&ppguid)) == NULL)
TRACE ((" PPunknown"));
else
{
/* Renew lease if arrival of this message didn't already do so, also renew the lease
of the virtual participant used for DS-discovered endpoints */
if (!config.arrival_of_data_asserts_pp_and_ep_liveliness)
lease_renew (os_atomic_ldvoidp (&pp->lease), now_et ());
}
}
break;
case NN_STATUSINFO_DISPOSE:
case NN_STATUSINFO_UNREGISTER:
case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER:
/* Serialized key; BE or LE doesn't matter as both fields are
defined as octets. */
if (len < (int) (sizeof (struct CDRHeader) + sizeof (nn_guid_prefix_t)))
debug_print_rawdata (" SHORT3", data, len);
else
{
ppguid.prefix = nn_ntoh_guid_prefix (*((nn_guid_prefix_t *) (data + 1)));
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
if (delete_proxy_participant_by_guid (&ppguid, timestamp, 0) < 0)
TRACE ((" unknown"));
else
TRACE ((" delete"));
}
break;
}
TRACE (("\n"));
}

185
src/core/ddsi/src/q_log.c Normal file
View file

@ -0,0 +1,185 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "os/os.h"
#include "ddsi/q_config.h"
#include "ddsi/q_globals.h"
#include "ddsi/q_thread.h"
#include "ddsi/q_time.h"
#include "ddsi/q_log.h"
#define MAX_TIMESTAMP_LENGTH (10 + 1 + 6)
#define MAX_TID_LENGTH 10
#define MAX_HDR_LENGTH (MAX_TIMESTAMP_LENGTH + 1 + MAX_TID_LENGTH + + 2)
#define BUF_OFFSET MAX_HDR_LENGTH
static void logbuf_flush_real (struct thread_state1 *self, logbuf_t lb)
{
if (config.tracingOutputFile != NULL)
{
const char *tname = self ? self->name : "(anon)";
char hdr[MAX_HDR_LENGTH + 1];
int n, tsec, tusec;
if (lb->tstamp.v < 0)
lb->tstamp = now ();
wctime_to_sec_usec (&tsec, &tusec, lb->tstamp);
lb->tstamp.v = -1;
n = snprintf (hdr, sizeof (hdr), "%d.%06d/%*.*s: ", tsec, tusec, MAX_TID_LENGTH, MAX_TID_LENGTH, tname);
assert (0 < n && n <= BUF_OFFSET);
memcpy (lb->buf + BUF_OFFSET - n, hdr, (size_t) n);
fwrite (lb->buf + BUF_OFFSET - n, 1, lb->pos - BUF_OFFSET + (size_t) n, config.tracingOutputFile);
fflush (config.tracingOutputFile);
}
lb->pos = BUF_OFFSET;
lb->buf[lb->pos] = 0;
}
static void logbuf_flush (struct thread_state1 *self, logbuf_t lb)
{
if (lb->pos > BUF_OFFSET)
{
if (lb->pos < (int) sizeof (lb->buf))
lb->buf[lb->pos++] = '\n';
else
lb->buf[sizeof (lb->buf) - 1] = '\n';
logbuf_flush_real (self, lb);
}
}
void logbuf_init (logbuf_t lb)
{
lb->bufsz = sizeof (lb->buf);
lb->pos = BUF_OFFSET;
lb->tstamp.v = -1;
lb->buf[lb->pos] = 0;
}
logbuf_t logbuf_new (void)
{
logbuf_t lb = os_malloc (sizeof (*lb));
logbuf_init (lb);
return lb;
}
void logbuf_free (logbuf_t lb)
{
logbuf_flush (lookup_thread_state (), lb);
os_free (lb);
}
/* LOGGING ROUTINES */
static void nn_vlogb (struct thread_state1 *self, const char *fmt, va_list ap)
{
int n, trunc = 0;
size_t nrem;
logbuf_t lb;
if (*fmt == 0)
return;
if (self && self->lb)
lb = self->lb;
else
{
lb = &gv.static_logbuf;
if (gv.static_logbuf_lock_inited)
{
/* not supposed to be multi-threaded when mutex not
initialized */
os_mutexLock (&gv.static_logbuf_lock);
}
}
nrem = lb->bufsz - lb->pos;
if (nrem > 0)
{
n = os_vsnprintf (lb->buf + lb->pos, nrem, fmt, ap);
if (n >= 0 && (size_t) n < nrem)
lb->pos += (size_t) n;
else
{
lb->pos += nrem;
trunc = 1;
}
if (trunc)
{
static const char msg[] = "(trunc)\n";
const size_t msglen = sizeof (msg) - 1;
assert (lb->pos <= lb->bufsz);
assert (lb->pos >= msglen);
memcpy (lb->buf + lb->pos - msglen, msg, msglen);
}
}
if (fmt[strlen (fmt) - 1] == '\n')
{
logbuf_flush_real (self, lb);
}
if (lb == &gv.static_logbuf && gv.static_logbuf_lock_inited)
{
os_mutexUnlock (&gv.static_logbuf_lock);
}
}
int nn_vlog (logcat_t cat, const char *fmt, va_list ap)
{
if (config.enabled_logcats & cat)
{
struct thread_state1 *self = lookup_thread_state ();
nn_vlogb (self, fmt, ap);
}
return 0;
}
int nn_log (_In_ logcat_t cat, _In_z_ _Printf_format_string_ const char *fmt, ...)
{
if (config.enabled_logcats & cat)
{
struct thread_state1 *self = lookup_thread_state ();
va_list ap;
va_start (ap, fmt);
nn_vlogb (self, fmt, ap);
va_end (ap);
}
if (cat == LC_FATAL)
{
abort ();
}
return 0;
}
int nn_trace (_In_z_ _Printf_format_string_ const char *fmt, ...)
{
if (config.enabled_logcats & LC_TRACE)
{
struct thread_state1 *self = lookup_thread_state ();
va_list ap;
va_start (ap, fmt);
nn_vlogb (self, fmt, ap);
va_end (ap);
}
return 0;
}
void nn_log_set_tstamp (nn_wctime_t tnow)
{
struct thread_state1 *self = lookup_thread_state ();
if (self && self->lb)
self->lb->tstamp = tnow;
}

209
src/core/ddsi/src/q_misc.c Normal file
View file

@ -0,0 +1,209 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <string.h>
#include "ddsi/q_misc.h"
#include "ddsi/q_bswap.h"
#include "ddsi/q_md5.h"
int vendor_is_rti (nn_vendorid_t vendor)
{
const nn_vendorid_t rti = NN_VENDORID_RTI;
return vendor.id[0] == rti.id[0] && vendor.id[1] == rti.id[1];
}
int vendor_is_twinoaks (nn_vendorid_t vendor)
{
const nn_vendorid_t twinoaks = NN_VENDORID_TWINOAKS;
return vendor.id[0] == twinoaks.id[0] && vendor.id[1] == twinoaks.id[1];
}
int vendor_is_cloud (nn_vendorid_t vendor)
{
const nn_vendorid_t cloud = NN_VENDORID_PRISMTECH_CLOUD;
return vendor.id[0] == cloud.id[0] && vendor.id[1] == cloud.id[1];
}
int vendor_is_prismtech (nn_vendorid_t vid)
{
const nn_vendorid_t pt1 = NN_VENDORID_PRISMTECH_OSPL;
const nn_vendorid_t pt2 = NN_VENDORID_PRISMTECH_LITE;
const nn_vendorid_t pt3 = NN_VENDORID_PRISMTECH_GATEWAY;
const nn_vendorid_t pt4 = NN_VENDORID_PRISMTECH_JAVA;
const nn_vendorid_t pt5 = NN_VENDORID_PRISMTECH_CLOUD;
const nn_vendorid_t pt6 = NN_VENDORID_ECLIPSE_CYCLONEDDS;
return
(vid.id[0] == pt1.id[0]) &&
((vid.id[1] == pt1.id[1]) || (vid.id[1] == pt2.id[1])
|| (vid.id[1] == pt3.id[1]) || (vid.id[1] == pt4.id[1])
|| (vid.id[1] == pt5.id[1]) || (vid.id[1] == pt6.id[1]));
}
int vendor_is_opensplice (nn_vendorid_t vid)
{
const nn_vendorid_t pt1 = NN_VENDORID_PRISMTECH_OSPL;
return (vid.id[0] == pt1.id[0] && vid.id[1] == pt1.id[1]);
}
int is_own_vendor (nn_vendorid_t vendor)
{
const nn_vendorid_t ownid = MY_VENDOR_ID;
return vendor.id[0] == ownid.id[0] && vendor.id[1] == ownid.id[1];
}
seqno_t fromSN (const nn_sequence_number_t sn)
{
return ((seqno_t) sn.high << 32) | sn.low;
}
nn_sequence_number_t toSN (seqno_t n)
{
nn_sequence_number_t x;
x.high = (int) (n >> 32);
x.low = (unsigned) n;
return x;
}
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
int WildcardOverlap(char * p1, char * p2)
{
/* both patterns are empty or contain wildcards => overlap */
if ((p1 == NULL || strcmp(p1,"") == 0 || strcmp(p1,"*") == 0) &&
(p2 == NULL || strcmp(p2,"") == 0 || strcmp(p2,"*") == 0))
return 1;
/* Either pattern is empty (but the other is not empty or wildcard only) => no overlap */
if (p1 == NULL || strcmp(p1,"") == 0 || p2 == NULL || strcmp(p2,"")==0)
return 0;
if ( (p1[0] == '*' || p2[0] == '*') && (WildcardOverlap(p1,p2+1)|| WildcardOverlap(p1+1,p2)))
return 1;
if ( (p1[0] == '?' || p2[0] == '?' || p1[0] == p2[0] ) && WildcardOverlap(p1+1,p2+1))
return 1;
/* else, no match, return false */
return 0;
}
#endif
int ddsi2_patmatch (const char *pat, const char *str)
{
while (*pat)
{
if (*pat == '?')
{
/* any character will do */
if (*str++ == 0)
{
return 0;
}
pat++;
}
else if (*pat == '*')
{
/* collapse a sequence of wildcards, requiring as many
characters in str as there are ?s in the sequence */
while (*pat == '*' || *pat == '?')
{
if (*pat == '?' && *str++ == 0)
{
return 0;
}
pat++;
}
/* try matching on all positions where str matches pat */
while (*str)
{
if (*str == *pat && ddsi2_patmatch (pat+1, str+1))
{
return 1;
}
str++;
}
return *pat == 0;
}
else
{
/* only an exact match */
if (*str++ != *pat++)
{
return 0;
}
}
}
return *str == 0;
}
static const uint32_t crc32_table[] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
uint32_t crc32_calc (const void *buf, uint32_t length)
{
const uint8_t *vptr = buf;
uint32_t i, reg = 0;
uint8_t top;
for (i = 0; i < length; i++)
{
top = (uint8_t) (reg >> 24);
top ^= *vptr;
reg = (reg << 8) ^ crc32_table[top];
vptr++;
}
return reg;
}

1160
src/core/ddsi/src/q_nwif.c Normal file

File diff suppressed because it is too large Load diff

209
src/core/ddsi/src/q_pcap.c Normal file
View file

@ -0,0 +1,209 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <stdio.h>
#include <assert.h>
#include "os/os.h"
#include "ddsi/q_log.h"
#include "ddsi/q_time.h"
#include "ddsi/q_config.h"
#include "ddsi/q_globals.h"
#include "ddsi/q_bswap.h"
#include "ddsi/sysdeps.h"
#include "ddsi/q_pcap.h"
/* pcap format info taken from http://wiki.wireshark.org/Development/LibpcapFileFormat */
#define LINKTYPE_RAW 101 /* Raw IP; the packet begins with an IPv4 or IPv6 header, with the "version" field of the header indicating whether it's an IPv4 or IPv6 header. */
typedef struct pcap_hdr_s {
uint32_t magic_number; /* magic number */
uint16_t version_major; /* major version number */
uint16_t version_minor; /* minor version number */
int32_t thiszone; /* GMT to local correction */
uint32_t sigfigs; /* accuracy of timestamps */
uint32_t snaplen; /* max length of captured packets, in octets */
uint32_t network; /* data link type */
} pcap_hdr_t;
typedef struct pcaprec_hdr_s {
int32_t ts_sec; /* timestamp seconds (orig: unsigned) */
int32_t ts_usec; /* timestamp microseconds (orig: unsigned) */
uint32_t incl_len; /* number of octets of packet saved in file */
uint32_t orig_len; /* actual length of packet */
} pcaprec_hdr_t;
typedef struct ipv4_hdr_s {
unsigned char version_hdrlength;
unsigned char diffserv_congestion;
uint16_t totallength;
uint16_t identification;
uint16_t flags_fragment_offset;
unsigned char ttl;
unsigned char proto;
uint16_t checksum;
uint32_t srcip;
uint32_t dstip;
} ipv4_hdr_t;
typedef struct udp_hdr_s {
uint16_t srcport;
uint16_t dstport;
uint16_t length;
uint16_t checksum;
} udp_hdr_t;
static const ipv4_hdr_t ipv4_hdr_template = {
(4 << 4) | 5, /* IPv4, minimum header length */
0 | 0, /* no diffserv, congestion */
0, /* total length will be overridden */
0, /* not fragmenting, so irrelevant */
0, /* not fragmenting */
0, /* TTL: received has it at 128, sent at 255 */
17, /* UDP */
0, /* checksum will be overridden */
0, /* srcip: set per packet */
0 /* dstip: set per packet */
};
#define IPV4_HDR_SIZE 20
#define UDP_HDR_SIZE 8
FILE *new_pcap_file (const char *name)
{
FILE *fp;
pcap_hdr_t hdr;
if ((fp = fopen (name, "wb")) == NULL)
{
NN_WARNING ("packet capture disabled: file %s could not be opened for writing\n", name);
return NULL;
}
hdr.magic_number = 0xa1b2c3d4;
hdr.version_major = 2;
hdr.version_minor = 4;
hdr.thiszone = 0;
hdr.sigfigs = 0;
hdr.snaplen = 65535;
hdr.network = LINKTYPE_RAW;
fwrite (&hdr, sizeof (hdr), 1, fp);
return fp;
}
static void write_data (FILE *fp, const struct msghdr *msghdr, size_t sz)
{
size_t i, n = 0;
for (i = 0; i < (size_t) msghdr->msg_iovlen && n < sz; i++)
{
size_t m1 = msghdr->msg_iov[i].iov_len;
size_t m = (n + m1 <= sz) ? m1 : sz - n;
fwrite (msghdr->msg_iov[i].iov_base, m, 1, fp);
n += m;
}
assert (n == sz);
}
static uint16_t calc_ipv4_checksum (const uint16_t *x)
{
uint32_t s = 0;
int i;
for (i = 0; i < 10; i++)
{
s += x[i];
}
s = (s & 0xffff) + (s >> 16);
return (uint16_t) ~s;
}
void write_pcap_received
(
FILE * fp,
nn_wctime_t tstamp,
const os_sockaddr_storage * src,
const os_sockaddr_storage * dst,
unsigned char * buf,
size_t sz
)
{
if (!config.useIpv6)
{
pcaprec_hdr_t pcap_hdr;
union {
ipv4_hdr_t ipv4_hdr;
uint16_t x[10];
} u;
udp_hdr_t udp_hdr;
size_t sz_ud = sz + UDP_HDR_SIZE;
size_t sz_iud = sz_ud + IPV4_HDR_SIZE;
os_mutexLock (&gv.pcap_lock);
wctime_to_sec_usec (&pcap_hdr.ts_sec, &pcap_hdr.ts_usec, tstamp);
pcap_hdr.incl_len = pcap_hdr.orig_len = (uint32_t) sz_iud;
fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, fp);
u.ipv4_hdr = ipv4_hdr_template;
u.ipv4_hdr.totallength = toBE2u ((unsigned short) sz_iud);
u.ipv4_hdr.ttl = 128;
u.ipv4_hdr.srcip = ((os_sockaddr_in*) src)->sin_addr.s_addr;
u.ipv4_hdr.dstip = ((os_sockaddr_in*) dst)->sin_addr.s_addr;
u.ipv4_hdr.checksum = calc_ipv4_checksum (u.x);
fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, fp);
udp_hdr.srcport = ((os_sockaddr_in*) src)->sin_port;
udp_hdr.dstport = ((os_sockaddr_in*) dst)->sin_port;
udp_hdr.length = toBE2u ((unsigned short) sz_ud);
udp_hdr.checksum = 0; /* don't have to compute a checksum for UDPv4 */
fwrite (&udp_hdr, sizeof (udp_hdr), 1, fp);
fwrite (buf, sz, 1, fp);
os_mutexUnlock (&gv.pcap_lock);
}
}
void write_pcap_sent
(
FILE * fp,
nn_wctime_t tstamp,
const os_sockaddr_storage * src,
const struct msghdr * hdr,
size_t sz
)
{
if (!config.useIpv6)
{
pcaprec_hdr_t pcap_hdr;
union {
ipv4_hdr_t ipv4_hdr;
uint16_t x[10];
} u;
udp_hdr_t udp_hdr;
size_t sz_ud = sz + UDP_HDR_SIZE;
size_t sz_iud = sz_ud + IPV4_HDR_SIZE;
os_mutexLock (&gv.pcap_lock);
wctime_to_sec_usec (&pcap_hdr.ts_sec, &pcap_hdr.ts_usec, tstamp);
pcap_hdr.incl_len = pcap_hdr.orig_len = (uint32_t) sz_iud;
fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, fp);
u.ipv4_hdr = ipv4_hdr_template;
u.ipv4_hdr.totallength = toBE2u ((unsigned short) sz_iud);
u.ipv4_hdr.ttl = 255;
u.ipv4_hdr.srcip = ((os_sockaddr_in*) src)->sin_addr.s_addr;
u.ipv4_hdr.dstip = ((os_sockaddr_in*) hdr->msg_name)->sin_addr.s_addr;
u.ipv4_hdr.checksum = calc_ipv4_checksum (u.x);
fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, fp);
udp_hdr.srcport = ((os_sockaddr_in*) src)->sin_port;
udp_hdr.dstport = ((os_sockaddr_in*) hdr->msg_name)->sin_port;
udp_hdr.length = toBE2u ((unsigned short) sz_ud);
udp_hdr.checksum = 0; /* don't have to compute a checksum for UDPv4 */
fwrite (&udp_hdr, sizeof (udp_hdr), 1, fp);
write_data (fp, hdr, sz);
os_mutexUnlock (&gv.pcap_lock);
}
}

4099
src/core/ddsi/src/q_plist.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,222 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <string.h>
#include <assert.h>
#include "ddsi/q_time.h"
#include "ddsi/q_xqos.h"
#include "ddsi/q_misc.h"
#include "ddsi/q_qosmatch.h"
int is_wildcard_partition (const char *str)
{
return strchr (str, '*') || strchr (str, '?');
}
static int partition_patmatch_p (const char *pat, const char *name)
{
/* pat may be a wildcard expression, name must not be */
if (!is_wildcard_partition (pat))
/* no wildcard in pat => must equal name */
return (strcmp (pat, name) == 0);
else if (is_wildcard_partition (name))
/* (we know: wildcard in pat) => wildcard in name => no match */
return 0;
else
return ddsi2_patmatch (pat, name);
}
static int partitions_match_default (const nn_xqos_t *x)
{
unsigned i;
if (!(x->present & QP_PARTITION) || x->partition.n == 0)
return 1;
for (i = 0; i < x->partition.n; i++)
if (partition_patmatch_p (x->partition.strs[i], ""))
return 1;
return 0;
}
int partitions_match_p (const nn_xqos_t *a, const nn_xqos_t *b)
{
if (!(a->present & QP_PARTITION) || a->partition.n == 0)
return partitions_match_default (b);
else if (!(b->present & QP_PARTITION) || b->partition.n == 0)
return partitions_match_default (a);
else
{
unsigned i, j;
for (i = 0; i < a->partition.n; i++)
for (j = 0; j < b->partition.n; j++)
{
if (partition_patmatch_p (a->partition.strs[i], b->partition.strs[j]) ||
partition_patmatch_p (b->partition.strs[j], a->partition.strs[i]))
return 1;
}
return 0;
}
}
int partition_match_based_on_wildcard_in_left_operand (const nn_xqos_t *a, const nn_xqos_t *b, const char **realname)
{
assert (partitions_match_p (a, b));
if (!(a->present & QP_PARTITION) || a->partition.n == 0)
{
return 0;
}
else if (!(b->present & QP_PARTITION) || b->partition.n == 0)
{
/* Either A explicitly includes the default partition, or it is a
wildcard that matches it */
unsigned i;
for (i = 0; i < a->partition.n; i++)
if (strcmp (a->partition.strs[i], "") == 0)
return 0;
*realname = "";
return 1;
}
else
{
unsigned i, j;
int maybe_yes = 0;
for (i = 0; i < a->partition.n; i++)
for (j = 0; j < b->partition.n; j++)
{
if (partition_patmatch_p (a->partition.strs[i], b->partition.strs[j]))
{
if (!is_wildcard_partition (a->partition.strs[i]))
return 0;
else
{
*realname = b->partition.strs[j];
maybe_yes = 1;
}
}
}
return maybe_yes;
}
}
static int ddsi_duration_is_lt (nn_duration_t a0, nn_duration_t b0)
{
/* inf counts as <= inf */
const int64_t a = nn_from_ddsi_duration (a0);
const int64_t b = nn_from_ddsi_duration (b0);
if (a == T_NEVER)
return 0;
else if (b == T_NEVER)
return 1;
else
return a < b;
}
/* Duplicates of DDS policy ids to avoid inclusion of actual definitions */
#define Q_INVALID_QOS_POLICY_ID 0
#define Q_USERDATA_QOS_POLICY_ID 1
#define Q_DURABILITY_QOS_POLICY_ID 2
#define Q_PRESENTATION_QOS_POLICY_ID 3
#define Q_DEADLINE_QOS_POLICY_ID 4
#define Q_LATENCYBUDGET_QOS_POLICY_ID 5
#define Q_OWNERSHIP_QOS_POLICY_ID 6
#define Q_OWNERSHIPSTRENGTH_QOS_POLICY_ID 7
#define Q_LIVELINESS_QOS_POLICY_ID 8
#define Q_TIMEBASEDFILTER_QOS_POLICY_ID 9
#define Q_PARTITION_QOS_POLICY_ID 10
#define Q_RELIABILITY_QOS_POLICY_ID 11
#define Q_DESTINATIONORDER_QOS_POLICY_ID 12
#define Q_HISTORY_QOS_POLICY_ID 13
#define Q_RESOURCELIMITS_QOS_POLICY_ID 14
#define Q_ENTITYFACTORY_QOS_POLICY_ID 15
#define Q_WRITERDATALIFECYCLE_QOS_POLICY_ID 16
#define Q_READERDATALIFECYCLE_QOS_POLICY_ID 17
#define Q_TOPICDATA_QOS_POLICY_ID 18
#define Q_GROUPDATA_QOS_POLICY_ID 19
#define Q_TRANSPORTPRIORITY_QOS_POLICY_ID 20
#define Q_LIFESPAN_QOS_POLICY_ID 21
#define Q_DURABILITYSERVICE_QOS_POLICY_ID 22
int32_t qos_match_p (const nn_xqos_t *rd, const nn_xqos_t *wr)
{
#ifndef NDEBUG
unsigned musthave = (QP_RXO_MASK | QP_PARTITION | QP_TOPIC_NAME | QP_TYPE_NAME);
assert ((rd->present & musthave) == musthave);
assert ((wr->present & musthave) == musthave);
#endif
if (strcmp (rd->topic_name, wr->topic_name) != 0)
{
return Q_INVALID_QOS_POLICY_ID;
}
if (strcmp (rd->type_name, wr->type_name) != 0)
{
return Q_INVALID_QOS_POLICY_ID;
}
if (rd->relaxed_qos_matching.value || wr->relaxed_qos_matching.value)
{
if (rd->reliability.kind != wr->reliability.kind)
{
return Q_RELIABILITY_QOS_POLICY_ID;
}
}
else
{
if (rd->reliability.kind > wr->reliability.kind)
{
return Q_RELIABILITY_QOS_POLICY_ID;
}
if (rd->durability.kind > wr->durability.kind)
{
return Q_DURABILITY_QOS_POLICY_ID;
}
if (rd->presentation.access_scope > wr->presentation.access_scope)
{
return Q_PRESENTATION_QOS_POLICY_ID;
}
if (rd->presentation.coherent_access > wr->presentation.coherent_access)
{
return Q_PRESENTATION_QOS_POLICY_ID;
}
if (rd->presentation.ordered_access > wr->presentation.ordered_access)
{
return Q_PRESENTATION_QOS_POLICY_ID;
}
if (ddsi_duration_is_lt (rd->deadline.deadline, wr->deadline.deadline))
{
return Q_DEADLINE_QOS_POLICY_ID;
}
if (ddsi_duration_is_lt (rd->latency_budget.duration, wr->latency_budget.duration))
{
return Q_LATENCYBUDGET_QOS_POLICY_ID;
}
if (rd->ownership.kind != wr->ownership.kind)
{
return Q_OWNERSHIP_QOS_POLICY_ID;
}
if (rd->liveliness.kind > wr->liveliness.kind)
{
return Q_LIVELINESS_QOS_POLICY_ID;
}
if (ddsi_duration_is_lt (rd->liveliness.lease_duration, wr->liveliness.lease_duration))
{
return Q_LIVELINESS_QOS_POLICY_ID;
}
if (rd->destination_order.kind > wr->destination_order.kind)
{
return Q_DESTINATIONORDER_QOS_POLICY_ID;
}
}
if (!partitions_match_p (rd, wr))
{
return Q_PARTITION_QOS_POLICY_ID;
}
return -1;
}

2680
src/core/ddsi/src/q_radmin.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,240 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include "os/os.h"
#include "ddsi/q_servicelease.h"
#include "ddsi/q_config.h"
#include "ddsi/q_log.h"
#include "ddsi/q_thread.h"
#include "ddsi/q_time.h"
#include "ddsi/q_unused.h"
#include "ddsi/q_error.h"
#include "ddsi/q_globals.h" /* for mattr, cattr */
#include "ddsi/sysdeps.h" /* for getrusage() */
static void nn_retrieve_lease_settings (os_time *sleepTime)
{
const float leaseSec = config.servicelease_expiry_time;
float sleepSec = leaseSec * config.servicelease_update_factor;
/* Run at no less than 1Hz: internal liveliness monitoring is slaved
to this interval as well. 1Hz lease renewals and liveliness
checks is no large burden, and performing liveliness checks once
a second is a lot more useful than doing it once every few
seconds. Besides -- we're now also gathering CPU statistics. */
if (sleepSec > 1.0f)
sleepSec = 1.0f;
sleepTime->tv_sec = (int32_t) sleepSec;
sleepTime->tv_nsec = (int32_t) ((sleepSec - (float) sleepTime->tv_sec) * 1e9f);
}
struct alive_wd {
char alive;
vtime_t wd;
};
struct nn_servicelease {
os_time sleepTime;
int keepgoing;
struct alive_wd *av_ary;
void (*renew_cb) (void *arg);
void *renew_arg;
os_mutex lock;
os_cond cond;
struct thread_state1 *ts;
};
static uint32_t lease_renewal_thread (struct nn_servicelease *sl)
{
/* Do not check more often than once every 100ms (no particular
reason why it has to be 100ms), regardless of the lease settings.
Note: can't trust sl->self, may have been scheduled before the
assignment. */
const int64_t min_progress_check_intv = 100 * T_MILLISECOND;
struct thread_state1 *self = lookup_thread_state ();
nn_mtime_t next_thread_cputime = { 0 };
nn_mtime_t tlast = { 0 };
int was_alive = 1;
unsigned i;
for (i = 0; i < thread_states.nthreads; i++)
{
sl->av_ary[i].alive = 1;
sl->av_ary[i].wd = thread_states.ts[i].watchdog - 1;
}
os_mutexLock (&sl->lock);
while (sl->keepgoing)
{
unsigned n_alive = 0;
nn_mtime_t tnow = now_mt ();
LOG_THREAD_CPUTIME (next_thread_cputime);
TRACE (("servicelease: tnow %"PRId64":", tnow.v));
/* Check progress only if enough time has passed: there is no
guarantee that os_cond_timedwait wont ever return early, and we
do want to avoid spurious warnings. */
if (tnow.v < tlast.v + min_progress_check_intv)
{
n_alive = thread_states.nthreads;
}
else
{
tlast = tnow;
for (i = 0; i < thread_states.nthreads; i++)
{
if (thread_states.ts[i].state != THREAD_STATE_ALIVE)
n_alive++;
else
{
vtime_t vt = thread_states.ts[i].vtime;
vtime_t wd = thread_states.ts[i].watchdog;
int alive = vtime_asleep_p (vt) || vtime_asleep_p (wd) || vtime_gt (wd, sl->av_ary[i].wd);
n_alive += (unsigned) alive;
TRACE ((" %u(%s):%c:%u:%u->%u:", i, thread_states.ts[i].name, alive ? 'a' : 'd', vt, sl->av_ary[i].wd, wd));
sl->av_ary[i].wd = wd;
if (sl->av_ary[i].alive != alive)
{
const char *name = thread_states.ts[i].name;
const char *msg;
if (!alive)
msg = "failed to make progress";
else
msg = "once again made progress";
NN_WARNING ("thread %s %s\n", name ? name : "(anon)", msg);
sl->av_ary[i].alive = (char) alive;
}
}
}
}
/* Only renew the lease if all threads are alive, so that one
thread blocking for a while but not too extremely long will
cause warnings for that thread in the log file, but won't cause
the DDSI2 service to be marked as dead. */
if (n_alive == thread_states.nthreads)
{
TRACE ((": [%u] renewing\n", n_alive));
/* FIXME: perhaps it would be nice to control automatic
liveliness updates from here.
FIXME: should terminate failure of renew_cb() */
sl->renew_cb (sl->renew_arg);
was_alive = 1;
}
else
{
TRACE ((": [%u] NOT renewing\n", n_alive));
if (was_alive)
log_stack_traces ();
was_alive = 0;
}
#if SYSDEPS_HAVE_GETRUSAGE
/* If getrusage() is available, use it to log CPU and memory
statistics to the trace. Getrusage() can't fail if the
parameters are valid, and these are by the book. Still we
check. */
if (config.enabled_logcats & LC_TIMING)
{
struct rusage u;
if (getrusage (RUSAGE_SELF, &u) == 0)
{
nn_log (LC_TIMING,
"rusage: utime %d.%06d stime %d.%06d maxrss %ld data %ld vcsw %ld ivcsw %ld\n",
(int) u.ru_utime.tv_sec, (int) u.ru_utime.tv_usec,
(int) u.ru_stime.tv_sec, (int) u.ru_stime.tv_usec,
u.ru_maxrss, u.ru_idrss, u.ru_nvcsw, u.ru_nivcsw);
}
}
#endif
os_condTimedWait (&sl->cond, &sl->lock, &sl->sleepTime);
/* We are never active in a way that matters for the garbage
collection of old writers, &c. */
thread_state_asleep (self);
}
os_mutexUnlock (&sl->lock);
return 0;
}
static void dummy_renew_cb (UNUSED_ARG (void *arg))
{
}
struct nn_servicelease *nn_servicelease_new (void (*renew_cb) (void *arg), void *renew_arg)
{
struct nn_servicelease *sl;
sl = os_malloc (sizeof (*sl));
nn_retrieve_lease_settings (&sl->sleepTime);
sl->keepgoing = -1;
sl->renew_cb = renew_cb ? renew_cb : dummy_renew_cb;
sl->renew_arg = renew_arg;
sl->ts = NULL;
if ((sl->av_ary = os_malloc (thread_states.nthreads * sizeof (*sl->av_ary))) == NULL)
goto fail_vtimes;
/* service lease update thread initializes av_ary */
os_mutexInit (&sl->lock);
os_condInit (&sl->cond, &sl->lock);
return sl;
fail_vtimes:
os_free (sl);
return NULL;
}
int nn_servicelease_start_renewing (struct nn_servicelease *sl)
{
os_mutexLock (&sl->lock);
assert (sl->keepgoing == -1);
sl->keepgoing = 1;
os_mutexUnlock (&sl->lock);
sl->ts = create_thread ("lease", (uint32_t (*) (void *)) lease_renewal_thread, sl);
if (sl->ts == NULL)
goto fail_thread;
return 0;
fail_thread:
sl->keepgoing = -1;
return ERR_UNSPECIFIED;
}
void nn_servicelease_statechange_barrier (struct nn_servicelease *sl)
{
os_mutexLock (&sl->lock);
os_mutexUnlock (&sl->lock);
}
void nn_servicelease_free (struct nn_servicelease *sl)
{
if (sl->keepgoing != -1)
{
os_mutexLock (&sl->lock);
sl->keepgoing = 0;
os_condSignal (&sl->cond);
os_mutexUnlock (&sl->lock);
join_thread (sl->ts);
}
os_condDestroy (&sl->cond);
os_mutexDestroy (&sl->lock);
os_free (sl->av_ary);
os_free (sl);
}

View file

@ -0,0 +1,657 @@
/*
* 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
*/
#if defined (WIN32) || defined (OSPL_LINUX)
#define FD_SETSIZE 4096
#endif
#include <assert.h>
#include <stdlib.h>
#include "os/os.h"
#include "ddsi/q_sockwaitset.h"
#include "ddsi/q_config.h"
#include "ddsi/q_log.h"
#include "ddsi/ddsi_tran.h"
#define WAITSET_DELTA 8
#ifdef __VXWORKS__
#include <pipeDrv.h>
#include <ioLib.h>
#include <string.h>
#include <selectLib.h>
#define OSPL_PIPENAMESIZE 26
#endif
#ifdef WINCE
struct os_sockWaitsetCtx
{
ddsi_tran_conn_t conns[MAXIMUM_WAIT_OBJECTS]; /* connections and listeners */
WSAEVENT events[MAXIMUM_WAIT_OBJECTS]; /* events associated with sockets */
int index; /* last wakeup index, or -1 */
unsigned n; /* sockets/events [0 .. n-1] are occupied */
};
struct os_sockWaitset
{
os_mutex mutex; /* concurrency guard */
struct os_sockWaitsetCtx ctx;
struct os_sockWaitsetCtx ctx0;
};
os_sockWaitset os_sockWaitsetNew (void)
{
os_sockWaitset ws = os_malloc (sizeof (*ws));
ws->ctx.conns[0] = NULL;
ws->ctx.events[0] = WSACreateEvent ();
ws->ctx.n = 1;
ws->ctx.index = -1;
os_mutexInit (&ws->mutex);
return ws;
}
void os_sockWaitsetFree (os_sockWaitset ws)
{
unsigned i;
for (i = 0; i < ws->ctx.n; i++)
{
WSACloseEvent (ws->ctx.events[i]);
}
os_mutexDestroy (&ws->mutex);
os_free (ws);
}
void os_sockWaitsetPurge (os_sockWaitset ws, unsigned index)
{
unsigned i;
os_mutexLock (&ws->mutex);
for (i = index + 1; i < ws->ctx.n; i++)
{
ws->ctx.conns[i] = NULL;
if (!WSACloseEvent (ws->ctx.events[i]))
{
NN_WARNING ("os_sockWaitsetPurge: WSACloseEvent (%x failed, error %d", (os_uint32) ws->ctx.events[i], os_getErrno ());
}
}
ws->ctx.n = index + 1;
os_mutexUnlock (&ws->mutex);
}
void os_sockWaitsetRemove (os_sockWaitset ws, ddsi_tran_conn_t conn)
{
unsigned i;
os_mutexLock (&ws->mutex);
for (i = 0; i < ws->ctx.n; i++)
{
if (conn == ws->ctx.conns[i])
{
WSACloseEvent (ws->ctx.events[i]);
ws->ctx.n--;
if (i != ws->ctx.n)
{
ws->ctx.events[i] = ws->ctx.events[ws->ctx.n];
ws->ctx.conns[i] = ws->ctx.conns[ws->ctx.n];
}
break;
}
}
os_mutexUnlock (&ws->mutex);
}
void os_sockWaitsetTrigger (os_sockWaitset ws)
{
if (! WSASetEvent (ws->ctx.events[0]))
{
NN_WARNING ("os_sockWaitsetTrigger: WSASetEvent(%x) failed, error %d", (os_uint32) ws->ctx.events[0], os_getErrno ());
}
}
void os_sockWaitsetAdd (os_sockWaitset ws, ddsi_tran_conn_t conn)
{
WSAEVENT ev;
os_socket sock = ddsi_conn_handle (conn);
unsigned idx;
os_mutexLock (&ws->mutex);
for (idx = 0; idx < ws->ctx.n; idx++)
{
if (ws->ctx.conns[idx] == conn)
break;
}
if (idx == ws->ctx.n)
{
assert (ws->n < MAXIMUM_WAIT_OBJECTS);
ev = WSACreateEvent ();
assert (ev != WSA_INVALID_EVENT);
if (WSAEventSelect (sock, ev, FD_READ) == SOCKET_ERROR)
{
NN_WARNING ("os_sockWaitsetAdd: WSAEventSelect(%x,%x) failed, error %d", (os_uint32) sock, (os_uint32) ev, os_getErrno ());
WSACloseEvent (ev);
assert (0);
}
ws->ctx.conns[ws->ctx.n] = conn;
ws->ctx.events[ws->ctx.n] = ev;
ws->ctx.n++;
}
os_mutexUnlock (&ws->mutex);
}
os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws)
{
unsigned idx;
assert (ws->index == -1);
os_mutexLock (&ws->mutex);
ws->ctx0 = ws->ctx;
os_mutexUnlock (&ws->mutex);
if ((idx = WSAWaitForMultipleEvents (ws->ctx0.n, ws->ctx0.events, FALSE, WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED)
{
NN_WARNING ("os_sockWaitsetWait: WSAWaitForMultipleEvents(%d,...,0,0,0) failed, error %d", ws->ctx0.n, os_getErrno ());
return NULL;
}
#ifndef WAIT_IO_COMPLETION /* curious omission in the WinCE headers */
#define TEMP_DEF_WAIT_IO_COMPLETION
#define WAIT_IO_COMPLETION 0xc0L
#endif
if (idx >= WSA_WAIT_EVENT_0 && idx < WSA_WAIT_EVENT_0 + ws->ctx0.n)
{
ws->ctx0.index = idx - WSA_WAIT_EVENT_0;
if (ws->ctx0.index == 0)
{
/* pretend a spurious wakeup */
WSAResetEvent (ws->ctx0.events[0]);
ws->ctx0.index = -1;
}
return &ws->ctx0;
}
if (idx == WAIT_IO_COMPLETION)
{
/* Presumably can't happen with alertable = FALSE */
NN_WARNING ("os_sockWaitsetWait: WSAWaitForMultipleEvents(%d,...,0,0,0) returned unexpected WAIT_IO_COMPLETION", ws->ctx0.n);
}
else
{
NN_WARNING ("os_sockWaitsetWait: WSAWaitForMultipleEvents(%d,...,0,0,0) returned unrecognised %d", ws->ctx0.n, idx);
}
#ifdef TEMP_DEF_WAIT_IO_COMPLETION
#undef WAIT_IO_COMPLETION
#undef TEMP_DEF_WAIT_IO_COMPLETION
#endif
return NULL;
}
/* This implementation follows the pattern of simply looking at the
socket that triggered the wakeup; alternatively, one could scan the
entire set as we do for select(). If the likelihood of two sockets
having an event simultaneously is small, this is better, but if it
is large, the lower indices may get a disproportionally large
amount of attention. */
int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
{
assert (-1 <= ctx->index && ctx->index < ctx->n);
assert (0 < ctx->n && ctx->n <= ctx->sz);
if (ctx->index == -1)
{
return -1;
}
else
{
WSANETWORKEVENTS nwev;
int idx = ctx->index;
os_handle handle;
ctx->index = -1;
handle = ddsi_conn_handle (ctx->conns[idx]);
if (WSAEnumNetworkEvents (handle, ctx->events[idx], &nwev) == SOCKET_ERROR)
{
int err = os_getErrno ();
if (err != WSAENOTSOCK)
{
/* May have a wakeup and a close in parallel, so the handle
need not exist anymore. */
NN_ERROR ("os_sockWaitsetNextEvent: WSAEnumNetworkEvents(%x,%x,...) failed, error %d", (os_uint32) handle, (os_uint32) ctx->events[idx], err);
}
return -1;
}
*conn = ctx->conns[idx];
return idx - 1;
}
}
#else /* WINCE */
#if defined (_WIN32)
static int pipe (os_handle fd[2])
{
struct sockaddr_in addr;
socklen_t asize = sizeof (addr);
os_socket listener = socket (AF_INET, SOCK_STREAM, 0);
os_socket s1 = socket (AF_INET, SOCK_STREAM, 0);
os_socket s2 = Q_INVALID_SOCKET;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
addr.sin_port = 0;
if (bind (listener, (struct sockaddr *) &addr, sizeof (addr)) == -1)
{
goto fail;
}
if (getsockname (listener, (struct sockaddr *) &addr, &asize) == -1)
{
goto fail;
}
if (listen (listener, 1) == -1)
{
goto fail;
}
if (connect (s1, (struct sockaddr *) &addr, sizeof (addr)) == -1)
{
goto fail;
}
if ((s2 = accept (listener, 0, 0)) == -1)
{
goto fail;
}
closesocket (listener);
/* Equivalent to FD_CLOEXEC */
SetHandleInformation ((HANDLE) s1, HANDLE_FLAG_INHERIT, 0);
SetHandleInformation ((HANDLE) s2, HANDLE_FLAG_INHERIT, 0);
fd[0] = s1;
fd[1] = s2;
return 0;
fail:
closesocket (listener);
closesocket (s1);
closesocket (s2);
return -1;
}
#else
#ifndef __VXWORKS__
#if defined (AIX) || defined (__Lynx__) || defined (__QNX__)
#include <fcntl.h>
#elif ! defined(INTEGRITY)
#include <sys/fcntl.h>
#endif
#endif /* __VXWORKS__ */
#ifndef _WRS_KERNEL
#include <sys/select.h>
#endif
#ifdef __sun
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#endif
#endif /* _WIN32 */
typedef struct os_sockWaitsetSet
{
ddsi_tran_conn_t * conns; /* connections in set */
os_handle * fds; /* file descriptors in set */
unsigned sz; /* max number of fds in context */
unsigned n; /* actual number of fds in context */
} os_sockWaitsetSet;
struct os_sockWaitsetCtx
{
os_sockWaitsetSet set; /* set of connections and descriptors */
unsigned index; /* cursor for enumerating */
fd_set rdset; /* read file descriptors */
};
struct os_sockWaitset
{
os_handle pipe[2]; /* pipe used for triggering */
os_mutex mutex; /* concurrency guard */
int fdmax_plus_1; /* value for first parameter of select() */
os_sockWaitsetSet set; /* set of descriptors handled next */
struct os_sockWaitsetCtx ctx; /* set of descriptors being handled */
};
static void os_sockWaitsetNewSet (os_sockWaitsetSet * set)
{
set->fds = os_malloc (WAITSET_DELTA * sizeof (*set->fds));
set->conns = os_malloc (WAITSET_DELTA * sizeof (*set->conns));
set->sz = WAITSET_DELTA;
set->n = 1;
}
static void os_sockWaitsetNewCtx (os_sockWaitsetCtx ctx)
{
os_sockWaitsetNewSet (&ctx->set);
FD_ZERO (&ctx->rdset);
}
os_sockWaitset os_sockWaitsetNew (void)
{
int result;
os_sockWaitset ws = os_malloc (sizeof (*ws));
os_sockWaitsetNewSet (&ws->set);
os_sockWaitsetNewCtx (&ws->ctx);
#if ! defined (_WIN32)
ws->fdmax_plus_1 = 0;
#else
ws->fdmax_plus_1 = FD_SETSIZE;
#endif
#if defined (VXWORKS_RTP) || defined (_WRS_KERNEL)
{
char pipename[OSPL_PIPENAMESIZE];
int pipecount=0;
do
{
snprintf ((char*)&pipename, sizeof(pipename), "/pipe/ospl%d", pipecount++ );
}
while ((result = pipeDevCreate ((char*) &pipename, 1, 1)) == -1 && os_getErrno() == EINVAL);
if (result != -1)
{
result = open ((char*) &pipename, O_RDWR, 0644);
if (result != -1)
{
ws->pipe[0] = result;
result =open ((char*) &pipename, O_RDWR, 0644);
if (result != -1)
{
ws->pipe[1] = result;
}
else
{
close (ws->pipe[0]);
pipeDevDelete (pipename, 0);
}
}
}
}
#else
result = pipe (ws->pipe);
#endif
assert (result != -1);
(void) result;
ws->set.fds[0] = ws->pipe[0];
ws->set.conns[0] = NULL;
#if ! defined (VXWORKS_RTP) && ! defined ( _WRS_KERNEL ) && ! defined (_WIN32)
fcntl (ws->pipe[0], F_SETFD, fcntl (ws->pipe[0], F_GETFD) | FD_CLOEXEC);
fcntl (ws->pipe[1], F_SETFD, fcntl (ws->pipe[1], F_GETFD) | FD_CLOEXEC);
#endif
FD_SET (ws->set.fds[0], &ws->ctx.rdset);
#if ! defined (_WIN32)
ws->fdmax_plus_1 = ws->set.fds[0] + 1;
#endif
os_mutexInit (&ws->mutex);
return ws;
}
static void os_sockWaitsetGrow (os_sockWaitsetSet * set)
{
set->sz += WAITSET_DELTA;
set->conns = os_realloc (set->conns, set->sz * sizeof (*set->conns));
set->fds = os_realloc (set->fds, set->sz * sizeof (*set->fds));
}
static void os_sockWaitsetFreeSet (os_sockWaitsetSet * set)
{
os_free (set->fds);
os_free (set->conns);
}
static void os_sockWaitsetFreeCtx (os_sockWaitsetCtx ctx)
{
os_sockWaitsetFreeSet (&ctx->set);
}
void os_sockWaitsetFree (os_sockWaitset ws)
{
#ifdef VXWORKS_RTP
char nameBuf[OSPL_PIPENAMESIZE];
ioctl (ws->pipe[0], FIOGETNAME, &nameBuf);
#endif
#if defined (_WIN32)
closesocket (ws->pipe[0]);
closesocket (ws->pipe[1]);
#else
close (ws->pipe[0]);
close (ws->pipe[1]);
#endif
#ifdef VXWORKS_RTP
pipeDevDelete ((char*) &nameBuf, 0);
#endif
os_sockWaitsetFreeSet (&ws->set);
os_sockWaitsetFreeCtx (&ws->ctx);
os_mutexDestroy (&ws->mutex);
os_free (ws);
}
void os_sockWaitsetTrigger (os_sockWaitset ws)
{
char buf = 0;
int n;
int err;
#if defined (_WIN32)
n = send (ws->pipe[1], &buf, 1, 0);
#else
n = (int) write (ws->pipe[1], &buf, 1);
#endif
if (n != 1)
{
err = os_getErrno ();
NN_WARNING ("os_sockWaitsetTrigger: read failed on trigger pipe, errno = %d", err);
}
}
void os_sockWaitsetAdd (os_sockWaitset ws, ddsi_tran_conn_t conn)
{
os_handle handle = ddsi_conn_handle (conn);
os_sockWaitsetSet * set = &ws->set;
unsigned idx;
assert (handle >= 0);
#if ! defined (_WIN32)
assert (handle < FD_SETSIZE);
#endif
os_mutexLock (&ws->mutex);
for (idx = 0; idx < set->n; idx++)
{
if (set->conns[idx] == conn)
break;
}
if (idx == set->n)
{
if (set->n == set->sz)
{
os_sockWaitsetGrow (set);
}
#if ! defined (_WIN32)
if ((int) handle >= ws->fdmax_plus_1)
{
ws->fdmax_plus_1 = handle + 1;
}
#endif
set->conns[set->n] = conn;
set->fds[set->n] = handle;
set->n++;
}
os_mutexUnlock (&ws->mutex);
}
void os_sockWaitsetPurge (os_sockWaitset ws, unsigned index)
{
unsigned i;
os_sockWaitsetSet * set = &ws->set;
os_mutexLock (&ws->mutex);
if (index + 1 <= set->n)
{
for (i = index + 1; i < set->n; i++)
{
set->conns[i] = NULL;
set->fds[i] = 0;
}
set->n = index + 1;
}
os_mutexUnlock (&ws->mutex);
}
void os_sockWaitsetRemove (os_sockWaitset ws, ddsi_tran_conn_t conn)
{
unsigned i;
os_sockWaitsetSet * set = &ws->set;
os_mutexLock (&ws->mutex);
for (i = 0; i < set->n; i++)
{
if (conn == set->conns[i])
{
set->n--;
if (i != set->n)
{
set->fds[i] = set->fds[set->n];
set->conns[i] = set->conns[set->n];
}
break;
}
}
os_mutexUnlock (&ws->mutex);
}
os_sockWaitsetCtx os_sockWaitsetWait (os_sockWaitset ws)
{
int n;
unsigned u;
int err;
int fdmax;
fd_set * rdset = NULL;
os_sockWaitsetCtx ctx = &ws->ctx;
os_sockWaitsetSet * dst = &ctx->set;
os_sockWaitsetSet * src = &ws->set;
os_mutexLock (&ws->mutex);
fdmax = ws->fdmax_plus_1;
/* Copy context to working context */
while (dst->sz < src->sz)
{
os_sockWaitsetGrow (dst);
}
dst->n = src->n;
for (u = 0; u < src->sz; u++)
{
dst->conns[u] = src->conns[u];
dst->fds[u] = src->fds[u];
}
os_mutexUnlock (&ws->mutex);
/* Copy file descriptors into select read set */
rdset = &ctx->rdset;
FD_ZERO (rdset);
for (u = 0; u < dst->n; u++)
{
FD_SET (dst->fds[u], rdset);
}
do
{
n = select (fdmax, rdset, NULL, NULL, NULL);
if (n < 0)
{
err = os_getErrno ();
if ((err != os_sockEINTR) && (err != os_sockEAGAIN))
{
NN_WARNING ("os_sockWaitsetWait: select failed, errno = %d", err);
break;
}
}
}
while (n == -1);
if (n > 0)
{
/* this simply skips the trigger fd */
ctx->index = 1;
if (FD_ISSET (dst->fds[0], rdset))
{
char buf;
int n1;
#if defined (_WIN32)
n1 = recv (dst->fds[0], &buf, 1, 0);
#else
n1 = (int) read (dst->fds[0], &buf, 1);
#endif
if (n1 != 1)
{
err = os_getErrno ();
NN_WARNING ("os_sockWaitsetWait: read failed on trigger pipe, errno = %d", err);
assert (0);
}
}
return ctx;
}
return NULL;
}
int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn)
{
while (ctx->index < ctx->set.n)
{
unsigned idx = ctx->index++;
os_handle fd = ctx->set.fds[idx];
assert(idx > 0);
if (FD_ISSET (fd, &ctx->rdset))
{
*conn = ctx->set.conns[idx];
return (int) (idx - 1);
}
}
return -1;
}
#endif /* WINCE */

View file

@ -0,0 +1,357 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "os/os.h"
#include "ddsi/q_thread.h"
#include "ddsi/q_servicelease.h"
#include "ddsi/q_error.h"
#include "ddsi/q_log.h"
#include "ddsi/q_config.h"
#include "ddsi/q_globals.h"
#include "ddsi/sysdeps.h"
static char main_thread_name[] = "main";
struct thread_states thread_states;
os_threadLocal struct thread_state1 *tsd_thread_state;
_Ret_bytecap_(size)
void * os_malloc_aligned_cacheline (_In_ size_t size)
{
/* This wastes some space, but we use it only once and it isn't a
huge amount of memory, just a little over a cache line.
Alternatively, we good use valloc() and have it aligned to a page
boundary, but that one isn't part of the O/S abstraction layer
... */
const uintptr_t clm1 = CACHE_LINE_SIZE - 1;
uintptr_t ptrA;
void **pptr;
void *ptr;
ptr = os_malloc (size + CACHE_LINE_SIZE + sizeof (void *));
ptrA = ((uintptr_t) ptr + sizeof (void *) + clm1) & ~clm1;
pptr = (void **) ptrA;
pptr[-1] = ptr;
return (void *) ptrA;
}
static void os_free_aligned ( _Pre_maybenull_ _Post_invalid_ void *ptr)
{
if (ptr) {
void **pptr = ptr;
os_free (pptr[-1]);
}
}
void thread_states_init (_In_ unsigned maxthreads)
{
unsigned i;
os_mutexInit (&thread_states.lock);
thread_states.nthreads = maxthreads;
thread_states.ts =
os_malloc_aligned_cacheline (maxthreads * sizeof (*thread_states.ts));
memset (thread_states.ts, 0, maxthreads * sizeof (*thread_states.ts));
/* The compiler doesn't realize that ts is large enough. */
OS_WARNING_MSVC_OFF(6386);
for (i = 0; i < thread_states.nthreads; i++)
{
thread_states.ts[i].state = THREAD_STATE_ZERO;
thread_states.ts[i].vtime = 1;
thread_states.ts[i].watchdog = 1;
thread_states.ts[i].lb = NULL;
thread_states.ts[i].name = NULL;
}
OS_WARNING_MSVC_ON(6386);
}
void thread_states_fini (void)
{
unsigned i;
for (i = 0; i < thread_states.nthreads; i++)
assert (thread_states.ts[i].state != THREAD_STATE_ALIVE);
os_mutexDestroy (&thread_states.lock);
os_free_aligned (thread_states.ts);
/* All spawned threads are gone, but the main thread is still alive,
downgraded to an ordinary thread (we're on it right now). We
don't want to lose the ability to log messages, so set ts to a
NULL pointer and rely on lookup_thread_state()'s checks
thread_states.ts. */
thread_states.ts = NULL;
}
static void
cleanup_thread_state(
_In_opt_ void *data)
{
struct thread_state1 *ts = get_thread_state(os_threadIdSelf());
assert(ts->state == THREAD_STATE_ALIVE);
assert(vtime_asleep_p(ts->vtime));
reset_thread_state(ts);
os_reportExit(); /* FIXME: Should not be here! */
}
_Ret_valid_ struct thread_state1 *
lookup_thread_state(
void)
{
struct thread_state1 *ts1 = NULL;
char tname[128];
os_threadId tid;
if ((ts1 = tsd_thread_state) == NULL) {
if ((ts1 = lookup_thread_state_real()) == NULL) {
/* this situation only arises for threads that were not created
using create_thread, aka application threads. since registering
thread state should be fully automatic the name will simply be
the identifier */
tid = os_threadIdSelf();
(void)snprintf(
tname, sizeof(tname), "0x%"PRIxMAX, os_threadIdToInteger(tid));
os_mutexLock(&thread_states.lock);
ts1 = init_thread_state(tname);
if (ts1 != NULL) {
ts1->lb = 0;
ts1->extTid = tid;
ts1->tid = tid;
nn_log (LC_INFO, "started application thread %s\n", tname);
os_threadCleanupPush(&cleanup_thread_state, NULL);
}
os_mutexUnlock(&thread_states.lock);
}
tsd_thread_state = ts1;
}
assert(ts1 != NULL);
return ts1;
}
_Success_(return != NULL) _Ret_maybenull_
struct thread_state1 *lookup_thread_state_real (void)
{
if (thread_states.ts) {
os_threadId tid = os_threadIdSelf ();
unsigned i;
for (i = 0; i < thread_states.nthreads; i++) {
if (os_threadEqual (thread_states.ts[i].tid, tid)) {
return &thread_states.ts[i];
}
}
}
return NULL;
}
struct thread_context {
struct thread_state1 *self;
uint32_t (*f) (_In_opt_ void *arg);
void *arg;
};
static uint32_t create_thread_wrapper (_In_ _Post_invalid_ struct thread_context *ctxt)
{
uint32_t ret;
ctxt->self->tid = os_threadIdSelf ();
ret = ctxt->f (ctxt->arg);
logbuf_free (ctxt->self->lb);
os_free (ctxt);
return ret;
}
static int find_free_slot (_In_z_ const char *name)
{
unsigned i;
int cand;
for (i = 0, cand = -1; i < thread_states.nthreads; i++)
{
if (thread_states.ts[i].state != THREAD_STATE_ALIVE)
cand = (int) i;
if (thread_states.ts[i].state == THREAD_STATE_ZERO)
break;
}
if (cand == -1)
NN_FATAL ("create_thread: %s: no free slot\n", name ? name : "(anon)");
return cand;
}
void upgrade_main_thread (void)
{
int cand;
struct thread_state1 *ts1;
os_mutexLock (&thread_states.lock);
if ((cand = find_free_slot ("name")) < 0)
abort ();
ts1 = &thread_states.ts[cand];
if (ts1->state == THREAD_STATE_ZERO)
assert (vtime_asleep_p (ts1->vtime));
ts1->state = THREAD_STATE_ALIVE;
ts1->tid = os_threadIdSelf ();
ts1->lb = logbuf_new ();
ts1->name = main_thread_name;
os_mutexUnlock (&thread_states.lock);
tsd_thread_state = ts1;
}
const struct config_thread_properties_listelem *lookup_thread_properties (_In_z_ const char *name)
{
const struct config_thread_properties_listelem *e;
for (e = config.thread_properties; e != NULL; e = e->next)
if (strcmp (e->name, name) == 0)
break;
return e;
}
struct thread_state1 * init_thread_state (_In_z_ const char *tname)
{
int cand;
struct thread_state1 *ts;
if ((cand = find_free_slot (tname)) < 0)
return NULL;
ts = &thread_states.ts[cand];
if (ts->state == THREAD_STATE_ZERO)
assert (vtime_asleep_p (ts->vtime));
ts->name = os_strdup (tname);
ts->state = THREAD_STATE_ALIVE;
return ts;
}
_Success_(return != NULL)
_Ret_maybenull_
struct thread_state1 *create_thread (_In_z_ const char *name, _In_ uint32_t (*f) (void *arg), _In_opt_ void *arg)
{
struct config_thread_properties_listelem const * const tprops = lookup_thread_properties (name);
os_threadAttr tattr;
struct thread_state1 *ts1;
os_threadId tid;
struct thread_context *ctxt;
ctxt = os_malloc (sizeof (*ctxt));
os_mutexLock (&thread_states.lock);
ts1 = init_thread_state (name);
if (ts1 == NULL)
goto fatal;
ts1->lb = logbuf_new ();
ctxt->self = ts1;
ctxt->f = f;
ctxt->arg = arg;
os_threadAttrInit (&tattr);
if (tprops != NULL)
{
if (!tprops->sched_priority.isdefault)
tattr.schedPriority = tprops->sched_priority.value;
tattr.schedClass = tprops->sched_class; /* explicit default value in the enum */
if (!tprops->stack_size.isdefault)
tattr.stackSize = tprops->stack_size.value;
}
TRACE (("create_thread: %s: class %d priority %d stack %u\n", name, (int) tattr.schedClass, tattr.schedPriority, tattr.stackSize));
if (os_threadCreate (&tid, name, &tattr, (os_threadRoutine)&create_thread_wrapper, ctxt) != os_resultSuccess)
{
ts1->state = THREAD_STATE_ZERO;
NN_FATAL ("create_thread: %s: os_threadCreate failed\n", name);
goto fatal;
}
nn_log (LC_INFO, "started new thread 0x%"PRIxMAX" : %s\n", os_threadIdToInteger (tid), name);
ts1->extTid = tid; /* overwrite the temporary value with the correct external one */
os_mutexUnlock (&thread_states.lock);
return ts1;
fatal:
os_mutexUnlock (&thread_states.lock);
os_free (ctxt);
abort ();
return NULL;
}
static void reap_thread_state (_Inout_ struct thread_state1 *ts1, _In_ int sync_with_servicelease)
{
os_mutexLock (&thread_states.lock);
ts1->state = THREAD_STATE_ZERO;
if (sync_with_servicelease)
nn_servicelease_statechange_barrier (gv.servicelease);
if (ts1->name != main_thread_name)
os_free (ts1->name);
os_mutexUnlock (&thread_states.lock);
}
_Success_(return == 0)
int join_thread (_Inout_ struct thread_state1 *ts1)
{
int ret;
assert (ts1->state == THREAD_STATE_ALIVE);
if (os_threadWaitExit (ts1->extTid, NULL) == os_resultSuccess)
ret = 0;
else
ret = ERR_UNSPECIFIED;
assert (vtime_asleep_p (ts1->vtime));
reap_thread_state (ts1, 1);
return ret;
}
void reset_thread_state (_Inout_opt_ struct thread_state1 *ts1)
{
if (ts1)
{
reap_thread_state (ts1, 1);
ts1->name = NULL;
}
}
void downgrade_main_thread (void)
{
struct thread_state1 *ts1 = lookup_thread_state ();
thread_state_asleep (ts1);
logbuf_free (ts1->lb);
/* no need to sync with service lease: already stopped */
reap_thread_state (ts1, 0);
tsd_thread_state = NULL;
}
struct thread_state1 *get_thread_state (_In_ os_threadId id)
{
unsigned i;
struct thread_state1 *ts = NULL;
for (i = 0; i < thread_states.nthreads; i++)
{
if (os_threadEqual (thread_states.ts[i].extTid, id))
{
ts = &thread_states.ts[i];
break;
}
}
return ts;
}
void log_stack_traces (void)
{
unsigned i;
for (i = 0; i < thread_states.nthreads; i++)
{
if (thread_states.ts[i].state == THREAD_STATE_ALIVE)
{
log_stacktrace (thread_states.ts[i].name, thread_states.ts[i].tid);
}
}
}

View file

@ -0,0 +1,15 @@
/*
* 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
*/
#define SUPPRESS_THREAD_INLINES
#include "ddsi/q_thread.h"
#include "ddsi/q_thread_template.h"

224
src/core/ddsi/src/q_time.c Normal file
View file

@ -0,0 +1,224 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include "os/os.h"
#include "ddsi/q_time.h"
const nn_ddsi_time_t invalid_ddsi_timestamp = { -1, UINT32_MAX };
const nn_ddsi_time_t ddsi_time_infinite = { INT32_MAX, UINT32_MAX };
#if DDSI_DURATION_ACCORDING_TO_SPEC
const nn_duration_t duration_infinite = { INT32_MAX, INT32_MAX };
#else
const nn_duration_t duration_infinite = { INT32_MAX, UINT32_MAX };
#endif
nn_wctime_t now (void)
{
/* This function uses the wall clock.
* This clock is not affected by time spent in suspend mode.
* This clock is affected when the real time system clock jumps
* forwards/backwards */
os_time tv;
nn_wctime_t t;
tv = os_timeGet ();
t.v = ((int64_t) tv.tv_sec * T_SECOND + tv.tv_nsec);
return t;
}
nn_mtime_t now_mt (void)
{
/* This function uses the monotonic clock.
* This clock stops while the system is in suspend mode.
* This clock is not affected by any jumps of the realtime clock. */
os_time tv;
nn_mtime_t t;
tv = os_timeGetMonotonic ();
t.v = ((int64_t) tv.tv_sec * T_SECOND + tv.tv_nsec);
return t;
}
nn_etime_t now_et (void)
{
/* This function uses the elapsed clock.
* This clock is not affected by any jumps of the realtime clock.
* This clock does NOT stop when the system is in suspend mode.
* This clock stops when the system is shut down, and starts when the system is restarted.
* When restarted, there are no assumptions about the initial value of clock. */
os_time tv;
nn_etime_t t;
tv = os_timeGetElapsed ();
t.v = ((int64_t) tv.tv_sec * T_SECOND + tv.tv_nsec);
return t;
}
static void time_to_sec_usec (_Out_ int * __restrict sec, _Out_ int * __restrict usec, _In_ int64_t t)
{
*sec = (int) (t / T_SECOND);
*usec = (int) (t % T_SECOND) / 1000;
}
void mtime_to_sec_usec (_Out_ int * __restrict sec, _Out_ int * __restrict usec, _In_ nn_mtime_t t)
{
time_to_sec_usec (sec, usec, t.v);
}
void wctime_to_sec_usec (_Out_ int * __restrict sec, _Out_ int * __restrict usec, _In_ nn_wctime_t t)
{
time_to_sec_usec (sec, usec, t.v);
}
void etime_to_sec_usec (_Out_ int * __restrict sec, _Out_ int * __restrict usec, _In_ nn_etime_t t)
{
time_to_sec_usec (sec, usec, t.v);
}
nn_mtime_t mtime_round_up (nn_mtime_t t, int64_t round)
{
/* This function rounds up t to the nearest next multiple of round.
t is nanoseconds, round is milliseconds. Avoid functions from
maths libraries to keep code portable */
assert (t.v >= 0 && round >= 0);
if (round == 0 || t.v == T_NEVER)
{
return t;
}
else
{
int64_t remainder = t.v % round;
if (remainder == 0)
{
return t;
}
else
{
nn_mtime_t u;
u.v = t.v + round - remainder;
return u;
}
}
}
static int64_t add_duration_to_time (int64_t t, int64_t d)
{
uint64_t sum;
assert (t >= 0 && d >= 0);
sum = (uint64_t)t + (uint64_t)d;
return sum >= T_NEVER ? T_NEVER : (int64_t)sum;
}
nn_mtime_t add_duration_to_mtime (nn_mtime_t t, int64_t d)
{
/* assumed T_NEVER <=> MAX_INT64 */
nn_mtime_t u;
u.v = add_duration_to_time (t.v, d);
return u;
}
nn_wctime_t add_duration_to_wctime (nn_wctime_t t, int64_t d)
{
/* assumed T_NEVER <=> MAX_INT64 */
nn_wctime_t u;
u.v = add_duration_to_time (t.v, d);
return u;
}
nn_etime_t add_duration_to_etime (nn_etime_t t, int64_t d)
{
/* assumed T_NEVER <=> MAX_INT64 */
nn_etime_t u;
u.v = add_duration_to_time (t.v, d);
return u;
}
int valid_ddsi_timestamp (nn_ddsi_time_t t)
{
return t.seconds != invalid_ddsi_timestamp.seconds && t.fraction != invalid_ddsi_timestamp.fraction;
}
static nn_ddsi_time_t nn_to_ddsi_time (int64_t t)
{
if (t == T_NEVER)
return ddsi_time_infinite;
else
{
/* ceiling(ns * 2^32/10^9) -- can't change the ceiling to round-to-nearest
because that would break backwards compatibility, but round-to-nearest
of the inverse is correctly rounded anyway, so it shouldn't ever matter. */
nn_ddsi_time_t x;
int ns = (int) (t % T_SECOND);
x.seconds = (int) (t / T_SECOND);
x.fraction = (unsigned) (((T_SECOND-1) + ((int64_t) ns << 32)) / T_SECOND);
return x;
}
}
nn_ddsi_time_t nn_wctime_to_ddsi_time (nn_wctime_t t)
{
return nn_to_ddsi_time (t.v);
}
static int64_t nn_from_ddsi_time (nn_ddsi_time_t x)
{
if (x.seconds == ddsi_time_infinite.seconds && x.fraction == ddsi_time_infinite.fraction)
return T_NEVER;
else
{
/* Round-to-nearest conversion of DDSI time fraction to nanoseconds */
int ns = (int) (((int64_t) 2147483648u + (int64_t) x.fraction * T_SECOND) >> 32);
return x.seconds * (int64_t) T_SECOND + ns;
}
}
nn_wctime_t nn_wctime_from_ddsi_time (nn_ddsi_time_t x)
{
nn_wctime_t t;
t.v = nn_from_ddsi_time (x);
return t;
}
#if DDSI_DURATION_ACCORDING_TO_SPEC
nn_duration_t nn_to_ddsi_duration (int64_t t)
{
if (t == T_NEVER)
return duration_infinite;
else
{
nn_duration_t x;
x.sec = (int) (t / T_SECOND);
x.nanosec = (int) (t % T_SECOND);
return x;
}
}
int64_t nn_from_ddsi_duration (nn_duration_t x)
{
int64_t t;
if (x.sec == duration_infinite.sec && x.nanosec == duration_infinite.nanosec)
t = T_NEVER;
else
t = x.sec * T_SECOND + x.nanosec;
return t;
}
#else
nn_duration_t nn_to_ddsi_duration (int64_t x)
{
return nn_to_ddsi_time (x);
}
int64_t nn_from_ddsi_duration (nn_duration_t x)
{
return nn_from_ddsi_time (x);
}
#endif

File diff suppressed because it is too large Load diff

1085
src/core/ddsi/src/q_whc.c Normal file

File diff suppressed because it is too large Load diff

1594
src/core/ddsi/src/q_xevent.c Normal file

File diff suppressed because it is too large Load diff

1882
src/core/ddsi/src/q_xmsg.c Normal file

File diff suppressed because it is too large Load diff

355
src/core/ddsi/src/sysdeps.c Normal file
View file

@ -0,0 +1,355 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <stdlib.h>
#include "os/os.h"
#include "ddsi/q_error.h"
#include "ddsi/q_log.h"
#include "ddsi/q_config.h"
#include "ddsi/sysdeps.h"
#ifdef NEED_ARM_MEMBAR_SUPPORT
static void q_membar_autodecide (void);
void (*q_maybe_membar) (void) = q_membar_autodecide;
static void q_membar_nop (void) { }
static void q_membar_dmb (void) { MemoryBarrierARM; }
static void q_membar_autodecide (void)
{
SYSTEM_INFO sysinfo;
GetSystemInfo (&sysinfo);
assert (sysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM);
if (sysinfo.wProcessorLevel >= 7)
{
q_maybe_membar = q_membar_dmb;
}
else
{
q_maybe_membar = q_membar_nop;
}
q_maybe_membar ();
}
#endif
/* MISSING IN OS ABSTRACTION LAYER ------------------------------------- */
#if ! SYSDEPS_HAVE_RECVMSG
ssize_t recvmsg (os_handle fd, struct msghdr *message, int flags)
{
ssize_t ret;
assert (message->msg_iovlen == 1);
#if SYSDEPS_MSGHDR_ACCRIGHTS
assert (message->msg_accrightslen == 0);
#else
assert (message->msg_controllen == 0);
#endif
#if SYSDEPS_MSGHDR_FLAGS
message->msg_flags = 0;
#endif
ret = recvfrom (fd, message->msg_iov[0].iov_base, (int)message->msg_iov[0].iov_len, flags,
message->msg_name, &message->msg_namelen); /* To fix the warning of conversion from 'size_t' to 'int', which may cause possible loss of data, type casting is done*/
#if defined (_WIN32)
/* Windows returns an error for too-large messages, Unix expects
original size and the MSG_TRUNC flag. MSDN says it is truncated,
which presumably means it returned as much of the message as it
could - so we return that the message was 1 byte larger than the
available space, and set MSG_TRUNC if we can. */
if (ret == -1 && os_getErrno () == WSAEMSGSIZE) {
ret = message->msg_iov[0].iov_len + 1;
#if SYSDEPS_MSGHDR_FLAGS
message->msg_flags |= MSG_TRUNC;
#endif
}
#endif
return ret;
}
#endif
#if ! SYSDEPS_HAVE_SENDMSG
#if !(defined _WIN32 && !defined WINCE)
ssize_t sendmsg (os_handle fd, const struct msghdr *message, int flags)
{
char stbuf[3072], *buf;
ssize_t sz, ret;
size_t sent = 0;
unsigned i;
#if SYSDEPS_MSGHDR_ACCRIGHTS
assert (message->msg_accrightslen == 0);
#else
assert (message->msg_controllen == 0);
#endif
if (message->msg_iovlen == 1)
{
/* if only one fragment, skip all copying */
buf = message->msg_iov[0].iov_base;
sz = message->msg_iov[0].iov_len;
}
else
{
/* first determine the size of the message, then select the
on-stack buffer or allocate one on the heap ... */
sz = 0;
for (i = 0; i < message->msg_iovlen; i++)
{
sz += message->msg_iov[i].iov_len;
}
if (sz <= sizeof (stbuf))
{
buf = stbuf;
}
else
{
buf = os_malloc (sz);
}
/* ... then copy data into buffer */
sz = 0;
for (i = 0; i < message->msg_iovlen; i++)
{
memcpy (buf + sz, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len);
sz += message->msg_iov[i].iov_len;
}
}
while (TRUE)
{
ret = sendto (fd, buf + sent, sz - sent, flags, message->msg_name, message->msg_namelen);
if (ret < 0)
{
break;
}
sent += (size_t) ret;
if (sent == sz)
{
ret = sent;
break;
}
}
if (buf != stbuf)
{
os_free (buf);
}
return ret;
}
#else /* _WIN32 && !WINCE */
ssize_t sendmsg (os_handle fd, const struct msghdr *message, int flags)
{
WSABUF stbufs[128], *bufs;
DWORD sent;
unsigned i;
ssize_t ret;
#if SYSDEPS_MSGHDR_ACCRIGHTS
assert (message->msg_accrightslen == 0);
#else
assert (message->msg_controllen == 0);
#endif
if (message->msg_iovlen <= (int)(sizeof(stbufs) / sizeof(*stbufs)))
bufs = stbufs;
else
bufs = os_malloc (message->msg_iovlen * sizeof (*bufs));
for (i = 0; i < message->msg_iovlen; i++)
{
bufs[i].buf = (void *) message->msg_iov[i].iov_base;
bufs[i].len = (unsigned) message->msg_iov[i].iov_len;
}
if (WSASendTo (fd, bufs, (DWORD)message->msg_iovlen, &sent, (DWORD)flags, (SOCKADDR *) message->msg_name, message->msg_namelen, NULL, NULL) == 0) /* Type casting to silence the warning of conversion from 'size_t' to 'DWORD', which may cause possible loss of data */
ret = (ssize_t) sent;
else
ret = -1;
if (bufs != stbufs)
os_free (bufs);
return ret;
}
#endif
#endif
#ifndef SYSDEPS_HAVE_RANDOM
long random (void)
{
/* rand() is a really terribly bad PRNG */
union { long x; unsigned char c[4]; } t;
int i;
for (i = 0; i < 4; i++)
t.c[i] = (unsigned char) ((rand () >> 4) & 0xff);
#if RAND_MAX == INT32_MAX || RAND_MAX == 0x7fff
t.x &= RAND_MAX;
#elif RAND_MAX <= 0x7ffffffe
t.x %= (RAND_MAX+1);
#else
#error "RAND_MAX out of range"
#endif
return t.x;
}
#endif
#if SYSDEPS_HAVE_CLOCK_THREAD_CPUTIME
int64_t get_thread_cputime (void)
{
struct timespec ts;
clock_gettime (CLOCK_THREAD_CPUTIME_ID, &ts);
return ts.tv_sec * (int64_t) 1000000000 + ts.tv_nsec;
}
#else
int64_t get_thread_cputime (void)
{
return 0;
}
#endif
#if ! OS_HAVE_THREADEQUAL
int os_threadEqual (os_threadId a, os_threadId b)
{
/* on pthreads boxes, pthread_equal (a, b); as a workaround: */
return os_threadIdToInteger (a) == os_threadIdToInteger (b);
}
#endif
#if defined __sun && __GNUC__ && defined __sparc__
int __S_exchange_and_add (volatile int *mem, int val)
{
/* Hopefully cache lines are <= 64 bytes, we then use 8 bytes, 64
bytes. Should be a lot better than just one lock byte if it gets
used often, but the overhead is a bit larger, so who knows what's
best without trying it out?. We want 3 bits + 6 lsbs zero, so
need to shift addr_hash by 23 bits. */
static unsigned char locks[8 * 64];
unsigned addr_hash = 0xe2c7 * (unsigned short) ((os_address) mem >> 2);
unsigned lock_idx = (addr_hash >> 23) & ~0x1c0;
unsigned char * const lock = &locks[lock_idx];
int result, tmp;
__asm__ __volatile__("1: ldstub [%1], %0\n\t"
" cmp %0, 0\n\t"
" bne 1b\n\t"
" nop"
: "=&r" (tmp)
: "r" (lock)
: "memory");
result = *mem;
*mem += val;
__asm__ __volatile__("stb %%g0, [%0]"
: /* no outputs */
: "r" (lock)
: "memory");
return result;
}
#endif
#if !(defined __APPLE__ || defined __linux) || (__GNUC__ > 0 && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40100)
void log_stacktrace (const char *name, os_threadId tid)
{
OS_UNUSED_ARG (name);
OS_UNUSED_ARG (tid);
}
#else
#include <execinfo.h>
#include <signal.h>
static os_atomic_uint32_t log_stacktrace_flag = OS_ATOMIC_UINT32_INIT(0);
static struct {
int depth;
void *stk[64];
} log_stacktrace_stk;
static void log_stacktrace_sigh (int sig __attribute__ ((unused)))
{
int e = os_getErrno();
log_stacktrace_stk.depth = backtrace (log_stacktrace_stk.stk, (int) (sizeof (log_stacktrace_stk.stk) / sizeof (*log_stacktrace_stk.stk)));
os_atomic_inc32 (&log_stacktrace_flag);
os_setErrno(e);
}
void log_stacktrace (const char *name, os_threadId tid)
{
if (config.enabled_logcats == 0)
; /* no op if nothing logged */
else if (!config.noprogress_log_stacktraces)
nn_log (~0u, "-- stack trace of %s requested, but traces disabled --\n", name);
else
{
const os_time d = { 0, 1000000 };
struct sigaction act, oact;
char **strs;
int i;
nn_log (~0u, "-- stack trace of %s requested --\n", name);
act.sa_handler = log_stacktrace_sigh;
act.sa_flags = 0;
sigfillset (&act.sa_mask);
while (!os_atomic_cas32 (&log_stacktrace_flag, 0, 1))
os_nanoSleep (d);
sigaction (SIGXCPU, &act, &oact);
pthread_kill (tid.v, SIGXCPU);
while (!os_atomic_cas32 (&log_stacktrace_flag, 2, 3))
os_nanoSleep (d);
sigaction (SIGXCPU, &oact, NULL);
nn_log (~0u, "-- stack trace follows --\n");
strs = backtrace_symbols (log_stacktrace_stk.stk, log_stacktrace_stk.depth);
for (i = 0; i < log_stacktrace_stk.depth; i++)
nn_log (~0u, "%s\n", strs[i]);
free (strs);
nn_log (~0u, "-- end of stack trace --\n");
os_atomic_st32 (&log_stacktrace_flag, 0);
}
}
#endif
#if HAVE_ATOMIC_LIFO
static int os_atomic_casvoidp2 (volatile os_atomic_uintptr2_t *x, uintptr_t a0, uintptr_t b0, uintptr_t a1, uintptr_t b1)
{
os_atomic_uintptr2_t o, n;
o.s.a = a0; o.s.b = b0;
n.s.a = a1; n.s.b = b1;
return __sync_bool_compare_and_swap(&x->x, o.x, n.x);
}
void os_atomic_lifo_init (os_atomic_lifo_t *head)
{
head->aba_head.s.a = head->aba_head.s.b = 0;
}
void os_atomic_lifo_push (os_atomic_lifo_t *head, void *elem, size_t linkoff)
{
uintptr_t a0, b0;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
*((volatile uintptr_t *) ((char *) elem + linkoff)) = b0;
} while (!os_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, (uintptr_t)elem));
}
void *os_atomic_lifo_pop (os_atomic_lifo_t *head, size_t linkoff) {
uintptr_t a0, b0, b1;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
if (b0 == 0) {
return NULL;
}
b1 = (*((volatile uintptr_t *) ((char *) b0 + linkoff)));
} while (!os_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, b1));
return (void *) b0;
}
void os_atomic_lifo_pushmany (os_atomic_lifo_t *head, void *first, void *last, size_t linkoff)
{
uintptr_t a0, b0;
do {
a0 = *((volatile uintptr_t *) &head->aba_head.s.a);
b0 = *((volatile uintptr_t *) &head->aba_head.s.b);
*((volatile uintptr_t *) ((char *) last + linkoff)) = b0;
} while (!os_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, (uintptr_t)first));
}
#endif