Improve ACLK according to results of the smoke-test. (#8358)
* Cleaning up the ACLK part 2 (#8187) * Initial proxy support implementation (#8146) * Implement the ACLK Challenge-Response Authentication (#8317) Co-authored-by: Timo <6674623+underhood@users.noreply.github.com>
This commit is contained in:
parent
3e272d1cff
commit
4acc880bab
@ -472,6 +472,8 @@ CLAIM_PLUGIN_FILES = \
|
||||
$(NULL)
|
||||
|
||||
ACLK_PLUGIN_FILES = \
|
||||
aclk/aclk_common.c \
|
||||
aclk/aclk_common.h \
|
||||
aclk/agent_cloud_link.c \
|
||||
aclk/agent_cloud_link.h \
|
||||
aclk/mqtt.c \
|
||||
|
35
aclk/aclk_common.c
Normal file
35
aclk/aclk_common.c
Normal file
@ -0,0 +1,35 @@
|
||||
#include "aclk_common.h"
|
||||
|
||||
struct {
|
||||
ACLK_PROXY_TYPE type;
|
||||
const char *url_str;
|
||||
} supported_proxy_types[] = {
|
||||
{ .type = PROXY_TYPE_SOCKS5, .url_str = "socks5" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
|
||||
{ .type = PROXY_TYPE_SOCKS5, .url_str = "socks5h" ACLK_PROXY_PROTO_ADDR_SEPARATOR },
|
||||
{ .type = PROXY_TYPE_UNKNOWN, .url_str = NULL },
|
||||
};
|
||||
|
||||
static inline ACLK_PROXY_TYPE aclk_find_proxy(const char *string)
|
||||
{
|
||||
int i = 0;
|
||||
while( supported_proxy_types[i].url_str ) {
|
||||
if(!strncmp(supported_proxy_types[i].url_str, string, strlen(supported_proxy_types[i].url_str)))
|
||||
return supported_proxy_types[i].type;
|
||||
i++;
|
||||
}
|
||||
return PROXY_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
ACLK_PROXY_TYPE aclk_verify_proxy(const char *string)
|
||||
{
|
||||
if(!string)
|
||||
return PROXY_TYPE_UNKNOWN;
|
||||
|
||||
while(*string == 0x20)
|
||||
string++;
|
||||
|
||||
if(!*string)
|
||||
return PROXY_TYPE_UNKNOWN;
|
||||
|
||||
return aclk_find_proxy(string);
|
||||
}
|
20
aclk/aclk_common.h
Normal file
20
aclk/aclk_common.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef ACLK_COMMON_H
|
||||
#define ACLK_COMMON_H
|
||||
|
||||
#include "libnetdata/libnetdata.h"
|
||||
|
||||
typedef enum aclk_proxy_type {
|
||||
PROXY_TYPE_UNKNOWN = 0,
|
||||
PROXY_TYPE_SOCKS5,
|
||||
PROXY_TYPE_HTTP,
|
||||
PROXY_DISABLED,
|
||||
PROXY_NOT_SET,
|
||||
} ACLK_PROXY_TYPE;
|
||||
|
||||
#define ACLK_PROXY_PROTO_ADDR_SEPARATOR "://"
|
||||
#define ACLK_PROXY_ENV "env"
|
||||
#define ACLK_PROXY_CONFIG_VAR "proxy"
|
||||
|
||||
ACLK_PROXY_TYPE aclk_verify_proxy(const char *string);
|
||||
|
||||
#endif //ACLK_COMMON_H
|
@ -1,382 +1,505 @@
|
||||
#include "aclk_lws_wss_client.h"
|
||||
|
||||
#include "libnetdata/libnetdata.h"
|
||||
#include "../daemon/common.h"
|
||||
#include "aclk_common.h"
|
||||
|
||||
static int aclk_lws_wss_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
|
||||
struct aclk_lws_wss_perconnect_data {
|
||||
int todo;
|
||||
int todo;
|
||||
};
|
||||
|
||||
struct lws_wss_packet_buffer {
|
||||
unsigned char* data;
|
||||
size_t data_size;
|
||||
struct lws_wss_packet_buffer *next;
|
||||
unsigned char *data;
|
||||
size_t data_size;
|
||||
struct lws_wss_packet_buffer *next;
|
||||
};
|
||||
|
||||
static inline struct lws_wss_packet_buffer *lws_wss_packet_buffer_new(void* data, size_t size)
|
||||
static struct aclk_lws_wss_engine_instance *engine_instance = NULL;
|
||||
|
||||
static inline struct lws_wss_packet_buffer *lws_wss_packet_buffer_new(void *data, size_t size)
|
||||
{
|
||||
struct lws_wss_packet_buffer *new = callocz(1, sizeof(struct lws_wss_packet_buffer));
|
||||
if(data) {
|
||||
new->data = mallocz(LWS_PRE+size);
|
||||
memcpy(new->data+LWS_PRE, data, size);
|
||||
new->data_size = size;
|
||||
}
|
||||
return new;
|
||||
struct lws_wss_packet_buffer *new = callocz(1, sizeof(struct lws_wss_packet_buffer));
|
||||
if (data) {
|
||||
new->data = mallocz(LWS_PRE + size);
|
||||
memcpy(new->data + LWS_PRE, data, size);
|
||||
new->data_size = size;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
static inline void lws_wss_packet_buffer_append(struct lws_wss_packet_buffer **list, struct lws_wss_packet_buffer *item)
|
||||
{
|
||||
struct lws_wss_packet_buffer *tail = *list;
|
||||
if(!*list) {
|
||||
*list = item;
|
||||
return;
|
||||
}
|
||||
while(tail->next) {
|
||||
tail = tail->next;
|
||||
}
|
||||
tail->next = item;
|
||||
struct lws_wss_packet_buffer *tail = *list;
|
||||
if (!*list) {
|
||||
*list = item;
|
||||
return;
|
||||
}
|
||||
while (tail->next) {
|
||||
tail = tail->next;
|
||||
}
|
||||
tail->next = item;
|
||||
}
|
||||
|
||||
static inline struct lws_wss_packet_buffer *lws_wss_packet_buffer_pop(struct lws_wss_packet_buffer **list)
|
||||
{
|
||||
struct lws_wss_packet_buffer *ret = *list;
|
||||
if(ret != NULL)
|
||||
*list = ret->next;
|
||||
struct lws_wss_packet_buffer *ret = *list;
|
||||
if (ret != NULL)
|
||||
*list = ret->next;
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void lws_wss_packet_buffer_free(struct lws_wss_packet_buffer *item)
|
||||
{
|
||||
freez(item->data);
|
||||
freez(item);
|
||||
freez(item->data);
|
||||
freez(item);
|
||||
}
|
||||
|
||||
static inline void _aclk_lws_wss_read_buffer_clear(struct lws_ring *ringbuffer)
|
||||
{
|
||||
size_t elems = lws_ring_get_count_waiting_elements(ringbuffer, NULL);
|
||||
if(elems > 0)
|
||||
lws_ring_consume(ringbuffer, NULL, NULL, elems);
|
||||
size_t elems = lws_ring_get_count_waiting_elements(ringbuffer, NULL);
|
||||
if (elems > 0)
|
||||
lws_ring_consume(ringbuffer, NULL, NULL, elems);
|
||||
}
|
||||
|
||||
static inline void _aclk_lws_wss_write_buffer_clear(struct lws_wss_packet_buffer **list)
|
||||
{
|
||||
struct lws_wss_packet_buffer *i;
|
||||
while((i = lws_wss_packet_buffer_pop(list)) != NULL) {
|
||||
lws_wss_packet_buffer_free(i);
|
||||
}
|
||||
*list = NULL;
|
||||
struct lws_wss_packet_buffer *i;
|
||||
while ((i = lws_wss_packet_buffer_pop(list)) != NULL) {
|
||||
lws_wss_packet_buffer_free(i);
|
||||
}
|
||||
*list = NULL;
|
||||
}
|
||||
|
||||
static inline void aclk_lws_wss_clear_io_buffers(struct aclk_lws_wss_engine_instance *inst)
|
||||
static inline void aclk_lws_wss_clear_io_buffers()
|
||||
{
|
||||
aclk_lws_mutex_lock(&inst->read_buf_mutex);
|
||||
_aclk_lws_wss_read_buffer_clear(inst->read_ringbuffer);
|
||||
aclk_lws_mutex_unlock(&inst->read_buf_mutex);
|
||||
aclk_lws_mutex_lock(&inst->write_buf_mutex);
|
||||
_aclk_lws_wss_write_buffer_clear(&inst->write_buffer_head);
|
||||
aclk_lws_mutex_unlock(&inst->write_buf_mutex);
|
||||
aclk_lws_mutex_lock(&engine_instance->read_buf_mutex);
|
||||
_aclk_lws_wss_read_buffer_clear(engine_instance->read_ringbuffer);
|
||||
aclk_lws_mutex_unlock(&engine_instance->read_buf_mutex);
|
||||
aclk_lws_mutex_lock(&engine_instance->write_buf_mutex);
|
||||
_aclk_lws_wss_write_buffer_clear(&engine_instance->write_buffer_head);
|
||||
aclk_lws_mutex_unlock(&engine_instance->write_buf_mutex);
|
||||
}
|
||||
|
||||
static const struct lws_protocols protocols[] = {
|
||||
{
|
||||
"aclk-wss",
|
||||
aclk_lws_wss_callback,
|
||||
sizeof(struct aclk_lws_wss_perconnect_data),
|
||||
0, 0, 0, 0
|
||||
},
|
||||
{ NULL, NULL, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
static const struct lws_protocols protocols[] = { { "aclk-wss", aclk_lws_wss_callback,
|
||||
sizeof(struct aclk_lws_wss_perconnect_data), 0, 0, 0, 0 },
|
||||
{ NULL, NULL, 0, 0, 0, 0, 0 } };
|
||||
|
||||
static void aclk_lws_wss_log_divert(int level, const char *line) {
|
||||
switch(level){
|
||||
case LLL_ERR:
|
||||
error("Libwebsockets Error: %s", line);
|
||||
break;
|
||||
case LLL_WARN:
|
||||
debug(D_ACLK, "Libwebsockets Warn: %s", line);
|
||||
break;
|
||||
default:
|
||||
error("Libwebsockets try to log with unknown log level (%d), msg: %s", level, line);
|
||||
}
|
||||
static void aclk_lws_wss_log_divert(int level, const char *line)
|
||||
{
|
||||
switch (level) {
|
||||
case LLL_ERR:
|
||||
error("Libwebsockets Error: %s", line);
|
||||
break;
|
||||
case LLL_WARN:
|
||||
debug(D_ACLK, "Libwebsockets Warn: %s", line);
|
||||
break;
|
||||
default:
|
||||
error("Libwebsockets try to log with unknown log level (%d), msg: %s", level, line);
|
||||
}
|
||||
}
|
||||
|
||||
struct aclk_lws_wss_engine_instance* aclk_lws_wss_client_init (const struct aclk_lws_wss_engine_callbacks *callbacks, const char *target_hostname, int target_port) {
|
||||
static int lws_logging_initialized = 0;
|
||||
struct lws_context_creation_info info;
|
||||
struct aclk_lws_wss_engine_instance *inst;
|
||||
static int aclk_lws_wss_client_init( char *target_hostname, int target_port)
|
||||
{
|
||||
static int lws_logging_initialized = 0;
|
||||
struct lws_context_creation_info info;
|
||||
|
||||
if(unlikely(!lws_logging_initialized)) {
|
||||
lws_set_log_level(LLL_ERR | LLL_WARN, aclk_lws_wss_log_divert);
|
||||
lws_logging_initialized = 1;
|
||||
}
|
||||
|
||||
if(!callbacks || !target_hostname)
|
||||
return NULL;
|
||||
|
||||
inst = callocz(1, sizeof(struct aclk_lws_wss_engine_instance));
|
||||
|
||||
inst->host = target_hostname;
|
||||
inst->port = target_port;
|
||||
|
||||
memset(&info, 0, sizeof(struct lws_context_creation_info));
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
info.protocols = protocols;
|
||||
info.user = inst;
|
||||
|
||||
inst->lws_context = lws_create_context(&info);
|
||||
if(!inst->lws_context)
|
||||
goto failure_cleanup_2;
|
||||
|
||||
inst->callbacks = *callbacks;
|
||||
|
||||
aclk_lws_mutex_init(&inst->write_buf_mutex);
|
||||
aclk_lws_mutex_init(&inst->read_buf_mutex);
|
||||
|
||||
inst->read_ringbuffer = lws_ring_create(1, ACLK_LWS_WSS_RECV_BUFF_SIZE_BYTES, NULL);
|
||||
if(!inst->read_ringbuffer)
|
||||
goto failure_cleanup;
|
||||
|
||||
return inst;
|
||||
|
||||
failure_cleanup:
|
||||
lws_context_destroy(inst->lws_context);
|
||||
failure_cleanup_2:
|
||||
freez(inst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void aclk_lws_wss_client_destroy(struct aclk_lws_wss_engine_instance* inst) {
|
||||
lws_context_destroy(inst->lws_context);
|
||||
inst->lws_context = NULL;
|
||||
inst->lws_wsi = NULL;
|
||||
|
||||
aclk_lws_wss_clear_io_buffers(inst);
|
||||
|
||||
#ifdef ACLK_LWS_MOSQUITTO_IO_CALLS_MULTITHREADED
|
||||
pthread_mutex_destroy(&inst->write_buf_mutex);
|
||||
pthread_mutex_destroy(&inst->read_buf_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void aclk_lws_wss_connect(struct aclk_lws_wss_engine_instance *inst){
|
||||
struct lws_client_connect_info i;
|
||||
|
||||
if(inst->lws_wsi) {
|
||||
error("Already Connected. Only one connection supported at a time.");
|
||||
return;
|
||||
if (unlikely(!lws_logging_initialized)) {
|
||||
lws_set_log_level(LLL_ERR | LLL_WARN, aclk_lws_wss_log_divert);
|
||||
lws_logging_initialized = 1;
|
||||
}
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.context = inst->lws_context;
|
||||
i.port = inst->port;
|
||||
i.address = inst->host;
|
||||
i.path = "/mqtt";
|
||||
i.host = inst->host;
|
||||
i.protocol = "mqtt";
|
||||
#ifdef ACLK_SSL_ALLOW_SELF_SIGNED
|
||||
i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
|
||||
#else
|
||||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
#endif
|
||||
lws_client_connect_via_info(&i);
|
||||
if (!target_hostname)
|
||||
return 1;
|
||||
|
||||
engine_instance = callocz(1, sizeof(struct aclk_lws_wss_engine_instance));
|
||||
|
||||
engine_instance->host = target_hostname;
|
||||
engine_instance->port = target_port;
|
||||
|
||||
memset(&info, 0, sizeof(struct lws_context_creation_info));
|
||||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
info.protocols = protocols;
|
||||
|
||||
engine_instance->lws_context = lws_create_context(&info);
|
||||
if (!engine_instance->lws_context)
|
||||
goto failure_cleanup_2;
|
||||
|
||||
aclk_lws_mutex_init(&engine_instance->write_buf_mutex);
|
||||
aclk_lws_mutex_init(&engine_instance->read_buf_mutex);
|
||||
|
||||
engine_instance->read_ringbuffer = lws_ring_create(1, ACLK_LWS_WSS_RECV_BUFF_SIZE_BYTES, NULL);
|
||||
if (!engine_instance->read_ringbuffer)
|
||||
goto failure_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
failure_cleanup:
|
||||
lws_context_destroy(engine_instance->lws_context);
|
||||
failure_cleanup_2:
|
||||
freez(engine_instance);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int received_data_to_ringbuff(struct lws_ring *buffer, void* data, size_t len) {
|
||||
if( lws_ring_insert(buffer, data, len) != len ) {
|
||||
error("ACLK_LWS_WSS_CLIENT: receive buffer full. Closing connection to prevent flooding.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
void aclk_lws_wss_client_destroy(struct aclk_lws_wss_engine_instance *engine_instance)
|
||||
{
|
||||
if (engine_instance == NULL)
|
||||
return;
|
||||
lws_context_destroy(engine_instance->lws_context);
|
||||
engine_instance->lws_context = NULL;
|
||||
engine_instance->lws_wsi = NULL;
|
||||
|
||||
aclk_lws_wss_clear_io_buffers(engine_instance);
|
||||
|
||||
#ifdef ACLK_LWS_MOSQUITTO_IO_CALLS_MULTITHREADED
|
||||
pthread_mutex_destroy(&engine_instance->write_buf_mutex);
|
||||
pthread_mutex_destroy(&engine_instance->read_buf_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int _aclk_wss_set_socks(struct lws_vhost *vhost, const char *socks)
|
||||
{
|
||||
char *proxy = strstr(socks, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
|
||||
|
||||
if(!proxy)
|
||||
return -1;
|
||||
|
||||
proxy += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
|
||||
|
||||
if(!*proxy)
|
||||
return -1;
|
||||
|
||||
return lws_set_socks(vhost, proxy);
|
||||
}
|
||||
|
||||
// helper function to censor user&password
|
||||
// for logging purposes
|
||||
static void safe_log_proxy_censor(char *proxy) {
|
||||
size_t length = strlen(proxy);
|
||||
char *auth = proxy+length-1;
|
||||
char *cur;
|
||||
|
||||
while( (auth >= proxy) && (*auth != '@') )
|
||||
auth--;
|
||||
|
||||
//if not found or @ is first char do nothing
|
||||
if(auth<=proxy)
|
||||
return;
|
||||
|
||||
cur = strstr(proxy, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
|
||||
if(!cur)
|
||||
cur = proxy;
|
||||
else
|
||||
cur += strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
|
||||
|
||||
while(cur < auth) {
|
||||
*cur='X';
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void safe_log_proxy_error(char *str, const char *proxy) {
|
||||
char *log = strdupz(proxy);
|
||||
safe_log_proxy_censor(log);
|
||||
error("%s Provided Value:\"%s\"", str, log);
|
||||
freez(log);
|
||||
}
|
||||
|
||||
static inline int check_socks_enviroment(const char **proxy) {
|
||||
char *tmp = getenv("socks_proxy");
|
||||
|
||||
if(!tmp)
|
||||
return 1;
|
||||
|
||||
if(aclk_verify_proxy(tmp) == PROXY_TYPE_SOCKS5) {
|
||||
*proxy = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
safe_log_proxy_error("Environment var \"socks_proxy\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".", tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type) {
|
||||
const char *proxy = config_get(CONFIG_SECTION_ACLK, ACLK_PROXY_CONFIG_VAR, ACLK_PROXY_ENV);
|
||||
*type = PROXY_DISABLED;
|
||||
|
||||
if(strcmp(proxy, "none") == 0)
|
||||
return proxy;
|
||||
|
||||
if(strcmp(proxy, ACLK_PROXY_ENV) == 0) {
|
||||
if(check_socks_enviroment(&proxy) == 0)
|
||||
*type = PROXY_TYPE_SOCKS5;
|
||||
return proxy;
|
||||
}
|
||||
|
||||
*type = aclk_verify_proxy(proxy);
|
||||
if(*type == PROXY_TYPE_UNKNOWN) {
|
||||
*type = PROXY_DISABLED;
|
||||
safe_log_proxy_error("Config var \"" ACLK_PROXY_CONFIG_VAR "\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".", proxy);
|
||||
}
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
// Return code indicates if connection attempt has started async.
|
||||
int aclk_lws_wss_connect(char *host, int port)
|
||||
{
|
||||
struct lws_client_connect_info i;
|
||||
struct lws_vhost *vhost;
|
||||
static const char *proxy = NULL;
|
||||
static ACLK_PROXY_TYPE proxy_type = PROXY_NOT_SET;
|
||||
char *log;
|
||||
|
||||
if (!engine_instance) {
|
||||
return aclk_lws_wss_client_init(host, port);
|
||||
// PROTOCOL_INIT callback will call again.
|
||||
}
|
||||
|
||||
if(proxy_type == PROXY_NOT_SET)
|
||||
proxy = aclk_lws_wss_get_proxy_setting(&proxy_type);
|
||||
|
||||
if (engine_instance->lws_wsi) {
|
||||
error("Already Connected. Only one connection supported at a time.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// from LWS docu:
|
||||
// If option LWS_SERVER_OPTION_EXPLICIT_VHOSTS is given, no vhost is
|
||||
// created; you're expected to create your own vhosts afterwards using
|
||||
// lws_create_vhost(). Otherwise a vhost named "default" is also created
|
||||
// using the information in the vhost-related members, for compatibility.
|
||||
vhost = lws_get_vhost_by_name(engine_instance->lws_context, "default");
|
||||
if(!vhost)
|
||||
fatal("Could not find the default LWS vhost.");
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.context = engine_instance->lws_context;
|
||||
i.port = engine_instance->port;
|
||||
i.address = engine_instance->host;
|
||||
i.path = "/mqtt";
|
||||
i.host = engine_instance->host;
|
||||
i.protocol = "mqtt";
|
||||
|
||||
switch (proxy_type) {
|
||||
case PROXY_DISABLED:
|
||||
lws_set_socks(vhost, ":");
|
||||
lws_set_proxy(vhost, ":");
|
||||
break;
|
||||
case PROXY_TYPE_SOCKS5:
|
||||
log = strdupz(proxy);
|
||||
safe_log_proxy_censor(log);
|
||||
info("Connecting using SOCKS5 proxy:\"%s\"", log);
|
||||
freez(log);
|
||||
if(_aclk_wss_set_socks(vhost, proxy))
|
||||
error("LWS failed to accept socks proxy.");
|
||||
break;
|
||||
default:
|
||||
error("The proxy could not be set. Unknown proxy type.");
|
||||
}
|
||||
|
||||
#ifdef ACLK_SSL_ALLOW_SELF_SIGNED
|
||||
i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
|
||||
info("Disabling SSL certificate checks");
|
||||
#else
|
||||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
#endif
|
||||
lws_client_connect_via_info(&i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int received_data_to_ringbuff(struct lws_ring *buffer, void *data, size_t len)
|
||||
{
|
||||
if (lws_ring_insert(buffer, data, len) != len) {
|
||||
error("ACLK_LWS_WSS_CLIENT: receive buffer full. Closing connection to prevent flooding.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *aclk_lws_callback_name(enum lws_callback_reasons reason)
|
||||
{
|
||||
switch(reason)
|
||||
{
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
return "LWS_CALLBACK_CLIENT_WRITEABLE";
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
return "LWS_CALLBACK_CLIENT_RECEIVE";
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
return "LWS_CALLBACK_PROTOCOL_INIT";
|
||||
case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
|
||||
return "LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED";
|
||||
case LWS_CALLBACK_USER:
|
||||
return "LWS_CALLBACK_USER";
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
return "LWS_CALLBACK_CLIENT_CONNECTION_ERROR";
|
||||
case LWS_CALLBACK_CLIENT_CLOSED:
|
||||
return "LWS_CALLBACK_CLIENT_CLOSED";
|
||||
case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
|
||||
return "LWS_CALLBACK_WS_PEER_INITIATED_CLOSE";
|
||||
case LWS_CALLBACK_WSI_DESTROY:
|
||||
return "LWS_CALLBACK_WSI_DESTROY";
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
return "LWS_CALLBACK_CLIENT_ESTABLISHED";
|
||||
default:
|
||||
// Not using an internal buffer here for thread-safety with unknown calling context.
|
||||
error("Unknown LWS callback %u", reason);
|
||||
return "unknown";
|
||||
}
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
return "LWS_CALLBACK_CLIENT_WRITEABLE";
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
return "LWS_CALLBACK_CLIENT_RECEIVE";
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
return "LWS_CALLBACK_PROTOCOL_INIT";
|
||||
case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
|
||||
return "LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED";
|
||||
case LWS_CALLBACK_USER:
|
||||
return "LWS_CALLBACK_USER";
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
return "LWS_CALLBACK_CLIENT_CONNECTION_ERROR";
|
||||
case LWS_CALLBACK_CLIENT_CLOSED:
|
||||
return "LWS_CALLBACK_CLIENT_CLOSED";
|
||||
case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
|
||||
return "LWS_CALLBACK_WS_PEER_INITIATED_CLOSE";
|
||||
case LWS_CALLBACK_WSI_DESTROY:
|
||||
return "LWS_CALLBACK_WSI_DESTROY";
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
return "LWS_CALLBACK_CLIENT_ESTABLISHED";
|
||||
case LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION:
|
||||
return "LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION";
|
||||
default:
|
||||
// Not using an internal buffer here for thread-safety with unknown calling context.
|
||||
error("Unknown LWS callback %u", reason);
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
static int
|
||||
aclk_lws_wss_callback(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
static int aclk_lws_wss_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
|
||||
{
|
||||
UNUSED(user);
|
||||
struct aclk_lws_wss_engine_instance *inst = lws_context_user(lws_get_context(wsi));
|
||||
struct lws_wss_packet_buffer *data;
|
||||
int retval = 0;
|
||||
UNUSED(user);
|
||||
struct lws_wss_packet_buffer *data;
|
||||
int retval = 0;
|
||||
|
||||
if( !inst ) {
|
||||
error("Callback received without any aclk_lws_wss_engine_instance!");
|
||||
return -1;
|
||||
}
|
||||
// Callback servicing is forced when we are closed from above.
|
||||
if (engine_instance->upstream_reconnect_request) {
|
||||
error("Closing lws connectino due to libmosquitto error.");
|
||||
char *upstream_connection_error = "MQTT protocol error. Closing underlying wss connection.";
|
||||
lws_close_reason(
|
||||
wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR, (unsigned char *)upstream_connection_error,
|
||||
strlen(upstream_connection_error));
|
||||
retval = -1;
|
||||
engine_instance->upstream_reconnect_request = 0;
|
||||
}
|
||||
|
||||
// Callback servicing is forced when we are closed from above.
|
||||
if( inst->upstream_reconnect_request ) {
|
||||
error("Closing lws connectino due to libmosquitto error.");
|
||||
char *upstream_connection_error = "MQTT protocol error. Closing underlying wss connection.";
|
||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR, (unsigned char*)upstream_connection_error, strlen(upstream_connection_error));
|
||||
retval = -1;
|
||||
inst->upstream_reconnect_request = 0;
|
||||
}
|
||||
// Don't log to info - volume is proportional to message flow on ACLK.
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
aclk_lws_mutex_lock(&engine_instance->write_buf_mutex);
|
||||
data = lws_wss_packet_buffer_pop(&engine_instance->write_buffer_head);
|
||||
if (likely(data)) {
|
||||
lws_write(wsi, data->data + LWS_PRE, data->data_size, LWS_WRITE_BINARY);
|
||||
lws_wss_packet_buffer_free(data);
|
||||
if (engine_instance->write_buffer_head)
|
||||
lws_callback_on_writable(engine_instance->lws_wsi);
|
||||
}
|
||||
aclk_lws_mutex_unlock(&engine_instance->write_buf_mutex);
|
||||
return retval;
|
||||
|
||||
// Don't log to info - volume is proportional to message flow on ACLK.
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
aclk_lws_mutex_lock(&inst->write_buf_mutex);
|
||||
data = lws_wss_packet_buffer_pop(&inst->write_buffer_head);
|
||||
if(likely(data)) {
|
||||
lws_write(wsi, data->data + LWS_PRE, data->data_size, LWS_WRITE_BINARY);
|
||||
lws_wss_packet_buffer_free(data);
|
||||
if(inst->write_buffer_head)
|
||||
lws_callback_on_writable(inst->lws_wsi);
|
||||
}
|
||||
aclk_lws_mutex_unlock(&inst->write_buf_mutex);
|
||||
return retval;
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
aclk_lws_mutex_lock(&engine_instance->read_buf_mutex);
|
||||
if (!received_data_to_ringbuff(engine_instance->read_ringbuffer, in, len))
|
||||
retval = 1;
|
||||
aclk_lws_mutex_unlock(&engine_instance->read_buf_mutex);
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
aclk_lws_mutex_lock(&inst->read_buf_mutex);
|
||||
if(!received_data_to_ringbuff(inst->read_ringbuffer, in, len))
|
||||
retval = 1;
|
||||
aclk_lws_mutex_unlock(&inst->read_buf_mutex);
|
||||
// to future myself -> do not call this while read lock is active as it will eventually
|
||||
// want to acquire same lock later in aclk_lws_wss_client_read() function
|
||||
aclk_lws_connection_data_received();
|
||||
return retval;
|
||||
|
||||
if(likely(inst->callbacks.data_rcvd_callback))
|
||||
// to future myself -> do not call this while read lock is active as it will eventually
|
||||
// want to acquire same lock later in aclk_lws_wss_client_read() function
|
||||
inst->callbacks.data_rcvd_callback();
|
||||
else
|
||||
inst->data_to_read = 1; //to inform logic above there is reason to call mosquitto_loop_read
|
||||
return retval;
|
||||
|
||||
case LWS_CALLBACK_WSI_CREATE:
|
||||
case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH:
|
||||
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
|
||||
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
|
||||
case LWS_CALLBACK_GET_THREAD_ID: // ?
|
||||
case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
|
||||
// Expected and safe to ignore.
|
||||
return retval;
|
||||
case LWS_CALLBACK_WSI_CREATE:
|
||||
case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH:
|
||||
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
|
||||
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
|
||||
case LWS_CALLBACK_GET_THREAD_ID: // ?
|
||||
case LWS_CALLBACK_EVENT_WAIT_CANCELLED:
|
||||
case LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION:
|
||||
// Expected and safe to ignore.
|
||||
debug(D_ACLK, "Ignoring expected callback from LWS: %s", aclk_lws_callback_name(reason));
|
||||
return retval;
|
||||
|
||||
default:
|
||||
// Pass to next switch, this case removes compiler warnings.
|
||||
break;
|
||||
default:
|
||||
// Pass to next switch, this case removes compiler warnings.
|
||||
break;
|
||||
}
|
||||
// Log to info - volume is proportional to connection attempts.
|
||||
info("Processing callback %s", aclk_lws_callback_name(reason));
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
aclk_lws_wss_connect(engine_instance->host, engine_instance->port); // Makes the outgoing connection
|
||||
break;
|
||||
case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
|
||||
if (engine_instance->lws_wsi != NULL && engine_instance->lws_wsi != wsi)
|
||||
error("Multiple connections on same WSI? %p vs %p", engine_instance->lws_wsi, wsi);
|
||||
engine_instance->lws_wsi = wsi;
|
||||
break;
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
error(
|
||||
"Could not connect MQTT over WSS server \"%s:%d\". LwsReason:\"%s\"", engine_instance->host,
|
||||
engine_instance->port, (in ? (char *)in : "not given"));
|
||||
// Fall-through
|
||||
case LWS_CALLBACK_CLIENT_CLOSED:
|
||||
case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
|
||||
engine_instance->lws_wsi = NULL; // inside libwebsockets lws_close_free_wsi is called after callback
|
||||
aclk_lws_connection_closed();
|
||||
return -1; // the callback response is ignored, hope the above remains true
|
||||
case LWS_CALLBACK_WSI_DESTROY:
|
||||
aclk_lws_wss_clear_io_buffers(engine_instance);
|
||||
engine_instance->lws_wsi = NULL;
|
||||
engine_instance->websocket_connection_up = 0;
|
||||
aclk_lws_connection_closed();
|
||||
break;
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
engine_instance->websocket_connection_up = 1;
|
||||
aclk_lws_connection_established(engine_instance->host, engine_instance->port);
|
||||
break;
|
||||
|
||||
}
|
||||
// Log to info - volume is proportional to connection attempts.
|
||||
info("Processing callback %s", aclk_lws_callback_name(reason));
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
aclk_lws_wss_connect(inst); // Makes the outgoing connection
|
||||
break;
|
||||
case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
|
||||
if (inst->lws_wsi != NULL && inst->lws_wsi != wsi)
|
||||
error("Multiple connections on same WSI? %p vs %p", inst->lws_wsi, wsi);
|
||||
inst->lws_wsi = wsi;
|
||||
break;
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
error("Could not connect MQTT over WSS server \"%s:%d\". LwsReason:\"%s\"", inst->host, inst->port, (in ? (char*)in : "not given"));
|
||||
// Fall-through
|
||||
case LWS_CALLBACK_CLIENT_CLOSED:
|
||||
case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
|
||||
inst->lws_wsi = NULL; // inside libwebsockets lws_close_free_wsi is called after callback
|
||||
if (inst->callbacks.connection_closed)
|
||||
inst->callbacks.connection_closed();
|
||||
return -1; // the callback response is ignored, hope the above remains true
|
||||
case LWS_CALLBACK_WSI_DESTROY:
|
||||
aclk_lws_wss_clear_io_buffers(inst);
|
||||
inst->lws_wsi = NULL;
|
||||
inst->websocket_connection_up = 0;
|
||||
if (inst->callbacks.connection_closed)
|
||||
inst->callbacks.connection_closed();
|
||||
break;
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
inst->websocket_connection_up = 1;
|
||||
if(inst->callbacks.connection_established_callback)
|
||||
inst->callbacks.connection_established_callback();
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Unexecpted callback from libwebsockets %s",aclk_lws_callback_name(reason));
|
||||
break;
|
||||
}
|
||||
return retval; //0-OK, other connection should be closed!
|
||||
default:
|
||||
error("Unexpected callback from libwebsockets %s", aclk_lws_callback_name(reason));
|
||||
break;
|
||||
}
|
||||
return retval; //0-OK, other connection should be closed!
|
||||
}
|
||||
|
||||
int aclk_lws_wss_client_write(struct aclk_lws_wss_engine_instance *inst, void *buf, size_t count)
|
||||
int aclk_lws_wss_client_write(void *buf, size_t count)
|
||||
{
|
||||
if(inst && inst->lws_wsi && inst->websocket_connection_up)
|
||||
{
|
||||
aclk_lws_mutex_lock(&inst->write_buf_mutex);
|
||||
lws_wss_packet_buffer_append(&inst->write_buffer_head, lws_wss_packet_buffer_new(buf, count));
|
||||
aclk_lws_mutex_unlock(&inst->write_buf_mutex);
|
||||
if (engine_instance && engine_instance->lws_wsi && engine_instance->websocket_connection_up) {
|
||||
aclk_lws_mutex_lock(&engine_instance->write_buf_mutex);
|
||||
lws_wss_packet_buffer_append(&engine_instance->write_buffer_head, lws_wss_packet_buffer_new(buf, count));
|
||||
aclk_lws_mutex_unlock(&engine_instance->write_buf_mutex);
|
||||
|
||||
lws_callback_on_writable(inst->lws_wsi);
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
lws_callback_on_writable(engine_instance->lws_wsi);
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aclk_lws_wss_client_read(struct aclk_lws_wss_engine_instance *inst, void *buf, size_t count)
|
||||
int aclk_lws_wss_client_read(void *buf, size_t count)
|
||||
{
|
||||
size_t data_to_be_read = count;
|
||||
size_t data_to_be_read = count;
|
||||
|
||||
aclk_lws_mutex_lock(&inst->read_buf_mutex);
|
||||
size_t readable_byte_count = lws_ring_get_count_waiting_elements(inst->read_ringbuffer, NULL);
|
||||
if(unlikely(readable_byte_count == 0)) {
|
||||
errno = EAGAIN;
|
||||
data_to_be_read = -1;
|
||||
goto abort;
|
||||
}
|
||||
aclk_lws_mutex_lock(&engine_instance->read_buf_mutex);
|
||||
size_t readable_byte_count = lws_ring_get_count_waiting_elements(engine_instance->read_ringbuffer, NULL);
|
||||
if (unlikely(readable_byte_count == 0)) {
|
||||
errno = EAGAIN;
|
||||
data_to_be_read = -1;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if( readable_byte_count < data_to_be_read )
|
||||
data_to_be_read = readable_byte_count;
|
||||
if (readable_byte_count < data_to_be_read)
|
||||
data_to_be_read = readable_byte_count;
|
||||
|
||||
data_to_be_read = lws_ring_consume(inst->read_ringbuffer, NULL, buf, data_to_be_read);
|
||||
if(data_to_be_read == readable_byte_count)
|
||||
inst->data_to_read = 0;
|
||||
data_to_be_read = lws_ring_consume(engine_instance->read_ringbuffer, NULL, buf, data_to_be_read);
|
||||
if (data_to_be_read == readable_byte_count)
|
||||
engine_instance->data_to_read = 0;
|
||||
|
||||
abort:
|
||||
aclk_lws_mutex_unlock(&inst->read_buf_mutex);
|
||||
return data_to_be_read;
|
||||
aclk_lws_mutex_unlock(&engine_instance->read_buf_mutex);
|
||||
return data_to_be_read;
|
||||
}
|
||||
|
||||
int aclk_lws_wss_service_loop(struct aclk_lws_wss_engine_instance *inst)
|
||||
void aclk_lws_wss_service_loop()
|
||||
{
|
||||
return lws_service(inst->lws_context, 0);
|
||||
if (engine_instance)
|
||||
lws_service(engine_instance->lws_context, 0);
|
||||
}
|
||||
|
||||
// in case the MQTT connection disconnect while lws transport is still operational
|
||||
// we should drop connection and reconnect
|
||||
// this function should be called when that happens to notify lws of that situation
|
||||
void aclk_lws_wss_mqtt_layer_disconect_notif(struct aclk_lws_wss_engine_instance *inst)
|
||||
void aclk_lws_wss_mqtt_layer_disconect_notif()
|
||||
{
|
||||
if(inst->lws_wsi && inst->websocket_connection_up) {
|
||||
inst->upstream_reconnect_request = 1;
|
||||
lws_callback_on_writable(inst->lws_wsi); //here we just do it to ensure we get callback called from lws, we don't need any actual data to be written.
|
||||
}
|
||||
}
|
||||
if (!engine_instance)
|
||||
return;
|
||||
if (engine_instance->lws_wsi && engine_instance->websocket_connection_up) {
|
||||
engine_instance->upstream_reconnect_request = 1;
|
||||
lws_callback_on_writable(
|
||||
engine_instance->lws_wsi); //here we just do it to ensure we get callback called from lws, we don't need any actual data to be written.
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@
|
||||
|
||||
#include "libnetdata/libnetdata.h"
|
||||
|
||||
#define ACLK_LWS_WSS_RECONNECT_TIMEOUT 5
|
||||
|
||||
// This is as define because ideally the ACLK at high level
|
||||
// can do mosqitto writes and reads only from one thread
|
||||
// which is cleaner implementation IMHO
|
||||
@ -14,64 +12,67 @@
|
||||
// is simpler
|
||||
#define ACLK_LWS_MOSQUITTO_IO_CALLS_MULTITHREADED 1
|
||||
|
||||
#define ACLK_LWS_WSS_RECV_BUFF_SIZE_BYTES 128*1024
|
||||
#define ACLK_LWS_WSS_RECV_BUFF_SIZE_BYTES (128 * 1024)
|
||||
|
||||
#ifdef ACLK_LWS_MOSQUITTO_IO_CALLS_MULTITHREADED
|
||||
#define aclk_lws_mutex_init(x) netdata_mutex_init(x)
|
||||
#define aclk_lws_mutex_lock(x) netdata_mutex_lock(x)
|
||||
#define aclk_lws_mutex_unlock(x) netdata_mutex_unlock(x)
|
||||
#define aclk_lws_mutex_init(x) netdata_mutex_init(x)
|
||||
#define aclk_lws_mutex_lock(x) netdata_mutex_lock(x)
|
||||
#define aclk_lws_mutex_unlock(x) netdata_mutex_unlock(x)
|
||||
#else
|
||||
#define aclk_lws_mutex_init(x)
|
||||
#define aclk_lws_mutex_lock(x)
|
||||
#define aclk_lws_mutex_unlock(x)
|
||||
#define aclk_lws_mutex_init(x)
|
||||
#define aclk_lws_mutex_lock(x)
|
||||
#define aclk_lws_mutex_unlock(x)
|
||||
#endif
|
||||
|
||||
struct aclk_lws_wss_engine_callbacks {
|
||||
void (*connection_established_callback)();
|
||||
void (*data_rcvd_callback)();
|
||||
void (*data_writable_callback)();
|
||||
void (*connection_established_callback)();
|
||||
void (*data_rcvd_callback)();
|
||||
void (*data_writable_callback)();
|
||||
void (*connection_closed)();
|
||||
};
|
||||
|
||||
struct lws_wss_packet_buffer;
|
||||
|
||||
struct aclk_lws_wss_engine_instance {
|
||||
//target host/port for connection
|
||||
const char *host;
|
||||
int port;
|
||||
//target host/port for connection
|
||||
char *host;
|
||||
int port;
|
||||
|
||||
//internal data
|
||||
struct lws_context *lws_context;
|
||||
struct lws *lws_wsi;
|
||||
//internal data
|
||||
struct lws_context *lws_context;
|
||||
struct lws *lws_wsi;
|
||||
|
||||
#ifdef ACLK_LWS_MOSQUITTO_IO_CALLS_MULTITHREADED
|
||||
netdata_mutex_t write_buf_mutex;
|
||||
netdata_mutex_t read_buf_mutex;
|
||||
netdata_mutex_t write_buf_mutex;
|
||||
netdata_mutex_t read_buf_mutex;
|
||||
#endif
|
||||
|
||||
struct lws_wss_packet_buffer *write_buffer_head;
|
||||
struct lws_ring *read_ringbuffer;
|
||||
struct lws_wss_packet_buffer *write_buffer_head;
|
||||
struct lws_ring *read_ringbuffer;
|
||||
|
||||
struct aclk_lws_wss_engine_callbacks callbacks;
|
||||
//flags to be readed by engine user
|
||||
int websocket_connection_up;
|
||||
|
||||
//flags to be readed by engine user
|
||||
int websocket_connection_up;
|
||||
// currently this is by default disabled
|
||||
|
||||
// currently this is by default disabled
|
||||
|
||||
int data_to_read;
|
||||
int upstream_reconnect_request;
|
||||
int data_to_read;
|
||||
int upstream_reconnect_request;
|
||||
};
|
||||
|
||||
struct aclk_lws_wss_engine_instance* aclk_lws_wss_client_init (const struct aclk_lws_wss_engine_callbacks *callbacks, const char *target_hostname, int target_port);
|
||||
void aclk_lws_wss_client_destroy(struct aclk_lws_wss_engine_instance* inst);
|
||||
void aclk_lws_wss_client_destroy();
|
||||
|
||||
void aclk_lws_wss_connect(struct aclk_lws_wss_engine_instance *inst);
|
||||
int aclk_lws_wss_connect(char *host, int port);
|
||||
|
||||
int aclk_lws_wss_client_write(struct aclk_lws_wss_engine_instance *inst, void *buf, size_t count);
|
||||
int aclk_lws_wss_client_read (struct aclk_lws_wss_engine_instance *inst, void *buf, size_t count);
|
||||
int aclk_lws_wss_service_loop(struct aclk_lws_wss_engine_instance *inst);
|
||||
int aclk_lws_wss_client_write(void *buf, size_t count);
|
||||
int aclk_lws_wss_client_read(void *buf, size_t count);
|
||||
void aclk_lws_wss_service_loop();
|
||||
|
||||
void aclk_lws_wss_mqtt_layer_disconect_notif(struct aclk_lws_wss_engine_instance *inst);
|
||||
void aclk_lws_wss_mqtt_layer_disconect_notif();
|
||||
|
||||
#endif
|
||||
// Notifications inside the layer above
|
||||
void aclk_lws_connection_established();
|
||||
void aclk_lws_connection_data_received();
|
||||
void aclk_lws_connection_closed();
|
||||
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,11 +8,6 @@
|
||||
|
||||
#define ACLK_VERSION 1
|
||||
#define ACLK_THREAD_NAME "ACLK_Query"
|
||||
#define ACLK_JSON_IN_MSGID "msg-id"
|
||||
#define ACLK_JSON_IN_TYPE "type"
|
||||
#define ACLK_JSON_IN_VERSION "version"
|
||||
#define ACLK_JSON_IN_TOPIC "callback-topic"
|
||||
#define ACLK_JSON_IN_URL "payload"
|
||||
#define ACLK_CHART_TOPIC "chart"
|
||||
#define ACLK_ALARMS_TOPIC "alarms"
|
||||
#define ACLK_METADATA_TOPIC "meta"
|
||||
@ -25,26 +20,23 @@
|
||||
#define ACLK_INITIALIZATION_SLEEP_WAIT 1 // Wait time @ spin lock for MQTT initialization in seconds
|
||||
#define ACLK_QOS 1
|
||||
#define ACLK_PING_INTERVAL 60
|
||||
#define ACLK_LOOP_TIMEOUT 5 // seconds to wait for operations in the library loop
|
||||
#define ACLK_LOOP_TIMEOUT 5 // seconds to wait for operations in the library loop
|
||||
|
||||
#define ACLK_MAX_TOPIC 255
|
||||
#define ACLK_MAX_TOPIC 255
|
||||
|
||||
#define ACLK_RECONNECT_DELAY 1 // reconnect delay -- with backoff stragegy fow now
|
||||
#define ACLK_STABLE_TIMEOUT 10 // Minimum delay to mark AGENT as stable
|
||||
#define ACLK_DEFAULT_PORT 9002
|
||||
#define ACLK_DEFAULT_PORT 9002
|
||||
#define ACLK_DEFAULT_HOST "localhost"
|
||||
|
||||
#define CONFIG_SECTION_ACLK "agent_cloud_link"
|
||||
|
||||
struct aclk_request {
|
||||
char *type_id;
|
||||
char *msg_id;
|
||||
char *callback_topic;
|
||||
char *payload;
|
||||
int version;
|
||||
char *type_id;
|
||||
char *msg_id;
|
||||
char *callback_topic;
|
||||
char *payload;
|
||||
int version;
|
||||
};
|
||||
|
||||
|
||||
typedef enum aclk_cmd {
|
||||
ACLK_CMD_CLOUD,
|
||||
ACLK_CMD_ONCONNECT,
|
||||
@ -56,24 +48,29 @@ typedef enum aclk_cmd {
|
||||
ACLK_CMD_MAX
|
||||
} ACLK_CMD;
|
||||
|
||||
typedef enum aclk_init_action {
|
||||
ACLK_INIT,
|
||||
ACLK_REINIT
|
||||
} ACLK_INIT_ACTION;
|
||||
typedef enum aclk_metadata_state {
|
||||
ACLK_METADATA_REQUIRED,
|
||||
ACLK_METADATA_CMD_QUEUED,
|
||||
ACLK_METADATA_SENT
|
||||
} ACLK_METADATA_STATE;
|
||||
|
||||
typedef enum agent_state {
|
||||
AGENT_INITIALIZING,
|
||||
AGENT_STABLE
|
||||
} AGENT_STATE;
|
||||
|
||||
typedef enum aclk_init_action { ACLK_INIT, ACLK_REINIT } ACLK_INIT_ACTION;
|
||||
|
||||
void *aclk_main(void *ptr);
|
||||
|
||||
#define NETDATA_ACLK_HOOK \
|
||||
{ \
|
||||
.name = "ACLK_Main", \
|
||||
.config_section = NULL, \
|
||||
.config_name = NULL, \
|
||||
.enabled = 1, \
|
||||
.thread = NULL, \
|
||||
.init_routine = NULL, \
|
||||
.start_routine = aclk_main \
|
||||
},
|
||||
#define NETDATA_ACLK_HOOK \
|
||||
{ .name = "ACLK_Main", \
|
||||
.config_section = NULL, \
|
||||
.config_name = NULL, \
|
||||
.enabled = 1, \
|
||||
.thread = NULL, \
|
||||
.init_routine = NULL, \
|
||||
.start_routine = aclk_main },
|
||||
|
||||
extern int aclk_send_message(char *sub_topic, char *message, char *msg_id);
|
||||
|
||||
@ -83,23 +80,21 @@ extern int aclk_send_message(char *sub_topic, char *message, char *msg_id);
|
||||
extern char *is_agent_claimed(void);
|
||||
char *create_uuid();
|
||||
|
||||
|
||||
// callbacks for agent cloud link
|
||||
int aclk_subscribe(char *topic, int qos);
|
||||
void aclk_shutdown();
|
||||
int cloud_to_agent_parse(JSON_ENTRY *e);
|
||||
void aclk_disconnect(void *conn);
|
||||
void aclk_connect(void *conn);
|
||||
void aclk_disconnect();
|
||||
void aclk_connect();
|
||||
int aclk_send_metadata();
|
||||
int aclk_send_info_metadata();
|
||||
int aclk_wait_for_initialization();
|
||||
char *create_publish_base_topic();
|
||||
void aclk_try_to_connect();
|
||||
|
||||
int aclk_send_single_chart(char *host, char *chart);
|
||||
int aclk_queue_query(char *token, char *data, char *msg_type, char *query, int run_after, int internal, ACLK_CMD cmd);
|
||||
struct aclk_query *aclk_query_find(char *token, char *data, char *msg_id,
|
||||
char *query, ACLK_CMD cmd, struct aclk_query **last_query);
|
||||
struct aclk_query *
|
||||
aclk_query_find(char *token, char *data, char *msg_id, char *query, ACLK_CMD cmd, struct aclk_query **last_query);
|
||||
int aclk_update_chart(RRDHOST *host, char *chart_name, ACLK_CMD aclk_cmd);
|
||||
int aclk_update_alarm(RRDHOST *host, ALARM_ENTRY *ae);
|
||||
void aclk_create_header(BUFFER *dest, char *type, char *msg_id);
|
||||
@ -116,5 +111,4 @@ extern void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST
|
||||
void aclk_single_update_enable();
|
||||
void aclk_single_update_disable();
|
||||
|
||||
|
||||
#endif //NETDATA_AGENT_CLOUD_LINK_H
|
||||
|
220
aclk/mqtt.c
220
aclk/mqtt.c
@ -5,62 +5,14 @@
|
||||
#include "mqtt.h"
|
||||
#include "aclk_lws_wss_client.h"
|
||||
|
||||
void (*_on_connect)(void *ptr) = NULL;
|
||||
void (*_on_disconnect)(void *ptr) = NULL;
|
||||
|
||||
#ifndef ENABLE_ACLK
|
||||
|
||||
inline const char *_link_strerror(int rc)
|
||||
{
|
||||
UNUSED(rc);
|
||||
return "no error";
|
||||
}
|
||||
|
||||
int _link_event_loop(int timeout)
|
||||
{
|
||||
UNUSED(timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _link_send_message(char *topic, char *message, int *mid)
|
||||
{
|
||||
UNUSED(topic);
|
||||
UNUSED(message);
|
||||
UNUSED(mid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _link_subscribe(char *topic, int qos)
|
||||
{
|
||||
UNUSED(topic);
|
||||
UNUSED(qos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _link_shutdown()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int _link_lib_init(char *aclk_hostname, int aclk_port, void (*on_connect)(void *), void (*on_disconnect)(void *))
|
||||
{
|
||||
UNUSED(aclk_hostname);
|
||||
UNUSED(aclk_port);
|
||||
UNUSED(on_connect);
|
||||
UNUSED(on_disconnect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct mosquitto *mosq = NULL;
|
||||
|
||||
// Get a string description of the error
|
||||
inline const char *_link_strerror(int rc)
|
||||
{
|
||||
return mosquitto_strerror(rc);
|
||||
}
|
||||
|
||||
static struct mosquitto *mosq = NULL;
|
||||
|
||||
|
||||
void mqtt_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg)
|
||||
{
|
||||
UNUSED(mosq);
|
||||
@ -69,12 +21,6 @@ void mqtt_message_callback(struct mosquitto *mosq, void *obj, const struct mosqu
|
||||
aclk_handle_cloud_request(msg->payload);
|
||||
}
|
||||
|
||||
// This is not define because in future we might want to try plain
|
||||
// MQTT as fallback ?
|
||||
// e.g. try 1st MQTT-WSS, 2nd MQTT plain, 3rd https fallback...
|
||||
int mqtt_over_websockets = 1;
|
||||
struct aclk_lws_wss_engine_instance *lws_engine_instance = NULL;
|
||||
|
||||
void publish_callback(struct mosquitto *mosq, void *obj, int rc)
|
||||
{
|
||||
UNUSED(mosq);
|
||||
@ -87,29 +33,26 @@ void publish_callback(struct mosquitto *mosq, void *obj, int rc)
|
||||
|
||||
void connect_callback(struct mosquitto *mosq, void *obj, int rc)
|
||||
{
|
||||
UNUSED(mosq);
|
||||
UNUSED(obj);
|
||||
UNUSED(rc);
|
||||
|
||||
info("Connection to cloud estabilished");
|
||||
|
||||
aclk_mqtt_connected = 1;
|
||||
_on_connect((void *)mosq);
|
||||
aclk_connect();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
|
||||
{
|
||||
UNUSED(mosq);
|
||||
UNUSED(obj);
|
||||
UNUSED(rc);
|
||||
|
||||
info("Connection to cloud failed");
|
||||
aclk_disconnect();
|
||||
|
||||
aclk_mqtt_connected = 0;
|
||||
_on_disconnect((void *)mosq);
|
||||
|
||||
if (mqtt_over_websockets && lws_engine_instance)
|
||||
aclk_lws_wss_mqtt_layer_disconect_notif(lws_engine_instance);
|
||||
aclk_lws_wss_mqtt_layer_disconect_notif();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -126,24 +69,25 @@ void _show_mqtt_info()
|
||||
|
||||
size_t _mqtt_external_write_hook(void *buf, size_t count)
|
||||
{
|
||||
return aclk_lws_wss_client_write(lws_engine_instance, buf, count);
|
||||
return aclk_lws_wss_client_write(buf, count);
|
||||
}
|
||||
|
||||
size_t _mqtt_external_read_hook(void *buf, size_t count)
|
||||
{
|
||||
return aclk_lws_wss_client_read(lws_engine_instance, buf, count);
|
||||
return aclk_lws_wss_client_read(buf, count);
|
||||
}
|
||||
|
||||
int _mqtt_lib_init(void (*on_connect)(void *), void (*on_disconnect)(void *))
|
||||
int _mqtt_lib_init()
|
||||
{
|
||||
int rc;
|
||||
int libmosq_major, libmosq_minor, libmosq_revision, libmosq_version;
|
||||
//int libmosq_major, libmosq_minor, libmosq_revision, libmosq_version;
|
||||
/* Commenting out now as it is unused - do not delete, this is needed for the on-prem version.
|
||||
char *ca_crt;
|
||||
char *server_crt;
|
||||
char *server_key;
|
||||
|
||||
// show library info so can have it in the logfile
|
||||
libmosq_version = mosquitto_lib_version(&libmosq_major, &libmosq_minor, &libmosq_revision);
|
||||
//libmosq_version = mosquitto_lib_version(&libmosq_major, &libmosq_minor, &libmosq_revision);
|
||||
ca_crt = config_get(CONFIG_SECTION_ACLK, "agent cloud link cert", "*");
|
||||
server_crt = config_get(CONFIG_SECTION_ACLK, "agent cloud link server cert", "*");
|
||||
server_key = config_get(CONFIG_SECTION_ACLK, "agent cloud link server key", "*");
|
||||
@ -162,6 +106,7 @@ int _mqtt_lib_init(void (*on_connect)(void *), void (*on_disconnect)(void *))
|
||||
freez(server_key);
|
||||
server_key = NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
// info(
|
||||
// "Detected libmosquitto library version %d, %d.%d.%d", libmosq_version, libmosq_major, libmosq_minor,
|
||||
@ -172,24 +117,28 @@ int _mqtt_lib_init(void (*on_connect)(void *), void (*on_disconnect)(void *))
|
||||
error("Failed to initialize MQTT (libmosquitto library)");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
mosq = mosquitto_new("anon", true, NULL);
|
||||
static int _mqtt_create_connection(char *username, char *password)
|
||||
{
|
||||
if (mosq != NULL)
|
||||
mosquitto_destroy(mosq);
|
||||
mosq = mosquitto_new(username, true, NULL);
|
||||
if (unlikely(!mosq)) {
|
||||
mosquitto_lib_cleanup();
|
||||
error("MQTT new structure -- %s", mosquitto_strerror(errno));
|
||||
return 1;
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
_on_connect = on_connect;
|
||||
_on_disconnect = on_disconnect;
|
||||
|
||||
mosquitto_connect_callback_set(mosq, connect_callback);
|
||||
mosquitto_disconnect_callback_set(mosq, disconnect_callback);
|
||||
mosquitto_publish_callback_set(mosq, publish_callback);
|
||||
|
||||
mosquitto_username_pw_set(mosq, NULL, NULL);
|
||||
info("Using challenge-response: %s / %s", username, password);
|
||||
mosquitto_username_pw_set(mosq, username, password);
|
||||
|
||||
rc = mosquitto_threaded_set(mosq, 1);
|
||||
int rc = mosquitto_threaded_set(mosq, 1);
|
||||
if (unlikely(rc != MOSQ_ERR_SUCCESS))
|
||||
error("Failed to tune the thread model for libmoquitto (%s)", mosquitto_strerror(rc));
|
||||
|
||||
@ -202,19 +151,10 @@ int _mqtt_lib_init(void (*on_connect)(void *), void (*on_disconnect)(void *))
|
||||
info("MQTT in flight messages set to 1 -- %s", mosquitto_strerror(rc));
|
||||
#endif
|
||||
|
||||
if (!mqtt_over_websockets) {
|
||||
rc = mosquitto_reconnect_delay_set(mosq, ACLK_RECONNECT_DELAY, ACLK_MAX_BACKOFF_DELAY, 1);
|
||||
|
||||
if (unlikely(rc != MOSQ_ERR_SUCCESS))
|
||||
error("Failed to set the reconnect delay (%d) (%s)", rc, mosquitto_strerror(rc));
|
||||
|
||||
mosquitto_tls_set(mosq, ca_crt, NULL, server_crt, server_key, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int _link_mqtt_connect(char *aclk_hostname, int aclk_port)
|
||||
static int _link_mqtt_connect(char *aclk_hostname, int aclk_port)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@ -234,9 +174,6 @@ static inline void _link_mosquitto_write()
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!mqtt_over_websockets)
|
||||
return;
|
||||
|
||||
rc = mosquitto_loop_misc(mosq);
|
||||
if (unlikely(rc != MOSQ_ERR_SUCCESS))
|
||||
debug(D_ACLK, "ACLK: failure during mosquitto_loop_misc %s", mosquitto_strerror(rc));
|
||||
@ -248,15 +185,13 @@ static inline void _link_mosquitto_write()
|
||||
}
|
||||
}
|
||||
|
||||
void aclk_lws_connect_notif_callback()
|
||||
void aclk_lws_connection_established(char *hostname, int port)
|
||||
{
|
||||
//the connection is done by LWS so this parameters dont matter
|
||||
//ig MQTT over LWS is used
|
||||
_link_mqtt_connect(aclk_hostname, aclk_port);
|
||||
_link_mqtt_connect(hostname, port); // Parameters only used for logging, lower layer connected.
|
||||
_link_mosquitto_write();
|
||||
}
|
||||
|
||||
void aclk_lws_data_received_callback()
|
||||
void aclk_lws_connection_data_received()
|
||||
{
|
||||
int rc = mosquitto_loop_read(mosq, 1);
|
||||
if (rc != MOSQ_ERR_SUCCESS)
|
||||
@ -268,85 +203,31 @@ void aclk_lws_connection_closed()
|
||||
aclk_disconnect(NULL);
|
||||
}
|
||||
|
||||
static const struct aclk_lws_wss_engine_callbacks aclk_lws_engine_callbacks = {
|
||||
.connection_established_callback = aclk_lws_connect_notif_callback,
|
||||
.data_rcvd_callback = aclk_lws_data_received_callback,
|
||||
.data_writable_callback = NULL,
|
||||
.connection_closed = aclk_lws_connection_closed
|
||||
};
|
||||
|
||||
int _link_lib_init(char *aclk_hostname, int aclk_port, void (*on_connect)(void *), void (*on_disconnect)(void *))
|
||||
int mqtt_attempt_connection(char *aclk_hostname, int aclk_port, char *username, char *password)
|
||||
{
|
||||
int rc;
|
||||
if(aclk_lws_wss_connect(aclk_hostname, aclk_port))
|
||||
return MOSQ_ERR_UNKNOWN;
|
||||
aclk_lws_wss_service_loop();
|
||||
|
||||
if (mqtt_over_websockets) {
|
||||
// we will connect when WebSocket connection is up
|
||||
// based on callback
|
||||
if (!lws_engine_instance)
|
||||
lws_engine_instance = aclk_lws_wss_client_init(&aclk_lws_engine_callbacks, aclk_hostname, aclk_port);
|
||||
else
|
||||
aclk_lws_wss_connect(lws_engine_instance);
|
||||
|
||||
aclk_lws_wss_service_loop(lws_engine_instance);
|
||||
}
|
||||
|
||||
rc = _mqtt_lib_init(on_connect, on_disconnect);
|
||||
if (rc != MOSQ_ERR_SUCCESS)
|
||||
int rc = _mqtt_create_connection(username, password);
|
||||
if (rc!= MOSQ_ERR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
if (mqtt_over_websockets) {
|
||||
mosquitto_external_callbacks_set(mosq, _mqtt_external_write_hook, _mqtt_external_read_hook);
|
||||
if (!lws_engine_instance)
|
||||
return 1;
|
||||
else
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
} else {
|
||||
// if direct mqtt connection is used
|
||||
// connect immediatelly
|
||||
return _link_mqtt_connect(aclk_hostname, aclk_port);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int _link_event_loop_wss()
|
||||
{
|
||||
if (unlikely(!lws_engine_instance)) {
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
if (lws_engine_instance && lws_engine_instance->websocket_connection_up)
|
||||
_link_mosquitto_write();
|
||||
|
||||
aclk_lws_wss_service_loop(lws_engine_instance);
|
||||
// this is because if use LWS we don't want
|
||||
// mqtt to reconnect by itself
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int _link_event_loop_plain_mqtt(int timeout)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = mosquitto_loop(mosq, timeout, 1);
|
||||
|
||||
if (unlikely(rc != MOSQ_ERR_SUCCESS)) {
|
||||
errno = 0;
|
||||
error("Loop error code %d (%s)", rc, mosquitto_strerror(rc));
|
||||
rc = mosquitto_reconnect(mosq);
|
||||
if (unlikely(rc != MOSQ_ERR_SUCCESS)) {
|
||||
error("Reconnect loop error code %d (%s)", rc, mosquitto_strerror(rc));
|
||||
}
|
||||
// TBD: Using delay
|
||||
sleep_usec(USEC_PER_SEC * 10);
|
||||
}
|
||||
mosquitto_external_callbacks_set(mosq, _mqtt_external_write_hook, _mqtt_external_read_hook);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int _link_event_loop(int timeout)
|
||||
inline int _link_event_loop()
|
||||
{
|
||||
if (mqtt_over_websockets)
|
||||
return _link_event_loop_wss();
|
||||
|
||||
return _link_event_loop_plain_mqtt(timeout);
|
||||
// TODO: Check if we need to flush undelivered messages from libmosquitto on new connection attempts (QoS=1).
|
||||
_link_mosquitto_write();
|
||||
aclk_lws_wss_service_loop();
|
||||
|
||||
// this is because if use LWS we don't want
|
||||
// mqtt to reconnect by itself
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
void _link_shutdown()
|
||||
@ -366,12 +247,7 @@ void _link_shutdown()
|
||||
mosquitto_destroy(mosq);
|
||||
mosq = NULL;
|
||||
|
||||
if (lws_engine_instance) {
|
||||
aclk_lws_wss_client_destroy(lws_engine_instance);
|
||||
lws_engine_instance = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
aclk_lws_wss_client_destroy();
|
||||
}
|
||||
|
||||
int _link_subscribe(char *topic, int qos)
|
||||
@ -391,7 +267,6 @@ int _link_subscribe(char *topic, int qos)
|
||||
}
|
||||
|
||||
_link_mosquitto_write();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -418,9 +293,6 @@ int _link_send_message(char *topic, char *message, int *mid)
|
||||
errno = 0;
|
||||
error("MQTT message failed : %s", mosquitto_strerror(rc));
|
||||
}
|
||||
|
||||
_link_mosquitto_write();
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
11
aclk/mqtt.h
11
aclk/mqtt.h
@ -8,18 +8,15 @@
|
||||
#endif
|
||||
|
||||
void _show_mqtt_info();
|
||||
int _link_event_loop(int timeout);
|
||||
int _link_event_loop();
|
||||
void _link_shutdown();
|
||||
int _link_lib_init(char *aclk_hostname, int aclk_port, void (*on_connect)(void *), void (*on_disconnect)(void *));
|
||||
int mqtt_attempt_connection(char *aclk_hostname, int aclk_port, char *username, char *password);
|
||||
//int _link_lib_init();
|
||||
int _mqtt_lib_init();
|
||||
int _link_subscribe(char *topic, int qos);
|
||||
int _link_send_message(char *topic, char *message, int *mid);
|
||||
const char *_link_strerror(int rc);
|
||||
|
||||
int aclk_handle_cloud_request(char *);
|
||||
|
||||
extern int aclk_connection_initialized;
|
||||
extern int aclk_mqtt_connected;
|
||||
extern char *aclk_hostname;
|
||||
extern int aclk_port;
|
||||
|
||||
#endif //NETDATA_MQTT_H
|
||||
|
@ -19,7 +19,7 @@ RUN pacman --noconfirm --needed -S autoconf \
|
||||
pkgconfig \
|
||||
python \
|
||||
libvirt \
|
||||
libwebsockets \
|
||||
cmake \
|
||||
valgrind
|
||||
|
||||
ARG ACLK=no
|
||||
|
@ -19,7 +19,7 @@ RUN pacman --noconfirm --needed -S autoconf \
|
||||
pkgconfig \
|
||||
python \
|
||||
libvirt \
|
||||
libwebsockets
|
||||
cmake
|
||||
|
||||
ARG ACLK=no
|
||||
ARG EXTRA_CFLAGS
|
||||
@ -51,4 +51,4 @@ RUN ln -sf /dev/stdout /var/log/netdata/access.log
|
||||
RUN ln -sf /dev/stdout /var/log/netdata/debug.log
|
||||
RUN ln -sf /dev/stderr /var/log/netdata/error.log
|
||||
|
||||
CMD ["/usr/sbin/netdata", "-D"]
|
||||
CMD ["/usr/sbin/netdata", "-D"]
|
||||
|
@ -7,13 +7,13 @@ services:
|
||||
args:
|
||||
- DISTRO=arch
|
||||
- VERSION=extras
|
||||
image: arch_current_dev:latest
|
||||
image: arch_extras_dev:latest
|
||||
command: >
|
||||
sh -c "echo -n 00000000-0000-0000-0000-000000000000 >/etc/netdata/claim.d/claimed_id &&
|
||||
echo '[agent_cloud_link]' >>/etc/netdata/netdata.conf &&
|
||||
echo ' agent cloud link hostname = vernemq' >>/etc/netdata/netdata.conf &&
|
||||
echo ' agent cloud link port = 9002' >>/etc/netdata/netdata.conf &&
|
||||
/usr/sbin/valgrind --leak-check=full /usr/sbin/netdata -D"
|
||||
/usr/sbin/valgrind --leak-check=full /usr/sbin/netdata -D -W debug_flags=0x200000000"
|
||||
ports:
|
||||
- 20000:19999
|
||||
|
||||
|
@ -36,8 +36,10 @@ extern struct registry registry;
|
||||
/* rrd_init() must have been called before this function */
|
||||
void claim_agent(char *claiming_arguments)
|
||||
{
|
||||
#ifndef ENABLE_ACLK
|
||||
info("The claiming feature is under development and still subject to change before the next release");
|
||||
return;
|
||||
#endif
|
||||
|
||||
int exit_code;
|
||||
pid_t command_pid;
|
||||
|
@ -93,6 +93,7 @@
|
||||
#define CONFIG_SECTION_STREAM "stream"
|
||||
#define CONFIG_SECTION_EXPORTING "exporting:global"
|
||||
#define CONFIG_SECTION_HOST_LABEL "host labels"
|
||||
#define CONFIG_SECTION_ACLK "agent_cloud_link"
|
||||
#define EXPORTING_CONF "exporting.conf"
|
||||
|
||||
// these are used to limit the configuration names and values lengths
|
||||
|
@ -84,7 +84,7 @@ void security_openssl_common_options(SSL_CTX *ctx) {
|
||||
*
|
||||
* @return It returns the context on success or NULL otherwise
|
||||
*/
|
||||
static SSL_CTX * security_initialize_openssl_client() {
|
||||
SSL_CTX * security_initialize_openssl_client() {
|
||||
SSL_CTX *ctx;
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
|
@ -41,6 +41,7 @@ void security_clean_openssl();
|
||||
void security_start_ssl(int selector);
|
||||
int security_process_accept(SSL *ssl,int msg);
|
||||
int security_test_certificate(SSL *ssl);
|
||||
SSL_CTX * security_initialize_openssl_client();
|
||||
|
||||
# endif //ENABLE_HTTPS
|
||||
#endif //NETDATA_SECURITY_H
|
||||
|
@ -607,7 +607,7 @@ static inline int connect_to_unix(const char *path, struct timeval *timeout) {
|
||||
// service the service name or port to connect to
|
||||
// timeout the timeout for establishing a connection
|
||||
|
||||
static inline int connect_to_this_ip46(int protocol, int socktype, const char *host, uint32_t scope_id, const char *service, struct timeval *timeout) {
|
||||
int connect_to_this_ip46(int protocol, int socktype, const char *host, uint32_t scope_id, const char *service, struct timeval *timeout) {
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *ai_head = NULL, *ai = NULL;
|
||||
|
||||
|
@ -56,6 +56,7 @@ extern void listen_sockets_close(LISTEN_SOCKETS *sockets);
|
||||
|
||||
extern int connect_to_this(const char *definition, int default_port, struct timeval *timeout);
|
||||
extern int connect_to_one_of(const char *destination, int default_port, struct timeval *timeout, size_t *reconnects_counter, char *connected_to, size_t connected_to_size);
|
||||
int connect_to_this_ip46(int protocol, int socktype, const char *host, uint32_t scope_id, const char *service, struct timeval *timeout);
|
||||
|
||||
#ifdef ENABLE_HTTPS
|
||||
extern ssize_t recv_timeout(struct netdata_ssl *ssl,int sockfd, void *buf, size_t len, int flags, int timeout);
|
||||
|
Loading…
Reference in New Issue
Block a user