Initial contribution
This commit is contained in:
parent
7b5cc4fa59
commit
11d9ce37aa
580 changed files with 155133 additions and 162 deletions
42
src/core/ddsi/.fileids
Normal file
42
src/core/ddsi/.fileids
Normal 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
|
||||
|
||||
120
src/core/ddsi/CMakeLists.txt
Normal file
120
src/core/ddsi/CMakeLists.txt
Normal 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")
|
||||
192
src/core/ddsi/include/ddsi/ddsi_ser.h
Normal file
192
src/core/ddsi/include/ddsi/ddsi_ser.h
Normal 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
|
||||
28
src/core/ddsi/include/ddsi/ddsi_ssl.h
Normal file
28
src/core/ddsi/include/ddsi/ddsi_ssl.h
Normal 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
|
||||
41
src/core/ddsi/include/ddsi/ddsi_tcp.h
Normal file
41
src/core/ddsi/include/ddsi/ddsi_tcp.h
Normal 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
|
||||
191
src/core/ddsi/include/ddsi/ddsi_tran.h
Normal file
191
src/core/ddsi/include/ddsi/ddsi_tran.h
Normal 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
|
||||
17
src/core/ddsi/include/ddsi/ddsi_udp.h
Normal file
17
src/core/ddsi/include/ddsi/ddsi_udp.h
Normal 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
|
||||
18
src/core/ddsi/include/ddsi/probes-constants.h
Normal file
18
src/core/ddsi/include/ddsi/probes-constants.h
Normal 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
|
||||
92
src/core/ddsi/include/ddsi/q_addrset.h
Normal file
92
src/core/ddsi/include/ddsi/q_addrset.h
Normal 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 */
|
||||
18
src/core/ddsi/include/ddsi/q_align.h
Normal file
18
src/core/ddsi/include/ddsi/q_align.h
Normal 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 */
|
||||
36
src/core/ddsi/include/ddsi/q_bitset.h
Normal file
36
src/core/ddsi/include/ddsi/q_bitset.h
Normal 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 */
|
||||
53
src/core/ddsi/include/ddsi/q_bitset_template.h
Normal file
53
src/core/ddsi/include/ddsi/q_bitset_template.h
Normal 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);
|
||||
}
|
||||
}
|
||||
87
src/core/ddsi/include/ddsi/q_bswap.h
Normal file
87
src/core/ddsi/include/ddsi/q_bswap.h
Normal 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 */
|
||||
41
src/core/ddsi/include/ddsi/q_bswap_template.h
Normal file
41
src/core/ddsi/include/ddsi/q_bswap_template.h
Normal 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);
|
||||
}
|
||||
|
||||
75
src/core/ddsi/include/ddsi/q_builtin_topic.h
Normal file
75
src/core/ddsi/include/ddsi/q_builtin_topic.h
Normal 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
|
||||
446
src/core/ddsi/include/ddsi/q_config.h
Normal file
446
src/core/ddsi/include/ddsi/q_config.h
Normal 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 */
|
||||
47
src/core/ddsi/include/ddsi/q_ddsi_discovery.h
Normal file
47
src/core/ddsi/include/ddsi/q_ddsi_discovery.h
Normal 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 */
|
||||
23
src/core/ddsi/include/ddsi/q_debmon.h
Normal file
23
src/core/ddsi/include/ddsi/q_debmon.h
Normal 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__) */
|
||||
579
src/core/ddsi/include/ddsi/q_entity.h
Normal file
579
src/core/ddsi/include/ddsi/q_entity.h
Normal 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 */
|
||||
142
src/core/ddsi/include/ddsi/q_ephash.h
Normal file
142
src/core/ddsi/include/ddsi/q_ephash.h
Normal 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 */
|
||||
26
src/core/ddsi/include/ddsi/q_error.h
Normal file
26
src/core/ddsi/include/ddsi/q_error.h
Normal 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 */
|
||||
57
src/core/ddsi/include/ddsi/q_feature_check.h
Normal file
57
src/core/ddsi/include/ddsi/q_feature_check.h
Normal 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
|
||||
77
src/core/ddsi/include/ddsi/q_freelist.h
Normal file
77
src/core/ddsi/include/ddsi/q_freelist.h
Normal 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 */
|
||||
57
src/core/ddsi/include/ddsi/q_gc.h
Normal file
57
src/core/ddsi/include/ddsi/q_gc.h
Normal 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 */
|
||||
310
src/core/ddsi/include/ddsi/q_globals.h
Normal file
310
src/core/ddsi/include/ddsi/q_globals.h
Normal 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 */
|
||||
42
src/core/ddsi/include/ddsi/q_hbcontrol.h
Normal file
42
src/core/ddsi/include/ddsi/q_hbcontrol.h
Normal 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 */
|
||||
70
src/core/ddsi/include/ddsi/q_inline.h
Normal file
70
src/core/ddsi/include/ddsi/q_inline.h
Normal 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 */
|
||||
44
src/core/ddsi/include/ddsi/q_lat_estim.h
Normal file
44
src/core/ddsi/include/ddsi/q_lat_estim.h
Normal 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 */
|
||||
42
src/core/ddsi/include/ddsi/q_lease.h
Normal file
42
src/core/ddsi/include/ddsi/q_lease.h
Normal 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 */
|
||||
85
src/core/ddsi/include/ddsi/q_log.h
Normal file
85
src/core/ddsi/include/ddsi/q_log.h
Normal 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 */
|
||||
48
src/core/ddsi/include/ddsi/q_misc.h
Normal file
48
src/core/ddsi/include/ddsi/q_misc.h
Normal 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 */
|
||||
62
src/core/ddsi/include/ddsi/q_nwif.h
Normal file
62
src/core/ddsi/include/ddsi/q_nwif.h
Normal 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 */
|
||||
49
src/core/ddsi/include/ddsi/q_pcap.h
Normal file
49
src/core/ddsi/include/ddsi/q_pcap.h
Normal 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 */
|
||||
241
src/core/ddsi/include/ddsi/q_plist.h
Normal file
241
src/core/ddsi/include/ddsi/q_plist.h
Normal 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 */
|
||||
484
src/core/ddsi/include/ddsi/q_protocol.h
Normal file
484
src/core/ddsi/include/ddsi/q_protocol.h
Normal 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 */
|
||||
33
src/core/ddsi/include/ddsi/q_qosmatch.h
Normal file
33
src/core/ddsi/include/ddsi/q_qosmatch.h
Normal 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 */
|
||||
250
src/core/ddsi/include/ddsi/q_radmin.h
Normal file
250
src/core/ddsi/include/ddsi/q_radmin.h
Normal 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 */
|
||||
32
src/core/ddsi/include/ddsi/q_receive.h
Normal file
32
src/core/ddsi/include/ddsi/q_receive.h
Normal 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 */
|
||||
90
src/core/ddsi/include/ddsi/q_rtps.h
Normal file
90
src/core/ddsi/include/ddsi/q_rtps.h
Normal 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 */
|
||||
46
src/core/ddsi/include/ddsi/q_security.h
Normal file
46
src/core/ddsi/include/ddsi/q_security.h
Normal 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
|
||||
30
src/core/ddsi/include/ddsi/q_servicelease.h
Normal file
30
src/core/ddsi/include/ddsi/q_servicelease.h
Normal 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 */
|
||||
111
src/core/ddsi/include/ddsi/q_sockwaitset.h
Normal file
111
src/core/ddsi/include/ddsi/q_sockwaitset.h
Normal 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 */
|
||||
37
src/core/ddsi/include/ddsi/q_static_assert.h
Normal file
37
src/core/ddsi/include/ddsi/q_static_assert.h
Normal 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 */
|
||||
128
src/core/ddsi/include/ddsi/q_thread.h
Normal file
128
src/core/ddsi/include/ddsi/q_thread.h
Normal 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 */
|
||||
101
src/core/ddsi/include/ddsi/q_thread_template.h
Normal file
101
src/core/ddsi/include/ddsi/q_thread_template.h
Normal 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;
|
||||
}
|
||||
}
|
||||
78
src/core/ddsi/include/ddsi/q_time.h
Normal file
78
src/core/ddsi/include/ddsi/q_time.h
Normal 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 */
|
||||
50
src/core/ddsi/include/ddsi/q_transmit.h
Normal file
50
src/core/ddsi/include/ddsi/q_transmit.h
Normal 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 */
|
||||
27
src/core/ddsi/include/ddsi/q_unused.h
Normal file
27
src/core/ddsi/include/ddsi/q_unused.h
Normal 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 */
|
||||
122
src/core/ddsi/include/ddsi/q_whc.h
Normal file
122
src/core/ddsi/include/ddsi/q_whc.h
Normal 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 */
|
||||
73
src/core/ddsi/include/ddsi/q_xevent.h
Normal file
73
src/core/ddsi/include/ddsi/q_xevent.h
Normal 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 */
|
||||
158
src/core/ddsi/include/ddsi/q_xmsg.h
Normal file
158
src/core/ddsi/include/ddsi/q_xmsg.h
Normal 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 */
|
||||
349
src/core/ddsi/include/ddsi/q_xqos.h
Normal file
349
src/core/ddsi/include/ddsi/q_xqos.h
Normal 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 */
|
||||
195
src/core/ddsi/include/ddsi/sysdeps.h
Normal file
195
src/core/ddsi/include/ddsi/sysdeps.h
Normal 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 */
|
||||
226
src/core/ddsi/src/ddsi_ser.c
Normal file
226
src/core/ddsi/src/ddsi_ser.c
Normal 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;
|
||||
}
|
||||
437
src/core/ddsi/src/ddsi_ssl.c
Normal file
437
src/core/ddsi/src/ddsi_ssl.c
Normal 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
1068
src/core/ddsi/src/ddsi_tcp.c
Normal file
File diff suppressed because it is too large
Load diff
206
src/core/ddsi/src/ddsi_tran.c
Normal file
206
src/core/ddsi/src/ddsi_tran.c
Normal 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);
|
||||
}
|
||||
}
|
||||
337
src/core/ddsi/src/ddsi_udp.c
Normal file
337
src/core/ddsi/src/ddsi_udp.c
Normal 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;
|
||||
}
|
||||
681
src/core/ddsi/src/q_addrset.c
Normal file
681
src/core/ddsi/src/q_addrset.c
Normal 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;
|
||||
}
|
||||
16
src/core/ddsi/src/q_bitset_inlines.c
Normal file
16
src/core/ddsi/src/q_bitset_inlines.c
Normal 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"
|
||||
|
||||
80
src/core/ddsi/src/q_bswap.c
Normal file
80
src/core/ddsi/src/q_bswap.c
Normal 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]);
|
||||
}
|
||||
15
src/core/ddsi/src/q_bswap_inlines.c
Normal file
15
src/core/ddsi/src/q_bswap_inlines.c
Normal 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"
|
||||
183
src/core/ddsi/src/q_builtin_topic.c
Normal file
183
src/core/ddsi/src/q_builtin_topic.c
Normal 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
2817
src/core/ddsi/src/q_config.c
Normal file
File diff suppressed because it is too large
Load diff
1996
src/core/ddsi/src/q_ddsi_discovery.c
Normal file
1996
src/core/ddsi/src/q_ddsi_discovery.c
Normal file
File diff suppressed because it is too large
Load diff
433
src/core/ddsi/src/q_debmon.c
Normal file
433
src/core/ddsi/src/q_debmon.c
Normal 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
4480
src/core/ddsi/src/q_entity.c
Normal file
File diff suppressed because it is too large
Load diff
365
src/core/ddsi/src/q_ephash.c
Normal file
365
src/core/ddsi/src/q_ephash.c
Normal 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);
|
||||
}
|
||||
248
src/core/ddsi/src/q_freelist.c
Normal file
248
src/core/ddsi/src/q_freelist.c
Normal 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
254
src/core/ddsi/src/q_gc.c
Normal 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
1465
src/core/ddsi/src/q_init.c
Normal file
File diff suppressed because it is too large
Load diff
84
src/core/ddsi/src/q_lat_estim.c
Normal file
84
src/core/ddsi/src/q_lat_estim.c
Normal 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
370
src/core/ddsi/src/q_lease.c
Normal 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
185
src/core/ddsi/src/q_log.c
Normal 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
209
src/core/ddsi/src/q_misc.c
Normal 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
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
209
src/core/ddsi/src/q_pcap.c
Normal 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
4099
src/core/ddsi/src/q_plist.c
Normal file
File diff suppressed because it is too large
Load diff
222
src/core/ddsi/src/q_qosmatch.c
Normal file
222
src/core/ddsi/src/q_qosmatch.c
Normal 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
2680
src/core/ddsi/src/q_radmin.c
Normal file
File diff suppressed because it is too large
Load diff
3309
src/core/ddsi/src/q_receive.c
Normal file
3309
src/core/ddsi/src/q_receive.c
Normal file
File diff suppressed because it is too large
Load diff
1758
src/core/ddsi/src/q_security.c
Normal file
1758
src/core/ddsi/src/q_security.c
Normal file
File diff suppressed because it is too large
Load diff
240
src/core/ddsi/src/q_servicelease.c
Normal file
240
src/core/ddsi/src/q_servicelease.c
Normal 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);
|
||||
}
|
||||
657
src/core/ddsi/src/q_sockwaitset.c
Normal file
657
src/core/ddsi/src/q_sockwaitset.c
Normal 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 */
|
||||
357
src/core/ddsi/src/q_thread.c
Normal file
357
src/core/ddsi/src/q_thread.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
15
src/core/ddsi/src/q_thread_inlines.c
Normal file
15
src/core/ddsi/src/q_thread_inlines.c
Normal 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
224
src/core/ddsi/src/q_time.c
Normal 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
|
||||
1156
src/core/ddsi/src/q_transmit.c
Normal file
1156
src/core/ddsi/src/q_transmit.c
Normal file
File diff suppressed because it is too large
Load diff
1085
src/core/ddsi/src/q_whc.c
Normal file
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
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
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
355
src/core/ddsi/src/sysdeps.c
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue