@cryptotaxi247 / netdata-1 / commits / fbeee6b12

Misc mqtt related code cleanup (#18622)

* Remove pthread locks / use spinlocks * Remove redundant checks as mallocz, callocz can't return NULL * Change logging More code cleanup * Change random number generation Set Origin to empty Use BCryptGenRandom * More cleanup Deduplicate base64_encode/decode * Address review comments

Stelios Fragkakis committed Sep 29, 2024 at 20:42 UTC fbeee6b12268b9fea06bdae93463eec5deabc68f
20 files changed +546 -1016
CMakeLists.txt
+1 -3
@@ -1555,8 +1555,6 @@ endif()
1555 set(MQTT_WEBSOCKETS_FILES
1556 src/aclk/mqtt_websockets/mqtt_wss_client.c
1557 src/aclk/mqtt_websockets/mqtt_wss_client.h
1558 - src/aclk/mqtt_websockets/mqtt_wss_log.c
1559 - src/aclk/mqtt_websockets/mqtt_wss_log.h
1558 src/aclk/mqtt_websockets/ws_client.c
1559 src/aclk/mqtt_websockets/ws_client.h
1560 src/aclk/mqtt_websockets/mqtt_ng.c
@@ -1721,7 +1719,7 @@ target_include_directories(libnetdata BEFORE PUBLIC ${CONFIG_H_DIR} ${CMAKE_SOUR
1719 target_link_libraries(libnetdata PUBLIC
1720 "$<$<NOT:$<BOOL:${HAVE_BUILTIN_ATOMICS}>>:atomic>"
1721 "$<$<OR:$<BOOL:${OS_LINUX}>,$<BOOL:${OS_FREEBSD}>>:pthread;rt>"
1724 - "$<$<BOOL:${OS_WINDOWS}>:kernel32;advapi32;winmm;rpcrt4>"
1722 + "$<$<BOOL:${OS_WINDOWS}>:kernel32;advapi32;winmm;rpcrt4;bcrypt>"
1723 "$<$<BOOL:${LINK_LIBM}>:m>"
1724 "${SYSTEMD_LDFLAGS}")
1725
src/aclk/aclk.c
+8 -32
@@ -226,30 +226,6 @@ static int wait_till_agent_claim_ready()
226 return 1;
227 }
228
229 -void aclk_mqtt_wss_log_cb(mqtt_wss_log_type_t log_type, const char* str)
230 -{
231 - switch(log_type) {
232 - case MQTT_WSS_LOG_ERROR:
233 - case MQTT_WSS_LOG_FATAL:
234 - nd_log(NDLS_DAEMON, NDLP_ERR, "%s", str);
235 - return;
236 -
237 - case MQTT_WSS_LOG_WARN:
238 - nd_log(NDLS_DAEMON, NDLP_WARNING, "%s", str);
239 - return;
240 -
241 - case MQTT_WSS_LOG_INFO:
242 - nd_log(NDLS_DAEMON, NDLP_INFO, "%s", str);
243 - return;
244 -
245 - case MQTT_WSS_LOG_DEBUG:
246 - return;
247 -
248 - default:
249 - nd_log(NDLS_DAEMON, NDLP_ERR, "Unknown log type from mqtt_wss");
250 - }
251 -}
252 -
229 static void msg_callback(const char *topic, const void *msg, size_t msglen, int qos)
230 {
231 UNUSED(qos);
@@ -362,7 +338,7 @@ static inline void mqtt_connected_actions(mqtt_wss_client client)
338 aclk_rcvd_cloud_msgs = 0;
339 aclk_connection_counter++;
340
365 - aclk_topic_cache_iter_t iter = ACLK_TOPIC_CACHE_ITER_T_INITIALIZER;
341 + size_t iter = 0;
342 while ((topic = (char*)aclk_topic_cache_iterate(&iter)) != NULL)
343 mqtt_wss_set_topic_alias(client, topic);
344
@@ -768,7 +744,7 @@ static int aclk_attempt_to_connect(mqtt_wss_client client)
744 */
745 void *aclk_main(void *ptr)
746 {
771 - struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
747 + struct netdata_static_thread *static_thread = ptr;
748
749 ACLK_PROXY_TYPE proxy_type;
750 aclk_get_proxy(&proxy_type);
@@ -783,7 +759,7 @@ void *aclk_main(void *ptr)
759 if (wait_till_agent_claim_ready())
760 goto exit;
761
786 - if (!(mqttwss_client = mqtt_wss_new("mqtt_wss", aclk_mqtt_wss_log_cb, msg_callback, puback_callback))) {
762 + if (!((mqttwss_client = mqtt_wss_new(msg_callback, puback_callback)))) {
763 netdata_log_error("Couldn't initialize MQTT_WSS network library");
764 goto exit;
765 }
@@ -1025,22 +1001,22 @@ char *aclk_state(void)
1001 }
1002
1003 buffer_sprintf(wb, "Online: %s\nReconnect count: %d\nBanned By Cloud: %s\n", aclk_online() ? "Yes" : "No", aclk_connection_counter > 0 ? (aclk_connection_counter - 1) : 0, aclk_disable_runtime ? "Yes" : "No");
1028 - if (last_conn_time_mqtt && (tmptr = localtime_r(&last_conn_time_mqtt, &tmbuf)) ) {
1004 + if (last_conn_time_mqtt && ((tmptr = localtime_r(&last_conn_time_mqtt, &tmbuf))) ) {
1005 char timebuf[26];
1006 strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
1007 buffer_sprintf(wb, "Last Connection Time: %s\n", timebuf);
1008 }
1033 - if (last_conn_time_appl && (tmptr = localtime_r(&last_conn_time_appl, &tmbuf)) ) {
1009 + if (last_conn_time_appl && ((tmptr = localtime_r(&last_conn_time_appl, &tmbuf))) ) {
1010 char timebuf[26];
1011 strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
1012 buffer_sprintf(wb, "Last Connection Time + %d PUBACKs received: %s\n", ACLK_PUBACKS_CONN_STABLE, timebuf);
1013 }
1038 - if (last_disconnect_time && (tmptr = localtime_r(&last_disconnect_time, &tmbuf)) ) {
1014 + if (last_disconnect_time && ((tmptr = localtime_r(&last_disconnect_time, &tmbuf))) ) {
1015 char timebuf[26];
1016 strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
1017 buffer_sprintf(wb, "Last Disconnect Time: %s\n", timebuf);
1018 }
1043 - if (!aclk_connected && next_connection_attempt && (tmptr = localtime_r(&next_connection_attempt, &tmbuf)) ) {
1019 + if (!aclk_connected && next_connection_attempt && ((tmptr = localtime_r(&next_connection_attempt, &tmbuf))) ) {
1020 char timebuf[26];
1021 strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
1022 buffer_sprintf(wb, "Next Connection Attempt At: %s\nLast Backoff: %.3f", timebuf, last_backoff_value);
@@ -1107,7 +1083,7 @@ static void fill_alert_status_for_host_json(json_object *obj, RRDHOST *host)
1083 static json_object *timestamp_to_json(const time_t *t)
1084 {
1085 struct tm *tmptr, tmbuf;
1110 - if (*t && (tmptr = gmtime_r(t, &tmbuf)) ) {
1086 + if (*t && ((tmptr = gmtime_r(t, &tmbuf))) ) {
1087 char timebuf[26];
1088 strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tmptr);
1089 return json_object_new_string(timebuf);
src/aclk/aclk_otp.c
+5 -37
@@ -267,40 +267,8 @@ exit:
267 }
268 #endif
269
270 -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
271 -static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
272 -{
273 - EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
274 -
275 - if (ctx != NULL) {
276 - memset(ctx, 0, sizeof(*ctx));
277 - }
278 - return ctx;
279 -}
280 -static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
281 -{
282 - OPENSSL_free(ctx);
283 - return;
284 -}
285 -#endif
286 -
270 #define CHALLENGE_LEN 256
271 #define CHALLENGE_LEN_BASE64 344
289 -inline static int base64_decode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
290 -{
291 - unsigned char remaining_data[CHALLENGE_LEN];
292 - EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
293 - EVP_DecodeInit(ctx);
294 - EVP_DecodeUpdate(ctx, out, outl, in, in_len);
295 - int remainder = 0;
296 - EVP_DecodeFinal(ctx, remaining_data, &remainder);
297 - EVP_ENCODE_CTX_free(ctx);
298 - if (remainder) {
299 - netdata_log_error("Unexpected data at EVP_DecodeFinal");
300 - return 1;
301 - }
302 - return 0;
303 -}
272
273 #define OTP_URL_PREFIX "/api/v1/auth/node/"
274 int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **challenge, int *challenge_bytes, bool *fallback_ipv4)
@@ -347,7 +315,7 @@ int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **
315 goto cleanup_json;
316 }
317 const char *challenge_base64;
350 - if (!(challenge_base64 = json_object_get_string(challenge_json))) {
318 + if (!((challenge_base64 = json_object_get_string(challenge_json)))) {
319 netdata_log_error("Failed to extract challenge from JSON object");
320 goto cleanup_json;
321 }
@@ -356,8 +324,9 @@ int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **
324 goto cleanup_json;
325 }
326
359 - *challenge = mallocz((CHALLENGE_LEN_BASE64 / 4) * 3);
360 - base64_decode_helper(*challenge, challenge_bytes, (const unsigned char*)challenge_base64, strlen(challenge_base64));
327 + *challenge = mallocz(CHALLENGE_LEN);
328 + *challenge_bytes = netdata_base64_decode(*challenge, (const unsigned char *) challenge_base64, CHALLENGE_LEN_BASE64);
329 +
330 if (*challenge_bytes != CHALLENGE_LEN) {
331 netdata_log_error("Unexpected challenge length of %d instead of %d", *challenge_bytes, CHALLENGE_LEN);
332 freez(*challenge);
@@ -375,7 +344,6 @@ cleanup_resp:
344
345 int aclk_send_otp_response(const char *agent_id, const unsigned char *response, int response_bytes, url_t *target, struct auth_data *mqtt_auth, bool *fallback_ipv4)
346 {
378 - int len;
347 int rc = 1;
348 https_req_t req = HTTPS_REQ_T_INITIALIZER;
349 https_req_response_t resp = HTTPS_REQ_RESPONSE_T_INITIALIZER;
@@ -387,7 +355,7 @@ int aclk_send_otp_response(const char *agent_id, const unsigned char *response,
355 unsigned char base64[CHALLENGE_LEN_BASE64 + 1];
356 memset(base64, 0, CHALLENGE_LEN_BASE64 + 1);
357
390 - base64_encode_helper(base64, &len, response, response_bytes);
358 + (void) netdata_base64_encode(base64, response, response_bytes);
359
360 BUFFER *url = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20, &netdata_buffers_statistics.buffers_aclk);
361 BUFFER *resp_json = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20, &netdata_buffers_statistics.buffers_aclk);
src/aclk/aclk_tx_msgs.c
+1 -1
@@ -77,7 +77,7 @@ static short aclk_send_message_with_bin_payload(mqtt_wss_client client, json_obj
77
78 int rc = mqtt_wss_publish5(client, (char*)topic, NULL, full_msg, &freez_aclk_publish5b, full_msg_len, MQTT_WSS_PUB_QOS1, &packet_id);
79
80 - if (rc == MQTT_WSS_ERR_TOO_BIG_FOR_SERVER)
80 + if (rc == MQTT_WSS_ERR_MSG_TOO_BIG)
81 return HTTP_RESP_CONTENT_TOO_LONG;
82
83 return 0;
src/aclk/aclk_util.c
+1 -42
@@ -309,7 +309,7 @@ const char *aclk_get_topic(enum aclk_topics topic)
309 * having to resort to callbacks.
310 */
311
312 -const char *aclk_topic_cache_iterate(aclk_topic_cache_iter_t *iter)
312 +const char *aclk_topic_cache_iterate(size_t *iter)
313 {
314 if (!aclk_topic_cache) {
315 netdata_log_error("Topic cache not initialized when %s was called.", __FUNCTION__);
@@ -434,44 +434,3 @@ void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt
434
435 freez(proxy);
436 }
437 -
438 -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
439 -static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
440 -{
441 - EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
442 -
443 - if (ctx != NULL) {
444 - memset(ctx, 0, sizeof(*ctx));
445 - }
446 - return ctx;
447 -}
448 -static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
449 -{
450 - OPENSSL_free(ctx);
451 - return;
452 -}
453 -#endif
454 -
455 -int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
456 -{
457 - int len;
458 - unsigned char *str = out;
459 - EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
460 - EVP_EncodeInit(ctx);
461 - EVP_EncodeUpdate(ctx, str, outl, in, in_len);
462 - str += *outl;
463 - EVP_EncodeFinal(ctx, str, &len);
464 - *outl += len;
465 -
466 - str = out;
467 - while(*str) {
468 - if (*str != 0x0D && *str != 0x0A)
469 - *out++ = *str++;
470 - else
471 - str++;
472 - }
473 - *out = 0;
474 -
475 - EVP_ENCODE_CTX_free(ctx);
476 - return 0;
477 -}
src/aclk/aclk_util.h
+2 -9
@@ -93,15 +93,10 @@ enum aclk_topics {
93 ACLK_TOPICID_CTXS_UPDATED = 20
94 };
95
96 -typedef size_t aclk_topic_cache_iter_t;
97 -#define ACLK_TOPIC_CACHE_ITER_T_INITIALIZER (0)
98 -
96 const char *aclk_get_topic(enum aclk_topics topic);
100 -int aclk_generate_topic_cache(struct json_object *json);
97 +int aclk_generate_topic_cache(json_object *json);
98 void free_topic_cache(void);
102 -const char *aclk_topic_cache_iterate(aclk_topic_cache_iter_t *iter);
103 -// TODO
104 -// aclk_topics_reload //when claim id changes
99 +const char *aclk_topic_cache_iterate(size_t *iter);
100
101 #ifdef ACLK_LOG_CONVERSATION_DIR
102 extern volatile int aclk_conversation_log_counter;
@@ -113,6 +108,4 @@ unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, un
108
109 void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type);
110
116 -int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len);
117 -
111 #endif /* ACLK_UTIL_H */
src/aclk/https_client.c
+1 -2
@@ -556,7 +556,7 @@ static int handle_http_request(https_req_ctx_t *ctx) {
556 // we remove those but during encoding we need that space in the buffer
557 creds_base64_len += (1+(creds_base64_len/64)) * strlen("\n");
558 char *creds_base64 = callocz(1, creds_base64_len + 1);
559 - base64_encode_helper((unsigned char*)creds_base64, &creds_base64_len, (unsigned char*)creds_plain, creds_plain_len);
559 + (void) netdata_base64_encode((unsigned char *)creds_base64, (unsigned char *)creds_plain, creds_plain_len);
560 buffer_sprintf(hdr, "Proxy-Authorization: Basic %s\x0D\x0A", creds_base64);
561 freez(creds_plain);
562 }
@@ -584,7 +584,6 @@ static int handle_http_request(https_req_ctx_t *ctx) {
584 if (ctx->parse_ctx.chunked_response)
585 freez(ctx->parse_ctx.chunked_response);
586 rc = 4;
587 - goto err_exit;
587 }
588
589 err_exit:
src/aclk/mqtt_websockets/mqtt_ng.c
+210 -281
@@ -8,16 +8,8 @@
8
9 #include "common_internal.h"
10 #include "mqtt_constants.h"
11 -#include "mqtt_wss_log.h"
11 #include "mqtt_ng.h"
12
14 -#define UNIT_LOG_PREFIX "mqtt_client: "
15 -#define FATAL(fmt, ...) mws_fatal(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
16 -#define ERROR(fmt, ...) mws_error(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
17 -#define WARN(fmt, ...) mws_warn (client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
18 -#define INFO(fmt, ...) mws_info (client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
19 -#define DEBUG(fmt, ...) mws_debug(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
20 -
13 #define SMALL_STRING_DONT_FRAGMENT_LIMIT 128
14
15 #define LOCK_HDR_BUFFER(buffer) spinlock_lock(&((buffer)->spinlock))
@@ -216,7 +208,7 @@ struct topic_aliases_data {
208 c_rhash stoi_dict;
209 uint32_t idx_max;
210 uint32_t idx_assigned;
219 - pthread_rwlock_t rwlock;
211 + SPINLOCK spinlock;
212 };
213
214 struct mqtt_ng_client {
@@ -226,8 +218,6 @@ struct mqtt_ng_client {
218
219 mqtt_msg_data connect_msg;
220
229 - mqtt_wss_log_ctx_t log;
230 -
221 mqtt_ng_send_fnc_t send_fnc_ptr;
222 void *user_ctx;
223
@@ -245,7 +235,7 @@ struct mqtt_ng_client {
235 unsigned int ping_pending:1;
236
237 struct mqtt_ng_stats stats;
248 - pthread_mutex_t stats_mutex;
238 + SPINLOCK stats_spinlock;
239
240 struct topic_aliases_data tx_topic_aliases;
241 c_rhash rx_aliases;
@@ -399,7 +389,7 @@ enum memory_mode {
389 CALLER_RESPONSIBLE
390 };
391
402 -static inline enum memory_mode ptr2memory_mode(void * ptr) {
392 +static enum memory_mode ptr2memory_mode(void * ptr) {
393 if (ptr == NULL)
394 return MEMCPY;
395 if (ptr == CALLER_RESPONSIBILITY)
@@ -484,15 +474,8 @@ static void buffer_rebuild(struct header_buffer *buf)
474 } while(frag);
475 }
476
487 -static void buffer_garbage_collect(struct header_buffer *buf, mqtt_wss_log_ctx_t log_ctx)
477 +static void buffer_garbage_collect(struct header_buffer *buf)
478 {
489 -#if !defined(MQTT_DEBUG_VERBOSE) && !defined(ADDITIONAL_CHECKS)
490 - (void) log_ctx;
491 -#endif
492 -#ifdef MQTT_DEBUG_VERBOSE
493 - mws_debug(log_ctx, "Buffer Garbage Collection!");
494 -#endif
495 -
479 struct buffer_fragment *frag = BUFFER_FIRST_FRAG(buf);
480 while (frag) {
481 if (!frag_is_marked_for_gc(frag))
@@ -503,12 +486,8 @@ static void buffer_garbage_collect(struct header_buffer *buf, mqtt_wss_log_ctx_t
486 frag = frag->next;
487 }
488
506 - if (frag == BUFFER_FIRST_FRAG(buf)) {
507 -#ifdef MQTT_DEBUG_VERBOSE
508 - mws_debug(log_ctx, "Buffer Garbage Collection! No Space Reclaimed!");
509 -#endif
489 + if (frag == BUFFER_FIRST_FRAG(buf))
490 return;
511 - }
491
492 if (!frag) {
493 buf->tail_frag = NULL;
@@ -527,21 +506,17 @@ static void buffer_garbage_collect(struct header_buffer *buf, mqtt_wss_log_ctx_t
506 buffer_rebuild(buf);
507 }
508
530 -static void transaction_buffer_garbage_collect(struct transaction_buffer *buf, mqtt_wss_log_ctx_t log_ctx)
509 +static void transaction_buffer_garbage_collect(struct transaction_buffer *buf)
510 {
532 -#ifdef MQTT_DEBUG_VERBOSE
533 - mws_debug(log_ctx, "Transaction Buffer Garbage Collection! %s", buf->sending_frag == NULL ? "NULL" : "in flight message");
534 -#endif
535 -
511 // Invalidate the cached sending fragment
512 // as we will move data around
513 if (buf->sending_frag != &ping_frag)
514 buf->sending_frag = NULL;
515
541 - buffer_garbage_collect(&buf->hdr_buffer, log_ctx);
516 + buffer_garbage_collect(&buf->hdr_buffer);
517 }
518
544 -static int transaction_buffer_grow(struct transaction_buffer *buf, mqtt_wss_log_ctx_t log_ctx, float rate, size_t max)
519 +static int transaction_buffer_grow(struct transaction_buffer *buf, float rate, size_t max)
520 {
521 if (buf->hdr_buffer.size >= max)
522 return 0;
@@ -557,29 +532,25 @@ static int transaction_buffer_grow(struct transaction_buffer *buf, mqtt_wss_log_
532
533 void *ret = reallocz(buf->hdr_buffer.data, buf->hdr_buffer.size);
534 if (ret == NULL) {
560 - mws_warn(log_ctx, "Buffer growth failed (realloc)");
535 + nd_log(NDLS_DAEMON, NDLP_WARNING, "Buffer growth failed (realloc)");
536 return 1;
537 }
538
564 - mws_debug(log_ctx, "Message metadata buffer was grown");
539 + nd_log(NDLS_DAEMON, NDLP_DEBUG, "Message metadata buffer was grown");
540
541 buf->hdr_buffer.data = ret;
542 buffer_rebuild(&buf->hdr_buffer);
543 return 0;
544 }
545
571 -inline static int transaction_buffer_init(struct transaction_buffer *to_init, size_t size)
546 +inline static void transaction_buffer_init(struct transaction_buffer *to_init, size_t size)
547 {
548 spinlock_init(&to_init->spinlock);
549
550 to_init->hdr_buffer.size = size;
551 to_init->hdr_buffer.data = mallocz(size);
577 - if (to_init->hdr_buffer.data == NULL)
578 - return 1;
579 -
552 to_init->hdr_buffer.tail = to_init->hdr_buffer.data;
553 to_init->hdr_buffer.tail_frag = NULL;
582 - return 0;
554 }
555
556 static void transaction_buffer_destroy(struct transaction_buffer *to_init)
@@ -620,54 +591,30 @@ void transaction_buffer_transaction_rollback(struct transaction_buffer *buf, str
591 struct mqtt_ng_client *mqtt_ng_init(struct mqtt_ng_init *settings)
592 {
593 struct mqtt_ng_client *client = callocz(1, sizeof(struct mqtt_ng_client));
623 - if (client == NULL)
624 - return NULL;
594
626 - if (transaction_buffer_init(&client->main_buffer, HEADER_BUFFER_SIZE))
627 - goto err_free_client;
595 + transaction_buffer_init(&client->main_buffer, HEADER_BUFFER_SIZE);
596
597 client->rx_aliases = RX_ALIASES_INITIALIZE();
630 - if (client->rx_aliases == NULL)
631 - goto err_free_trx_buf;
598
633 - if (pthread_mutex_init(&client->stats_mutex, NULL))
634 - goto err_free_rx_alias;
599 + spinlock_init(&client->stats_spinlock);
600 + spinlock_init(&client->tx_topic_aliases.spinlock);
601
602 client->tx_topic_aliases.stoi_dict = TX_ALIASES_INITIALIZE();
637 - if (client->tx_topic_aliases.stoi_dict == NULL)
638 - goto err_free_stats_mutex;
603 client->tx_topic_aliases.idx_max = UINT16_MAX;
604
641 - if (pthread_rwlock_init(&client->tx_topic_aliases.rwlock, NULL))
642 - goto err_free_tx_alias;
643 -
605 // TODO just embed the struct into mqtt_ng_client
606 client->parser.received_data = settings->data_in;
607 client->send_fnc_ptr = settings->data_out_fnc;
608 client->user_ctx = settings->user_ctx;
609
649 - client->log = settings->log;
650 -
610 client->puback_callback = settings->puback_callback;
611 client->connack_callback = settings->connack_callback;
612 client->msg_callback = settings->msg_callback;
613
614 return client;
656 -
657 -err_free_tx_alias:
658 - c_rhash_destroy(client->tx_topic_aliases.stoi_dict);
659 -err_free_stats_mutex:
660 - pthread_mutex_destroy(&client->stats_mutex);
661 -err_free_rx_alias:
662 - c_rhash_destroy(client->rx_aliases);
663 -err_free_trx_buf:
664 - transaction_buffer_destroy(&client->main_buffer);
665 -err_free_client:
666 - freez(client);
667 - return NULL;
615 }
616
670 -static inline uint8_t get_control_packet_type(uint8_t first_hdr_byte)
617 +static uint8_t get_control_packet_type(uint8_t first_hdr_byte)
618 {
619 return first_hdr_byte >> 4;
620 }
@@ -699,33 +646,27 @@ static void mqtt_ng_destroy_tx_alias_hash(c_rhash hash)
646 void mqtt_ng_destroy(struct mqtt_ng_client *client)
647 {
648 transaction_buffer_destroy(&client->main_buffer);
702 - pthread_mutex_destroy(&client->stats_mutex);
649
650 mqtt_ng_destroy_tx_alias_hash(client->tx_topic_aliases.stoi_dict);
705 - pthread_rwlock_destroy(&client->tx_topic_aliases.rwlock);
651 mqtt_ng_destroy_rx_alias_hash(client->rx_aliases);
652
653 freez(client);
654 }
655
711 -int frag_set_external_data(mqtt_wss_log_ctx_t log, struct buffer_fragment *frag, void *data, size_t data_len, free_fnc_t data_free_fnc)
656 +int frag_set_external_data(struct buffer_fragment *frag, void *data, size_t data_len, free_fnc_t data_free_fnc)
657 {
658 if (frag->len) {
659 // TODO?: This could potentially be done in future if we set rule
660 // external data always follows in buffer data
661 // could help reduce fragmentation in some messages but
662 // currently not worth it considering time is tight
718 - mws_fatal(log, UNIT_LOG_PREFIX "INTERNAL ERROR: Cannot set external data to fragment already containing in buffer data!");
663 + nd_log(NDLS_DAEMON, NDLP_ERR, "INTERNAL ERROR: Cannot set external data to fragment already containing in buffer data!");
664 return 1;
665 }
666
667 switch (ptr2memory_mode(data_free_fnc)) {
668 case MEMCPY:
669 frag->data = mallocz(data_len);
725 - if (frag->data == NULL) {
726 - mws_error(log, UNIT_LOG_PREFIX "OOM while malloc @_optimized_add");
727 - return 1;
728 - }
670 memcpy(frag->data, data, data_len);
671 break;
672 case EXTERNAL_FREE_AFTER_USE:
@@ -807,18 +748,18 @@ static size_t mqtt_ng_connect_size(struct mqtt_auth_properties *auth,
748 #define PACK_2B_INT(buffer, integer, frag) { *(uint16_t *)WRITE_POS(frag) = htobe16((integer)); \
749 DATA_ADVANCE(buffer, sizeof(uint16_t), frag); }
750
810 -static int _optimized_add(struct header_buffer *buf, mqtt_wss_log_ctx_t log_ctx, void *data, size_t data_len, free_fnc_t data_free_fnc, struct buffer_fragment **frag)
751 +static int _optimized_add(struct header_buffer *buf, void *data, size_t data_len, free_fnc_t data_free_fnc, struct buffer_fragment **frag)
752 {
753 if (data_len > SMALL_STRING_DONT_FRAGMENT_LIMIT) {
754 buffer_frag_flag_t flags = BUFFER_FRAG_DATA_EXTERNAL;
755 if ((*frag)->flags & BUFFER_FRAG_GARBAGE_COLLECT_ON_SEND)
756 flags |= BUFFER_FRAG_GARBAGE_COLLECT_ON_SEND;
757 if( (*frag = buffer_new_frag(buf, flags)) == NULL ) {
817 - mws_error(log_ctx, "Out of buffer space while generating the message");
758 + nd_log(NDLS_DAEMON, NDLP_ERR, "Out of buffer space while generating the message");
759 return 1;
760 }
820 - if (frag_set_external_data(log_ctx, *frag, data, data_len, data_free_fnc)) {
821 - mws_error(log_ctx, "Error adding external data to newly created fragment");
761 + if (frag_set_external_data(*frag, data, data_len, data_free_fnc)) {
762 + nd_log(NDLS_DAEMON, NDLP_ERR, "Error adding external data to newly created fragment");
763 return 1;
764 }
765 // we dont want to write to this fragment anymore
@@ -833,31 +774,30 @@ static int _optimized_add(struct header_buffer *buf, mqtt_wss_log_ctx_t log_ctx,
774 return 0;
775 }
776
836 -#define TRY_GENERATE_MESSAGE(generator_function, client, ...) \
837 - int rc = generator_function(&client->main_buffer, client->log, ##__VA_ARGS__); \
777 +#define TRY_GENERATE_MESSAGE(generator_function, ...) \
778 + int rc = generator_function(&client->main_buffer, ##__VA_ARGS__); \
779 if (rc == MQTT_NG_MSGGEN_BUFFER_OOM) { \
780 LOCK_HDR_BUFFER(&client->main_buffer); \
840 - transaction_buffer_garbage_collect((&client->main_buffer), client->log); \
781 + transaction_buffer_garbage_collect((&client->main_buffer)); \
782 UNLOCK_HDR_BUFFER(&client->main_buffer); \
842 - rc = generator_function(&client->main_buffer, client->log, ##__VA_ARGS__); \
783 + rc = generator_function(&client->main_buffer, ##__VA_ARGS__); \
784 if (rc == MQTT_NG_MSGGEN_BUFFER_OOM && client->max_mem_bytes) { \
785 LOCK_HDR_BUFFER(&client->main_buffer); \
845 - transaction_buffer_grow((&client->main_buffer), client->log, GROWTH_FACTOR, client->max_mem_bytes); \
786 + transaction_buffer_grow((&client->main_buffer),GROWTH_FACTOR, client->max_mem_bytes); \
787 UNLOCK_HDR_BUFFER(&client->main_buffer); \
847 - rc = generator_function(&client->main_buffer, client->log, ##__VA_ARGS__); \
788 + rc = generator_function(&client->main_buffer, ##__VA_ARGS__); \
789 } \
790 if (rc == MQTT_NG_MSGGEN_BUFFER_OOM) \
850 - mws_error(client->log, "%s failed to generate message due to insufficient buffer space (line %d)", __FUNCTION__, __LINE__); \
791 + nd_log(NDLS_DAEMON, NDLP_ERR, "%s failed to generate message due to insufficient buffer space (line %d)", __FUNCTION__, __LINE__); \
792 } \
793 if (rc == MQTT_NG_MSGGEN_OK) { \
853 - pthread_mutex_lock(&client->stats_mutex); \
794 + spinlock_lock(&client->stats_spinlock); \
795 client->stats.tx_messages_queued++; \
855 - pthread_mutex_unlock(&client->stats_mutex); \
796 + spinlock_unlock(&client->stats_spinlock); \
797 } \
798 return rc;
799
800 mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
860 - mqtt_wss_log_ctx_t log_ctx,
801 struct mqtt_auth_properties *auth,
802 struct mqtt_lwt_properties *lwt,
803 uint8_t clean_start,
@@ -865,7 +805,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
805 {
806 // Sanity Checks First (are given parameters correct and up to MQTT spec)
807 if (!auth->client_id) {
868 - mws_error(log_ctx, "ClientID must be set. [MQTT-3.1.3-3]");
808 + nd_log(NDLS_DAEMON, NDLP_ERR, "ClientID must be set. [MQTT-3.1.3-3]");
809 return NULL;
810 }
811
@@ -876,29 +816,29 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
816 // however server MUST allow ClientIDs between 1-23 bytes [MQTT-3.1.3-5]
817 // so we will warn client server might not like this and he is using it
818 // at his own risk!
879 - mws_warn(log_ctx, "client_id provided is empty string. This might not be allowed by server [MQTT-3.1.3-6]");
819 + nd_log(NDLS_DAEMON, NDLP_WARNING, "client_id provided is empty string. This might not be allowed by server [MQTT-3.1.3-6]");
820 }
821 if(len > MQTT_MAX_CLIENT_ID) {
822 // [MQTT-3.1.3-5] server MUST allow client_id length 1-32
823 // server MAY allow longer client_id, if user provides longer client_id
824 // warn them he is doing so at his own risk!
885 - mws_warn(log_ctx, "client_id provided is longer than 23 bytes, server might not allow that [MQTT-3.1.3-5]");
825 + nd_log(NDLS_DAEMON, NDLP_WARNING, "client_id provided is longer than 23 bytes, server might not allow that [MQTT-3.1.3-5]");
826 }
827
828 if (lwt) {
829 if (lwt->will_message && lwt->will_message_size > 65535) {
890 - mws_error(log_ctx, "Will message cannot be longer than 65535 bytes due to MQTT protocol limitations [MQTT-3.1.3-4] and [MQTT-1.5.6]");
830 + nd_log(NDLS_DAEMON, NDLP_ERR, "Will message cannot be longer than 65535 bytes due to MQTT protocol limitations [MQTT-3.1.3-4] and [MQTT-1.5.6]");
831 return NULL;
832 }
833
834 if (!lwt->will_topic) { //TODO topic given with strlen==0 ? check specs
895 - mws_error(log_ctx, "If will message is given will topic must also be given [MQTT-3.1.3.3]");
835 + nd_log(NDLS_DAEMON, NDLP_ERR, "If will message is given will topic must also be given [MQTT-3.1.3.3]");
836 return NULL;
837 }
838
839 if (lwt->will_qos > MQTT_MAX_QOS) {
840 // refer to [MQTT-3-1.2-12]
901 - mws_error(log_ctx, "QOS for LWT message is bigger than max");
841 + nd_log(NDLS_DAEMON, NDLP_ERR, "QOS for LWT message is bigger than max");
842 return NULL;
843 }
844 }
@@ -932,8 +872,10 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
872 *connect_flags = 0;
873 if (auth->username)
874 *connect_flags |= MQTT_CONNECT_FLAG_USERNAME;
875 +
876 if (auth->password)
877 *connect_flags |= MQTT_CONNECT_FLAG_PASSWORD;
878 +
879 if (lwt) {
880 *connect_flags |= MQTT_CONNECT_FLAG_LWT;
881 *connect_flags |= lwt->will_qos << MQTT_CONNECT_FLAG_QOS_BITSHIFT;
@@ -957,7 +899,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
899 // [MQTT-3.1.3.1] Client identifier
900 CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
901 PACK_2B_INT(&trx_buf->hdr_buffer, strlen(auth->client_id), frag);
960 - if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, auth->client_id, strlen(auth->client_id), auth->client_id_free, &frag))
902 + if (_optimized_add(&trx_buf->hdr_buffer, auth->client_id, strlen(auth->client_id), auth->client_id_free, &frag))
903 goto fail_rollback;
904
905 if (lwt != NULL) {
@@ -971,7 +913,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
913 // Will Topic [MQTT-3.1.3.3]
914 CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
915 PACK_2B_INT(&trx_buf->hdr_buffer, strlen(lwt->will_topic), frag);
974 - if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, lwt->will_topic, strlen(lwt->will_topic), lwt->will_topic_free, &frag))
916 + if (_optimized_add(&trx_buf->hdr_buffer, lwt->will_topic, strlen(lwt->will_topic), lwt->will_topic_free, &frag))
917 goto fail_rollback;
918
919 // Will Payload [MQTT-3.1.3.4]
@@ -979,7 +921,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
921 BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
922 CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
923 PACK_2B_INT(&trx_buf->hdr_buffer, lwt->will_message_size, frag);
982 - if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, lwt->will_message, lwt->will_message_size, lwt->will_topic_free, &frag))
924 + if (_optimized_add(&trx_buf->hdr_buffer, lwt->will_message, lwt->will_message_size, lwt->will_topic_free, &frag))
925 goto fail_rollback;
926 }
927 }
@@ -989,7 +931,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
931 BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
932 CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
933 PACK_2B_INT(&trx_buf->hdr_buffer, strlen(auth->username), frag);
992 - if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, auth->username, strlen(auth->username), auth->username_free, &frag))
934 + if (_optimized_add(&trx_buf->hdr_buffer, auth->username, strlen(auth->username), auth->username_free, &frag))
935 goto fail_rollback;
936 }
937
@@ -998,7 +940,7 @@ mqtt_msg_data mqtt_ng_generate_connect(struct transaction_buffer *trx_buf,
940 BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
941 CHECK_BYTES_AVAILABLE(&trx_buf->hdr_buffer, 2, goto fail_rollback);
942 PACK_2B_INT(&trx_buf->hdr_buffer, strlen(auth->password), frag);
1001 - if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, auth->password, strlen(auth->password), auth->password_free, &frag))
943 + if (_optimized_add(&trx_buf->hdr_buffer, auth->password, strlen(auth->password), auth->password_free, &frag))
944 goto fail_rollback;
945 }
946 trx_buf->hdr_buffer.tail_frag->flags |= BUFFER_FRAG_MQTT_PACKET_TAIL;
@@ -1024,28 +966,23 @@ int mqtt_ng_connect(struct mqtt_ng_client *client,
966 buffer_purge(&client->main_buffer.hdr_buffer);
967 UNLOCK_HDR_BUFFER(&client->main_buffer);
968
1027 - pthread_rwlock_wrlock(&client->tx_topic_aliases.rwlock);
969 + spinlock_lock(&client->tx_topic_aliases.spinlock);
970 // according to MQTT spec topic aliases should not be persisted
971 // even if clean session is true
972 mqtt_ng_destroy_tx_alias_hash(client->tx_topic_aliases.stoi_dict);
973 +
974 client->tx_topic_aliases.stoi_dict = TX_ALIASES_INITIALIZE();
1032 - if (client->tx_topic_aliases.stoi_dict == NULL) {
1033 - pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
1034 - return 1;
1035 - }
975 client->tx_topic_aliases.idx_assigned = 0;
1037 - pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
976 + spinlock_unlock(&client->tx_topic_aliases.spinlock);
977
978 mqtt_ng_destroy_rx_alias_hash(client->rx_aliases);
979 client->rx_aliases = RX_ALIASES_INITIALIZE();
1041 - if (client->rx_aliases == NULL)
1042 - return 1;
980
1044 - client->connect_msg = mqtt_ng_generate_connect(&client->main_buffer, client->log, auth, lwt, clean_start, keep_alive);
981 + client->connect_msg = mqtt_ng_generate_connect(&client->main_buffer, auth, lwt, clean_start, keep_alive);
982 if (client->connect_msg == NULL)
983 return 1;
984
1048 - pthread_mutex_lock(&client->stats_mutex);
985 + spinlock_lock(&client->stats_spinlock);
986 if (clean_start)
987 client->stats.tx_messages_queued = 1;
988 else
@@ -1053,7 +990,7 @@ int mqtt_ng_connect(struct mqtt_ng_client *client,
990
991 client->stats.tx_messages_sent = 0;
992 client->stats.rx_messages_rcvd = 0;
1056 - pthread_mutex_unlock(&client->stats_mutex);
993 + spinlock_unlock(&client->stats_spinlock);
994
995 client->client_state = CONNECT_PENDING;
996 return 0;
@@ -1065,15 +1002,16 @@ uint16_t get_unused_packet_id() {
1002 return packet_id ? packet_id : ++packet_id;
1003 }
1004
1068 -static inline size_t mqtt_ng_publish_size(const char *topic,
1069 - size_t msg_len,
1070 - uint16_t topic_id)
1005 +static size_t mqtt_ng_publish_size(
1006 + const char *topic,
1007 + size_t msg_len,
1008 + uint16_t topic_id)
1009 {
1072 - size_t retval = 2 /* Topic Name Length */
1073 - + (topic == NULL ? 0 : strlen(topic))
1074 - + 2 /* Packet identifier */
1075 - + 1 /* Properties Length TODO for now fixed to 1 property */
1076 - + msg_len;
1010 + size_t retval = 2
1011 + + (topic == NULL ? 0 : strlen(topic)) /* Topic Name Length */
1012 + + 2 /* Packet identifier */
1013 + + 1 /* Properties Length for now fixed to 1 property */
1014 + + msg_len;
1015
1016 if (topic_id)
1017 retval += 3;
@@ -1082,7 +1020,6 @@ static inline size_t mqtt_ng_publish_size(const char *topic,
1020 }
1021
1022 int mqtt_ng_generate_publish(struct transaction_buffer *trx_buf,
1085 - mqtt_wss_log_ctx_t log_ctx,
1023 char *topic,
1024 free_fnc_t topic_free,
1025 void *msg,
@@ -1121,7 +1058,7 @@ int mqtt_ng_generate_publish(struct transaction_buffer *trx_buf,
1058 // [MQTT-3.3.2.1]
1059 PACK_2B_INT(&trx_buf->hdr_buffer, topic == NULL ? 0 : strlen(topic), frag);
1060 if (topic != NULL) {
1124 - if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, topic, strlen(topic), topic_free, &frag))
1061 + if (_optimized_add(&trx_buf->hdr_buffer, topic, strlen(topic), topic_free, &frag))
1062 goto fail_rollback;
1063 BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
1064 }
@@ -1145,7 +1082,7 @@ int mqtt_ng_generate_publish(struct transaction_buffer *trx_buf,
1082 if( (frag = buffer_new_frag(&trx_buf->hdr_buffer, BUFFER_FRAG_DATA_EXTERNAL)) == NULL )
1083 goto fail_rollback;
1084
1148 - if (frag_set_external_data(log_ctx, frag, msg, msg_len, msg_free))
1085 + if (frag_set_external_data(frag, msg, msg_len, msg_free))
1086 goto fail_rollback;
1087
1088 trx_buf->hdr_buffer.tail_frag->flags |= BUFFER_FRAG_MQTT_PACKET_TAIL;
@@ -1169,9 +1106,9 @@ int mqtt_ng_publish(struct mqtt_ng_client *client,
1106 uint16_t *packet_id)
1107 {
1108 struct topic_alias_data *alias = NULL;
1172 - pthread_rwlock_rdlock(&client->tx_topic_aliases.rwlock);
1109 + spinlock_lock(&client->tx_topic_aliases.spinlock);
1110 c_rhash_get_ptr_by_str(client->tx_topic_aliases.stoi_dict, topic, (void**)&alias);
1174 - pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
1111 + spinlock_unlock(&client->tx_topic_aliases.spinlock);
1112
1113 uint16_t topic_id = 0;
1114
@@ -1185,14 +1122,14 @@ int mqtt_ng_publish(struct mqtt_ng_client *client,
1122 }
1123
1124 if (client->max_msg_size && PUBLISH_SP_SIZE + mqtt_ng_publish_size(topic, msg_len, topic_id) > client->max_msg_size) {
1188 - mws_error(client->log, "Message too big for server: %zu", msg_len);
1125 + nd_log(NDLS_DAEMON, NDLP_ERR, "Message too big for server: %zu", msg_len);
1126 return MQTT_NG_MSGGEN_MSG_TOO_BIG;
1127 }
1128
1192 - TRY_GENERATE_MESSAGE(mqtt_ng_generate_publish, client, topic, topic_free, msg, msg_free, msg_len, publish_flags, packet_id, topic_id);
1129 + TRY_GENERATE_MESSAGE(mqtt_ng_generate_publish, topic, topic_free, msg, msg_free, msg_len, publish_flags, packet_id, topic_id);
1130 }
1131
1195 -static inline size_t mqtt_ng_subscribe_size(struct mqtt_sub *subs, size_t sub_count)
1132 +static size_t mqtt_ng_subscribe_size(struct mqtt_sub *subs, size_t sub_count)
1133 {
1134 size_t len = 2 /* Packet Identifier */ + 1 /* Properties Length TODO for now fixed 0 */;
1135 len += sub_count * (2 /* topic filter string length */ + 1 /* [MQTT-3.8.3.1] Subscription Options Byte */);
@@ -1203,7 +1140,7 @@ static inline size_t mqtt_ng_subscribe_size(struct mqtt_sub *subs, size_t sub_co
1140 return len;
1141 }
1142
1206 -int mqtt_ng_generate_subscribe(struct transaction_buffer *trx_buf, mqtt_wss_log_ctx_t log_ctx, struct mqtt_sub *subs, size_t sub_count)
1143 +int mqtt_ng_generate_subscribe(struct transaction_buffer *trx_buf, struct mqtt_sub *subs, size_t sub_count)
1144 {
1145 // >> START THE RODEO <<
1146 transaction_buffer_transaction_start(trx_buf);
@@ -1238,7 +1175,7 @@ int mqtt_ng_generate_subscribe(struct transaction_buffer *trx_buf, mqtt_wss_log_
1175 for (size_t i = 0; i < sub_count; i++) {
1176 BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
1177 PACK_2B_INT(&trx_buf->hdr_buffer, strlen(subs[i].topic), frag);
1241 - if (_optimized_add(&trx_buf->hdr_buffer, log_ctx, subs[i].topic, strlen(subs[i].topic), subs[i].topic_free, &frag))
1178 + if (_optimized_add(&trx_buf->hdr_buffer, subs[i].topic, strlen(subs[i].topic), subs[i].topic_free, &frag))
1179 goto fail_rollback;
1180 BUFFER_TRANSACTION_NEW_FRAG(&trx_buf->hdr_buffer, 0, frag, goto fail_rollback);
1181 *WRITE_POS(frag) = subs[i].options;
@@ -1255,12 +1192,11 @@ fail_rollback:
1192
1193 int mqtt_ng_subscribe(struct mqtt_ng_client *client, struct mqtt_sub *subs, size_t sub_count)
1194 {
1258 - TRY_GENERATE_MESSAGE(mqtt_ng_generate_subscribe, client, subs, sub_count);
1195 + TRY_GENERATE_MESSAGE(mqtt_ng_generate_subscribe, subs, sub_count);
1196 }
1197
1261 -int mqtt_ng_generate_disconnect(struct transaction_buffer *trx_buf, mqtt_wss_log_ctx_t log_ctx, uint8_t reason_code)
1198 +int mqtt_ng_generate_disconnect(struct transaction_buffer *trx_buf, uint8_t reason_code)
1199 {
1263 - (void) log_ctx;
1200 // >> START THE RODEO <<
1201 transaction_buffer_transaction_start(trx_buf);
1202
@@ -1299,12 +1235,11 @@ fail_rollback:
1235
1236 int mqtt_ng_disconnect(struct mqtt_ng_client *client, uint8_t reason_code)
1237 {
1302 - TRY_GENERATE_MESSAGE(mqtt_ng_generate_disconnect, client, reason_code);
1238 + TRY_GENERATE_MESSAGE(mqtt_ng_generate_disconnect, reason_code);
1239 }
1240
1305 -static int mqtt_generate_puback(struct transaction_buffer *trx_buf, mqtt_wss_log_ctx_t log_ctx, uint16_t packet_id, uint8_t reason_code)
1241 +static int mqtt_generate_puback(struct transaction_buffer *trx_buf, uint16_t packet_id, uint8_t reason_code)
1242 {
1307 - (void) log_ctx;
1243 // >> START THE RODEO <<
1244 transaction_buffer_transaction_start(trx_buf);
1245
@@ -1344,7 +1279,7 @@ fail_rollback:
1279
1280 static int mqtt_ng_puback(struct mqtt_ng_client *client, uint16_t packet_id, uint8_t reason_code)
1281 {
1347 - TRY_GENERATE_MESSAGE(mqtt_generate_puback, client, packet_id, reason_code);
1282 + TRY_GENERATE_MESSAGE(mqtt_generate_puback, packet_id, reason_code);
1283 }
1284
1285 int mqtt_ng_ping(struct mqtt_ng_client *client)
@@ -1361,7 +1296,6 @@ int mqtt_ng_ping(struct mqtt_ng_client *client)
1296 #define MQTT_NG_CLIENT_PROTOCOL_ERROR -1
1297 #define MQTT_NG_CLIENT_SERVER_RETURNED_ERROR -2
1298 #define MQTT_NG_CLIENT_NOT_IMPL_YET -3
1364 -#define MQTT_NG_CLIENT_OOM -4
1299 #define MQTT_NG_CLIENT_INTERNAL_ERROR -5
1300
1301 #define BUF_READ_CHECK_AT_LEAST(buf, x) \
@@ -1370,10 +1304,10 @@ int mqtt_ng_ping(struct mqtt_ng_client *client)
1304
1305 #define vbi_parser_reset_ctx(ctx) memset(ctx, 0, sizeof(struct mqtt_vbi_parser_ctx))
1306
1373 -static int vbi_parser_parse(struct mqtt_vbi_parser_ctx *ctx, rbuf_t data, mqtt_wss_log_ctx_t log)
1307 +static int vbi_parser_parse(struct mqtt_vbi_parser_ctx *ctx, rbuf_t data)
1308 {
1309 if (ctx->bytes > MQTT_VBI_MAXBYTES - 1) {
1376 - mws_error(log, "MQTT Variable Byte Integer can't be longer than %d bytes", MQTT_VBI_MAXBYTES);
1310 + nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT Variable Byte Integer can't be longer than %d bytes", MQTT_VBI_MAXBYTES);
1311 return MQTT_NG_CLIENT_PROTOCOL_ERROR;
1312 }
1313 if (!ctx->bytes || ctx->data[ctx->bytes-1] & MQTT_VBI_CONTINUATION_FLAG) {
@@ -1385,7 +1319,7 @@ static int vbi_parser_parse(struct mqtt_vbi_parser_ctx *ctx, rbuf_t data, mqtt_w
1319 }
1320
1321 if (mqtt_vbi_to_uint32(ctx->data, &ctx->result)) {
1388 - mws_error(log, "MQTT Variable Byte Integer failed to be parsed.");
1322 + nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT Variable Byte Integer failed to be parsed.");
1323 return MQTT_NG_CLIENT_PROTOCOL_ERROR;
1324 }
1325
@@ -1471,12 +1405,12 @@ struct mqtt_property *get_property_by_id(struct mqtt_property *props, uint8_t pr
1405 }
1406
1407 // Parses [MQTT-2.2.2]
1474 -static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t data, mqtt_wss_log_ctx_t log)
1408 +static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t data)
1409 {
1410 int rc;
1411 switch (ctx->state) {
1412 case PROPERTIES_LENGTH:
1479 - rc = vbi_parser_parse(&ctx->vbi_parser_ctx, data, log);
1413 + rc = vbi_parser_parse(&ctx->vbi_parser_ctx, data);
1414 if (rc == MQTT_NG_CLIENT_PARSE_DONE) {
1415 ctx->properties_length = ctx->vbi_parser_ctx.result;
1416 ctx->bytes_consumed += ctx->vbi_parser_ctx.bytes;
@@ -1525,7 +1459,7 @@ static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t
1459 ctx->state = PROPERTY_TYPE_STR_BIN_LEN;
1460 break;
1461 default:
1528 - mws_error(log, "Unsupported property type %d for property id %d.", (int)ctx->tail->type, (int)ctx->tail->id);
1462 + nd_log(NDLS_DAEMON, NDLP_ERR, "Unsupported property type %d for property id %d.", (int)ctx->tail->type, (int)ctx->tail->id);
1463 return MQTT_NG_CLIENT_PROTOCOL_ERROR;
1464 }
1465 break;
@@ -1543,7 +1477,7 @@ static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t
1477 ctx->state = PROPERTY_TYPE_STR;
1478 break;
1479 default:
1546 - mws_error(log, "Unexpected datatype in PROPERTY_TYPE_STR_BIN_LEN %d", (int)ctx->tail->type);
1480 + nd_log(NDLS_DAEMON, NDLP_ERR, "Unexpected datatype in PROPERTY_TYPE_STR_BIN_LEN %d", (int)ctx->tail->type);
1481 return MQTT_NG_CLIENT_INTERNAL_ERROR;
1482 }
1483 break;
@@ -1568,7 +1502,7 @@ static int parse_properties_array(struct mqtt_properties_parser_ctx *ctx, rbuf_t
1502 ctx->state = PROPERTY_NEXT;
1503 break;
1504 case PROPERTY_TYPE_VBI:
1571 - rc = vbi_parser_parse(&ctx->vbi_parser_ctx, data, log);
1505 + rc = vbi_parser_parse(&ctx->vbi_parser_ctx, data);
1506 if (rc == MQTT_NG_CLIENT_PARSE_DONE) {
1507 ctx->tail->data.uint32 = ctx->vbi_parser_ctx.result;
1508 ctx->bytes_consumed += ctx->vbi_parser_ctx.bytes;
@@ -1618,9 +1552,9 @@ static int parse_connack_varhdr(struct mqtt_ng_client *client)
1552 mqtt_properties_parser_ctx_reset(&parser->properties_parser);
1553 break;
1554 case MQTT_PARSE_VARHDR_PROPS:
1621 - return parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
1555 + return parse_properties_array(&parser->properties_parser, parser->received_data);
1556 default:
1623 - ERROR("invalid state for connack varhdr parser");
1557 + nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for connack varhdr parser");
1558 return MQTT_NG_CLIENT_INTERNAL_ERROR;
1559 }
1560 return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1644,9 +1578,9 @@ static int parse_disconnect_varhdr(struct mqtt_ng_client *client)
1578 mqtt_properties_parser_ctx_reset(&parser->properties_parser);
1579 break;
1580 case MQTT_PARSE_VARHDR_PROPS:
1647 - return parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
1581 + return parse_properties_array(&parser->properties_parser, parser->received_data);
1582 default:
1649 - ERROR("invalid state for connack varhdr parser");
1583 + nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for connack varhdr parser");
1584 return MQTT_NG_CLIENT_INTERNAL_ERROR;
1585 }
1586 return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1682,9 +1616,9 @@ static int parse_puback_varhdr(struct mqtt_ng_client *client)
1616 mqtt_properties_parser_ctx_reset(&parser->properties_parser);
1617 /* FALLTHROUGH */
1618 case MQTT_PARSE_VARHDR_PROPS:
1685 - return parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
1619 + return parse_properties_array(&parser->properties_parser, parser->received_data);
1620 default:
1687 - ERROR("invalid state for puback varhdr parser");
1621 + nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for puback varhdr parser");
1622 return MQTT_NG_CLIENT_INTERNAL_ERROR;
1623 }
1624 return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1707,7 +1641,7 @@ static int parse_suback_varhdr(struct mqtt_ng_client *client)
1641 mqtt_properties_parser_ctx_reset(&parser->properties_parser);
1642 /* FALLTHROUGH */
1643 case MQTT_PARSE_VARHDR_PROPS:
1710 - rc = parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
1644 + rc = parse_properties_array(&parser->properties_parser, parser->received_data);
1645 if (rc != MQTT_NG_CLIENT_PARSE_DONE)
1646 return rc;
1647 parser->mqtt_parsed_len += parser->properties_parser.bytes_consumed;
@@ -1728,7 +1662,7 @@ static int parse_suback_varhdr(struct mqtt_ng_client *client)
1662
1663 return MQTT_NG_CLIENT_NEED_MORE_BYTES;
1664 default:
1731 - ERROR("invalid state for suback varhdr parser");
1665 + nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for suback varhdr parser");
1666 return MQTT_NG_CLIENT_INTERNAL_ERROR;
1667 }
1668 return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1752,8 +1686,6 @@ static int parse_publish_varhdr(struct mqtt_ng_client *client)
1686 break;
1687 }
1688 publish->topic = callocz(1, publish->topic_len + 1 /* add 0x00 */);
1755 - if (publish->topic == NULL)
1756 - return MQTT_NG_CLIENT_OOM;
1689 parser->varhdr_state = MQTT_PARSE_VARHDR_TOPICNAME;
1690 /* FALLTHROUGH */
1691 case MQTT_PARSE_VARHDR_TOPICNAME:
@@ -1779,7 +1711,7 @@ static int parse_publish_varhdr(struct mqtt_ng_client *client)
1711 parser->mqtt_parsed_len += 2;
1712 /* FALLTHROUGH */
1713 case MQTT_PARSE_VARHDR_PROPS:
1782 - rc = parse_properties_array(&parser->properties_parser, parser->received_data, client->log);
1714 + rc = parse_properties_array(&parser->properties_parser, parser->received_data);
1715 if (rc != MQTT_NG_CLIENT_PARSE_DONE)
1716 return rc;
1717 parser->mqtt_parsed_len += parser->properties_parser.bytes_consumed;
@@ -1789,7 +1721,7 @@ static int parse_publish_varhdr(struct mqtt_ng_client *client)
1721 if (parser->mqtt_fixed_hdr_remaining_length < parser->mqtt_parsed_len) {
1722 freez(publish->topic);
1723 publish->topic = NULL;
1792 - ERROR("Error parsing PUBLISH message");
1724 + nd_log(NDLS_DAEMON, NDLP_ERR, "Error parsing PUBLISH message");
1725 return MQTT_NG_CLIENT_PROTOCOL_ERROR;
1726 }
1727 publish->data_len = parser->mqtt_fixed_hdr_remaining_length - parser->mqtt_parsed_len;
@@ -1800,18 +1732,12 @@ static int parse_publish_varhdr(struct mqtt_ng_client *client)
1732 BUF_READ_CHECK_AT_LEAST(parser->received_data, publish->data_len);
1733
1734 publish->data = mallocz(publish->data_len);
1803 - if (publish->data == NULL) {
1804 - freez(publish->topic);
1805 - publish->topic = NULL;
1806 - return MQTT_NG_CLIENT_OOM;
1807 - }
1808 -
1735 rbuf_pop(parser->received_data, publish->data, publish->data_len);
1736 parser->mqtt_parsed_len += publish->data_len;
1737
1738 return MQTT_NG_CLIENT_PARSE_DONE;
1739 default:
1814 - ERROR("invalid state for publish varhdr parser");
1740 + nd_log(NDLS_DAEMON, NDLP_ERR, "invalid state for publish varhdr parser");
1741 return MQTT_NG_CLIENT_INTERNAL_ERROR;
1742 }
1743 return MQTT_NG_CLIENT_OK_CALL_AGAIN;
@@ -1831,7 +1757,7 @@ static int parse_data(struct mqtt_ng_client *client)
1757 parser->state = MQTT_PARSE_FIXED_HEADER_LEN;
1758 break;
1759 case MQTT_PARSE_FIXED_HEADER_LEN:
1834 - rc = vbi_parser_parse(&parser->vbi_parser, parser->received_data, client->log);
1760 + rc = vbi_parser_parse(&parser->vbi_parser, parser->received_data);
1761 if (rc == MQTT_NG_CLIENT_PARSE_DONE) {
1762 parser->mqtt_fixed_hdr_remaining_length = parser->vbi_parser.result;
1763 parser->state = MQTT_PARSE_VARIABLE_HEADER;
@@ -1874,7 +1800,7 @@ static int parse_data(struct mqtt_ng_client *client)
1800 return rc;
1801 case MQTT_CPT_PINGRESP:
1802 if (parser->mqtt_fixed_hdr_remaining_length) {
1877 - ERROR ("PINGRESP has to be 0 Remaining Length."); // [MQTT-3.13.1]
1803 + nd_log(NDLS_DAEMON, NDLP_ERR, "PINGRESP has to be 0 Remaining Length."); // [MQTT-3.13.1]
1804 return MQTT_NG_CLIENT_PROTOCOL_ERROR;
1805 }
1806 parser->state = MQTT_PARSE_MQTT_PACKET_DONE;
@@ -1887,7 +1813,7 @@ static int parse_data(struct mqtt_ng_client *client)
1813 }
1814 return rc;
1815 default:
1890 - ERROR("Parsing Control Packet Type %" PRIu8 " not implemented yet.", get_control_packet_type(parser->mqtt_control_packet_type));
1816 + nd_log(NDLS_DAEMON, NDLP_ERR, "Parsing Control Packet Type %" PRIu8 " not implemented yet.", get_control_packet_type(parser->mqtt_control_packet_type));
1817 rbuf_bump_tail(parser->received_data, parser->mqtt_fixed_hdr_remaining_length);
1818 parser->state = MQTT_PARSE_MQTT_PACKET_DONE;
1819 return MQTT_NG_CLIENT_NOT_IMPL_YET;
@@ -1950,7 +1876,7 @@ static int send_fragment(struct mqtt_ng_client *client) {
1876 if (bytes)
1877 processed = client->send_fnc_ptr(client->user_ctx, ptr, bytes);
1878 else
1953 - WARN("This fragment was fully sent already. This should not happen!");
1879 + nd_log(NDLS_DAEMON, NDLP_WARNING, "This fragment was fully sent already. This should not happen!");
1880
1881 frag->sent += processed;
1882 if (frag->sent != frag->len)
@@ -1958,11 +1884,11 @@ static int send_fragment(struct mqtt_ng_client *client) {
1884
1885 if (frag->flags & BUFFER_FRAG_MQTT_PACKET_TAIL) {
1886 client->time_of_last_send = time(NULL);
1961 - pthread_mutex_lock(&client->stats_mutex);
1887 + spinlock_lock(&client->stats_spinlock);
1888 if (client->main_buffer.sending_frag != &ping_frag)
1889 client->stats.tx_messages_queued--;
1890 client->stats.tx_messages_sent++;
1965 - pthread_mutex_unlock(&client->stats_mutex);
1891 + spinlock_unlock(&client->stats_spinlock);
1892 client->main_buffer.sending_frag = NULL;
1893 return 1;
1894 }
@@ -1986,7 +1912,7 @@ static void try_send_all(struct mqtt_ng_client *client) {
1912 } while(send_all_message_fragments(client) >= 0);
1913 }
1914
1989 -static inline void mark_message_for_gc(struct buffer_fragment *frag)
1915 +static void mark_message_for_gc(struct buffer_fragment *frag)
1916 {
1917 while (frag) {
1918 frag->flags |= BUFFER_FRAG_GARBAGE_COLLECT;
@@ -2004,7 +1930,7 @@ static int mark_packet_acked(struct mqtt_ng_client *client, uint16_t packet_id)
1930 while (frag) {
1931 if ( (frag->flags & BUFFER_FRAG_MQTT_PACKET_HEAD) && frag->packet_id == packet_id) {
1932 if (!frag->sent) {
2007 - ERROR("Received packet_id (%" PRIu16 ") belongs to MQTT packet which was not yet sent!", packet_id);
1933 + nd_log(NDLS_DAEMON, NDLP_ERR, "Received packet_id (%" PRIu16 ") belongs to MQTT packet which was not yet sent!", packet_id);
1934 UNLOCK_HDR_BUFFER(&client->main_buffer);
1935 return 1;
1936 }
@@ -2014,7 +1940,7 @@ static int mark_packet_acked(struct mqtt_ng_client *client, uint16_t packet_id)
1940 }
1941 frag = frag->next;
1942 }
2017 - ERROR("Received packet_id (%" PRIu16 ") is unknown!", packet_id);
1943 + nd_log(NDLS_DAEMON, NDLP_ERR, "Received packet_id (%" PRIu16 ") is unknown!", packet_id);
1944 UNLOCK_HDR_BUFFER(&client->main_buffer);
1945 return 1;
1946 }
@@ -2022,110 +1948,113 @@ static int mark_packet_acked(struct mqtt_ng_client *client, uint16_t packet_id)
1948 int handle_incoming_traffic(struct mqtt_ng_client *client)
1949 {
1950 int rc;
1951 + while ((rc = parse_data(client)) == MQTT_NG_CLIENT_OK_CALL_AGAIN) {
1952 + ;
1953 + }
1954 + if (rc != MQTT_NG_CLIENT_MQTT_PACKET_DONE)
1955 + return rc;
1956 +
1957 struct mqtt_publish *pub;
2026 - while( (rc = parse_data(client)) == MQTT_NG_CLIENT_OK_CALL_AGAIN );
2027 - if ( rc == MQTT_NG_CLIENT_MQTT_PACKET_DONE ) {
2028 - struct mqtt_property *prop;
2029 -#ifdef MQTT_DEBUG_VERBOSE
2030 - DEBUG("MQTT Packet Parsed Successfully!");
2031 -#endif
2032 - pthread_mutex_lock(&client->stats_mutex);
2033 - client->stats.rx_messages_rcvd++;
2034 - pthread_mutex_unlock(&client->stats_mutex);
2035 -
2036 - switch (get_control_packet_type(client->parser.mqtt_control_packet_type)) {
2037 - case MQTT_CPT_CONNACK:
2038 -#ifdef MQTT_DEBUG_VERBOSE
2039 - DEBUG("Received CONNACK");
2040 -#endif
2041 - LOCK_HDR_BUFFER(&client->main_buffer);
2042 - mark_message_for_gc(client->connect_msg);
2043 - UNLOCK_HDR_BUFFER(&client->main_buffer);
2044 - client->connect_msg = NULL;
2045 - if (client->client_state != CONNECTING) {
2046 - ERROR("Received unexpected CONNACK");
2047 - client->client_state = ERROR;
2048 - return MQTT_NG_CLIENT_PROTOCOL_ERROR;
2049 - }
2050 - if ((prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_MAX_PKT_SIZE)) != NULL) {
2051 - INFO("MQTT server limits message size to %" PRIu32, prop->data.uint32);
2052 - client->max_msg_size = prop->data.uint32;
2053 - }
2054 - if (client->connack_callback)
2055 - client->connack_callback(client->user_ctx, client->parser.mqtt_packet.connack.reason_code);
2056 - if (!client->parser.mqtt_packet.connack.reason_code) {
2057 - INFO("MQTT Connection Accepted By Server");
2058 - client->client_state = CONNECTED;
2059 - break;
2060 - }
1958 + struct mqtt_property *prop;
1959 + spinlock_lock(&client->stats_spinlock);
1960 + client->stats.rx_messages_rcvd++;
1961 + spinlock_unlock(&client->stats_spinlock);
1962 +
1963 + uint8_t ctrl_packet_type = get_control_packet_type(client->parser.mqtt_control_packet_type);
1964 + switch (ctrl_packet_type) {
1965 + case MQTT_CPT_CONNACK:
1966 + LOCK_HDR_BUFFER(&client->main_buffer);
1967 + mark_message_for_gc(client->connect_msg);
1968 + UNLOCK_HDR_BUFFER(&client->main_buffer);
1969 +
1970 + client->connect_msg = NULL;
1971 +
1972 + if (client->client_state != CONNECTING) {
1973 + nd_log(NDLS_DAEMON, NDLP_ERR, "Received unexpected CONNACK");
1974 client->client_state = ERROR;
2062 - return MQTT_NG_CLIENT_SERVER_RETURNED_ERROR;
2063 - case MQTT_CPT_PUBACK:
2064 -#ifdef MQTT_DEBUG_VERBOSE
2065 - DEBUG("Received PUBACK %" PRIu16, client->parser.mqtt_packet.puback.packet_id);
2066 -#endif
2067 - if (mark_packet_acked(client, client->parser.mqtt_packet.puback.packet_id))
2068 - return MQTT_NG_CLIENT_PROTOCOL_ERROR;
2069 - if (client->puback_callback)
2070 - client->puback_callback(client->parser.mqtt_packet.puback.packet_id);
2071 - break;
2072 - case MQTT_CPT_PINGRESP:
2073 -#ifdef MQTT_DEBUG_VERBOSE
2074 - DEBUG("Received PINGRESP");
2075 -#endif
2076 - break;
2077 - case MQTT_CPT_SUBACK:
2078 -#ifdef MQTT_DEBUG_VERBOSE
2079 - DEBUG("Received SUBACK %" PRIu16, client->parser.mqtt_packet.suback.packet_id);
2080 -#endif
2081 - if (mark_packet_acked(client, client->parser.mqtt_packet.suback.packet_id))
2082 - return MQTT_NG_CLIENT_PROTOCOL_ERROR;
1975 + return MQTT_NG_CLIENT_PROTOCOL_ERROR;
1976 + }
1977 +
1978 + if ((prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_MAX_PKT_SIZE)) != NULL) {
1979 + nd_log(NDLS_DAEMON, NDLP_INFO, "MQTT server limits message size to %" PRIu32, prop->data.uint32);
1980 + client->max_msg_size = prop->data.uint32;
1981 + }
1982 +
1983 + if (client->connack_callback)
1984 + client->connack_callback(client->user_ctx, client->parser.mqtt_packet.connack.reason_code);
1985 + if (!client->parser.mqtt_packet.connack.reason_code) {
1986 + nd_log(NDLS_DAEMON, NDLP_INFO, "MQTT Connection Accepted By Server");
1987 + client->client_state = CONNECTED;
1988 break;
2084 - case MQTT_CPT_PUBLISH:
2085 -#ifdef MQTT_DEBUG_VERBOSE
2086 - DEBUG("Recevied PUBLISH");
2087 -#endif
2088 - pub = &client->parser.mqtt_packet.publish;
2089 - if (pub->qos > 1) {
2090 - freez(pub->topic);
2091 - freez(pub->data);
2092 - return MQTT_NG_CLIENT_NOT_IMPL_YET;
2093 - }
2094 - if ( pub->qos == 1 && (rc = mqtt_ng_puback(client, pub->packet_id, 0)) ) {
2095 - client->client_state = ERROR;
2096 - ERROR("Error generating PUBACK reply for PUBLISH");
2097 - return rc;
2098 - }
2099 - if ( (prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_TOPIC_ALIAS)) != NULL ) {
2100 - // Topic Alias property was sent from server
2101 - void *topic_ptr;
2102 - if (!c_rhash_get_ptr_by_uint64(client->rx_aliases, prop->data.uint8, &topic_ptr)) {
2103 - if (pub->topic != NULL) {
2104 - ERROR("We do not yet support topic alias reassignment");
2105 - return MQTT_NG_CLIENT_NOT_IMPL_YET;
2106 - }
2107 - pub->topic = topic_ptr;
2108 - } else {
2109 - if (pub->topic == NULL) {
2110 - ERROR("Topic alias with id %d unknown and topic not set by server!", prop->data.uint8);
2111 - return MQTT_NG_CLIENT_PROTOCOL_ERROR;
2112 - }
2113 - c_rhash_insert_uint64_ptr(client->rx_aliases, prop->data.uint8, pub->topic);
1989 + }
1990 + client->client_state = ERROR;
1991 + return MQTT_NG_CLIENT_SERVER_RETURNED_ERROR;
1992 +
1993 + case MQTT_CPT_PUBACK:
1994 + if (mark_packet_acked(client, client->parser.mqtt_packet.puback.packet_id))
1995 + return MQTT_NG_CLIENT_PROTOCOL_ERROR;
1996 + if (client->puback_callback)
1997 + client->puback_callback(client->parser.mqtt_packet.puback.packet_id);
1998 + break;
1999 +
2000 + case MQTT_CPT_PINGRESP:
2001 + break;
2002 +
2003 + case MQTT_CPT_SUBACK:
2004 + if (mark_packet_acked(client, client->parser.mqtt_packet.suback.packet_id))
2005 + return MQTT_NG_CLIENT_PROTOCOL_ERROR;
2006 + break;
2007 +
2008 + case MQTT_CPT_PUBLISH:
2009 + pub = &client->parser.mqtt_packet.publish;
2010 +
2011 + if (pub->qos > 1) {
2012 + freez(pub->topic);
2013 + freez(pub->data);
2014 + return MQTT_NG_CLIENT_NOT_IMPL_YET;
2015 + }
2016 +
2017 + if ( pub->qos == 1 && ((rc = mqtt_ng_puback(client, pub->packet_id, 0))) ) {
2018 + client->client_state = ERROR;
2019 + nd_log(NDLS_DAEMON, NDLP_ERR, "Error generating PUBACK reply for PUBLISH");
2020 + return rc;
2021 + }
2022 +
2023 + if ( (prop = get_property_by_id(client->parser.properties_parser.head, MQTT_PROP_TOPIC_ALIAS)) != NULL ) {
2024 + // Topic Alias property was sent from server
2025 + void *topic_ptr;
2026 + if (!c_rhash_get_ptr_by_uint64(client->rx_aliases, prop->data.uint8, &topic_ptr)) {
2027 + if (pub->topic != NULL) {
2028 + nd_log(NDLS_DAEMON, NDLP_ERR, "We do not yet support topic alias reassignment");
2029 + return MQTT_NG_CLIENT_NOT_IMPL_YET;
2030 }
2031 + pub->topic = topic_ptr;
2032 + } else {
2033 + if (pub->topic == NULL) {
2034 + nd_log(NDLS_DAEMON, NDLP_ERR, "Topic alias with id %d unknown and topic not set by server!", prop->data.uint8);
2035 + return MQTT_NG_CLIENT_PROTOCOL_ERROR;
2036 + }
2037 + c_rhash_insert_uint64_ptr(client->rx_aliases, prop->data.uint8, pub->topic);
2038 }
2116 - if (client->msg_callback)
2117 - client->msg_callback(pub->topic, pub->data, pub->data_len, pub->qos);
2118 - // in case we have property topic alias and we have topic we take over the string
2119 - // and add pointer to it into topic alias list
2120 - if (prop == NULL)
2121 - freez(pub->topic);
2122 - freez(pub->data);
2123 - return MQTT_NG_CLIENT_WANT_WRITE;
2124 - case MQTT_CPT_DISCONNECT:
2125 - INFO ("Got MQTT DISCONNECT control packet from server. Reason code: %d", (int)client->parser.mqtt_packet.disconnect.reason_code);
2126 - client->client_state = DISCONNECTED;
2127 - break;
2128 - }
2039 + }
2040 +
2041 + if (client->msg_callback)
2042 + client->msg_callback(pub->topic, pub->data, pub->data_len, pub->qos);
2043 + // in case we have property topic alias and we have topic we take over the string
2044 + // and add pointer to it into topic alias list
2045 + if (prop == NULL)
2046 + freez(pub->topic);
2047 + freez(pub->data);
2048 + return MQTT_NG_CLIENT_WANT_WRITE;
2049 +
2050 + case MQTT_CPT_DISCONNECT:
2051 + nd_log(NDLS_DAEMON, NDLP_INFO, "Got MQTT DISCONNECT control packet from server. Reason code: %d", (int)client->parser.mqtt_packet.disconnect.reason_code);
2052 + client->client_state = DISCONNECTED;
2053 + break;
2054 +
2055 + default:
2056 + nd_log(NDLS_DAEMON, NDLP_INFO, "Got unknown control packet %u from server", ctrl_packet_type);
2057 + break;
2058 }
2059
2060 return rc;
@@ -2173,9 +2102,9 @@ void mqtt_ng_set_max_mem(struct mqtt_ng_client *client, size_t bytes)
2102
2103 void mqtt_ng_get_stats(struct mqtt_ng_client *client, struct mqtt_ng_stats *stats)
2104 {
2176 - pthread_mutex_lock(&client->stats_mutex);
2105 + spinlock_lock(&client->stats_spinlock);
2106 memcpy(stats, &client->stats, sizeof(struct mqtt_ng_stats));
2178 - pthread_mutex_unlock(&client->stats_mutex);
2107 + spinlock_unlock(&client->stats_spinlock);
2108
2109 stats->tx_bytes_queued = 0;
2110 stats->tx_buffer_reclaimable = 0;
@@ -2198,11 +2127,11 @@ void mqtt_ng_get_stats(struct mqtt_ng_client *client, struct mqtt_ng_stats *stat
2127 int mqtt_ng_set_topic_alias(struct mqtt_ng_client *client, const char *topic)
2128 {
2129 uint16_t idx;
2201 - pthread_rwlock_wrlock(&client->tx_topic_aliases.rwlock);
2130 + spinlock_lock(&client->tx_topic_aliases.spinlock);
2131
2132 if (client->tx_topic_aliases.idx_assigned >= client->tx_topic_aliases.idx_max) {
2204 - pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
2205 - mws_error(client->log, "Tx topic alias indexes were exhausted (current version of the library doesn't support reassigning yet. Feel free to contribute.");
2133 + spinlock_unlock(&client->tx_topic_aliases.spinlock);
2134 + nd_log(NDLS_DAEMON, NDLP_ERR, "Tx topic alias indexes were exhausted (current version of the library doesn't support reassigning yet. Feel free to contribute.");
2135 return 0; //0 is not a valid topic alias
2136 }
2137
@@ -2211,8 +2140,8 @@ int mqtt_ng_set_topic_alias(struct mqtt_ng_client *client, const char *topic)
2140 // this is not a problem for library but might be helpful to warn user
2141 // as it might indicate bug in their program (but also might be expected)
2142 idx = alias->idx;
2214 - pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
2215 - mws_debug(client->log, "%s topic \"%s\" already has alias set. Ignoring.", __FUNCTION__, topic);
2143 + spinlock_unlock(&client->tx_topic_aliases.spinlock);
2144 + nd_log(NDLS_DAEMON, NDLP_DEBUG, "%s topic \"%s\" already has alias set. Ignoring.", __FUNCTION__, topic);
2145 return idx;
2146 }
2147
@@ -2223,6 +2152,6 @@ int mqtt_ng_set_topic_alias(struct mqtt_ng_client *client, const char *topic)
2152
2153 c_rhash_insert_str_ptr(client->tx_topic_aliases.stoi_dict, topic, (void*)alias);
2154
2226 - pthread_rwlock_unlock(&client->tx_topic_aliases.rwlock);
2155 + spinlock_unlock(&client->tx_topic_aliases.spinlock);
2156 return idx;
2157 }
src/aclk/mqtt_websockets/mqtt_ng.h
-1
@@ -67,7 +67,6 @@ int mqtt_ng_ping(struct mqtt_ng_client *client);
67 typedef ssize_t (*mqtt_ng_send_fnc_t)(void *user_ctx, const void* buf, size_t len);
68
69 struct mqtt_ng_init {
70 - mqtt_wss_log_ctx_t log;
70 rbuf_t data_in;
71 mqtt_ng_send_fnc_t data_out_fnc;
72 void *user_ctx;
src/aclk/mqtt_websockets/mqtt_wss_client.c
+97 -219
@@ -57,6 +57,8 @@ char *util_openssl_ret_err(int err)
57 return "SSL_ERROR_SYSCALL";
58 case SSL_ERROR_SSL:
59 return "SSL_ERROR_SSL";
60 + default:
61 + break;
62 }
63 return "UNKNOWN";
64 }
@@ -64,8 +66,6 @@ char *util_openssl_ret_err(int err)
66 struct mqtt_wss_client_struct {
67 ws_client *ws_client;
68
67 - mqtt_wss_log_ctx_t log;
68 -
69 // immediate connection (e.g. proxy server)
70 char *host;
71 int port;
@@ -117,69 +117,49 @@ static void mws_connack_callback_ng(void *user_ctx, int code)
117 switch(code) {
118 case 0:
119 client->mqtt_connected = 1;
120 - return;
120 + break;
121 //TODO manual labor: all the CONNACK error codes with some nice error message
122 default:
123 - mws_error(client->log, "MQTT CONNACK returned error %d", code);
124 - return;
123 + nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT CONNACK returned error %d", code);
124 + break;
125 }
126 }
127
128 static ssize_t mqtt_send_cb(void *user_ctx, const void* buf, size_t len)
129 {
130 mqtt_wss_client client = user_ctx;
131 -#ifdef DEBUG_ULTRA_VERBOSE
132 - mws_debug(client->log, "mqtt_pal_sendall(len=%d)", len);
133 -#endif
131 int ret = ws_client_send(client->ws_client, WS_OP_BINARY_FRAME, buf, len);
135 - if (ret >= 0 && (size_t)ret != len) {
136 -#ifdef DEBUG_ULTRA_VERBOSE
137 - mws_debug(client->log, "Not complete message sent (Msg=%d,Sent=%d). Need to arm POLLOUT!", len, ret);
138 -#endif
132 + if (ret >= 0 && (size_t)ret != len)
133 client->mqtt_didnt_finish_write = 1;
140 - }
134 return ret;
135 }
136
144 -mqtt_wss_client mqtt_wss_new(const char *log_prefix,
145 - mqtt_wss_log_callback_t log_callback,
146 - msg_callback_fnc_t msg_callback,
147 - void (*puback_callback)(uint16_t packet_id))
137 +mqtt_wss_client mqtt_wss_new(
138 + msg_callback_fnc_t msg_callback,
139 + void (*puback_callback)(uint16_t packet_id))
140 {
149 - mqtt_wss_log_ctx_t log;
150 -
151 - log = mqtt_wss_log_ctx_create(log_prefix, log_callback);
152 - if(!log)
153 - return NULL;
154 -
141 SSL_library_init();
142 SSL_load_error_strings();
143
144 mqtt_wss_client client = callocz(1, sizeof(struct mqtt_wss_client_struct));
159 - if (!client) {
160 - mws_error(log, "OOM alocating mqtt_wss_client");
161 - goto fail;
162 - }
145
146 spinlock_init(&client->stat_lock);
147
148 client->msg_callback = msg_callback;
149 client->puback_callback = puback_callback;
150
169 - client->ws_client = ws_client_new(0, &client->target_host, log);
151 + client->ws_client = ws_client_new(0, &client->target_host);
152 if (!client->ws_client) {
171 - mws_error(log, "Error creating ws_client");
153 + nd_log(NDLS_DAEMON, NDLP_ERR, "Error creating ws_client");
154 goto fail_1;
155 }
156
175 - client->log = log;
176 -
157 #ifdef __APPLE__
158 if (pipe(client->write_notif_pipe)) {
159 #else
160 if (pipe2(client->write_notif_pipe, O_CLOEXEC /*| O_DIRECT*/)) {
161 #endif
182 - mws_error(log, "Couldn't create pipe");
162 + nd_log(NDLS_DAEMON, NDLP_ERR, "Couldn't create pipe");
163 goto fail_2;
164 }
165
@@ -189,7 +169,6 @@ mqtt_wss_client mqtt_wss_new(const char *log_prefix,
169 client->poll_fds[POLLFD_SOCKET].events = POLLIN;
170
171 struct mqtt_ng_init settings = {
192 - .log = log,
172 .data_in = client->ws_client->buf_to_mqtt,
173 .data_out_fnc = &mqtt_send_cb,
174 .user_ctx = client,
@@ -197,22 +176,14 @@ mqtt_wss_client mqtt_wss_new(const char *log_prefix,
176 .puback_callback = puback_callback,
177 .msg_callback = msg_callback
178 };
200 - if ( (client->mqtt = mqtt_ng_init(&settings)) == NULL ) {
201 - mws_error(log, "Error initializing internal MQTT client");
202 - goto fail_3;
203 - }
179 + client->mqtt = mqtt_ng_init(&settings);
180
181 return client;
182
207 -fail_3:
208 - close(client->write_notif_pipe[PIPE_WRITE_END]);
209 - close(client->write_notif_pipe[PIPE_READ_END]);
183 fail_2:
184 ws_client_destroy(client->ws_client);
185 fail_1:
186 freez(client);
214 -fail:
215 - mqtt_wss_log_ctx_destroy(log);
187 return NULL;
188 }
189
@@ -253,30 +224,25 @@ void mqtt_wss_destroy(mqtt_wss_client client)
224 if (client->sockfd > 0)
225 close(client->sockfd);
226
256 - mqtt_wss_log_ctx_destroy(client->log);
227 freez(client);
228 }
229
230 static int cert_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
231 {
262 - SSL *ssl;
263 - X509 *err_cert;
264 - mqtt_wss_client client;
265 - int err = 0, depth;
266 - char *err_str;
232 + int err = 0;
233
268 - ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
269 - client = SSL_get_ex_data(ssl, 0);
234 + SSL* ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
235 + mqtt_wss_client client = SSL_get_ex_data(ssl, 0);
236
237 // TODO handle depth as per https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
238
239 if (!preverify_ok) {
240 err = X509_STORE_CTX_get_error(ctx);
275 - depth = X509_STORE_CTX_get_error_depth(ctx);
276 - err_cert = X509_STORE_CTX_get_current_cert(ctx);
277 - err_str = X509_NAME_oneline(X509_get_subject_name(err_cert), NULL, 0);
241 + int depth = X509_STORE_CTX_get_error_depth(ctx);
242 + X509* err_cert = X509_STORE_CTX_get_current_cert(ctx);
243 + char* err_str = X509_NAME_oneline(X509_get_subject_name(err_cert), NULL, 0);
244
279 - mws_error(client->log, "verify error:num=%d:%s:depth=%d:%s", err,
245 + nd_log(NDLS_DAEMON, NDLP_ERR, "verify error:num=%d:%s:depth=%d:%s", err,
246 X509_verify_cert_error_string(err), depth, err_str);
247
248 freez(err_str);
@@ -286,7 +252,7 @@ static int cert_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
252 client->ssl_flags & MQTT_WSS_SSL_ALLOW_SELF_SIGNED)
253 {
254 preverify_ok = 1;
289 - mws_error(client->log, "Self Signed Certificate Accepted as the connection was "
255 + nd_log(NDLS_DAEMON, NDLP_ERR, "Self Signed Certificate Accepted as the connection was "
256 "requested with MQTT_WSS_SSL_ALLOW_SELF_SIGNED");
257 }
258
@@ -300,16 +266,14 @@ static int cert_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
266 #define HTTP_HDR_TERMINATOR "\x0D\x0A\x0D\x0A"
267 #define HTTP_CODE_LEN 4
268 #define HTTP_REASON_MAX_LEN 512
303 -static int http_parse_reply(mqtt_wss_client client, rbuf_t buf)
269 +static int http_parse_reply(rbuf_t buf)
270 {
305 - char *ptr;
271 char http_code_s[4];
307 - int http_code;
272 int idx;
273
274 if (rbuf_memcmp_n(buf, PROXY_HTTP, strlen(PROXY_HTTP))) {
275 if (rbuf_memcmp_n(buf, PROXY_HTTP10, strlen(PROXY_HTTP10))) {
312 - mws_error(client->log, "http_proxy expected reply with \"" PROXY_HTTP "\" or \"" PROXY_HTTP10 "\"");
276 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy expected reply with \"" PROXY_HTTP "\" or \"" PROXY_HTTP10 "\"");
277 return 1;
278 }
279 }
@@ -317,39 +281,37 @@ static int http_parse_reply(mqtt_wss_client client, rbuf_t buf)
281 rbuf_bump_tail(buf, strlen(PROXY_HTTP));
282
283 if (!rbuf_pop(buf, http_code_s, 1) || http_code_s[0] != 0x20) {
320 - mws_error(client->log, "http_proxy missing space after \"" PROXY_HTTP "\" or \"" PROXY_HTTP10 "\"");
284 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy missing space after \"" PROXY_HTTP "\" or \"" PROXY_HTTP10 "\"");
285 return 2;
286 }
287
288 if (!rbuf_pop(buf, http_code_s, HTTP_CODE_LEN)) {
325 - mws_error(client->log, "http_proxy missing HTTP code");
289 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy missing HTTP code");
290 return 3;
291 }
292
293 for (int i = 0; i < HTTP_CODE_LEN - 1; i++)
294 if (http_code_s[i] > 0x39 || http_code_s[i] < 0x30) {
331 - mws_error(client->log, "http_proxy HTTP code non numeric");
295 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy HTTP code non numeric");
296 return 4;
297 }
298
299 http_code_s[HTTP_CODE_LEN - 1] = 0;
336 - http_code = atoi(http_code_s);
300 + int http_code = str2i(http_code_s);
301
302 // TODO check if we ever have more headers here
303 rbuf_find_bytes(buf, HTTP_ENDLINE, strlen(HTTP_ENDLINE), &idx);
304 if (idx >= HTTP_REASON_MAX_LEN) {
341 - mws_error(client->log, "http_proxy returned reason that is too long");
305 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy returned reason that is too long");
306 return 5;
307 }
308
309 if (http_code != 200) {
346 - ptr = mallocz(idx + 1);
347 - if (!ptr)
348 - return 6;
310 + char *ptr = mallocz(idx + 1);
311 rbuf_pop(buf, ptr, idx);
312 ptr[idx] = 0;
313
352 - mws_error(client->log, "http_proxy returned error code %d \"%s\"", http_code, ptr);
314 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy returned error code %d \"%s\"", http_code, ptr);
315 freez(ptr);
316 return 7;
317 }/* else
@@ -362,52 +324,11 @@ static int http_parse_reply(mqtt_wss_client client, rbuf_t buf)
324 rbuf_bump_tail(buf, strlen(HTTP_HDR_TERMINATOR));
325
326 if (rbuf_bytes_available(buf)) {
365 - mws_error(client->log, "http_proxy unexpected trailing bytes after end of HTTP hdr");
327 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy unexpected trailing bytes after end of HTTP hdr");
328 return 8;
329 }
330
369 - mws_debug(client->log, "http_proxy CONNECT succeeded");
370 - return 0;
371 -}
372 -
373 -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
374 -static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
375 -{
376 - EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
377 -
378 - if (ctx != NULL) {
379 - memset(ctx, 0, sizeof(*ctx));
380 - }
381 - return ctx;
382 -}
383 -static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
384 -{
385 - OPENSSL_free(ctx);
386 - return;
387 -}
388 -#endif
389 -
390 -inline static int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
391 -{
392 - int len;
393 - unsigned char *str = out;
394 - EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
395 - EVP_EncodeInit(ctx);
396 - EVP_EncodeUpdate(ctx, str, outl, in, in_len);
397 - str += *outl;
398 - EVP_EncodeFinal(ctx, str, &len);
399 - *outl += len;
400 -
401 - str = out;
402 - while(*str) {
403 - if (*str != 0x0D && *str != 0x0A)
404 - *out++ = *str++;
405 - else
406 - str++;
407 - }
408 - *out = 0;
409 -
410 - EVP_ENCODE_CTX_free(ctx);
331 + nd_log(NDLS_DAEMON, NDLP_DEBUG, "http_proxy CONNECT succeeded");
332 return 0;
333 }
334
@@ -418,13 +339,12 @@ static int http_proxy_connect(mqtt_wss_client client)
339 rbuf_t r_buf = rbuf_create(4096);
340 if (!r_buf)
341 return 1;
421 - char *r_buf_ptr;
342 size_t r_buf_linear_insert_capacity;
343
344 poll_fd.fd = client->sockfd;
345 poll_fd.events = POLLIN;
346
427 - r_buf_ptr = rbuf_get_linear_insert_range(r_buf, &r_buf_linear_insert_capacity);
347 + char *r_buf_ptr = rbuf_get_linear_insert_range(r_buf, &r_buf_linear_insert_capacity);
348 snprintf(r_buf_ptr, r_buf_linear_insert_capacity,"%s %s:%d %s" HTTP_ENDLINE "Host: %s" HTTP_ENDLINE, PROXY_CONNECT,
349 client->target_host, client->target_port, PROXY_HTTP, client->target_host);
350 write(client->sockfd, r_buf_ptr, strlen(r_buf_ptr));
@@ -433,7 +353,7 @@ static int http_proxy_connect(mqtt_wss_client client)
353 size_t creds_plain_len = strlen(client->proxy_uname) + strlen(client->proxy_passwd) + 2;
354 char *creds_plain = mallocz(creds_plain_len);
355 if (!creds_plain) {
436 - mws_error(client->log, "OOM creds_plain");
356 + nd_log(NDLS_DAEMON, NDLP_ERR, "OOM creds_plain");
357 rc = 6;
358 goto cleanup;
359 }
@@ -444,7 +364,7 @@ static int http_proxy_connect(mqtt_wss_client client)
364 char *creds_base64 = mallocz(creds_base64_len + 1);
365 if (!creds_base64) {
366 freez(creds_plain);
447 - mws_error(client->log, "OOM creds_base64");
367 + nd_log(NDLS_DAEMON, NDLP_ERR, "OOM creds_base64");
368 rc = 6;
369 goto cleanup;
370 }
@@ -454,8 +374,7 @@ static int http_proxy_connect(mqtt_wss_client client)
374 *ptr++ = ':';
375 strcpy(ptr, client->proxy_passwd);
376
457 - int b64_len;
458 - base64_encode_helper((unsigned char*)creds_base64, &b64_len, (unsigned char*)creds_plain, strlen(creds_plain));
377 + (void) netdata_base64_encode((unsigned char*)creds_base64, (unsigned char*)creds_plain, strlen(creds_plain));
378 freez(creds_plain);
379
380 r_buf_ptr = rbuf_get_linear_insert_range(r_buf, &r_buf_linear_insert_capacity);
@@ -470,13 +389,13 @@ static int http_proxy_connect(mqtt_wss_client client)
389 // or timeout
390 while ((rc = poll(&poll_fd, 1, 1000)) >= 0) {
391 if (!rc) {
473 - mws_error(client->log, "http_proxy timeout waiting reply from proxy server");
392 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy timeout waiting reply from proxy server");
393 rc = 2;
394 goto cleanup;
395 }
396 r_buf_ptr = rbuf_get_linear_insert_range(r_buf, &r_buf_linear_insert_capacity);
397 if (!r_buf_ptr) {
479 - mws_error(client->log, "http_proxy read ring buffer full");
398 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy read ring buffer full");
399 rc = 3;
400 goto cleanup;
401 }
@@ -484,20 +403,20 @@ static int http_proxy_connect(mqtt_wss_client client)
403 if (errno == EWOULDBLOCK || errno == EAGAIN) {
404 continue;
405 }
487 - mws_error(client->log, "http_proxy error reading from socket \"%s\"", strerror(errno));
406 + nd_log(NDLS_DAEMON, NDLP_ERR, "http_proxy error reading from socket \"%s\"", strerror(errno));
407 rc = 4;
408 goto cleanup;
409 }
410 rbuf_bump_head(r_buf, rc);
411 if (rbuf_find_bytes(r_buf, HTTP_HDR_TERMINATOR, strlen(HTTP_HDR_TERMINATOR), &rc)) {
412 rc = 0;
494 - if (http_parse_reply(client, r_buf))
413 + if (http_parse_reply(r_buf))
414 rc = 5;
415
416 goto cleanup;
417 }
418 }
500 - mws_error(client->log, "proxy negotiation poll error \"%s\"", strerror(errno));
419 + nd_log(NDLS_DAEMON, NDLP_ERR, "proxy negotiation poll error \"%s\"", strerror(errno));
420 rc = 5;
421 cleanup:
422 rbuf_free(r_buf);
@@ -510,11 +429,11 @@ int mqtt_wss_connect(
429 int port,
430 struct mqtt_connect_params *mqtt_params,
431 int ssl_flags,
513 - struct mqtt_wss_proxy *proxy,
432 + const struct mqtt_wss_proxy *proxy,
433 bool *fallback_ipv4)
434 {
435 if (!mqtt_params) {
517 - mws_error(client->log, "mqtt_params can't be null!");
436 + nd_log(NDLS_DAEMON, NDLP_ERR, "mqtt_params can't be null!");
437 return -1;
438 }
439
@@ -571,7 +490,7 @@ int mqtt_wss_connect(
490 struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
491 int fd = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, client->host, 0, port_str, &timeout, fallback_ipv4);
492 if (fd < 0) {
574 - mws_error(client->log, "Could not connect to remote endpoint \"%s\", port %d.\n", client->host, port);
493 + nd_log(NDLS_DAEMON, NDLP_ERR, "Could not connect to remote endpoint \"%s\", port %d.\n", client->host, port);
494 return -3;
495 }
496
@@ -586,12 +505,12 @@ int mqtt_wss_connect(
505 int flag = 1;
506 int result = setsockopt(client->sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
507 if (result < 0)
589 - mws_error(client->log, "Could not dissable NAGLE");
508 + nd_log(NDLS_DAEMON, NDLP_ERR, "Could not dissable NAGLE");
509
510 client->poll_fds[POLLFD_SOCKET].fd = client->sockfd;
511
512 if (fcntl(client->sockfd, F_SETFL, fcntl(client->sockfd, F_GETFL, 0) | O_NONBLOCK) == -1) {
594 - mws_error(client->log, "Error setting O_NONBLOCK to TCP socket. \"%s\"", strerror(errno));
513 + nd_log(NDLS_DAEMON, NDLP_ERR, "Error setting O_NONBLOCK to TCP socket. \"%s\"", strerror(errno));
514 return -8;
515 }
516
@@ -607,7 +526,7 @@ int mqtt_wss_connect(
526 SSL_library_init();
527 #else
528 if (OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL) != 1) {
610 - mws_error(client->log, "Failed to initialize SSL");
529 + nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to initialize SSL");
530 return -1;
531 };
532 #endif
@@ -624,7 +543,7 @@ int mqtt_wss_connect(
543 SSL_CTX_set_default_verify_paths(client->ssl_ctx);
544 SSL_CTX_set_verify(client->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, cert_verify_callback);
545 } else
627 - mws_error(client->log, "SSL Certificate checking completely disabled!!!");
546 + nd_log(NDLS_DAEMON, NDLP_ERR, "SSL Certificate checking completely disabled!!!");
547
548 #ifdef MQTT_WSS_DEBUG
549 if(client->ssl_ctx_keylog_cb)
@@ -634,7 +553,7 @@ int mqtt_wss_connect(
553 client->ssl = SSL_new(client->ssl_ctx);
554 if (!(client->ssl_flags & MQTT_WSS_SSL_DONT_CHECK_CERTS)) {
555 if (!SSL_set_ex_data(client->ssl, 0, client)) {
637 - mws_error(client->log, "Could not SSL_set_ex_data");
556 + nd_log(NDLS_DAEMON, NDLP_ERR, "Could not SSL_set_ex_data");
557 return -4;
558 }
559 }
@@ -642,27 +561,27 @@ int mqtt_wss_connect(
561 SSL_set_connect_state(client->ssl);
562
563 if (!SSL_set_tlsext_host_name(client->ssl, client->target_host)) {
645 - mws_error(client->log, "Error setting TLS SNI host");
564 + nd_log(NDLS_DAEMON, NDLP_ERR, "Error setting TLS SNI host");
565 return -7;
566 }
567
568 result = SSL_connect(client->ssl);
569 if (result != -1 && result != 1) {
651 - mws_error(client->log, "SSL could not connect");
570 + nd_log(NDLS_DAEMON, NDLP_ERR, "SSL could not connect");
571 return -5;
572 }
573
574 if (result == -1) {
575 int ec = SSL_get_error(client->ssl, result);
576 if (ec != SSL_ERROR_WANT_READ && ec != SSL_ERROR_WANT_WRITE) {
658 - mws_error(client->log, "Failed to start SSL connection");
577 + nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to start SSL connection");
578 return -6;
579 }
580 }
581
582 client->mqtt_keepalive = (mqtt_params->keep_alive ? mqtt_params->keep_alive : 400);
583
665 - mws_info(client->log, "Going to connect using internal MQTT 5 implementation");
584 + nd_log(NDLS_DAEMON, NDLP_INFO, "Going to connect using internal MQTT 5 implementation");
585 struct mqtt_auth_properties auth;
586 auth.client_id = (char*)mqtt_params->clientid;
587 auth.client_id_free = NULL;
@@ -682,7 +601,7 @@ int mqtt_wss_connect(
601
602 int ret = mqtt_ng_connect(client->mqtt, &auth, mqtt_params->will_msg ? &lwt : NULL, 1, client->mqtt_keepalive);
603 if (ret) {
685 - mws_error(client->log, "Error generating MQTT connect");
604 + nd_log(NDLS_DAEMON, NDLP_ERR, "Error generating MQTT connect");
605 return 1;
606 }
607
@@ -691,7 +610,7 @@ int mqtt_wss_connect(
610 // wait till MQTT connection is established
611 while (!client->mqtt_connected) {
612 if(mqtt_wss_service(client, -1)) {
694 - mws_error(client->log, "Error connecting to MQTT WSS server \"%s\", port %d.", host, port);
613 + nd_log(NDLS_DAEMON, NDLP_ERR, "Error connecting to MQTT WSS server \"%s\", port %d.", host, port);
614 return 2;
615 }
616 }
@@ -704,14 +623,14 @@ int mqtt_wss_connect(
623 #define NSEC_PER_MSEC 1000000ULL
624 #define NSEC_PER_SEC 1000000000ULL
625
707 -static inline uint64_t boottime_usec(mqtt_wss_client client) {
626 +static uint64_t boottime_usec(void) {
627 struct timespec ts;
628 #if defined(__APPLE__) || defined(__FreeBSD__)
629 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
630 #else
631 if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) {
632 #endif
714 - mws_error(client->log, "clock_gettimte failed");
633 + nd_log(NDLS_DAEMON, NDLP_ERR, "clock_gettimte failed");
634 return 0;
635 }
636 return (uint64_t)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC;
@@ -720,7 +639,7 @@ static inline uint64_t boottime_usec(mqtt_wss_client client) {
639 #define MWS_TIMED_OUT 1
640 #define MWS_ERROR 2
641 #define MWS_OK 0
723 -static inline const char *mqtt_wss_error_tos(int ec)
642 +static const char *mqtt_wss_error_tos(int ec)
643 {
644 switch(ec) {
645 case MWS_TIMED_OUT:
@@ -733,13 +652,12 @@ static inline const char *mqtt_wss_error_tos(int ec)
652
653 }
654
736 -static inline int mqtt_wss_service_all(mqtt_wss_client client, int timeout_ms)
655 +static int mqtt_wss_service_all(mqtt_wss_client client, int timeout_ms)
656 {
738 - uint64_t exit_by = boottime_usec(client) + (timeout_ms * NSEC_PER_MSEC);
739 - uint64_t now;
657 + uint64_t exit_by = boottime_usec() + (timeout_ms * NSEC_PER_MSEC);
658 client->poll_fds[POLLFD_SOCKET].events |= POLLOUT; // TODO when entering mwtt_wss_service use out buffer size to arm POLLOUT
659 while (rbuf_bytes_available(client->ws_client->buf_write)) {
742 - now = boottime_usec(client);
660 + const uint64_t now = boottime_usec();
661 if (now >= exit_by)
662 return MWS_TIMED_OUT;
663 if (mqtt_wss_service(client, exit_by - now))
@@ -750,15 +668,13 @@ static inline int mqtt_wss_service_all(mqtt_wss_client client, int timeout_ms)
668
669 void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms)
670 {
753 - int ret;
754 -
671 // block application from sending more MQTT messages
672 client->mqtt_disconnecting = 1;
673
674 // send whatever was left at the time of calling this function
759 - ret = mqtt_wss_service_all(client, timeout_ms / 4);
675 + int ret = mqtt_wss_service_all(client, timeout_ms / 4);
676 if(ret)
761 - mws_error(client->log,
677 + nd_log(NDLS_DAEMON, NDLP_ERR,
678 "Error while trying to send all remaining data in an attempt "
679 "to gracefully disconnect! EC=%d Desc:\"%s\"",
680 ret,
@@ -770,7 +686,7 @@ void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms)
686
687 ret = mqtt_wss_service_all(client, timeout_ms / 4);
688 if(ret)
773 - mws_error(client->log,
689 + nd_log(NDLS_DAEMON, NDLP_ERR,
690 "Error while trying to send MQTT disconnect message in an attempt "
691 "to gracefully disconnect! EC=%d Desc:\"%s\"",
692 ret,
@@ -783,7 +699,7 @@ void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms)
699 if(ret) {
700 // Some MQTT/WSS servers will close socket on receipt of MQTT disconnect and
701 // do not wait for WebSocket to be closed properly
786 - mws_warn(client->log,
702 + nd_log(NDLS_DAEMON, NDLP_WARNING,
703 "Error while trying to send WebSocket disconnect message in an attempt "
704 "to gracefully disconnect! EC=%d Desc:\"%s\".",
705 ret,
@@ -798,22 +714,19 @@ void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms)
714 client->sockfd = -1;
715 }
716
801 -static inline void mqtt_wss_wakeup(mqtt_wss_client client)
717 +static void mqtt_wss_wakeup(mqtt_wss_client client)
718 {
803 -#ifdef DEBUG_ULTRA_VERBOSE
804 - mws_debug(client->log, "mqtt_wss_wakup - forcing wake up of main loop");
805 -#endif
719 write(client->write_notif_pipe[PIPE_WRITE_END], " ", 1);
720 }
721
722 #define THROWAWAY_BUF_SIZE 32
723 char throwaway[THROWAWAY_BUF_SIZE];
811 -static inline void util_clear_pipe(int fd)
724 +static void util_clear_pipe(int fd)
725 {
726 (void)read(fd, throwaway, THROWAWAY_BUF_SIZE);
727 }
728
816 -static inline void set_socket_pollfds(mqtt_wss_client client, int ssl_ret) {
729 +static void set_socket_pollfds(mqtt_wss_client client, int ssl_ret) {
730 if (ssl_ret == SSL_ERROR_WANT_WRITE)
731 client->poll_fds[POLLFD_SOCKET].events |= POLLOUT;
732 if (ssl_ret == SSL_ERROR_WANT_READ)
@@ -824,7 +737,7 @@ static int handle_mqtt_internal(mqtt_wss_client client)
737 {
738 int rc = mqtt_ng_sync(client->mqtt);
739 if (rc) {
827 - mws_error(client->log, "mqtt_ng_sync returned %d != 0", rc);
740 + nd_log(NDLS_DAEMON, NDLP_ERR, "mqtt_ng_sync returned %d != 0", rc);
741 client->mqtt_connected = 0;
742 return 1;
743 }
@@ -832,7 +745,7 @@ static int handle_mqtt_internal(mqtt_wss_client client)
745 }
746
747 #define SEC_TO_MSEC 1000
835 -static inline long long int t_till_next_keepalive_ms(mqtt_wss_client client)
748 +static long long int t_till_next_keepalive_ms(mqtt_wss_client client)
749 {
750 time_t last_send = mqtt_ng_last_send_time(client->mqtt);
751 long long int next_mqtt_keep_alive = (last_send * SEC_TO_MSEC)
@@ -841,10 +754,10 @@ static inline long long int t_till_next_keepalive_ms(mqtt_wss_client client)
754 }
755
756 #ifdef MQTT_WSS_CPUSTATS
844 -static inline uint64_t mqtt_wss_now_usec(mqtt_wss_client client) {
757 +static uint64_t mqtt_wss_now_usec(void) {
758 struct timespec ts;
759 if(clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
847 - mws_error(client->log, "clock_gettime(CLOCK_MONOTONIC, &timespec) failed.");
760 + nd_log(NDLS_DAEMON, NDLP_ERR, "clock_gettime(CLOCK_MONOTONIC, &timespec) failed.");
761 return 0;
762 }
763 return (uint64_t)ts.tv_sec * USEC_PER_SEC + (ts.tv_nsec % NSEC_PER_SEC) / NSEC_PER_USEC;
@@ -859,61 +772,39 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
772 int send_keepalive = 0;
773
774 #ifdef MQTT_WSS_CPUSTATS
862 - uint64_t t1,t2;
863 - t1 = mqtt_wss_now_usec(client);
864 -#endif
865 -
866 -#ifdef DEBUG_ULTRA_VERBOSE
867 - mws_debug(client->log, ">>>>> mqtt_wss_service <<<<<");
868 - mws_debug(client->log, "Waiting for events: %s%s%s",
869 - (client->poll_fds[POLLFD_SOCKET].events & POLLIN) ? "SOCKET_POLLIN " : "",
870 - (client->poll_fds[POLLFD_SOCKET].events & POLLOUT) ? "SOCKET_POLLOUT " : "",
871 - (client->poll_fds[POLLFD_PIPE].events & POLLIN) ? "PIPE_POLLIN" : "" );
775 + uint64_t t2;
776 + uint64_t t1 = mqtt_wss_now_usec();
777 #endif
778
779 // Check user requested TO doesn't interfere with MQTT keep alives
780 long long int till_next_keep_alive = t_till_next_keepalive_ms(client);
781 if (client->mqtt_connected && (timeout_ms < 0 || timeout_ms >= till_next_keep_alive)) {
877 - #ifdef DEBUG_ULTRA_VERBOSE
878 - mws_debug(client->log, "Shortening Timeout requested %d to %lld to ensure keep-alive can be sent", timeout_ms, till_next_keep_alive);
879 - #endif
782 timeout_ms = till_next_keep_alive;
783 send_keepalive = 1;
784 }
785
786 #ifdef MQTT_WSS_CPUSTATS
885 - t2 = mqtt_wss_now_usec(client);
787 + t2 = mqtt_wss_now_usec();
788 client->stats.time_keepalive += t2 - t1;
789 #endif
790
791 if ((ret = poll(client->poll_fds, 2, timeout_ms >= 0 ? timeout_ms : -1)) < 0) {
792 if (errno == EINTR) {
891 - mws_warn(client->log, "poll interrupted by EINTR");
793 + nd_log(NDLS_DAEMON, NDLP_WARNING, "poll interrupted by EINTR");
794 return 0;
795 }
894 - mws_error(client->log, "poll error \"%s\"", strerror(errno));
796 + nd_log(NDLS_DAEMON, NDLP_ERR, "poll error \"%s\"", strerror(errno));
797 return -2;
798 }
799
898 -#ifdef DEBUG_ULTRA_VERBOSE
899 - mws_debug(client->log, "Poll events happened: %s%s%s%s",
900 - (client->poll_fds[POLLFD_SOCKET].revents & POLLIN) ? "SOCKET_POLLIN " : "",
901 - (client->poll_fds[POLLFD_SOCKET].revents & POLLOUT) ? "SOCKET_POLLOUT " : "",
902 - (client->poll_fds[POLLFD_PIPE].revents & POLLIN) ? "PIPE_POLLIN " : "",
903 - (!ret) ? "POLL_TIMEOUT" : "");
904 -#endif
905 -
800 #ifdef MQTT_WSS_CPUSTATS
907 - t1 = mqtt_wss_now_usec(client);
801 + t1 = mqtt_wss_now_usec();
802 #endif
803
804 if (ret == 0) {
805 if (send_keepalive) {
806 // otherwise we shortened the timeout ourselves to take care of
807 // MQTT keep alives
914 -#ifdef DEBUG_ULTRA_VERBOSE
915 - mws_debug(client->log, "Forcing MQTT Ping/keep-alive");
916 -#endif
808 mqtt_ng_ping(client->mqtt);
809 } else {
810 // if poll timed out and user requested timeout was being used
@@ -923,7 +814,7 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
814 }
815
816 #ifdef MQTT_WSS_CPUSTATS
926 - t2 = mqtt_wss_now_usec(client);
817 + t2 = mqtt_wss_now_usec();
818 client->stats.time_keepalive += t2 - t1;
819 #endif
820
@@ -931,9 +822,6 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
822
823 if ((ptr = rbuf_get_linear_insert_range(client->ws_client->buf_read, &size))) {
824 if((ret = SSL_read(client->ssl, ptr, size)) > 0) {
934 -#ifdef DEBUG_ULTRA_VERBOSE
935 - mws_debug(client->log, "SSL_Read: Read %d.", ret);
936 -#endif
825 spinlock_lock(&client->stat_lock);
826 client->stats.bytes_rx += ret;
827 spinlock_unlock(&client->stat_lock);
@@ -941,22 +829,19 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
829 } else {
830 int errnobkp = errno;
831 ret = SSL_get_error(client->ssl, ret);
944 -#ifdef DEBUG_ULTRA_VERBOSE
945 - mws_debug(client->log, "Read Err: %s", util_openssl_ret_err(ret));
946 -#endif
832 set_socket_pollfds(client, ret);
833 if (ret != SSL_ERROR_WANT_READ &&
834 ret != SSL_ERROR_WANT_WRITE) {
950 - mws_error(client->log, "SSL_read error: %d %s", ret, util_openssl_ret_err(ret));
835 + nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_read error: %d %s", ret, util_openssl_ret_err(ret));
836 if (ret == SSL_ERROR_SYSCALL)
952 - mws_error(client->log, "SSL_read SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
837 + nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_read SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
838 return MQTT_WSS_ERR_CONN_DROP;
839 }
840 }
841 }
842
843 #ifdef MQTT_WSS_CPUSTATS
959 - t1 = mqtt_wss_now_usec(client);
844 + t1 = mqtt_wss_now_usec();
845 client->stats.time_read_socket += t1 - t2;
846 #endif
847
@@ -964,18 +849,20 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
849 switch(ret) {
850 case WS_CLIENT_PROTOCOL_ERROR:
851 return MQTT_WSS_ERR_PROTO_WS;
852 +
853 case WS_CLIENT_NEED_MORE_BYTES:
968 -#ifdef DEBUG_ULTRA_VERBOSE
969 - mws_debug(client->log, "WSCLIENT WANT READ");
970 -#endif
854 client->poll_fds[POLLFD_SOCKET].events |= POLLIN;
855 break;
856 +
857 case WS_CLIENT_CONNECTION_CLOSED:
858 return MQTT_WSS_ERR_CONN_DROP;
859 +
860 + default:
861 + return MQTT_WSS_ERR_PROTO_WS;
862 }
863
864 #ifdef MQTT_WSS_CPUSTATS
978 - t2 = mqtt_wss_now_usec(client);
865 + t2 = mqtt_wss_now_usec();
866 client->stats.time_process_websocket += t2 - t1;
867 #endif
868
@@ -990,18 +877,12 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
877 }
878
879 #ifdef MQTT_WSS_CPUSTATS
993 - t1 = mqtt_wss_now_usec(client);
880 + t1 = mqtt_wss_now_usec();
881 client->stats.time_process_mqtt += t1 - t2;
882 #endif
883
884 if ((ptr = rbuf_get_linear_read_range(client->ws_client->buf_write, &size))) {
998 -#ifdef DEBUG_ULTRA_VERBOSE
999 - mws_debug(client->log, "Have data to write to SSL");
1000 -#endif
885 if ((ret = SSL_write(client->ssl, ptr, size)) > 0) {
1002 -#ifdef DEBUG_ULTRA_VERBOSE
1003 - mws_debug(client->log, "SSL_Write: Written %d of avail %d.", ret, size);
1004 -#endif
886 spinlock_lock(&client->stat_lock);
887 client->stats.bytes_tx += ret;
888 spinlock_unlock(&client->stat_lock);
@@ -1009,15 +890,12 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
890 } else {
891 int errnobkp = errno;
892 ret = SSL_get_error(client->ssl, ret);
1012 -#ifdef DEBUG_ULTRA_VERBOSE
1013 - mws_debug(client->log, "Write Err: %s", util_openssl_ret_err(ret));
1014 -#endif
893 set_socket_pollfds(client, ret);
894 if (ret != SSL_ERROR_WANT_READ &&
895 ret != SSL_ERROR_WANT_WRITE) {
1018 - mws_error(client->log, "SSL_write error: %d %s", ret, util_openssl_ret_err(ret));
896 + nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_write error: %d %s", ret, util_openssl_ret_err(ret));
897 if (ret == SSL_ERROR_SYSCALL)
1020 - mws_error(client->log, "SSL_write SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
898 + nd_log(NDLS_DAEMON, NDLP_ERR, "SSL_write SYSCALL errno: %d %s", errnobkp, strerror(errnobkp));
899 return MQTT_WSS_ERR_CONN_DROP;
900 }
901 }
@@ -1027,7 +905,7 @@ int mqtt_wss_service(mqtt_wss_client client, int timeout_ms)
905 util_clear_pipe(client->write_notif_pipe[PIPE_READ_END]);
906
907 #ifdef MQTT_WSS_CPUSTATS
1030 - t2 = mqtt_wss_now_usec(client);
908 + t2 = mqtt_wss_now_usec();
909 client->stats.time_write_socket += t2 - t1;
910 #endif
911
@@ -1044,12 +922,12 @@ int mqtt_wss_publish5(mqtt_wss_client client,
922 uint16_t *packet_id)
923 {
924 if (client->mqtt_disconnecting) {
1047 - mws_error(client->log, "mqtt_wss is disconnecting can't publish");
925 + nd_log(NDLS_DAEMON, NDLP_ERR, "mqtt_wss is disconnecting can't publish");
926 return 1;
927 }
928
929 if (!client->mqtt_connected) {
1052 - mws_error(client->log, "MQTT is offline. Can't send message.");
930 + nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT is offline. Can't send message.");
931 return 1;
932 }
933 uint8_t mqtt_flags = 0;
@@ -1060,7 +938,7 @@ int mqtt_wss_publish5(mqtt_wss_client client,
938
939 int rc = mqtt_ng_publish(client->mqtt, topic, topic_free, msg, msg_free, msg_len, mqtt_flags, packet_id);
940 if (rc == MQTT_NG_MSGGEN_MSG_TOO_BIG)
1063 - return MQTT_WSS_ERR_TOO_BIG_FOR_SERVER;
941 + return MQTT_WSS_ERR_MSG_TOO_BIG;
942
943 mqtt_wss_wakeup(client);
944
@@ -1071,12 +949,12 @@ int mqtt_wss_subscribe(mqtt_wss_client client, char *topic, int max_qos_level)
949 {
950 (void)max_qos_level; //TODO now hardcoded
951 if (!client->mqtt_connected) {
1074 - mws_error(client->log, "MQTT is offline. Can't subscribe.");
952 + nd_log(NDLS_DAEMON, NDLP_ERR, "MQTT is offline. Can't subscribe.");
953 return 1;
954 }
955
956 if (client->mqtt_disconnecting) {
1079 - mws_error(client->log, "mqtt_wss is disconnecting can't subscribe");
957 + nd_log(NDLS_DAEMON, NDLP_ERR, "mqtt_wss is disconnecting can't subscribe");
958 return 1;
959 }
960
src/aclk/mqtt_websockets/mqtt_wss_client.h
+16 -31
@@ -3,49 +3,34 @@
3 #ifndef MQTT_WSS_CLIENT_H
4 #define MQTT_WSS_CLIENT_H
5
6 -#include "mqtt_wss_log.h"
6 #include "common_public.h"
7
9 -// All OK call me at your earliest convinience
10 -#define MQTT_WSS_OK 0
11 -/* All OK, poll timeout you requested when calling mqtt_wss_service expired - you might want to know if timeout
12 - * happened or we got some data or handle same as MQTT_WSS_OK
13 - */
14 -#define MQTT_WSS_OK_TO 1
15 -// Connection was closed by remote
16 -#define MQTT_WSS_ERR_CONN_DROP -1
17 -// Error in MQTT protocol (e.g. malformed packet)
18 -#define MQTT_WSS_ERR_PROTO_MQTT -2
19 -// Error in WebSocket protocol (e.g. malformed packet)
20 -#define MQTT_WSS_ERR_PROTO_WS -3
21 -
22 -#define MQTT_WSS_ERR_TX_BUF_TOO_SMALL -4
23 -#define MQTT_WSS_ERR_RX_BUF_TOO_SMALL -5
24 -
25 -#define MQTT_WSS_ERR_TOO_BIG_FOR_SERVER -6
26 -// if client was initialized with MQTT 3 but MQTT 5 feature
27 -// was requested by user of library
28 -#define MQTT_WSS_ERR_CANT_DO -8
8 +
9 +#define MQTT_WSS_OK 0 // All OK call me at your earliest convinience
10 +#define MQTT_WSS_OK_TO 1 // All OK, poll timeout you requested when calling mqtt_wss_service expired
11 + //you might want to know if timeout
12 + //happened or we got some data or handle same as MQTT_WSS_OK
13 +#define MQTT_WSS_ERR_CONN_DROP -1 // Connection was closed by remote
14 +#define MQTT_WSS_ERR_PROTO_MQTT -2 // Error in MQTT protocol (e.g. malformed packet)
15 +#define MQTT_WSS_ERR_PROTO_WS -3 // Error in WebSocket protocol (e.g. malformed packet)
16 +#define MQTT_WSS_ERR_MSG_TOO_BIG -6 // Message size too big for server
17 +#define MQTT_WSS_ERR_CANT_DO -8 // if client was initialized with MQTT 3 but MQTT 5 feature
18 + // was requested by user of library
19
20 typedef struct mqtt_wss_client_struct *mqtt_wss_client;
21
22 typedef void (*msg_callback_fnc_t)(const char *topic, const void *msg, size_t msglen, int qos);
23 +
24 /* Creates new instance of MQTT over WSS. Doesn't start connection.
34 - * @param log_prefix this is prefix to be used when logging to discern between multiple
35 - * mqtt_wss instances. Can be NULL.
36 - * @param log_callback is function pointer to fnc to be called when mqtt_wss wants
37 - * to log. This allows plugging this library into your own logging system/solution.
38 - * If NULL STDOUT/STDERR will be used.
25 * @param msg_callback is function pointer to function which will be called
26 * when application level message arrives from broker (for subscribed topics).
27 * Can be NULL if you are not interested about incoming messages.
28 * @param puback_callback is function pointer to function to be called when QOS1 Publish
29 * is acknowledged by server
30 */
45 -mqtt_wss_client mqtt_wss_new(const char *log_prefix,
46 - mqtt_wss_log_callback_t log_callback,
47 - msg_callback_fnc_t msg_callback,
48 - void (*puback_callback)(uint16_t packet_id));
31 +mqtt_wss_client mqtt_wss_new(
32 + msg_callback_fnc_t msg_callback,
33 + void (*puback_callback)(uint16_t packet_id));
34
35 void mqtt_wss_set_max_buf_size(mqtt_wss_client client, size_t size);
36
@@ -71,7 +56,7 @@ int mqtt_wss_connect(
56 int port,
57 struct mqtt_connect_params *mqtt_params,
58 int ssl_flags,
74 - struct mqtt_wss_proxy *proxy,
59 + const struct mqtt_wss_proxy *proxy,
60 bool *fallback_ipv4);
61 int mqtt_wss_service(mqtt_wss_client client, int timeout_ms);
62 void mqtt_wss_disconnect(mqtt_wss_client client, int timeout_ms);
src/aclk/mqtt_websockets/mqtt_wss_log.c deleted
-126
@@ -1,126 +0,0 @@
1 -// SPDX-License-Identifier: GPL-3.0-or-later
2 -
3 -#include "libnetdata/libnetdata.h"
4 -
5 -#include "mqtt_wss_log.h"
6 -
7 -struct mqtt_wss_log_ctx {
8 - mqtt_wss_log_callback_t extern_log_fnc;
9 - char *ctx_prefix;
10 - char *buffer;
11 - char *buffer_w_ptr;
12 - size_t buffer_bytes_avail;
13 -};
14 -
15 -#define LOG_BUFFER_SIZE 1024 * 4
16 -#define LOG_CTX_PREFIX_SEV_STR " : "
17 -#define LOG_CTX_PREFIX_LIMIT 15
18 -#define LOG_CTX_PREFIX_LIMIT_STR (LOG_CTX_PREFIX_LIMIT - (2 + strlen(LOG_CTX_PREFIX_SEV_STR))) // with [] characters and affixed ' ' it is total 15 chars
19 -#if (LOG_CTX_PREFIX_LIMIT * 10) > LOG_BUFFER_SIZE
20 -#error "LOG_BUFFER_SIZE too small"
21 -#endif
22 -mqtt_wss_log_ctx_t mqtt_wss_log_ctx_create(const char *ctx_prefix, mqtt_wss_log_callback_t log_callback)
23 -{
24 - mqtt_wss_log_ctx_t ctx = callocz(1, sizeof(struct mqtt_wss_log_ctx));
25 - if(!ctx)
26 - return NULL;
27 -
28 - if(log_callback) {
29 - ctx->extern_log_fnc = log_callback;
30 - ctx->buffer = callocz(1, LOG_BUFFER_SIZE);
31 - if(!ctx->buffer)
32 - goto cleanup;
33 -
34 - ctx->buffer_w_ptr = ctx->buffer;
35 - if(ctx_prefix) {
36 - *(ctx->buffer_w_ptr++) = '[';
37 - strncpy(ctx->buffer_w_ptr, ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
38 - ctx->buffer_w_ptr += strnlen(ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
39 - *(ctx->buffer_w_ptr++) = ']';
40 - }
41 - strcpy(ctx->buffer_w_ptr, LOG_CTX_PREFIX_SEV_STR);
42 - ctx->buffer_w_ptr += strlen(LOG_CTX_PREFIX_SEV_STR);
43 - // no term '\0' -> calloc is used
44 -
45 - ctx->buffer_bytes_avail = LOG_BUFFER_SIZE - strlen(ctx->buffer);
46 -
47 - return ctx;
48 - }
49 -
50 - if(ctx_prefix) {
51 - ctx->ctx_prefix = strndup(ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
52 - if(!ctx->ctx_prefix)
53 - goto cleanup;
54 - }
55 -
56 - return ctx;
57 -
58 -cleanup:
59 - freez(ctx);
60 - return NULL;
61 -}
62 -
63 -void mqtt_wss_log_ctx_destroy(mqtt_wss_log_ctx_t ctx)
64 -{
65 - freez(ctx->ctx_prefix);
66 - freez(ctx->buffer);
67 - freez(ctx);
68 -}
69 -
70 -static inline char severity_to_c(int severity)
71 -{
72 - switch (severity) {
73 - case MQTT_WSS_LOG_FATAL:
74 - return 'F';
75 - case MQTT_WSS_LOG_ERROR:
76 - return 'E';
77 - case MQTT_WSS_LOG_WARN:
78 - return 'W';
79 - case MQTT_WSS_LOG_INFO:
80 - return 'I';
81 - case MQTT_WSS_LOG_DEBUG:
82 - return 'D';
83 - default:
84 - return '?';
85 - }
86 -}
87 -
88 -void mws_log(int severity, mqtt_wss_log_ctx_t ctx, const char *fmt, va_list args)
89 -{
90 - size_t size;
91 -
92 - if(ctx->extern_log_fnc) {
93 - size = vsnprintf(ctx->buffer_w_ptr, ctx->buffer_bytes_avail, fmt, args);
94 - *(ctx->buffer_w_ptr - 3) = severity_to_c(severity);
95 -
96 - ctx->extern_log_fnc(severity, ctx->buffer);
97 -
98 - if(size >= ctx->buffer_bytes_avail)
99 - mws_error(ctx, "Last message of this type was truncated! Consider what you log or increase LOG_BUFFER_SIZE if really needed.");
100 -
101 - return;
102 - }
103 -
104 - if(ctx->ctx_prefix)
105 - printf("[%s] ", ctx->ctx_prefix);
106 -
107 - printf("%c: ", severity_to_c(severity));
108 -
109 - vprintf(fmt, args);
110 - putchar('\n');
111 -}
112 -
113 -#define DEFINE_MWS_SEV_FNC(severity_fncname, severity) \
114 -void mws_ ## severity_fncname(mqtt_wss_log_ctx_t ctx, const char *fmt, ...) \
115 -{ \
116 - va_list args; \
117 - va_start(args, fmt); \
118 - mws_log(severity, ctx, fmt, args); \
119 - va_end(args); \
120 -}
121 -
122 -DEFINE_MWS_SEV_FNC(fatal, MQTT_WSS_LOG_FATAL)
123 -DEFINE_MWS_SEV_FNC(error, MQTT_WSS_LOG_ERROR)
124 -DEFINE_MWS_SEV_FNC(warn, MQTT_WSS_LOG_WARN )
125 -DEFINE_MWS_SEV_FNC(info, MQTT_WSS_LOG_INFO )
126 -DEFINE_MWS_SEV_FNC(debug, MQTT_WSS_LOG_DEBUG)
src/aclk/mqtt_websockets/mqtt_wss_log.h deleted
-39
@@ -1,39 +0,0 @@
1 -// Copyright: SPDX-License-Identifier: GPL-3.0-only
2 -
3 -#ifndef MQTT_WSS_LOG_H
4 -#define MQTT_WSS_LOG_H
5 -
6 -typedef enum mqtt_wss_log_type {
7 - MQTT_WSS_LOG_DEBUG = 0x01,
8 - MQTT_WSS_LOG_INFO = 0x02,
9 - MQTT_WSS_LOG_WARN = 0x03,
10 - MQTT_WSS_LOG_ERROR = 0x81,
11 - MQTT_WSS_LOG_FATAL = 0x88
12 -} mqtt_wss_log_type_t;
13 -
14 -typedef void (*mqtt_wss_log_callback_t)(mqtt_wss_log_type_t, const char*);
15 -
16 -typedef struct mqtt_wss_log_ctx *mqtt_wss_log_ctx_t;
17 -
18 -/** Creates logging context with optional prefix and optional callback
19 - * @param ctx_prefix String to be prefixed to every log message.
20 - * This is useful if multiple clients are instantiated to be able to
21 - * know which one this message belongs to. Can be `NULL` for no prefix.
22 - * @param log_callback Callback to be called instead of logging to
23 - * `STDOUT` or `STDERR` (if debug enabled otherwise silent). Callback has to be
24 - * pointer to function of `void function(mqtt_wss_log_type_t, const char*)` type.
25 - * If `NULL` default will be used (silent or STDERR/STDOUT).
26 - * @return mqtt_wss_log_ctx_t or `NULL` on error */
27 -mqtt_wss_log_ctx_t mqtt_wss_log_ctx_create(const char *ctx_prefix, mqtt_wss_log_callback_t log_callback);
28 -
29 -/** Destroys logging context and cleans up the memory
30 - * @param ctx Context to destroy */
31 -void mqtt_wss_log_ctx_destroy(mqtt_wss_log_ctx_t ctx);
32 -
33 -void mws_fatal(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
34 -void mws_error(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
35 -void mws_warn (mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
36 -void mws_info (mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
37 -void mws_debug(mqtt_wss_log_ctx_t ctx, const char *fmt, ...);
38 -
39 -#endif /* MQTT_WSS_LOG_H */
src/aclk/mqtt_websockets/ws_client.c
+113 -134
@@ -5,78 +5,54 @@
5 #include "ws_client.h"
6 #include "common_internal.h"
7
8 -#define UNIT_LOG_PREFIX "ws_client: "
9 -#define FATAL(fmt, ...) mws_fatal(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
10 -#define ERROR(fmt, ...) mws_error(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
11 -#define WARN(fmt, ...) mws_warn (client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
12 -#define INFO(fmt, ...) mws_info (client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
13 -#define DEBUG(fmt, ...) mws_debug(client->log, UNIT_LOG_PREFIX fmt, ##__VA_ARGS__)
8 +#ifdef OS_WINDOWS
9 +#include <windows.h>
10 +#include <bcrypt.h> // For BCryptGenRandom
11 +#endif
12 +
13 +static uint32_t generate_random_32bit(void) {
14 + uint32_t random_number = 0;
15 +
16 + if (RAND_bytes((unsigned char *)&random_number, sizeof(random_number)) != 1) {
17 + nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to generate a random uint32 mask");
18 + }
19 +
20 + return random_number;
21 +}
22
23 const char *websocket_upgrage_hdr = "GET /mqtt HTTP/1.1\x0D\x0A"
24 "Host: %s\x0D\x0A"
25 "Upgrade: websocket\x0D\x0A"
26 "Connection: Upgrade\x0D\x0A"
27 "Sec-WebSocket-Key: %s\x0D\x0A"
20 - "Origin: http://example.com\x0D\x0A"
28 + "Origin: \x0D\x0A"
29 "Sec-WebSocket-Protocol: mqtt\x0D\x0A"
30 "Sec-WebSocket-Version: 13\x0D\x0A\x0D\x0A";
31
32 const char *mqtt_protoid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
33
34 #define DEFAULT_RINGBUFFER_SIZE (1024*128)
27 -#define ENTROPY_SOURCE "/dev/urandom"
28 -ws_client *ws_client_new(size_t buf_size, char **host, mqtt_wss_log_ctx_t log)
29 -{
30 - ws_client *client;
35
36 +ws_client *ws_client_new(size_t buf_size, char **host)
37 +{
38 if(!host)
39 return NULL;
40
35 - client = callocz(1, sizeof(ws_client));
36 - if (!client)
37 - return NULL;
38 -
41 + ws_client *client = callocz(1, sizeof(ws_client));
42 client->host = host;
40 - client->log = log;
41 -
43 client->buf_read = rbuf_create(buf_size ? buf_size : DEFAULT_RINGBUFFER_SIZE);
43 - if (!client->buf_read)
44 - goto cleanup;
45 -
44 client->buf_write = rbuf_create(buf_size ? buf_size : DEFAULT_RINGBUFFER_SIZE);
47 - if (!client->buf_write)
48 - goto cleanup_1;
49 -
45 client->buf_to_mqtt = rbuf_create(buf_size ? buf_size : DEFAULT_RINGBUFFER_SIZE);
51 - if (!client->buf_to_mqtt)
52 - goto cleanup_2;
53 -
54 - client->entropy_fd = open(ENTROPY_SOURCE, O_RDONLY | O_CLOEXEC);
55 - if (client->entropy_fd < 1) {
56 - ERROR("Error opening entropy source \"" ENTROPY_SOURCE "\". Reason: \"%s\"", strerror(errno));
57 - goto cleanup_3;
58 - }
46
47 return client;
61 -
62 -cleanup_3:
63 - rbuf_free(client->buf_to_mqtt);
64 -cleanup_2:
65 - rbuf_free(client->buf_write);
66 -cleanup_1:
67 - rbuf_free(client->buf_read);
68 -cleanup:
69 - freez(client);
70 - return NULL;
48 }
49
50 void ws_client_free_headers(ws_client *client)
51 {
52 struct http_header *ptr = client->hs.headers;
76 - struct http_header *tmp;
53
54 while (ptr) {
79 - tmp = ptr;
55 + struct http_header *tmp = ptr;
56 ptr = ptr->next;
57 freez(tmp);
58 }
@@ -91,7 +67,6 @@ void ws_client_destroy(ws_client *client)
67 ws_client_free_headers(client);
68 freez(client->hs.nonce_reply);
69 freez(client->hs.http_reply_msg);
94 - close(client->entropy_fd);
70 rbuf_free(client->buf_read);
71 rbuf_free(client->buf_write);
72 rbuf_free(client->buf_to_mqtt);
@@ -120,7 +95,7 @@ void ws_client_reset(ws_client *client)
95 int ws_client_add_http_header(ws_client *client, struct http_header *hdr)
96 {
97 if (client->hs.hdr_count > MAX_HTTP_HDR_COUNT) {
123 - ERROR("Too many HTTP response header fields");
98 + nd_log(NDLS_DAEMON, NDLP_ERR, "Too many HTTP response header fields");
99 return -1;
100 }
101
@@ -135,7 +110,7 @@ int ws_client_add_http_header(ws_client *client, struct http_header *hdr)
110 return 0;
111 }
112
138 -int ws_client_want_write(ws_client *client)
113 +int ws_client_want_write(const ws_client *client)
114 {
115 return rbuf_bytes_available(client->buf_write);
116 }
@@ -144,78 +119,92 @@ int ws_client_want_write(ws_client *client)
119 #define TEMP_BUF_SIZE 4096
120 int ws_client_start_handshake(ws_client *client)
121 {
147 - nd_uuid_t nonce;
122 + unsigned char nonce[WEBSOCKET_NONCE_SIZE];
123 char nonce_b64[256];
124 char second[TEMP_BUF_SIZE];
125 unsigned int md_len;
151 - unsigned char *digest;
126 + unsigned char digest[EVP_MAX_MD_SIZE]; // EVP_MAX_MD_SIZE ensures enough space
127 EVP_MD_CTX *md_ctx;
128 const EVP_MD *md;
129 + int rc = 1;
130
131 if(!client->host || !*client->host) {
156 - ERROR("Hostname has not been set. We should not be able to come here!");
132 + nd_log(NDLS_DAEMON, NDLP_ERR, "Hostname has not been set. We should not be able to come here!");
133 return 1;
134 }
135
160 - uuid_generate_random(nonce);
161 - EVP_EncodeBlock((unsigned char *)nonce_b64, (const unsigned char *)nonce, WEBSOCKET_NONCE_SIZE);
162 - snprintf(second, TEMP_BUF_SIZE, websocket_upgrage_hdr, *client->host, nonce_b64);
163 -
164 - if(rbuf_bytes_free(client->buf_write) < strlen(second)) {
165 - ERROR("Write buffer capacity too low.");
136 + // Generate a random 16-byte nonce
137 + if (!RAND_bytes(nonce, WEBSOCKET_NONCE_SIZE)) {
138 + nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to generate nonce");
139 return 1;
140 }
141
169 - rbuf_push(client->buf_write, second, strlen(second));
170 - client->state = WS_HANDSHAKE;
171 -
172 - //Calculating expected Sec-WebSocket-Accept reply
173 - snprintf(second, TEMP_BUF_SIZE, "%s%s", nonce_b64, mqtt_protoid);
174 -
142 + // Initialize the digest context
143 #if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110)
144 md_ctx = EVP_MD_CTX_create();
145 #else
146 md_ctx = EVP_MD_CTX_new();
147 #endif
148 if (md_ctx == NULL) {
181 - ERROR("Cant create EVP_MD Context");
149 + nd_log(NDLS_DAEMON, NDLP_ERR, "Can't create EVP_MD context");
150 return 1;
151 }
152
185 - md = EVP_get_digestbyname("sha1");
153 + md = EVP_sha1(); // Use SHA-1 for WebSocket handshake
154 if (!md) {
187 - ERROR("Unknown message digest");
188 - return 1;
155 + nd_log(NDLS_DAEMON, NDLP_ERR, "Unknown message digest SHA-1");
156 + goto exit_with_error;
157 }
158
191 - if ((digest = (unsigned char *)OPENSSL_malloc(EVP_MD_size(EVP_sha256()))) == NULL) {
192 - ERROR("Cant alloc digest");
193 - return 1;
159 + (void) netdata_base64_encode((unsigned char *) nonce_b64, nonce, WEBSOCKET_NONCE_SIZE);
160 +
161 + // Format and push the upgrade header to the write buffer
162 + size_t bytes = snprintf(second, TEMP_BUF_SIZE, websocket_upgrage_hdr, *client->host, nonce_b64);
163 + if(rbuf_bytes_free(client->buf_write) < bytes) {
164 + nd_log(NDLS_DAEMON, NDLP_ERR, "Write buffer capacity too low.");
165 + goto exit_with_error;
166 + }
167 + rbuf_push(client->buf_write, second, bytes);
168 +
169 + client->state = WS_HANDSHAKE;
170 +
171 + // Create the expected Sec-WebSocket-Accept value
172 + bytes = snprintf(second, TEMP_BUF_SIZE, "%s%s", nonce_b64, mqtt_protoid);
173 +
174 + if (!EVP_DigestInit_ex(md_ctx, md, NULL)) {
175 + nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to initialize digest context");
176 + goto exit_with_error;
177 + }
178 +
179 + if (!EVP_DigestUpdate(md_ctx, second, bytes)) {
180 + nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to update digest");
181 + goto exit_with_error;
182 }
183
196 - EVP_DigestInit_ex(md_ctx, md, NULL);
197 - EVP_DigestUpdate(md_ctx, second, strlen(second));
198 - EVP_DigestFinal_ex(md_ctx, digest, &md_len);
184 + if (!EVP_DigestFinal_ex(md_ctx, digest, &md_len)) {
185 + nd_log(NDLS_DAEMON, NDLP_ERR, "Failed to finalize digest");
186 + goto exit_with_error;
187 + }
188
200 - EVP_EncodeBlock((unsigned char *)nonce_b64, digest, (int) md_len);
189 + (void) netdata_base64_encode((unsigned char *) nonce_b64, digest, md_len);
190
191 freez(client->hs.nonce_reply);
192 client->hs.nonce_reply = strdupz(nonce_b64);
193 + rc = 0;
194
205 - OPENSSL_free(digest);
206 -
195 +exit_with_error:
196 #if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110)
197 EVP_MD_CTX_destroy(md_ctx);
198 #else
199 EVP_MD_CTX_free(md_ctx);
200 #endif
201
213 - return 0;
202 + return rc;
203 }
204
205 #define BUF_READ_MEMCMP_CONST(const, err) \
206 if (rbuf_memcmp_n(client->buf_read, const, strlen(const))) { \
218 - ERROR(err); \
207 + nd_log(NDLS_DAEMON, NDLP_ERR, err); \
208 rbuf_flush(client->buf_read); \
209 return WS_CLIENT_PROTOCOL_ERROR; \
210 }
@@ -241,7 +230,7 @@ int ws_client_start_handshake(ws_client *client)
230
231 #define HTTP_HDR_LINE_CHECK_LIMIT(x) \
232 if ((x) >= MAX_HTTP_LINE_LENGTH) { \
244 - ERROR("HTTP line received is too long. Maximum is %d", MAX_HTTP_LINE_LENGTH); \
233 + nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP line received is too long. Maximum is %d", MAX_HTTP_LINE_LENGTH); \
234 return WS_CLIENT_PROTOCOL_ERROR; \
235 }
236
@@ -264,13 +253,13 @@ int ws_client_parse_handshake_resp(ws_client *client)
253 BUF_READ_CHECK_AT_LEAST(HTTP_SC_LENGTH); // "XXX " http return code
254 rbuf_pop(client->buf_read, buf, HTTP_SC_LENGTH);
255 if (buf[HTTP_SC_LENGTH - 1] != 0x20) {
267 - ERROR("HTTP status code received is not terminated by space (0x20)");
256 + nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP status code received is not terminated by space (0x20)");
257 return WS_CLIENT_PROTOCOL_ERROR;
258 }
259 buf[HTTP_SC_LENGTH - 1] = 0;
260 client->hs.http_code = atoi(buf);
261 if (client->hs.http_code < 100 || client->hs.http_code >= 600) {
273 - ERROR("HTTP status code received not in valid range 100-600");
262 + nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP status code received not in valid range 100-600");
263 return WS_CLIENT_PROTOCOL_ERROR;
264 }
265 client->hs.hdr_state = WS_HDR_ENDLINE;
@@ -309,16 +298,16 @@ int ws_client_parse_handshake_resp(ws_client *client)
298
299 ptr = rbuf_find_bytes(client->buf_read, HTTP_HDR_SEPARATOR, strlen(HTTP_HDR_SEPARATOR), &idx_sep);
300 if (!ptr || idx_sep > idx_crlf) {
312 - ERROR("Expected HTTP hdr field key/value separator \": \" before endline in non empty HTTP header line");
301 + nd_log(NDLS_DAEMON, NDLP_ERR, "Expected HTTP hdr field key/value separator \": \" before endline in non empty HTTP header line");
302 return WS_CLIENT_PROTOCOL_ERROR;
303 }
304 if (idx_crlf == idx_sep + (int)strlen(HTTP_HDR_SEPARATOR)) {
316 - ERROR("HTTP Header value cannot be empty");
305 + nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP Header value cannot be empty");
306 return WS_CLIENT_PROTOCOL_ERROR;
307 }
308
309 if (idx_sep > HTTP_HEADER_NAME_MAX_LEN) {
321 - ERROR("HTTP header too long (%d)", idx_sep);
310 + nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP header too long (%d)", idx_sep);
311 return WS_CLIENT_PROTOCOL_ERROR;
312 }
313
@@ -326,23 +315,21 @@ int ws_client_parse_handshake_resp(ws_client *client)
315 hdr->key = ((char*)hdr) + sizeof(struct http_header);
316 hdr->value = hdr->key + idx_sep + 1;
317
329 - bytes = rbuf_pop(client->buf_read, hdr->key, idx_sep);
318 + rbuf_pop(client->buf_read, hdr->key, idx_sep);
319 rbuf_bump_tail(client->buf_read, strlen(HTTP_HDR_SEPARATOR));
320
332 - bytes = rbuf_pop(client->buf_read, hdr->value, idx_crlf - idx_sep - strlen(HTTP_HDR_SEPARATOR));
321 + rbuf_pop(client->buf_read, hdr->value, idx_crlf - idx_sep - strlen(HTTP_HDR_SEPARATOR));
322 rbuf_bump_tail(client->buf_read, strlen(WS_HTTP_NEWLINE));
323
324 for (int i = 0; hdr->key[i]; i++)
325 hdr->key[i] = tolower(hdr->key[i]);
326
338 -// DEBUG("HTTP header \"%s\" received. Value \"%s\"", hdr->key, hdr->value);
339 -
327 if (ws_client_add_http_header(client, hdr))
328 return WS_CLIENT_PROTOCOL_ERROR;
329
330 if (!strcmp(hdr->key, WS_CONN_ACCEPT)) {
331 if (strcmp(client->hs.nonce_reply, hdr->value)) {
345 - ERROR("Received NONCE \"%s\" does not match expected nonce of \"%s\"", hdr->value, client->hs.nonce_reply);
332 + nd_log(NDLS_DAEMON, NDLP_ERR, "Received NONCE \"%s\" does not match expected nonce of \"%s\"", hdr->value, client->hs.nonce_reply);
333 return WS_CLIENT_PROTOCOL_ERROR;
334 }
335 client->hs.nonce_matched = 1;
@@ -352,21 +339,21 @@ int ws_client_parse_handshake_resp(ws_client *client)
339
340 case WS_HDR_PARSE_DONE:
341 if (!client->hs.nonce_matched) {
355 - ERROR("Missing " WS_CONN_ACCEPT " header");
342 + nd_log(NDLS_DAEMON, NDLP_ERR, "Missing " WS_CONN_ACCEPT " header");
343 return WS_CLIENT_PROTOCOL_ERROR;
344 }
345 if (client->hs.http_code != 101) {
359 - ERROR("HTTP return code not 101. Received %d with msg \"%s\".", client->hs.http_code, client->hs.http_reply_msg);
346 + nd_log(NDLS_DAEMON, NDLP_ERR, "HTTP return code not 101. Received %d with msg \"%s\".", client->hs.http_code, client->hs.http_reply_msg);
347 return WS_CLIENT_PROTOCOL_ERROR;
348 }
349
350 client->state = WS_ESTABLISHED;
351 client->hs.hdr_state = WS_HDR_ALL_DONE;
365 - INFO("Websocket Connection Accepted By Server");
352 + nd_log(NDLS_DAEMON, NDLP_INFO, "Websocket Connection Accepted By Server");
353 return WS_CLIENT_PARSING_DONE;
354
355 case WS_HDR_ALL_DONE:
369 - FATAL("This is error we should never come here!");
356 + nd_log(NDLS_DAEMON, NDLP_CRIT, "This is error we should never come here!");
357 return WS_CLIENT_PROTOCOL_ERROR;
358 }
359 return 0;
@@ -376,7 +363,7 @@ int ws_client_parse_handshake_resp(ws_client *client)
363 #define WS_FINAL_FRAG BYTE_MSB
364 #define WS_PAYLOAD_MASKED BYTE_MSB
365
379 -static inline size_t get_ws_hdr_size(size_t payload_size)
366 +static size_t get_ws_hdr_size(size_t payload_size)
367 {
368 size_t hdr_len = 2 + 4 /*mask*/;
369 if(payload_size > 125)
@@ -387,7 +374,7 @@ static inline size_t get_ws_hdr_size(size_t payload_size)
374 }
375
376 #define MAX_POSSIBLE_HDR_LEN 14
390 -int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size)
377 +int ws_client_send(const ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size)
378 {
379 // TODO maybe? implement fragmenting, it is not necessary though
380 // as both tested MQTT brokers have no reuirement of one MQTT envelope
@@ -395,24 +382,16 @@ int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const ch
382 // one big MQTT message as single fragmented WebSocket envelope
383 char hdr[MAX_POSSIBLE_HDR_LEN];
384 char *ptr = hdr;
398 - char *mask;
385 int size_written = 0;
386 size_t j = 0;
387
388 size_t w_buff_free = rbuf_bytes_free(client->buf_write);
389 size_t hdr_len = get_ws_hdr_size(size);
390
405 - if (w_buff_free < hdr_len * 2) {
406 -#ifdef DEBUG_ULTRA_VERBOSE
407 - DEBUG("Write buffer full. Can't write requested %d size.", size);
408 -#endif
391 + if (w_buff_free < hdr_len * 2)
392 return 0;
410 - }
393
394 if (w_buff_free < (hdr_len + size)) {
413 -#ifdef DEBUG_ULTRA_VERBOSE
414 - DEBUG("Can't write whole MQTT packet of %d bytes into the buffer. Will do partial send of %d.", size, w_buff_free - hdr_len);
415 -#endif
395 size = w_buff_free - hdr_len;
396 hdr_len = get_ws_hdr_size(size);
397 // the actual needed header size might decrease if we cut number of bytes
@@ -438,12 +417,14 @@ int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const ch
417 ptr += sizeof(be);
418 } else
419 *ptr++ |= size;
441 -
442 - mask = ptr;
443 - if (read(client->entropy_fd, mask, sizeof(uint32_t)) < (ssize_t)sizeof(uint32_t)) {
444 - ERROR("Unable to get mask from \"" ENTROPY_SOURCE "\"");
420 +
421 + char *mask = ptr;
422 + uint32_t mask32 = generate_random_32bit();
423 + if (!mask32) {
424 + nd_log(NDLS_DAEMON, NDLP_ERR, "Unable to get mask to XOR websocket payload");
425 return -2;
426 }
427 + memcpy(mask, &mask32, sizeof(mask32));
428
429 rbuf_push(client->buf_write, hdr, hdr_len);
430
@@ -469,7 +450,7 @@ int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const ch
450 return size_written;
451 }
452
472 -static int check_opcode(ws_client *client,enum websocket_opcode oc)
453 +static int check_opcode(enum websocket_opcode oc)
454 {
455 switch(oc) {
456 case WS_OP_BINARY_FRAME:
@@ -477,34 +458,34 @@ static int check_opcode(ws_client *client,enum websocket_opcode oc)
458 case WS_OP_PING:
459 return 0;
460 case WS_OP_CONTINUATION_FRAME:
480 - FATAL("WS_OP_CONTINUATION_FRAME NOT IMPLEMENTED YET!!!!");
461 + nd_log(NDLS_DAEMON, NDLP_ERR, "WS_OP_CONTINUATION_FRAME NOT IMPLEMENTED YET!!!!");
462 return 0;
463 case WS_OP_TEXT_FRAME:
483 - FATAL("WS_OP_TEXT_FRAME NOT IMPLEMENTED YET!!!!");
464 + nd_log(NDLS_DAEMON, NDLP_ERR, "WS_OP_TEXT_FRAME NOT IMPLEMENTED YET!!!!");
465 return 0;
466 case WS_OP_PONG:
486 - FATAL("WS_OP_PONG NOT IMPLEMENTED YET!!!!");
467 + nd_log(NDLS_DAEMON, NDLP_ERR, "WS_OP_PONG NOT IMPLEMENTED YET!!!!");
468 return 0;
469 default:
470 return WS_CLIENT_PROTOCOL_ERROR;
471 }
472 }
473
493 -static inline void ws_client_rx_post_hdr_state(ws_client *client)
474 +static void ws_client_rx_post_hdr_state(ws_client *client)
475 {
476 switch(client->rx.opcode) {
477 case WS_OP_BINARY_FRAME:
478 client->rx.parse_state = WS_PAYLOAD_DATA;
498 - return;
479 + break;
480 case WS_OP_CONNECTION_CLOSE:
481 client->rx.parse_state = WS_PAYLOAD_CONNECTION_CLOSE;
501 - return;
482 + break;
483 case WS_OP_PING:
484 client->rx.parse_state = WS_PAYLOAD_PING_REQ_PAYLOAD;
504 - return;
485 + break;
486 default:
487 client->rx.parse_state = WS_PAYLOAD_SKIP_UNKNOWN_PAYLOAD;
507 - return;
488 + break;
489 }
490 }
491
@@ -520,15 +501,15 @@ int ws_client_process_rx_ws(ws_client *client)
501 client->rx.opcode = buf[0] & (char)~BYTE_MSB;
502
503 if (!(buf[0] & (char)~WS_FINAL_FRAG)) {
523 - ERROR("Not supporting fragmented messages yet!");
504 + nd_log(NDLS_DAEMON, NDLP_ERR, "Not supporting fragmented messages yet!");
505 return WS_CLIENT_PROTOCOL_ERROR;
506 }
507
527 - if (check_opcode(client, client->rx.opcode) == WS_CLIENT_PROTOCOL_ERROR)
508 + if (check_opcode(client->rx.opcode) == WS_CLIENT_PROTOCOL_ERROR)
509 return WS_CLIENT_PROTOCOL_ERROR;
510
511 if (buf[1] & (char)WS_PAYLOAD_MASKED) {
531 - ERROR("Mask is not allowed in Server->Client Websocket direction.");
512 + nd_log(NDLS_DAEMON, NDLP_ERR, "Mask is not allowed in Server->Client Websocket direction.");
513 return WS_CLIENT_PROTOCOL_ERROR;
514 }
515
@@ -563,12 +544,8 @@ int ws_client_process_rx_ws(ws_client *client)
544 if (!rbuf_bytes_available(client->buf_read))
545 return WS_CLIENT_NEED_MORE_BYTES;
546 char *insert = rbuf_get_linear_insert_range(client->buf_to_mqtt, &size);
566 - if (!insert) {
567 -#ifdef DEBUG_ULTRA_VERBOSE
568 - DEBUG("BUFFER TOO FULL. Avail %d req %d", (int)size, (int)remaining);
569 -#endif
547 + if (!insert)
548 return WS_CLIENT_BUFFER_FULL;
571 - }
549 size = (size > remaining) ? remaining : size;
550 size = rbuf_pop(client->buf_read, insert, size);
551 rbuf_bump_head(client->buf_to_mqtt, size);
@@ -582,11 +559,11 @@ int ws_client_process_rx_ws(ws_client *client)
559 // b) 2byte reason code
560 // c) 2byte reason code followed by message
561 if (client->rx.payload_length == 1) {
585 - ERROR("WebScoket CONNECTION_CLOSE can't have payload of size 1");
562 + nd_log(NDLS_DAEMON, NDLP_ERR, "WebScoket CONNECTION_CLOSE can't have payload of size 1");
563 return WS_CLIENT_PROTOCOL_ERROR;
564 }
565 if (!client->rx.payload_length) {
589 - INFO("WebSocket server closed the connection without giving reason.");
566 + nd_log(NDLS_DAEMON, NDLP_INFO, "WebSocket server closed the connection without giving reason.");
567 client->rx.parse_state = WS_PACKET_DONE;
568 break;
569 }
@@ -600,7 +577,7 @@ int ws_client_process_rx_ws(ws_client *client)
577 client->rx.payload_processed += sizeof(uint16_t);
578
579 if(client->rx.payload_processed == client->rx.payload_length) {
603 - INFO("WebSocket server closed the connection with EC=%d. Without message.",
580 + nd_log(NDLS_DAEMON, NDLP_INFO, "WebSocket server closed the connection with EC=%d. Without message.",
581 client->rx.specific_data.op_close.ec);
582 client->rx.parse_state = WS_PACKET_DONE;
583 break;
@@ -619,7 +596,7 @@ int ws_client_process_rx_ws(ws_client *client)
596 client->rx.payload_length - client->rx.payload_processed);
597 }
598 client->rx.specific_data.op_close.reason[client->rx.payload_length] = 0;
622 - INFO("WebSocket server closed the connection with EC=%d and reason \"%s\"",
599 + nd_log(NDLS_DAEMON, NDLP_INFO, "WebSocket server closed the connection with EC=%d and reason \"%s\"",
600 client->rx.specific_data.op_close.ec,
601 client->rx.specific_data.op_close.reason);
602 freez(client->rx.specific_data.op_close.reason);
@@ -628,14 +605,14 @@ int ws_client_process_rx_ws(ws_client *client)
605 break;
606 case WS_PAYLOAD_SKIP_UNKNOWN_PAYLOAD:
607 BUF_READ_CHECK_AT_LEAST(client->rx.payload_length);
631 - WARN("Skipping Websocket Packet of unsupported/unknown type");
608 + nd_log(NDLS_DAEMON, NDLP_WARNING, "Skipping Websocket Packet of unsupported/unknown type");
609 if (client->rx.payload_length)
610 rbuf_bump_tail(client->buf_read, client->rx.payload_length);
611 client->rx.parse_state = WS_PACKET_DONE;
612 return WS_CLIENT_PARSING_DONE;
613 case WS_PAYLOAD_PING_REQ_PAYLOAD:
614 if (client->rx.payload_length > rbuf_get_capacity(client->buf_read) / 2) {
638 - ERROR("Ping arrived with payload which is too big!");
615 + nd_log(NDLS_DAEMON, NDLP_ERR, "Ping arrived with payload which is too big!");
616 return WS_CLIENT_INTERNAL_ERROR;
617 }
618 BUF_READ_CHECK_AT_LEAST(client->rx.payload_length);
@@ -645,7 +622,7 @@ int ws_client_process_rx_ws(ws_client *client)
622 // then attempt to send as soon as buffer space clears up
623 size = ws_client_send(client, WS_OP_PONG, client->rx.specific_data.ping_msg, client->rx.payload_length);
624 if (size != client->rx.payload_length) {
648 - ERROR("Unable to send the PONG as one packet back. Closing connection.");
625 + nd_log(NDLS_DAEMON, NDLP_ERR, "Unable to send the PONG as one packet back. Closing connection.");
626 return WS_CLIENT_PROTOCOL_ERROR;
627 }
628 client->rx.parse_state = WS_PACKET_DONE;
@@ -657,7 +634,7 @@ int ws_client_process_rx_ws(ws_client *client)
634 return WS_CLIENT_CONNECTION_CLOSED;
635 return WS_CLIENT_PARSING_DONE;
636 default:
660 - FATAL("Unknown parse state");
637 + nd_log(NDLS_DAEMON, NDLP_ERR, "Unknown parse state");
638 return WS_CLIENT_INTERNAL_ERROR;
639 }
640 return 0;
@@ -690,6 +667,8 @@ int ws_client_process(ws_client *client)
667 case WS_CLIENT_CONNECTION_CLOSED:
668 client->state = WS_CONN_CLOSED_GRACEFUL;
669 break;
670 + default:
671 + break;
672 }
673 // if ret == 0 we can continue parsing
674 // if ret == WS_CLIENT_PARSING_DONE we processed
@@ -698,13 +677,13 @@ int ws_client_process(ws_client *client)
677 } while (!ret || ret == WS_CLIENT_PARSING_DONE);
678 break;
679 case WS_ERROR:
701 - ERROR("ws_client is in error state. Restart the connection!");
680 + nd_log(NDLS_DAEMON, NDLP_ERR, "ws_client is in error state. Restart the connection!");
681 return WS_CLIENT_PROTOCOL_ERROR;
682 case WS_CONN_CLOSED_GRACEFUL:
704 - ERROR("Connection has been gracefully closed. Calling this is useless (and probably bug) until you reconnect again.");
683 + nd_log(NDLS_DAEMON, NDLP_ERR, "Connection has been gracefully closed. Calling this is useless (and probably bug) until you reconnect again.");
684 return WS_CLIENT_CONNECTION_CLOSED;
685 default:
707 - FATAL("Unknown connection state! Probably memory corruption.");
686 + nd_log(NDLS_DAEMON, NDLP_CRIT, "Unknown connection state! Probably memory corruption.");
687 return WS_CLIENT_INTERNAL_ERROR;
688 }
689 return ret;
src/aclk/mqtt_websockets/ws_client.h
+3 -8
@@ -3,8 +3,6 @@
3 #ifndef WS_CLIENT_H
4 #define WS_CLIENT_H
5
6 -#include "mqtt_wss_log.h"
7 -
6 #define WS_CLIENT_NEED_MORE_BYTES 0x10
7 #define WS_CLIENT_PARSING_DONE 0x11
8 #define WS_CLIENT_CONNECTION_CLOSED 0x12
@@ -94,23 +92,20 @@ typedef struct websocket_client {
92 // memory usage and remove one more memcpy buf_read->buf_to_mqtt
93 rbuf_t buf_to_mqtt; // RAW data for MQTT lib
94
97 - int entropy_fd;
98 -
95 // careful host is borrowed, don't free
96 char **host;
101 - mqtt_wss_log_ctx_t log;
97 } ws_client;
98
104 -ws_client *ws_client_new(size_t buf_size, char **host, mqtt_wss_log_ctx_t log);
99 +ws_client *ws_client_new(size_t buf_size, char **host);
100 void ws_client_destroy(ws_client *client);
101 void ws_client_reset(ws_client *client);
102
103 int ws_client_start_handshake(ws_client *client);
104
110 -int ws_client_want_write(ws_client *client);
105 +int ws_client_want_write(const ws_client *client);
106
107 int ws_client_process(ws_client *client);
108
114 -int ws_client_send(ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size);
109 +int ws_client_send(const ws_client *client, enum websocket_opcode frame_type, const char *data, size_t size);
110
111 #endif /* WS_CLIENT_H */
src/libnetdata/c_rhash/c_rhash.c
-3
@@ -8,9 +8,6 @@ c_rhash c_rhash_new(size_t bin_count) {
8 bin_count = 1000;
9
10 c_rhash hash = callocz(1, sizeof(struct c_rhash_s) + (bin_count * sizeof(struct bin_ll*)) );
11 - if (hash == NULL)
12 - return NULL;
13 -
11 hash->bin_count = bin_count;
12 hash->bins = (c_rhash_bin *)((char*)hash + sizeof(struct c_rhash_s));
13
src/libnetdata/libnetdata.c
+85 -44
@@ -1570,52 +1570,93 @@ bool rrdr_relative_window_to_absolute_query(time_t *after, time_t *before, time_
1570 return (absolute_period_requested != 1);
1571 }
1572
1573 -int netdata_base64_decode(const char *encoded, char *decoded, size_t decoded_size) {
1574 - static const unsigned char base64_table[256] = {
1575 - ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7,
1576 - ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
1577 - ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23,
1578 - ['Y'] = 24, ['Z'] = 25, ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31,
1579 - ['g'] = 32, ['h'] = 33, ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39,
1580 - ['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47,
1581 - ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55,
1582 - ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59, ['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63,
1583 - [0 ... '+' - 1] = 255,
1584 - ['+' + 1 ... '/' - 1] = 255,
1585 - ['9' + 1 ... 'A' - 1] = 255,
1586 - ['Z' + 1 ... 'a' - 1] = 255,
1587 - ['z' + 1 ... 255] = 255
1588 - };
1573
1590 - size_t count = 0;
1591 - unsigned int tmp = 0;
1592 - int i, bit;
1593 -
1594 - if (decoded_size < 1)
1595 - return 0; // Buffer size must be at least 1 for null termination
1596 -
1597 - for (i = 0, bit = 0; encoded[i]; i++) {
1598 - unsigned char value = base64_table[(unsigned char)encoded[i]];
1599 - if (value > 63)
1600 - return -1; // Invalid character in input
1601 -
1602 - tmp = tmp << 6 | value;
1603 - if (++bit == 4) {
1604 - if (count + 3 >= decoded_size) break; // Stop decoding if buffer is full
1605 - decoded[count++] = (tmp >> 16) & 0xFF;
1606 - decoded[count++] = (tmp >> 8) & 0xFF;
1607 - decoded[count++] = tmp & 0xFF;
1608 - tmp = 0;
1609 - bit = 0;
1610 - }
1611 - }
1574 +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
1575 +static inline EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
1576 +{
1577 + EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
1578
1613 - if (bit > 0 && count + 1 < decoded_size) {
1614 - tmp <<= 6 * (4 - bit);
1615 - if (bit > 2 && count + 1 < decoded_size) decoded[count++] = (tmp >> 16) & 0xFF;
1616 - if (bit > 3 && count + 1 < decoded_size) decoded[count++] = (tmp >> 8) & 0xFF;
1579 + if (ctx != NULL) {
1580 + memset(ctx, 0, sizeof(*ctx));
1581 }
1582 + return ctx;
1583 +}
1584 +
1585 +static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
1586 +{
1587 + OPENSSL_free(ctx);
1588 +}
1589 +#endif
1590
1619 - decoded[count] = '\0'; // Null terminate the output string
1620 - return count;
1591 +int netdata_base64_decode(unsigned char *out, const unsigned char *in, const int in_len)
1592 +{
1593 + int outl;
1594 + unsigned char remaining_data[256];
1595 +
1596 + EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
1597 + EVP_DecodeInit(ctx);
1598 + EVP_DecodeUpdate(ctx, out, &outl, in, in_len);
1599 + int remainder = 0;
1600 + EVP_DecodeFinal(ctx, remaining_data, &remainder);
1601 + EVP_ENCODE_CTX_free(ctx);
1602 + if (remainder)
1603 + return -1;
1604 +
1605 + return outl;
1606 }
1607 +
1608 +int netdata_base64_encode(unsigned char *encoded, const unsigned char *input, size_t input_size)
1609 +{
1610 + return EVP_EncodeBlock(encoded, input, input_size);
1611 +}
1612 +
1613 +// Keep internal implementation
1614 +// int netdata_base64_decode_internal(const char *encoded, char *decoded, size_t decoded_size) {
1615 +// static const unsigned char base64_table[256] = {
1616 +// ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7,
1617 +// ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
1618 +// ['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23,
1619 +// ['Y'] = 24, ['Z'] = 25, ['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31,
1620 +// ['g'] = 32, ['h'] = 33, ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39,
1621 +// ['o'] = 40, ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47,
1622 +// ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55,
1623 +// ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59, ['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63,
1624 +// [0 ... '+' - 1] = 255,
1625 +// ['+' + 1 ... '/' - 1] = 255,
1626 +// ['9' + 1 ... 'A' - 1] = 255,
1627 +// ['Z' + 1 ... 'a' - 1] = 255,
1628 +// ['z' + 1 ... 255] = 255
1629 +// };
1630 +//
1631 +// size_t count = 0;
1632 +// unsigned int tmp = 0;
1633 +// int i, bit;
1634 +//
1635 +// if (decoded_size < 1)
1636 +// return 0; // Buffer size must be at least 1 for null termination
1637 +//
1638 +// for (i = 0, bit = 0; encoded[i]; i++) {
1639 +// unsigned char value = base64_table[(unsigned char)encoded[i]];
1640 +// if (value > 63)
1641 +// return -1; // Invalid character in input
1642 +//
1643 +// tmp = tmp << 6 | value;
1644 +// if (++bit == 4) {
1645 +// if (count + 3 >= decoded_size) break; // Stop decoding if buffer is full
1646 +// decoded[count++] = (tmp >> 16) & 0xFF;
1647 +// decoded[count++] = (tmp >> 8) & 0xFF;
1648 +// decoded[count++] = tmp & 0xFF;
1649 +// tmp = 0;
1650 +// bit = 0;
1651 +// }
1652 +// }
1653 +//
1654 +// if (bit > 0 && count + 1 < decoded_size) {
1655 +// tmp <<= 6 * (4 - bit);
1656 +// if (bit > 2 && count + 1 < decoded_size) decoded[count++] = (tmp >> 16) & 0xFF;
1657 +// if (bit > 3 && count + 1 < decoded_size) decoded[count++] = (tmp >> 8) & 0xFF;
1658 +// }
1659 +//
1660 +// decoded[count] = '\0'; // Null terminate the output string
1661 +// return count;
1662 +// }
src/libnetdata/libnetdata.h
+2 -1
@@ -642,7 +642,8 @@ extern bool unittest_running;
642 bool rrdr_relative_window_to_absolute(time_t *after, time_t *before, time_t now);
643 bool rrdr_relative_window_to_absolute_query(time_t *after, time_t *before, time_t *now_ptr, bool unittest);
644
645 -int netdata_base64_decode(const char *encoded, char *decoded, size_t decoded_size);
645 +int netdata_base64_decode(unsigned char *out, const unsigned char *in, int in_len);
646 +int netdata_base64_encode(unsigned char *encoded, const unsigned char *input, size_t input_size);
647
648 static inline void freez_charp(char **p) {
649 freez(*p);
src/libnetdata/ringbuffer/ringbuffer.c
-3
@@ -6,9 +6,6 @@
6 rbuf_t rbuf_create(size_t size)
7 {
8 rbuf_t buffer = mallocz(sizeof(struct rbuf) + size);
9 - if (!buffer)
10 - return NULL;
11 -
9 memset(buffer, 0, sizeof(struct rbuf));
10
11 buffer->data = ((char*)buffer) + sizeof(struct rbuf);
src/libnetdata/socket/security.h
+1
@@ -19,6 +19,7 @@ typedef enum __attribute__((packed)) {
19 #define OPENSSL_VERSION_300 0x30000000L
20
21 # include <openssl/ssl.h>
22 +# include <openssl/rand.h>
23 # include <openssl/err.h>
24 # include <openssl/evp.h>
25 # include <openssl/pem.h>