From 5679fa2af199cfcaa2485180f1ebfe1bb0deb5f6 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Tue, 3 Aug 2021 12:05:15 +0800 Subject: [PATCH 001/180] * submodule nng step1 --- CMakeLists.txt | 8 ++++++-- cmake/CheckSanitizer.cmake | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef4c2bc87..2a4457f3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ # Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. # Copyright 2016 Franklin "Snaipe" Mathieu # Copyright 2018 Capitar IT Group BV +# Copyright 2020 EMQX. All rights reserved. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), @@ -252,12 +253,15 @@ endif () add_subdirectory(src) if (NNG_TESTS) - add_subdirectory(tests) +# add_subdirectory(tests) endif () # Build the tools -add_subdirectory(docs/man) +# add_subdirectory(docs/man) + +include_directories(${CMAKE_SOURCE_DIR}/nanolib/include) +include_directories(${CMAKE_SOURCE_DIR}/nanomq/include) set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) set(CPACK_PACKAGE_VERSION ${NNG_PACKAGE_VERSION}) diff --git a/cmake/CheckSanitizer.cmake b/cmake/CheckSanitizer.cmake index b4d4f3202..1f8624e25 100644 --- a/cmake/CheckSanitizer.cmake +++ b/cmake/CheckSanitizer.cmake @@ -22,6 +22,9 @@ macro (CheckSanitizer) set (NNG_SANITIZER none CACHE STRING "Sanitizer to use (clang or gcc).") set_property(CACHE NNG_SANITIZER PROPERTY STRINGS ${NNG_SAN_LIST}) mark_as_advanced (NNG_SANITIZER) + if (DEBUG AND ASAN) + set (NNG_SANITIZER address) + endif (DEBUG AND ASAN) if (NOT NNG_SANITIZER STREQUAL "none") set (NNG_C_FLAG_SANITIZER "-fsanitize=${NNG_SANITIZER}") From fce9ed84852a565b96bed427a083f6f920893f18 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Tue, 3 Aug 2021 12:15:26 +0800 Subject: [PATCH 002/180] add nanomq's include dir into nng submodule --- include/nng/nng.h | 54 ++++++- include/nng/nng_debug.h | 107 ++++++++++++++ include/nng/protocol/mqtt/mqtt.h | 189 ++++++++++++++++++++++++ include/nng/protocol/mqtt/mqtt_parser.h | 55 +++++++ include/nng/protocol/mqtt/nano_tcp.h | 32 ++++ 5 files changed, 431 insertions(+), 6 deletions(-) create mode 100644 include/nng/nng_debug.h create mode 100644 include/nng/protocol/mqtt/mqtt.h create mode 100644 include/nng/protocol/mqtt/mqtt_parser.h create mode 100755 include/nng/protocol/mqtt/nano_tcp.h diff --git a/include/nng/nng.h b/include/nng/nng.h index 5c2b5c0ca..11591507e 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1,5 +1,5 @@ -// -// Copyright 2021 Staysail Systems, Inc. +// Copyright 2021 Jaylin +// Copyright 2020 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -49,9 +49,9 @@ extern "C" { // We use SemVer, and these versions are about the API, and // may not necessarily match the ABI versions. #define NNG_MAJOR_VERSION 1 -#define NNG_MINOR_VERSION 5 -#define NNG_PATCH_VERSION 1 -#define NNG_RELEASE_SUFFIX "" // if non-empty, this is a pre-release +#define NNG_MINOR_VERSION 4 +#define NNG_PATCH_VERSION 0 +#define NNG_RELEASE_SUFFIX "DEV" // if non-empty, this is a pre-release // Maximum length of a socket address. This includes the terminating NUL. // This limit is built into other implementations, so do not change it. @@ -91,6 +91,7 @@ typedef struct nng_pipe_s { typedef struct nng_socket_s { uint32_t id; + void *data; } nng_socket; typedef int32_t nng_duration; // in milliseconds @@ -456,6 +457,7 @@ NNG_DECL void *nng_alloc(size_t); // As the application is required to keep track of the size of memory, this // is probably less convenient for general uses than the C library malloc and // calloc. +NNG_DECL void *nng_zalloc(size_t sz); NNG_DECL void nng_free(void *, size_t); // nng_strdup duplicates the source string, using nng_alloc. The result @@ -1179,7 +1181,6 @@ NNG_DECL int nng_stream_listener_set_ptr( NNG_DECL int nng_stream_listener_set_addr( nng_stream_listener *, const char *, const nng_sockaddr *); - #ifndef NNG_ELIDE_DEPRECATED // These are legacy APIs that have been deprecated. // Their use is strongly discouraged. @@ -1279,6 +1280,47 @@ NNG_DECL void nng_closeall(void); #endif +// NANOMQ MQTT variables & APIs +typedef struct conn_param conn_param; +typedef struct pub_packet_struct pub_packet_struct; +typedef struct pipe_db nano_pipe_db; + +NNG_DECL void nng_aio_finish_error(nng_aio *aio, int rv); +NNG_DECL void nng_aio_finish_sync(nng_aio *aio, int rv); +NNG_DECL int nng_msg_cmd_type(nng_msg *msg); +NNG_DECL void * nng_msg_get_conn_param(nng_msg *msg); +NNG_DECL size_t nng_msg_remaining_len(nng_msg *msg); +NNG_DECL uint8_t *nng_msg_header_ptr(nng_msg *msg); +NNG_DECL uint8_t *nng_msg_variable_ptr(nng_msg *msg); +NNG_DECL uint8_t *nng_msg_payload_ptr(nng_msg *msg); +NNG_DECL void nng_msg_set_payload_ptr(nng_msg *msg, uint8_t *ptr); +NNG_DECL void nng_msg_set_remaining_len(nng_msg *msg, size_t len); +NNG_DECL void nng_msg_clone(nng_msg *msg); +NNG_DECL void nng_msg_set_cmd_type(nng_msg *m, uint8_t cmd); +NNG_DECL nng_msg *nng_msg_unique(nng_msg *m); +NNG_DECL int nng_file_put(const char *name, const void *data, size_t sz); +NNG_DECL int nng_file_get(const char *name, void **datap, size_t *szp); +NNG_DECL int nng_file_delete(const char *name); +NNG_DECL void nng_msg_set_timestamp(nng_msg *m, uint64_t time); + +NNG_DECL void nng_aio_set_dbtree(nng_aio *aio, void *db); +NNG_DECL void *nng_msg_get_conn_param(nng_msg *msg); + +NNG_DECL const uint8_t *conn_param_get_clientid(conn_param *cparam); +NNG_DECL const uint8_t *conn_param_get_pro_name(conn_param *cparam); +NNG_DECL const void * conn_param_get_will_topic(conn_param *cparam); +NNG_DECL const void * conn_param_get_will_msg(conn_param *cparam); +NNG_DECL const uint8_t *conn_param_get_username(conn_param *cparam); +NNG_DECL const uint8_t *conn_param_get_password(conn_param *cparam); +NNG_DECL uint8_t conn_param_get_con_flag(conn_param *cparam); +NNG_DECL uint8_t conn_param_get_clean_start(conn_param *cparam); +NNG_DECL uint8_t conn_param_get_will_flag(conn_param *cparam); +NNG_DECL uint8_t conn_param_get_will_qos(conn_param *cparam); +NNG_DECL uint8_t conn_param_get_will_retain(conn_param *cparam); +NNG_DECL uint16_t conn_param_get_keepalive(conn_param *cparam); +NNG_DECL uint8_t conn_param_get_protover(conn_param *cparam); + +NNG_DECL void nng_taskq_setter (int num_taskq_threads, int max_taskq_threads); #ifdef __cplusplus } #endif diff --git a/include/nng/nng_debug.h b/include/nng/nng_debug.h new file mode 100644 index 000000000..082b45386 --- /dev/null +++ b/include/nng/nng_debug.h @@ -0,0 +1,107 @@ + +#ifndef __NNG_NANO_H__ +#define __NNG_NANO_H__ + +#include +#include + +#define DEBUG_FILE_PATH "/tmp/debug_dash.log" + +#include +#include +#include +#include +#include +#include + +// later expose on makefile + +#if defined(NOLOG) +#undef DEBUG_CONSOLE +#undef DEBUG_FILE +#undef DEBUG_SYSLOG +#else +#define DEBUG_CONSOLE +#define DEBUG_FILE +#define DEBUG_SYSLOG +#endif + +#undef DASH_DEBUG +#if defined(DEBUG_CONSOLE) || defined(DEBUG_FILE) || defined(DEBUG_SYSLOG) +#define DASH_DEBUG 1 + +static inline char * +nanomq_time_str() +{ + char * buffer; + time_t now; + + now = time(NULL); + buffer = ctime(&now); + if (!buffer) + return NULL; + + if (buffer[strlen(buffer) - 1] == '\n') + buffer[strlen(buffer) - 1] = '\0'; + + return buffer; +} + +#endif + +#if defined(DEBUG_CONSOLE) +#define debug_console(fmt, arg...) \ + do { \ + char *_t = nanomq_time_str(); \ + fprintf(stderr, "%s %s: " fmt "\n", _t, __FUNCTION__, ##arg); \ + } while (0) +#else +#define debug_console(fmt, arg...) \ + do { \ + } while (0) +#endif + +#if defined(DEBUG_FILE) +#define debug_file(fmt, arg...) \ + do { \ + char *_t = nanomq_time_str(); \ + FILE *file = fopen(DEBUG_FILE_PATH, "a"); \ + fprintf(file, "%s [%i] %s: " fmt "\n", _t, getpid(), \ + __FUNCTION__, ##arg); \ + fclose(file); \ + } while (0) +#else +#define debug_file(fmt, arg...) \ + do { \ + } while (0) +#endif + +#if defined(DEBUG_SYSLOG) +#define debug_syslog(fmt, arg...) \ + do { \ + openlog("nng-nanomq", LOG_PID, LOG_DAEMON | LOG_EMERG); \ + syslog(0, "%s: " fmt, __FUNCTION__, ##arg); \ + closelog(); \ + } while (0) +#else +#define debug_syslog(fmt, arg...) \ + do { \ + } while (0) +#endif + +#if defined(DASH_DEBUG) +#define debug_msg(fmt, arg...) \ + do { \ + debug_console(fmt, ##arg); \ + debug_file(fmt, ##arg); \ + debug_syslog(fmt, ##arg); \ + } while (0) +#else +#define debug_msg(fmt, arg...) \ + do { \ + } while (0) +#endif + +#define DASH_UNUSED(x) (x) __attribute__((unused)) + +#endif /* __NNG_NANO_H__ */ diff --git a/include/nng/protocol/mqtt/mqtt.h b/include/nng/protocol/mqtt/mqtt.h new file mode 100644 index 000000000..ade0d863c --- /dev/null +++ b/include/nng/protocol/mqtt/mqtt.h @@ -0,0 +1,189 @@ +// +// Copyright 2020 NanoMQ Team, Inc. +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef MQTT_PROTOCOL_H +#define MQTT_PROTOCOL_H + +#define PROTOCOL_NAME_v31 "MQIsdp" +#define PROTOCOL_VERSION_v31 3 + +#define PROTOCOL_NAME "MQTT" + +#define PROTOCOL_VERSION_v311 4 +#define PROTOCOL_VERSION_v5 5 + +/* Length defination */ +#define NANO_MAX_PACKET_LEN NNI_NANO_MAX_PACKET_SIZE +#define NANO_MIN_PACKET_LEN sizeof(uint8_t) * 8 +#define NANO_CONNECT_PACKET_LEN sizeof(uint8_t) * 12 +#define NANO_MIN_FIXED_HEADER_LEN sizeof(uint8_t) * 2 + + +#ifdef NANO_PACKET_SIZE +#define NNI_NANO_MAX_PACKET_SIZE sizeof(uint8_t) * NANO_PACKET_SIZE +#else +#define NNI_NANO_MAX_PACKET_SIZE sizeof(uint8_t) * 12 +#endif + +/* Message types & flags */ +#define CMD_UNKNOWN 0x00 +#define CMD_CONNECT 0x10 +#define CMD_CONNACK 0x20 +#define CMD_PUBLISH 0x30 +#define CMD_PUBACK 0x40 +#define CMD_PUBREC 0x50 +#define CMD_PUBREL 0x60 +#define CMD_PUBCOMP 0x70 +#define CMD_SUBSCRIBE 0x80 +#define CMD_SUBACK 0x90 +#define CMD_UNSUBSCRIBE 0xA0 +#define CMD_UNSUBACK 0xB0 +#define CMD_PINGREQ 0xC0 +#define CMD_PINGRESP 0xD0 +#define CMD_DISCONNECT 0xE0 +#define CMD_AUTH_V5 0xF0 +#define CMD_PUBLISH_V5 0x31 +#define CMD_DISCONNECT_EV 0xE2 +#define CMD_LASTWILL 0XE3 + +/* Error values */ +enum err_t { + ERR_AUTH_CONTINUE = -4, + ERR_NO_SUBSCRIBERS = -3, + ERR_SUB_EXISTS = -2, + ERR_CONN_PENDING = -1, + ERR_SUCCESS = 0, + ERR_NOMEM = 1, + ERR_PROTOCOL = 2, + ERR_INVAL = 3, + ERR_NO_CONN = 4, + ERR_CONN_REFUSED = 5, + ERR_NOT_FOUND = 6, + ERR_CONN_LOST = 7, + ERR_TLS = 8, + ERR_PAYLOAD_SIZE = 9, + ERR_NOT_SUPPORTED = 10, + ERR_AUTH = 11, + ERR_ACL_DENIED = 12, + ERR_UNKNOWN = 13, + ERR_ERRNO = 14, + ERR_EAI = 15, + ERR_PROXY = 16, + ERR_PLUGIN_DEFER = 17, + ERR_MALFORMED_UTF8 = 18, + ERR_KEEPALIVE = 19, + ERR_LOOKUP = 20, + ERR_MALFORMED_PACKET = 21, + ERR_DUPLICATE_PROPERTY = 22, + ERR_TLS_HANDSHAKE = 23, + ERR_QOS_NOT_SUPPORTED = 24, + ERR_OVERSIZE_PACKET = 25, + ERR_OCSP = 26, +}; + +typedef enum { + SUCCESS = 0, + NORMAL_DISCONNECTION = 0, + GRANTED_QOS_0 = 0, + GRANTED_QOS_1 = 1, + GRANTED_QOS_2 = 2, + DISCONNECT_WITH_WILL_MESSAGE = 4, + NO_MATCHING_SUBSCRIBERS = 16, + NO_SUBSCRIPTION_EXISTED = 17, + CONTINUE_AUTHENTICATION = 24, + RE_AUTHENTICATE = 25, + UNSPECIFIED_ERROR = 128, + MALFORMED_PACKET = 129, + PROTOCOL_ERROR = 130, + IMPLEMENTATION_SPECIFIC_ERROR = 131, + UNSUPPORTED_PROTOCOL_VERSION = 132, + CLIENT_IDENTIFIER_NOT_VALID = 133, + BAD_USER_NAME_OR_PASSWORD = 134, + NOT_AUTHORIZED = 135, + SERVER_UNAVAILABLE = 136, + SERVER_BUSY = 137, + BANNED = 138, + SERVER_SHUTTING_DOWN = 139, + BAD_AUTHENTICATION_METHOD = 140, + KEEP_ALIVE_TIMEOUT = 141, + SESSION_TAKEN_OVER = 142, + TOPIC_FILTER_INVALID = 143, + TOPIC_NAME_INVALID = 144, + PACKET_IDENTIFIER_IN_USE = 145, + PACKET_IDENTIFIER_NOT_FOUND = 146, + RECEIVE_MAXIMUM_EXCEEDED = 147, + TOPIC_ALIAS_INVALID = 148, + PACKET_TOO_LARGE = 149, + MESSAGE_RATE_TOO_HIGH = 150, + QUOTA_EXCEEDED = 151, + ADMINISTRATIVE_ACTION = 152, + PAYLOAD_FORMAT_INVALID = 153, + RETAIN_NOT_SUPPORTED = 154, + QOS_NOT_SUPPORTED = 155, + USE_ANOTHER_SERVER = 156, + SERVER_MOVED = 157, + SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 158, + CONNECTION_RATE_EXCEEDED = 159, + MAXIMUM_CONNECT_TIME = 160, + SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED = 161, + WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 162 + +} reason_code; + +typedef enum { + PAYLOAD_FORMAT_INDICATOR = 1, + MESSAGE_EXPIRY_INTERVAL = 2, + CONTENT_TYPE = 3, + RESPONSE_TOPIC = 8, + CORRELATION_DATA = 9, + SUBSCRIPTION_IDENTIFIER = 11, + SESSION_EXPIRY_INTERVAL = 17, + ASSIGNED_CLIENT_IDENTIFIER = 18, + SERVER_KEEP_ALIVE = 19, + AUTHENTICATION_METHOD = 21, + AUTHENTICATION_DATA = 22, + REQUEST_PROBLEM_INFORMATION = 23, + WILL_DELAY_INTERVAL = 24, + REQUEST_RESPONSE_INFORMATION = 25, + RESPONSE_INFORMATION = 26, + SERVER_REFERENCE = 28, + REASON_STRING = 31, + RECEIVE_MAXIMUM = 33, + TOPIC_ALIAS_MAXIMUM = 34, + TOPIC_ALIAS = 35, + PUBLISH_MAXIMUM_QOS = 36, + RETAIN_AVAILABLE = 37, + USER_PROPERTY = 38, + MAXIMUM_PACKET_SIZE = 39, + WILDCARD_SUBSCRIPTION_AVAILABLE = 40, + SUBSCRIPTION_IDENTIFIER_AVAILABLE = 41, + SHARED_SUBSCRIPTION_AVAILABLE = 42 +} properties_type; + +// MQTT Control Packet types +typedef enum { + RESERVED = 0, + CONNECT = 1, + CONNACK = 2, + PUBLISH = 3, + PUBACK = 4, + PUBREC = 5, + PUBREL = 6, + PUBCOMP = 7, + SUBSCRIBE = 8, + SUBACK = 9, + UNSUBSCRIBE = 10, + UNSUBACK = 11, + PINGREQ = 12, + PINGRESP = 13, + DISCONNECT = 14, + AUTH = 15 +} mqtt_control_packet_types; + +#endif diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h new file mode 100644 index 000000000..0977a5ae5 --- /dev/null +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -0,0 +1,55 @@ + +#ifndef NNG_MQTT_H +#define NNG_MQTT_H + +#include +#include +#include +#include + +#define DISCONNECT_MSG \ + "{\"username\":\"%s\"," \ + "\"ts\":%lu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" +#define CONNECT_MSG \ + "{\"username\":\"%s\", " \ + "\"ts\":%lu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":\"%x\",\"proto_ver\":%d,\"client_id\":\"%s\", \"clean_start\":%d}" +#define DISCONNECT_TOPIC "$SYS/brokers/disconnected" +#define CONNECT_TOPIC "$SYS/brokers/connected" + +// Variables & Structs + +// int hex_to_oct(char *str); +// uint32_t htoi(char *str); + +// MQTT CONNECT +int32_t conn_handler(uint8_t *packet, conn_param *conn_param); +void init_conn_param(conn_param *cparam); +void destroy_conn_param(conn_param *cparam); +int fixed_header_adaptor(uint8_t *packet, nng_msg *dst); + +// parser +NNG_DECL uint8_t put_var_integer(uint8_t *dest, uint32_t value); + +NNG_DECL uint32_t get_var_integer(const uint8_t *buf, uint32_t *pos); + +NNG_DECL int32_t get_utf8_str(char **dest, const uint8_t *src, uint32_t *pos); +NNG_DECL uint8_t *copy_utf8_str( + const uint8_t *src, uint32_t *pos, int *str_len); + +NNG_DECL int utf8_check(const char *str, size_t length); + +NNG_DECL uint16_t get_variable_binary(uint8_t **dest, const uint8_t *src); + +NNG_DECL uint32_t DJBHash(char *str); +NNG_DECL uint32_t DJBHashn(char *str, uint16_t len); +NNG_DECL uint64_t nano_hash(char *str); +NNG_DECL uint8_t verify_connect(conn_param *cparam, conf *conf); + +// repack +NNG_DECL void nano_msg_set_dup(nng_msg *msg); +NNG_DECL nng_msg *nano_msg_composer( + uint8_t retain, uint8_t qos, mqtt_string *payload, mqtt_string *topic); +NNG_DECL nng_msg *nano_msg_notify_disconnect(conn_param *cparam, uint8_t code); +NNG_DECL nng_msg *nano_msg_notify_connect(conn_param *cparam, uint8_t code); + +#endif // NNG_MQTT_H diff --git a/include/nng/protocol/mqtt/nano_tcp.h b/include/nng/protocol/mqtt/nano_tcp.h new file mode 100755 index 000000000..d03fe13c5 --- /dev/null +++ b/include/nng/protocol/mqtt/nano_tcp.h @@ -0,0 +1,32 @@ +// +// Copyright 2020 NanoMQ Team, Inc. +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef NNG_PROTOCOL_REQREP0_REP_H +#define NNG_PROTOCOL_REQREP0_REP_H + +#ifdef __cplusplus +extern "C" { +#endif + +NNG_DECL int nng_nano_tcp0_open(nng_socket *); + +#ifndef nng_nano_tcp_open +#define nng_nano_tcp_open nng_nano_tcp0_open +#endif + +#define NNG_NANO_TCP_SELF 0x31 +#define NNG_NANO_TCP_PEER 0x30 +#define NNG_NANO_TCP_SELF_NAME "nano_rep" +#define NNG_NANO_TCP_PEER_NAME "nano_req" + +#ifdef __cplusplus +} +#endif + +#endif // NNG_PROTOCOL_REQREP0_REP_H From c54781b781a09a89cd63f0ef1ea1a6480dc7f89f Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Tue, 3 Aug 2021 18:43:42 +0800 Subject: [PATCH 003/180] * NEW sync --- src/CMakeLists.txt | 2 + src/compat/nanomsg/compat_tcp_test.c | 2 +- src/core/CMakeLists.txt | 2 +- src/core/aio.c | 58 +- src/core/aio.h | 12 + src/core/defs.h | 27 +- src/core/idhash.c | 71 ++ src/core/idhash.h | 21 +- src/core/message.c | 248 ++++- src/core/message.h | 78 ++ src/core/nng_impl.h | 5 +- src/core/panic.c | 2 +- src/core/pipe.c | 46 +- src/core/pipe.h | 6 + src/core/protocol.c | 17 + src/core/protocol.h | 5 + src/core/sockimpl.h | 6 + src/core/taskq.c | 37 +- src/core/taskq.h | 5 +- src/core/tcp.c | 3 +- src/nng.c | 233 ++++- src/sp/protocol/CMakeLists.txt | 4 + src/sp/protocol/mqtt/CMakeLists.txt | 17 + src/sp/protocol/mqtt/mqtt_parser.c | 823 +++++++++++++++ src/sp/protocol/reqrep0/CMakeLists.txt | 4 +- src/sp/protocol/reqrep0/nano_tcp.c | 1285 ++++++++++++++++++++++++ src/sp/transport/tcp/tcp.c | 872 ++++++++++------ 27 files changed, 3532 insertions(+), 359 deletions(-) create mode 100755 src/sp/protocol/mqtt/CMakeLists.txt create mode 100644 src/sp/protocol/mqtt/mqtt_parser.c create mode 100644 src/sp/protocol/reqrep0/nano_tcp.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 20a7bef0c..50a4b7732 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,8 @@ nng_sources(nng.c nng_legacy.c) nng_headers(nng/nng.h) +include_directories(${CMAKE_SOURCE_DIR}/nanolib/include) +include_directories(${CMAKE_SOURCE_DIR}/nanomq/include) target_include_directories(nng PRIVATE ${PROJECT_SOURCE_DIR}/src) target_include_directories(nng_testing PRIVATE ${PROJECT_SOURCE_DIR}/src) diff --git a/src/compat/nanomsg/compat_tcp_test.c b/src/compat/nanomsg/compat_tcp_test.c index d090463f9..f02852cb3 100644 --- a/src/compat/nanomsg/compat_tcp_test.c +++ b/src/compat/nanomsg/compat_tcp_test.c @@ -201,7 +201,7 @@ test_max_recv_size(void) int n; size_t sz; char buf[64]; - char *addr; + char * addr; NUTS_ADDR(addr, "tcp"); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b55bd70aa..3783dbd3c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2021 Staysail Systems, Inc. +# Copyright 2020 Staysail Systems, Inc. # # This software is supplied under the terms of the MIT License, a # copy of which should be located in the distribution where this diff --git a/src/core/aio.c b/src/core/aio.c index 3218c4b90..75b340789 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -1,5 +1,5 @@ // -// Copyright 2021 Staysail Systems, Inc. +// Copyright 2020 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -9,6 +9,7 @@ // #include "core/nng_impl.h" +#include "nng/nng_debug.h" #include struct nni_aio_expire_q { @@ -109,6 +110,7 @@ nni_aio_init(nni_aio *aio, nni_cb cb, void *arg) nni_task_init(&aio->a_task, NULL, cb, arg); aio->a_expire = NNI_TIME_NEVER; aio->a_timeout = NNG_DURATION_INFINITE; + aio->packet_id = 0; aio->a_expire_q = nni_aio_expire_q_list[nni_random() % nni_aio_expire_q_cnt]; } @@ -329,7 +331,7 @@ nni_aio_begin(nni_aio *aio) aio_safe_lock(&eq->eq_mtx); NNI_ASSERT(!nni_aio_list_active(aio)); - NNI_ASSERT(aio->a_cancel_fn == NULL); + //NNI_ASSERT(aio->a_cancel_fn == NULL); NNI_ASSERT(!nni_list_node_active(&aio->a_expire_node)); // Some initialization can be done outside of the lock, because @@ -388,7 +390,12 @@ nni_aio_schedule(nni_aio *aio, nni_aio_cancel_fn cancel, void *data) return (NNG_ECLOSED); } +#if defined(DEBUG) + debug_msg("aio->a_cancel_fn NULL %d?", (aio->a_cancel_fn == NULL)); +#else + NNI_ASSERT(aio->a_cancel_fn == NULL); +#endif aio->a_cancel_fn = cancel; aio->a_cancel_arg = data; @@ -457,18 +464,21 @@ nni_aio_finish_impl( void nni_aio_finish(nni_aio *aio, int result, size_t count) { + debug_msg("aio finish"); nni_aio_finish_impl(aio, result, count, NULL, false); } void nni_aio_finish_sync(nni_aio *aio, int result, size_t count) { + debug_msg("nni_aio_finish_sync"); nni_aio_finish_impl(aio, result, count, NULL, true); } void nni_aio_finish_error(nni_aio *aio, int result) { + debug_msg("nni_aio_finish_error"); nni_aio_finish_impl(aio, result, 0, NULL, false); } @@ -829,3 +839,47 @@ nni_aio_sys_init(void) return (0); } + +// NANOMQ APIs +void +nni_aio_set_packetid(nni_aio *aio, uint16_t id) +{ + aio->packet_id = id; +} + +uint16_t +nni_aio_get_packetid(nni_aio *aio) +{ + return aio->packet_id; +} + +/* +void +nni_aio_set_pipes(nni_aio *aio, uint32_t *pipes) +{ + aio->pipes = pipes; +} + +uint32_t* +nni_aio_get_pipes(nni_aio *aio) +{ + return aio->pipes; +} + + +void +nni_aio_set_pipelength(nni_aio *aio, uint32_t len) +{ + if (aio->pipes == NULL) { + aio->pipe_len = 0; + return; + } + aio->pipe_len = len; +} + +uint32_t +nni_aio_get_pipelength(nni_aio *aio) +{ + return aio->pipe_len; +} +*/ diff --git a/src/core/aio.h b/src/core/aio.h index ba231bd16..2e0d6bab2 100644 --- a/src/core/aio.h +++ b/src/core/aio.h @@ -165,6 +165,16 @@ extern void nni_sleep_aio(nni_duration, nni_aio *); extern int nni_aio_sys_init(void); extern void nni_aio_sys_fini(void); +// NANOMQ APIs +extern void nni_aio_set_sockaddr(nni_aio *aio, const nng_sockaddr *); +extern void nni_aio_get_sockaddr(nni_aio *aio, nng_sockaddr *); +extern uint16_t nni_aio_get_packetid(nni_aio *aio); +extern void nni_aio_set_packetid(nni_aio *aio, uint16_t id); + +// extern void nni_aio_set_pipelength(nni_aio *aio, uint32_t len); +// extern void nni_aio_set_pipes(nni_aio *aio, uint32_t *pipes); +// extern uint32_t *nni_aio_get_pipes(nni_aio *aio); + typedef struct nni_aio_expire_q nni_aio_expire_q; // An nni_aio is an async I/O handle. The details of this aio structure @@ -205,6 +215,8 @@ struct nng_aio { nni_aio_expire_q *a_expire_q; nni_list_node a_expire_node; // Expiration node nni_reap_node a_reap_node; + // NanoMQ var + uint16_t packet_id; }; #endif // CORE_AIO_H diff --git a/src/core/defs.h b/src/core/defs.h index b1dbed187..584335fa2 100644 --- a/src/core/defs.h +++ b/src/core/defs.h @@ -1,5 +1,5 @@ // -// Copyright 2021 Staysail Systems, Inc. +// Copyright 2020 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -36,6 +36,8 @@ typedef nng_sockaddr nni_sockaddr; typedef nng_url nni_url; typedef nng_iov nni_iov; typedef nng_aio nni_aio; +typedef struct nng_event nni_event; +typedef struct nng_notify nni_notify; // These are our own names. typedef struct nni_socket nni_sock; @@ -59,11 +61,19 @@ typedef struct nni_plat_cv nni_cv; typedef struct nni_thr nni_thr; typedef void (*nni_thr_func)(void *); +typedef int nni_signal; // Wakeup channel. typedef uint64_t nni_time; // Abs. time (ms). typedef int32_t nni_duration; // Rel. time (ms). typedef void (*nni_cb)(void *); +// Notify descriptor. +typedef struct { + int sn_wfd; // written to in order to flag an event + int sn_rfd; // read from in order to clear an event + int sn_init; +} nni_notifyfd; + // Some default timing things. #define NNI_TIME_NEVER ((nni_time) -1) #define NNI_TIME_ZERO ((nni_time) 0) @@ -162,12 +172,23 @@ typedef nni_type nni_opt_type; #define NNI_MAX_MAX_TTL 15 #endif -// NNI_MAX_HEADER_SIZE is our header size. -#define NNI_MAX_HEADER_SIZE ((NNI_MAX_MAX_TTL + 1) * sizeof(uint32_t)) +// NANOMQ Tcp layer +#define NNI_ARRAY_SIZE(x) (sizeof(x) / sizeof(uint32_t)) +typedef struct conn_param nano_conn_param; +typedef struct conn_propt nano_conn_propt; + +// TODO independent nano_msg +#ifdef NANO_HEADER_SIZE +#define NNI_NANO_MAX_HEADER_SIZE \ + sizeof(uint8_t) * NANO_HEADER_SIZE // ONLY FIXED HEADER +#else +#define NNI_NANO_MAX_HEADER_SIZE sizeof(uint8_t) * 5 // ONLY FIXED HEADER +#endif // NNI_EXPIRE_Q_SIZE is the default size of aio expire queue #ifndef NNI_EXPIRE_Q_SIZE #define NNI_EXPIRE_Q_SIZE 256 #endif + #endif // CORE_DEFS_H diff --git a/src/core/idhash.c b/src/core/idhash.c index c61850d29..a058b5d3c 100644 --- a/src/core/idhash.c +++ b/src/core/idhash.c @@ -102,6 +102,36 @@ nni_id_get(nni_id_map *m, uint32_t id) return (m->id_entries[index].val); } +/* + * return any solid value in hash, with key returned. + */ +void * +nni_id_get_any(nni_id_map *m, uint16_t *pid) +{ + size_t index; + size_t start; + if (m->id_count == 0 || m->id_entries == NULL) { + return NULL; + } + + index = 1; + start = index; + for (;;) { + // The value of ihe_key is only valid if ihe_val is not NULL. + if (m->id_entries[index].val != NULL) { + *pid = m->id_entries[index].key; + return m->id_entries[index].val; + } + index = ID_NEXT(m, index); + + if (index == start) { + break; + } + } + + return NULL; +} + static int id_resize(nni_id_map *m) { @@ -285,3 +315,44 @@ nni_id_alloc(nni_id_map *m, uint32_t *idp, void *val) } return (rv); } + +void +nni_id_msgfree_cb(nni_msg* msg) +{ + nni_msg_free(msg); + msg = NULL; +} + +void +nni_id_show_cb(nni_msg* msg) +{ + NNI_ARG_UNUSED(msg); + debug_msg("message has an address: %p", msg); +} + +// this function iterates through the the idhash table, and store the entries in a linked list +// the implementation of the linked list used the structure of the idhash entry +void +nni_id_iterate(nni_id_map *m, void (func_cb)(nni_msg*)) +{ + //int count = 0; + for (int i = 0; i < (int) m->id_cap; i++) { + if ((m->id_entries[i].val) != NULL) { + //count++; + func_cb(m->id_entries[i].val); + } + } + //debug_msg("This id_map has %d entries.\n", count); +} + +void* +nni_id_get_one(nni_id_map *m, uint32_t *key) +{ + for (int i = 0; i < (int) m->id_cap; i++) { + if ((m->id_entries[i].val) != NULL) { + *key = m->id_entries[i].key; + return &m->id_entries[i]; + } + } + return NULL; +} diff --git a/src/core/idhash.h b/src/core/idhash.h index 0c9043cec..6a0e9910d 100644 --- a/src/core/idhash.h +++ b/src/core/idhash.h @@ -23,8 +23,8 @@ // use table sizes that are powers of two. Note that hash items // must be non-NULL. The table is protected by an internal lock. -typedef struct nni_id_map nni_id_map; -typedef struct nni_id_entry nni_id_entry; +typedef struct nni_id_map nni_id_map; +typedef struct nni_id_entry nni_id_entry; // NB: These details are entirely private to the hash implementation. // They are provided here to facilitate inlining in structures. @@ -40,11 +40,18 @@ struct nni_id_map { nni_id_entry *id_entries; }; -extern void nni_id_map_init(nni_id_map *, uint32_t, uint32_t, bool); -extern void nni_id_map_fini(nni_id_map *); +extern void nni_id_map_init(nni_id_map *, uint32_t, uint32_t, bool); +extern void nni_id_map_fini(nni_id_map *); extern void *nni_id_get(nni_id_map *, uint32_t); -extern int nni_id_set(nni_id_map *, uint32_t, void *); -extern int nni_id_alloc(nni_id_map *, uint32_t *, void *); -extern int nni_id_remove(nni_id_map *, uint32_t); +extern int nni_id_set(nni_id_map *, uint32_t, void *); +extern int nni_id_alloc(nni_id_map *, uint32_t *, void *); +extern int nni_id_remove(nni_id_map *, uint32_t); + +// NanoMQ +void * nni_id_get_any(nni_id_map *m, uint16_t *pid); +extern void nni_id_msgfree_cb(nni_msg *msg); +extern void nni_id_show_cb(nni_msg *msg); +extern void nni_id_iterate(nni_id_map *m, void(func_cb)(nni_msg *)); +extern void *nni_id_get_one(nni_id_map *m, uint32_t *key); #endif // CORE_IDHASH_H diff --git a/src/core/message.c b/src/core/message.c index 2ff2d6da2..099ab0ea9 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -11,6 +11,8 @@ #include #include "core/nng_impl.h" +#include "nng/nng_debug.h" +#include "nng/protocol/mqtt/mqtt_parser.h" // Message API. @@ -23,12 +25,20 @@ typedef struct { } nni_chunk; // Underlying message structure. +// TODO independent nano_msg struct nng_msg { - uint32_t m_header_buf[(NNI_MAX_MAX_TTL + 1)]; + uint8_t + m_header_buf[NNI_NANO_MAX_HEADER_SIZE + 1]; // only Fixed header size_t m_header_len; - nni_chunk m_body; + nni_chunk m_body; // equal to variable header + payload uint32_t m_pipe; // set on receive nni_atomic_int m_refcnt; + // FOR NANOMQ + size_t remaining_len; + uint8_t CMD_TYPE; + uint8_t * payload_ptr; // payload + nni_time times; + nano_conn_param *cparam; }; #if 0 @@ -634,3 +644,237 @@ nni_msg_get_pipe(const nni_msg *m) { return (m->m_pipe); } + +// NAOMQ APIs +int +nni_msg_cmd_type(nni_msg *m) +{ + return (m->CMD_TYPE); +} + +uint8_t * +nni_msg_header_ptr(const nni_msg *m) +{ + return ((uint8_t *) m->m_header_buf); +} + +uint8_t * +nni_msg_variable_ptr(const nni_msg *m) +{ + return (m->m_body.ch_ptr); +} + +uint8_t * +nni_msg_payload_ptr(const nni_msg *m) +{ + return (m->payload_ptr); +} + +size_t +nni_msg_remaining_len(const nni_msg *m) +{ + return (m->remaining_len); +} + +void +nni_msg_set_payload_ptr(nni_msg *m, uint8_t *ptr) +{ + m->payload_ptr = ptr; +} + +void +nni_msg_set_conn_param(nni_msg *m, void *ptr) +{ + m->cparam = ptr; +} + +conn_param * +nni_msg_get_conn_param(nni_msg *m) +{ + return m->cparam; +} + +void +nni_msg_set_remaining_len(nni_msg *m, size_t len) +{ + m->remaining_len = len; +} + +void +nni_msg_set_cmd_type(nni_msg *m, uint8_t cmd) +{ + m->CMD_TYPE = cmd; +} + +uint8_t +nni_msg_get_pub_qos(nni_msg *m) +{ + uint8_t qos; + + if (nni_msg_cmd_type(m) != 0x30) { + return -1; + } + qos = (m->m_header_buf[0] & 0x06) >> 1; + return qos; +} + +uint16_t +nni_msg_get_pub_pid(nni_msg *m) +{ + uint16_t pid; + uint8_t *pos, len; + + pos = nni_msg_body(m); + NNI_GET16(pos, len); + NNI_GET16(pos + len + 2, pid); + return pid; +} + +void +nni_msg_set_timestamp(nni_msg *m, nni_time time) +{ + m->times = time; +} + +nni_time +nni_msg_get_timestamp(nni_msg *m) +{ + return m->times; +} + +nano_pipe_db * +nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root) +{ + char *topic; + nano_pipe_db *db = NULL, *tmp = NULL, *iter = NULL; + uint8_t len_of_topic = 0, *payload_ptr; + size_t bpos = 0, remain = 0; + bool repeat = false; + + payload_ptr = (char *) nni_msg_payload_ptr(msg); + remain = nni_msg_remaining_len(msg) - 2; + + if (nni_msg_cmd_type(msg) != 0x80) + return NULL; + + if (root != NULL) { + db = root; + while (db->next != NULL) { + db = db->next; + } + } + + while (bpos < remain) { + NNI_GET16(payload_ptr + bpos, len_of_topic); + + if (len_of_topic != 0) { + + debug_msg("The current process topic is %s", + payload_ptr + bpos + 2); + iter = root; + while (iter) { + if (strlen(iter->topic) == len_of_topic && + !strncmp(payload_ptr + bpos + 2, + iter->topic, len_of_topic)) { + repeat = true; + bpos += (2 + len_of_topic); + if (iter->qos != + *(payload_ptr + bpos)) { + iter->qos = + *(payload_ptr + bpos); + } + bpos += 1; + } + iter = iter->next; + } + + if (repeat) { + repeat = false; + continue; + } + + if (NULL != db) { + tmp = db; + db = db->next; + } + db = nng_alloc(sizeof(nano_pipe_db)); + topic = nng_alloc(len_of_topic + 1); + db->prev = tmp; + if (bpos == 0 && root == NULL) { + root = db; + } else { + tmp->next = db; + } + db->root = root; + if (topic == NULL || db == NULL) { + NNI_ASSERT("ERROR: nng_alloc"); + return NULL; + } else { + bpos += 2; + } + strncpy( + topic, (char *) payload_ptr + bpos, len_of_topic); + topic[len_of_topic] = 0x00; + db->topic = topic; + bpos += len_of_topic; + } else { + NNI_ASSERT("ERROR : topic length error."); + return NULL; + } + db->qos = *(payload_ptr + bpos); + db->next = NULL; + debug_msg("sub topic: %s qos : %x\n", db->topic, db->qos); + bpos += 1; + } + + return root; +} + +void +nano_msg_free_pipedb(nano_pipe_db *db) +{ + uint8_t len; + nano_pipe_db *db_next; + + if (NULL == db) { + return; + } + db = db->root; + + while (db) { + len = strlen(db->topic); + nng_free(db->topic, len); + db_next = db->next; + nng_free(db, sizeof(nano_pipe_db)); + db = db_next; + } + return; +} + +void +nano_msg_ubsub_free(nano_pipe_db *db) +{ + nano_pipe_db *ptr, *tmp; + uint8_t len; + + if (NULL == db) { + return; + } + if (db == db->root) { + ptr = db; + tmp = db->next; + while (ptr) { + ptr->root = tmp; + ptr = ptr->next; + } + } else { + tmp = db->prev; + tmp->next = db->next; + db->next->prev = tmp; + } + + len = strlen(db->topic); + nng_free(db->topic, len); + nng_free(db, sizeof(nano_pipe_db)); + return; +} diff --git a/src/core/message.h b/src/core/message.h index 7e35ba752..ec2a3eeb5 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -11,6 +11,8 @@ #ifndef CORE_MESSAGE_H #define CORE_MESSAGE_H +#include + // Internally used message API. Again, this is not part of our public API. // "trim" operations work from the front, and "chop" work from the end. @@ -62,4 +64,80 @@ extern bool nni_msg_shared(nni_msg *); // original message in that case (same semantics as realloc). extern nni_msg *nni_msg_pull_up(nni_msg *); +// NANOMQ MQTT +extern nni_time nni_msg_get_timestamp(nni_msg *m); +extern void nni_msg_set_timestamp(nni_msg *m, nni_time time); +extern int nni_msg_cmd_type(nni_msg *m); +extern uint8_t * nni_msg_header_ptr(const nni_msg *m); +extern uint8_t * nni_msg_variable_ptr(const nni_msg *m); +extern uint8_t * nni_msg_payload_ptr(const nni_msg *m); +extern uint8_t nni_msg_get_pub_qos(nni_msg *m); +extern size_t nni_msg_remaining_len(const nni_msg *m); +extern void nni_msg_set_payload_ptr(nni_msg *m, uint8_t *ptr); +extern void nni_msg_set_remaining_len(nni_msg *m, size_t len); +extern void nni_msg_set_cmd_type(nni_msg *m, uint8_t cmd); +extern void nni_msg_set_conn_param(nni_msg *m, void *ptr); +extern nano_pipe_db *nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root); +extern void nano_msg_free_pipedb(nano_pipe_db *db); +extern void nano_msg_ubsub_free(nano_pipe_db *db); +extern uint8_t nni_msg_get_preset_qos(nni_msg *m); +extern uint16_t nni_msg_get_pub_pid(nni_msg *m); + +extern conn_param *nni_msg_get_conn_param(nni_msg *m); + +typedef struct conn_propt conn_propt; + +struct conn_propt { + uint8_t session_exp_int[5]; +}; + +struct pipe_db { + // uint32_t p_id; + uint8_t qos; + char * topic; + // conn_param * conn_param; + // TODO MQTT5 property + struct pipe_db *next; + struct pipe_db *prev; + struct pipe_db *root; +}; + +// TODO use ZALLOC later +struct conn_param { + uint8_t pro_ver; + uint8_t con_flag; + uint16_t keepalive_mqtt; + uint8_t clean_start; + uint8_t will_flag; + uint8_t will_retain; + uint8_t will_qos; + nni_id_map * nano_qos_db; + struct mqtt_string pro_name; + struct mqtt_string clientid; + struct mqtt_string will_topic; + struct mqtt_string will_msg; + struct mqtt_string username; + struct mqtt_binary password; + // conn_propt ppt; + // mqtt_v5 + // variable header + uint32_t session_expiry_interval; + uint16_t rx_max; + uint32_t max_packet_size; + uint16_t topic_alias_max; + uint8_t req_resp_info; + uint8_t req_problem_info; + struct mqtt_string auth_method; + struct mqtt_binary auth_data; + struct mqtt_str_pair user_property; + // payload + uint32_t will_delay_interval; + uint8_t payload_format_indicator; + uint32_t msg_expiry_interval; + struct mqtt_string content_type; + struct mqtt_string resp_topic; + struct mqtt_binary corr_data; + struct mqtt_str_pair payload_user_property; +}; + #endif // CORE_SOCKET_H diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h index 15db8d160..c86458625 100644 --- a/src/core/nng_impl.h +++ b/src/core/nng_impl.h @@ -1,5 +1,5 @@ // -// Copyright 2021 Garrett D'Amore +// Copyright 2017 Garrett D'Amore // Copyright 2017 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -11,7 +11,8 @@ #define CORE_NNG_IMPL_H #include "nng/nng.h" - +// NanoMQ +#include "nng/nng_debug.h" // Internal implementation things for NNG, common definitions, etc. // All internal modules wind up including this file to avoid having // to figure out which header(s) to include. diff --git a/src/core/panic.c b/src/core/panic.c index d50664cfd..0a24d7239 100644 --- a/src/core/panic.c +++ b/src/core/panic.c @@ -60,7 +60,7 @@ nni_panic(const char *fmt, ...) nni_println(buf); nni_println("This message is indicative of a BUG."); - nni_println("Report this at https://github.com/nanomsg/nng/issues"); + nni_println("Report this at https://github.com/nanomq/nanomq"); nni_show_backtrace(); nni_plat_abort(); diff --git a/src/core/pipe.c b/src/core/pipe.c index a2b6411fc..b55e2fd61 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -69,6 +69,8 @@ pipe_destroy(void *arg) while (p->p_ref != 0) { nni_cv_wait(&p->p_cv); } + nni_id_map_fini(&p->nano_db); + // nni_id_map_fini(&p->nano_qos_db); nni_mtx_unlock(&pipes_lk); if (p->p_proto_data != NULL) { @@ -241,6 +243,7 @@ pipe_stats_init(nni_pipe *p) nni_stat_set_id(&p->st_root, (int) p->p_id); nni_stat_set_id(&p->st_id, (int) p->p_id); nni_stat_set_id(&p->st_sock_id, (int) nni_sock_id(p->p_sock)); + } #endif // NNG_ENABLE_STATS @@ -270,6 +273,8 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) p->p_closed = false; p->p_cbs = false; p->p_ref = 0; + // NanoMQ + p->packet_id = 0; nni_atomic_flag_reset(&p->p_stop); NNI_LIST_NODE_INIT(&p->p_sock_node); @@ -277,6 +282,9 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) nni_mtx_init(&p->p_mtx); nni_cv_init(&p->p_cv, &pipes_lk); + nni_id_map_init(&p->nano_db, 0, 0, false); + p->nano_qos_db = nng_alloc(sizeof(struct nni_id_map)); + nni_id_map_init(p->nano_qos_db, 0, 0, false); nni_mtx_lock(&pipes_lk); if ((rv = nni_id_alloc(&pipes, &p->p_id, p)) == 0) { @@ -302,9 +310,9 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) int nni_pipe_create_dialer(nni_pipe **pp, nni_dialer *d, void *tdata) { - int rv; + int rv; nni_sp_tran *tran = d->d_tran; - nni_pipe * p; + nni_pipe *p; if ((rv = pipe_create(&p, d->d_sock, tran, tdata)) != 0) { return (rv); @@ -326,9 +334,9 @@ nni_pipe_create_dialer(nni_pipe **pp, nni_dialer *d, void *tdata) int nni_pipe_create_listener(nni_pipe **pp, nni_listener *l, void *tdata) { - int rv; + int rv; nni_sp_tran *tran = l->l_tran; - nni_pipe * p; + nni_pipe *p; if ((rv = pipe_create(&p, l->l_sock, tran, tdata)) != 0) { return (rv); @@ -430,4 +438,32 @@ nni_pipe_bump_error(nni_pipe *p, int err) } else { nni_listener_bump_error(p->p_listener, err); } -} \ No newline at end of file +} + +// NanoMQ APIs +void +nni_pipe_set_conn_param(nni_pipe *p, void *c) +{ + p->conn_param = c; +} + +void * +nni_pipe_get_conn_param(nni_pipe *p) +{ + return p->conn_param; +} + +uint16_t +nni_pipe_inc_packetid(nni_pipe *p) +{ + p->packet_id++; + return p->packet_id; +} + +/* +nni_id_map * +nni_pipe_get_idhash(nni_pipe *p) +{ + return &p->pipedb; +} +*/ diff --git a/src/core/pipe.h b/src/core/pipe.h index fe9089369..dee21799c 100644 --- a/src/core/pipe.h +++ b/src/core/pipe.h @@ -65,4 +65,10 @@ extern void nni_pipe_bump_rx(nni_pipe *, size_t); extern void nni_pipe_bump_tx(nni_pipe *, size_t); extern void nni_pipe_bump_error(nni_pipe *, int); +// NanoMQ APIs +extern void nni_pipe_set_conn_param(nni_pipe *p, void *c); +extern void * nni_pipe_get_conn_param(nni_pipe *p); +extern uint16_t nni_pipe_inc_packetid(nni_pipe *p); +// extern nni_id_map* nni_pipe_get_idhash(nni_pipe *p); + #endif // CORE_PIPE_H diff --git a/src/core/protocol.c b/src/core/protocol.c index ea28ad0ac..6d07f6473 100644 --- a/src/core/protocol.c +++ b/src/core/protocol.c @@ -69,6 +69,23 @@ nni_proto_open(nng_socket *sockidp, const nni_proto *proto) return (rv); } +int +nni_proto_mqtt_open(nng_socket *sockidp, const nni_proto *proto, + void (*sock_setdb)(void *, void *)) +{ + int rv; + nni_sock *sock; + + if (((rv = nni_init()) != 0) || ((rv = nni_proto_init(proto)) != 0)) { + return (rv); + } + if ((rv = nni_sock_open(&sock, proto)) == 0) { + sockidp->id = nni_sock_id(sock); // Keep socket held open. + sock_setdb(nni_sock_proto_data(sock), sockidp->data); + } + return (rv); +} + int nni_proto_sys_init(void) { diff --git a/src/core/protocol.h b/src/core/protocol.h index 4edebfc26..9c6c49354 100644 --- a/src/core/protocol.h +++ b/src/core/protocol.h @@ -197,4 +197,9 @@ extern int nni_proto_open(nng_socket *, const nni_proto *); extern int nni_proto_sys_init(void); extern void nni_proto_sys_fini(void); +// For Nanomq + +extern int nni_proto_mqtt_open(nng_socket *, const nni_proto *, void (*sock_setdb)(void *, void *)); + + #endif // CORE_PROTOCOL_H diff --git a/src/core/sockimpl.h b/src/core/sockimpl.h index c3b39ab13..ff1c4aba7 100644 --- a/src/core/sockimpl.h +++ b/src/core/sockimpl.h @@ -123,6 +123,12 @@ struct nni_pipe { nni_stat_item st_rx_bytes; nni_stat_item st_tx_bytes; #endif + + // NanoMQ + void * conn_param; + uint16_t packet_id; + nni_id_map nano_db; // storing subscription topics + nni_id_map *nano_qos_db; // storing qos backup msgs }; extern int nni_sock_add_dialer(nni_sock *, nni_dialer *); diff --git a/src/core/taskq.c b/src/core/taskq.c index e06bc264d..a70719f13 100644 --- a/src/core/taskq.c +++ b/src/core/taskq.c @@ -27,6 +27,9 @@ struct nni_taskq { static nni_taskq *nni_taskq_systq = NULL; +static int var_num_taskq_threads; +static int var_max_taskq_threads; + static void nni_taskq_thread(void *self) { @@ -34,9 +37,9 @@ nni_taskq_thread(void *self) nni_taskq * tq = thr->tqt_tq; nni_task * task; - nni_thr_set_name(NULL, "nng:task"); + nni_thr_set_name(NULL, "nng:task"); - nni_mtx_lock(&tq->tq_mtx); + nni_mtx_lock(&tq->tq_mtx); for (;;) { if ((task = nni_list_first(&tq->tq_tasks)) != NULL) { @@ -232,6 +235,30 @@ nni_task_fini(nni_task *task) nni_mtx_fini(&task->task_mtx); } +void +nni_taskq_setter(int num_taskq_threads, int max_taskq_threads) +{ + if (num_taskq_threads) + var_num_taskq_threads = num_taskq_threads; + if (max_taskq_threads) + var_max_taskq_threads = max_taskq_threads; + debug_msg("command line given: tq [%d], max_tq [%d]", + var_num_taskq_threads, var_max_taskq_threads); +} + +static int +nni_taskq_getter(void) +{ + if (var_num_taskq_threads && var_max_taskq_threads) { + if (var_num_taskq_threads >= var_max_taskq_threads) + return var_max_taskq_threads; + } + debug_msg("command line given: tq [%d], max_tq [%d]", + var_num_taskq_threads, var_max_taskq_threads); + return var_num_taskq_threads ? var_num_taskq_threads + : var_max_taskq_threads; +} + int nni_taskq_sys_init(void) { @@ -248,6 +275,12 @@ nni_taskq_sys_init(void) } #endif + int result = nni_taskq_getter(); + debug_msg("result is %d", result); + if (result) { + nthrs = result; + } + return (nni_taskq_init(&nni_taskq_systq, nthrs)); } diff --git a/src/core/taskq.h b/src/core/taskq.h index 9cabfd9b8..908d26670 100644 --- a/src/core/taskq.h +++ b/src/core/taskq.h @@ -44,7 +44,7 @@ extern void nni_task_prep(nni_task *); extern void nni_task_abort(nni_task *); extern void nni_task_wait(nni_task *); -extern void nni_task_init(nni_task *, nni_taskq *, nni_cb, void *); +extern void nni_task_init(nni_task *, nni_taskq *, nni_cb, void *); // nni_task_fini destroys the task. It will reap resources asynchronously // if the task is currently executing. Use nni_task_wait() first if the @@ -69,4 +69,7 @@ struct nni_task { nni_cv task_cv; }; +// NanoMQ +extern void nni_taskq_setter(int num_taskq_threads, int max_taskq_threads); + #endif // CORE_TASKQ_H diff --git a/src/core/tcp.c b/src/core/tcp.c index 2b1bd987a..686f91af8 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -186,8 +186,7 @@ tcp_dialer_dial(void *arg, nng_aio *aio) } static int -tcp_dialer_get( - void *arg, const char *name, void *buf, size_t *szp, nni_type t) +tcp_dialer_get(void *arg, const char *name, void *buf, size_t *szp, nni_type t) { tcp_dialer *d = arg; return (nni_tcp_dialer_get(d->d, name, buf, szp, t)); diff --git a/src/nng.c b/src/nng.c index 1ccc1386c..f52b84dac 100644 --- a/src/nng.c +++ b/src/nng.c @@ -58,6 +58,12 @@ nng_alloc(size_t sz) return (nni_alloc(sz)); } +void * +nng_zalloc(size_t sz) +{ + return (nni_zalloc(sz)); +} + void nng_free(void *buf, size_t sz) { @@ -286,6 +292,7 @@ nng_ctx_recv(nng_ctx cid, nng_aio *aio) int rv; nni_ctx *ctx; + debug_msg(" ######## nng_ctx_recv context id %d ######## ", cid.id); if ((rv = nni_ctx_find(&ctx, cid.id, false)) != 0) { if (nni_aio_begin(aio) == 0) { nni_aio_finish_error(aio, rv); @@ -1328,13 +1335,13 @@ nng_msg_free(nng_msg *msg) int nng_msg_reserve(nng_msg *msg, size_t capacity) { - return (nni_msg_reserve(msg, capacity)); + return (nni_msg_reserve(msg, capacity)); } size_t nng_msg_capacity(nng_msg *msg) { - return (nni_msg_capacity(msg)); + return (nni_msg_capacity(msg)); } void * @@ -1900,3 +1907,225 @@ nng_version(void) return (xstr(NNG_MAJOR_VERSION) "." xstr(NNG_MINOR_VERSION) "." xstr( NNG_PATCH_VERSION) NNG_RELEASE_SUFFIX); } + +// NANOMQ MQTT APIs +int +nng_msg_cmd_type(nng_msg *msg) +{ + return (nni_msg_cmd_type(msg)); +} + +size_t +nng_msg_remaining_len(nng_msg *msg) +{ + return (nni_msg_remaining_len(msg)); +} + +uint8_t * +nng_msg_header_ptr(nng_msg *msg) +{ + return (nni_msg_header_ptr(msg)); +} + +uint8_t * +nng_msg_variable_ptr(nng_msg *msg) +{ + return (nni_msg_variable_ptr(msg)); +} + +uint8_t * +nng_msg_payload_ptr(nng_msg *msg) +{ + return (nni_msg_payload_ptr(msg)); +} + +void +nng_msg_set_payload_ptr(nng_msg *msg, uint8_t *ptr) +{ + nni_msg_set_payload_ptr(msg, ptr); +} + +void +nng_msg_set_remaining_len(nng_msg *msg, size_t len) +{ + nni_msg_set_remaining_len(msg, len); +} + +void +nng_msg_clone(nng_msg *msg) +{ + nni_msg_clone(msg); +} + +nng_msg * +nng_msg_unique(nng_msg *m) +{ + nng_msg *m2; + m2 = nni_msg_unique(m); + return m2; +} + +void * +nng_msg_get_conn_param(nng_msg *msg) +{ + return nni_msg_get_conn_param(msg); +} + +void +nng_msg_set_cmd_type(nng_msg *m, uint8_t cmd) +{ + nni_msg_set_cmd_type(m, cmd); +} + +const uint8_t * +conn_param_get_clientid(conn_param *cparam) +{ + return (const uint8_t *) cparam->clientid.body; +} + +const uint8_t * +conn_param_get_pro_name(conn_param *cparam) +{ + return (const uint8_t *) cparam->pro_name.body; +} + +const void * +conn_param_get_will_topic(conn_param *cparam) +{ + if (cparam->will_flag) { + return (void *) &(cparam->will_topic); + } else { + return NULL; + } +} + +const void * +conn_param_get_will_msg(conn_param *cparam) +{ + if (cparam->will_flag) { + return (void *) &(cparam->will_msg); + } else { + return NULL; + } +} + +const uint8_t * +conn_param_get_username(conn_param *cparam) +{ + if (cparam->con_flag & 0x80) { + return (const uint8_t *)cparam->username.body; + } else { + return NULL; + } +} + +const uint8_t * +conn_param_get_password(conn_param *cparam) +{ + if (cparam->con_flag & 0x40) { + return cparam->password.body; + } else { + return NULL; + } +} + +uint8_t +conn_param_get_con_flag(conn_param *cparam) +{ + return cparam->con_flag; +} + +uint8_t +conn_param_get_clean_start(conn_param *cparam) +{ + return cparam->clean_start; +} + +uint8_t +conn_param_get_will_flag(conn_param *cparam) +{ + return cparam->will_flag; +} + +uint8_t +conn_param_get_will_qos(conn_param *cparam) +{ + return cparam->will_qos; +} + +uint8_t +conn_param_get_will_retain(conn_param *cparam) +{ + return cparam->will_retain; +} + +uint16_t +conn_param_get_keepalive(conn_param *cparam) +{ + return cparam->keepalive_mqtt; +} + +uint8_t +conn_param_get_protover(conn_param *cparam) +{ + if (NULL == cparam) + return 0; + else + return cparam->pro_ver; +} + +void +nng_msg_set_timestamp(nni_msg *m, uint64_t time) +{ + nni_msg_set_timestamp(m, (nni_time)time); +} + +/* +void +nng_aio_set_pipelength(nng_aio *aio, uint32_t len) +{ + nni_aio_set_pipelength(aio, len); +} + +void +nng_aio_set_pipes(nng_aio *aio, uint32_t *pipes) +{ + nni_aio_set_pipes(aio, pipes); +} +*/ + +void +nng_aio_finish_error(nng_aio *aio, int rv) +{ + nni_aio_finish_error(aio, rv); +} + +void +nng_aio_finish_sync(nng_aio *aio, int rv) +{ + nni_aio_finish_sync(aio, rv, 0); +} + +int +nng_file_put(const char *name, const void *data, size_t sz) +{ + return nni_file_put(name, data, sz); +} + +int +nng_file_get(const char *name, void **datap, size_t *szp) +{ + return nni_file_get(name, datap, szp); +} + +int +nng_file_delete(const char *name) +{ + return nni_file_delete(name); +} + +void +nng_taskq_setter (int num_taskq_threads, int max_taskq_threads) +{ + nni_taskq_setter(num_taskq_threads, max_taskq_threads); +} diff --git a/src/sp/protocol/CMakeLists.txt b/src/sp/protocol/CMakeLists.txt index fd4805237..f74f459ab 100644 --- a/src/sp/protocol/CMakeLists.txt +++ b/src/sp/protocol/CMakeLists.txt @@ -18,3 +18,7 @@ add_subdirectory(pubsub0) add_subdirectory(reqrep0) add_subdirectory(survey0) +#NANOMQ MQTT library +add_subdirectory(mqtt) +#more industrial protols comming soon! + diff --git a/src/sp/protocol/mqtt/CMakeLists.txt b/src/sp/protocol/mqtt/CMakeLists.txt new file mode 100755 index 000000000..778315732 --- /dev/null +++ b/src/sp/protocol/mqtt/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Jaylin EMQ +# https://opensource.org/licenses/MIT. +# + +# static mqtt parser + +option(NNG_PROTO_REQ0 "Enable REQv0 protocol." ON) +mark_as_advanced(NNG_PROTO_REQ0) + +option(NNG_PROTO_REP0 "Enable REPv0 protocol." ON) +mark_as_advanced(NNG_PROTO_REP0) + +nng_sources_if(NNG_PROTO_REQ0 mqtt_parser.c) +nng_headers_if(NNG_PROTO_REQ0 nng/protocol/mqtt/mqtt_parser.h) +nng_defines_if(NNG_PROTO_REQ0 NNG_HAVE_MQTT) + diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c new file mode 100644 index 000000000..0ed6ec84c --- /dev/null +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -0,0 +1,823 @@ +// +// Copyright 2020 NanoMQ Team, Inc. +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include "nng/protocol/mqtt/mqtt_parser.h" +#include "core/nng_impl.h" +#include "nng/nng_debug.h" +#include "nng/protocol/mqtt/mqtt.h" + +#include +#include +#include + +static uint8_t get_value_size(uint64_t value); +static uint64_t power(uint64_t x, uint32_t n); + +static uint64_t +power(uint64_t x, uint32_t n) +{ + uint64_t val = 1; + + for (uint32_t i = 0; i <= n; ++i) { + val = x * val; + } + + return val / x; +} + +/** + * get size from value + * + * @param value + * @return + */ +static uint8_t +get_value_size(uint64_t value) +{ + uint8_t len = 1; + uint64_t pow; + for (int i = 1; i <= 4; ++i) { + pow = power(0x080, i); + if (value >= pow) { + ++len; + } else { + break; + } + } + return len; +} + +/** + * put a value to variable byte array + * @param dest + * @param value + * @return data length + */ +uint8_t +put_var_integer(uint8_t *dest, uint32_t value) +{ + uint8_t len = 0; + uint32_t init_val = 0x7F; + uint8_t value_size = get_value_size(value); + + for (uint32_t i = 0; i < value_size; ++i) { + + if (i > 0) { + init_val = (init_val * 0x80) | 0xFF; + } + dest[i] = value / (uint32_t) power(0x80, i); + if (value > init_val) { + dest[i] |= 0x80; + } + len++; + } + return len; +} + +/** + * Get variable integer value + * + * @param buf Byte array + * @param pos + * @return Integer value + */ +uint32_t +get_var_integer(const uint8_t *buf, uint32_t *pos) +{ + uint8_t temp; + uint32_t result = 0; + + uint32_t p = *pos; + int i = 0; + + do { + temp = *(buf + p); + result = result + (uint32_t)(temp & 0x7f) * (power(0x80, i)); + p++; + } while ((temp & 0x80) > 0 && i++ < 4); + *pos = p; + return result; +} + +/** + * Get utf-8 string + * + * @param dest output string + * @param src input bytes + * @param pos + * @return string length -1: not utf-8, 0: empty string, >0 : normal utf-8 + * string + */ +int32_t +get_utf8_str(char **dest, const uint8_t *src, uint32_t *pos) +{ + int32_t str_len = 0; + NNI_GET16(src + (*pos), str_len); + + *pos = (*pos) + 2; + if (str_len > 0) { + if (utf8_check((const char *) (src + *pos), str_len) == + ERR_SUCCESS) { + *dest = (char *) (src + (*pos)); + *pos = (*pos) + str_len; + } else { + str_len = -1; + } + } + return str_len; +} + +/** + * copy utf-8 string to dst + * + * @param dest output string + * @param src input bytes + * @param pos + * @return string length -1: not utf-8, 0: empty string, >0 : normal utf-8 + * string + */ +uint8_t * +copy_utf8_str(const uint8_t *src, uint32_t *pos, int *str_len) +{ + *str_len = 0; + uint8_t *dest = NULL; + + NNI_GET16(src + (*pos), *str_len); + + *pos = (*pos) + 2; + if (*str_len > 0) { + dest = nng_alloc(*str_len + 1); + if (utf8_check((const char *) (src + *pos), *str_len) == + ERR_SUCCESS) { + memcpy(dest, src + (*pos), *str_len); + dest[*str_len] = '\0'; + *pos = (*pos) + (*str_len); + } else { + nng_free(dest, *str_len + 1); + dest = NULL; + *str_len = -1; + } + } + return dest; +} + +int +utf8_check(const char *str, size_t len) +{ + int i; + int j; + int codelen; + int codepoint; + + const unsigned char *ustr = (const unsigned char *) str; + + if (!str) + return ERR_INVAL; + if (len > 65536) + return ERR_INVAL; + + for (i = 0; i < (int) len; i++) { + if (ustr[i] == 0) { + return ERR_MALFORMED_UTF8; + } else if (ustr[i] <= 0x7f) { + codelen = 1; + codepoint = ustr[i]; + } else if ((ustr[i] & 0xE0) == 0xC0) { + /* 110xxxxx - 2 byte sequence */ + if (ustr[i] == 0xC0 || ustr[i] == 0xC1) { + /* Invalid bytes */ + return ERR_MALFORMED_UTF8; + } + codelen = 2; + codepoint = (ustr[i] & 0x1F); + } else if ((ustr[i] & 0xF0) == 0xE0) { + /* 1110xxxx - 3 byte sequence */ + codelen = 3; + codepoint = (ustr[i] & 0x0F); + } else if ((ustr[i] & 0xF8) == 0xF0) { + /* 11110xxx - 4 byte sequence */ + if (ustr[i] > 0xF4) { + /* Invalid, this would produce values > + * 0x10FFFF. */ + return ERR_MALFORMED_UTF8; + } + codelen = 4; + codepoint = (ustr[i] & 0x07); + } else { + /* Unexpected continuation byte. */ + return ERR_MALFORMED_UTF8; + } + + /* Reconstruct full code point */ + if (i == (int) len - codelen + 1) { + /* Not enough data */ + return ERR_MALFORMED_UTF8; + } + for (j = 0; j < codelen - 1; j++) { + if ((ustr[++i] & 0xC0) != 0x80) { + /* Not a continuation byte */ + return ERR_MALFORMED_UTF8; + } + codepoint = (codepoint << 6) | (ustr[i] & 0x3F); + } + + /* Check for UTF-16 high/low surrogates */ + if (codepoint >= 0xD800 && codepoint <= 0xDFFF) { + return ERR_MALFORMED_UTF8; + } + + /* Check for overlong or out of range encodings */ + /* Checking codelen == 2 isn't necessary here, because it is + *already covered above in the C0 and C1 checks. if(codelen == + *2 && codepoint < 0x0080){ return ERR_MALFORMED_UTF8; }else + */ + if (codelen == 3 && codepoint < 0x0800) { + return ERR_MALFORMED_UTF8; + } else if (codelen == 4 && + (codepoint < 0x10000 || codepoint > 0x10FFFF)) { + return ERR_MALFORMED_UTF8; + } + + /* Check for non-characters */ + if (codepoint >= 0xFDD0 && codepoint <= 0xFDEF) { + return ERR_MALFORMED_UTF8; + } + if ((codepoint & 0xFFFF) == 0xFFFE || + (codepoint & 0xFFFF) == 0xFFFF) { + return ERR_MALFORMED_UTF8; + } + /* Check for control characters */ + if (codepoint <= 0x001F || + (codepoint >= 0x007F && codepoint <= 0x009F)) { + return ERR_MALFORMED_UTF8; + } + } + return ERR_SUCCESS; +} + +uint16_t +get_variable_binary(uint8_t **dest, const uint8_t *src) +{ + uint16_t len = 0; + NNI_GET16(src, len); + *dest = (uint8_t *) (src + 2); + return len; +} + +int +fixed_header_adaptor(uint8_t *packet, nng_msg *dst) +{ + nni_msg *m; + int rv; + size_t pos = 1; + + m = (nni_msg *) dst; + get_var_integer(packet, (uint32_t *) &pos); + + rv = nni_msg_header_append(m, packet, pos); + return rv; +} + +/* +int variable_header_adaptor(uint8_t *packet, nni_msg *dst) +{ + nni_msg *m; + int pos = 0; + uint32_t len; + return 0; +} +*/ +/* +static char *client_id_gen(int *idlen, const char *auto_id_prefix, int +auto_id_prefix_len) +{ + char *client_id; + return client_id; +} + +conn_param * copy_conn_param(conn_param * des, conn_param * src){ + return (conn_param *)memcpy((void *)des, (const void *)src, +sizeof(struct conn_param)); +} +*/ + +/** + * only use in nego_cb !!! + * + */ +int32_t +conn_handler(uint8_t *packet, conn_param *cparam) +{ + + uint32_t len, tmp, pos = 0, len_of_properties = 0; + int len_of_str = 0, len_of_var = 0; + int32_t rv = 0; + uint8_t property_id; + + if (packet[pos] != CMD_CONNECT) { + rv = -1; + return rv; + } else { + pos++; + } + + init_conn_param(cparam); + // remaining length + len = (uint32_t) get_var_integer(packet + pos, &len_of_var); + pos += len_of_var; + // protocol name + cparam->pro_name.body = + (char *) copy_utf8_str(packet, &pos, &len_of_str); + cparam->pro_name.len = len_of_str; + rv = len_of_str < 0 ? 1 : 0; + debug_msg("pro_name: %s", cparam->pro_name.body); + // protocol ver + cparam->pro_ver = packet[pos]; + pos++; + // connect flag + cparam->con_flag = packet[pos]; + cparam->clean_start = (cparam->con_flag & 0x02) >> 1; + cparam->will_flag = (cparam->con_flag & 0x04) >> 2; + cparam->will_qos = (cparam->con_flag & 0x18) >> 3; + cparam->will_retain = (cparam->con_flag & 0x20) >> 5; + debug_msg("conn flag:%x", cparam->con_flag); + pos++; + // keepalive + NNI_GET16(packet + pos, tmp); + cparam->keepalive_mqtt = tmp; + pos += 2; + // properties + if (cparam->pro_ver == PROTOCOL_VERSION_v5) { + debug_msg("MQTT 5 Properties"); + len_of_properties = (uint32_t) get_var_integer(packet, &pos); + uint32_t target_pos = pos + len_of_properties; + debug_msg("propertyLen in variable [%d]", len_of_properties); + + // parse property in variable header + if (len_of_properties > 0) { + while (1) { + property_id = packet[pos++]; + switch (property_id) { + case SESSION_EXPIRY_INTERVAL: + debug_msg("SESSION_EXPIRY_INTERVAL"); + NNI_GET32(packet + pos, + cparam->session_expiry_interval); + pos += 4; + break; + case RECEIVE_MAXIMUM: + debug_msg("RECEIVE_MAXIMUM"); + NNI_GET16( + packet + pos, cparam->rx_max); + pos += 2; + break; + case MAXIMUM_PACKET_SIZE: + debug_msg("MAXIMUM_PACKET_SIZE"); + NNI_GET32(packet + pos, + cparam->max_packet_size); + pos += 4; + break; + case TOPIC_ALIAS_MAXIMUM: + debug_msg("TOPIC_ALIAS_MAXIMUM"); + NNI_GET16(packet + pos, + cparam->topic_alias_max); + pos += 2; + break; + case REQUEST_RESPONSE_INFORMATION: + debug_msg( + "REQUEST_RESPONSE_INFORMATION"); + cparam->req_resp_info = packet[pos++]; + break; + case REQUEST_PROBLEM_INFORMATION: + debug_msg( + "REQUEST_PROBLEM_INFORMATION"); + cparam->req_problem_info = + packet[pos++]; + break; + case USER_PROPERTY: + debug_msg("USER_PROPERTY"); + // key + cparam->user_property.key = + (char *) copy_utf8_str( + packet, &pos, &len_of_str); + cparam->user_property.len_key = + len_of_str; + rv = len_of_str < 0 ? 1 : 0; + // value + cparam->user_property.val = + (char *) copy_utf8_str( + packet, &pos, &len_of_str); + cparam->user_property.len_val = + len_of_str; + rv = len_of_str < 0 ? 1 : 0; + break; + case AUTHENTICATION_METHOD: + debug_msg("AUTHENTICATION_METHOD"); + cparam->auth_method.body = + (char *) copy_utf8_str( + packet, &pos, &len_of_str); + rv = len_of_str < 0 ? 1 : 0; + cparam->auth_method.len = len_of_str; + len_of_str = 0; + break; + case AUTHENTICATION_DATA: + debug_msg("AUTHENTICATION_DATA"); + cparam->auth_data.body = copy_utf8_str( + packet, &pos, &len_of_str); + rv = len_of_str < 0 ? 1 : 0; + cparam->auth_data.len = len_of_str; + break; + default: + break; + } + if (pos == target_pos) { + break; + } else if (pos > target_pos) { + debug_msg("ERROR: protocol error"); + return PROTOCOL_ERROR; + } + } + } + } + debug_msg("pos after property: [%d]", pos); + // payload client_id + cparam->clientid.body = + (char *) copy_utf8_str(packet, &pos, &len_of_str); + rv = len_of_str < 0 ? 1 : 0; + cparam->clientid.len = len_of_str; + debug_msg("clientid: [%s] [%d]", cparam->clientid.body, len_of_str); + // will topic + if (cparam->will_flag != 0) { + if (cparam->pro_ver == PROTOCOL_VERSION_v5) { + len_of_properties = get_var_integer(packet, &pos); + uint32_t target_pos = pos + len_of_properties; + debug_msg( + "propertyLen in payload [%d]", len_of_properties); + + // parse property in variable header + if (len_of_properties > 0) { + while (1) { + property_id = packet[pos++]; + switch (property_id) { + case WILL_DELAY_INTERVAL: + debug_msg( + "WILL_DELAY_INTERVAL"); + NNI_GET32(packet + pos, + cparam + ->will_delay_interval); + pos += 4; + break; + case PAYLOAD_FORMAT_INDICATOR: + debug_msg("PAYLOAD_FORMAT_" + "INDICATOR"); + cparam + ->payload_format_indicator = + packet[pos++]; + break; + case MESSAGE_EXPIRY_INTERVAL: + debug_msg( + "MESSAGE_EXPIRY_INTERVAL"); + NNI_GET32(packet + pos, + cparam + ->msg_expiry_interval); + pos += 4; + break; + case CONTENT_TYPE: + debug_msg("CONTENT_TYPE"); + cparam->content_type.body = + (char *) copy_utf8_str( + packet, &pos, + &len_of_str); + cparam->content_type.len = + len_of_str; + rv = len_of_str < 0 ? 1 : 0; + debug_msg( + "content type: %s %d", + cparam->content_type.body, + rv); + break; + case RESPONSE_TOPIC: + debug_msg("RESPONSE_TOPIC"); + cparam->resp_topic.body = + (char *) copy_utf8_str( + packet, &pos, + &len_of_str); + cparam->resp_topic.len = + len_of_str; + rv = len_of_str < 0 ? 1 : 0; + debug_msg("resp topic: %s %d", + cparam->resp_topic.body, + rv); + break; + case CORRELATION_DATA: + debug_msg("CORRELATION_DATA"); + cparam->corr_data.body = + copy_utf8_str(packet, &pos, + &len_of_str); + cparam->corr_data.len = + len_of_str; + rv = len_of_str < 0 ? 1 : 0; + debug_msg("corr_data: %s %d", + cparam->corr_data.body, + rv); + break; + case USER_PROPERTY: + debug_msg("USER_PROPERTY"); + // key + cparam->payload_user_property + .key = + (char *) copy_utf8_str( + packet, &pos, + &len_of_str); + cparam->payload_user_property + .len_key = len_of_str; + rv = rv | len_of_str; + // value + cparam->payload_user_property + .val = + (char *) copy_utf8_str( + packet, &pos, + &len_of_str); + cparam->payload_user_property + .len_val = len_of_str; + rv = len_of_str < 0 ? 1 : 0; + break; + default: + break; + } + if (pos == target_pos) { + break; + } else if (pos > target_pos) { + debug_msg( + "ERROR: protocol error"); + return PROTOCOL_ERROR; + } + } + } + } + cparam->will_topic.body = + (char *) copy_utf8_str(packet, &pos, &len_of_str); + cparam->will_topic.len = len_of_str; + rv = len_of_str < 0 ? 1 : 0; + debug_msg("will_topic: %s %d", cparam->will_topic.body, rv); + // will msg + cparam->will_msg.body = + (char *) copy_utf8_str(packet, &pos, &len_of_str); + cparam->will_msg.len = len_of_str; + rv = len_of_str < 0 ? 1 : 0; + debug_msg("will_msg: %s %d", cparam->will_msg.body, rv); + } + // username + if ((cparam->con_flag & 0x80) > 0) { + cparam->username.body = + (char *) copy_utf8_str(packet, &pos, &len_of_str); + cparam->username.len = len_of_str; + rv = len_of_str < 0 ? 1 : 0; + debug_msg( + "username: %s %d", cparam->username.body, len_of_str); + } + // password + if ((cparam->con_flag & 0x40) > 0) { + cparam->password.body = + copy_utf8_str(packet, &pos, &len_of_str); + cparam->password.len = len_of_str; + rv = len_of_str < 0 ? 1 : 0; + debug_msg( + "password: %s %d", cparam->password.body, len_of_str); + } + // what if rv = 0? + if (len + len_of_var + 1 != pos) { + debug_msg("ERROR in connect handler"); + } + return rv; +} + +void +destroy_conn_param(conn_param *cparam) +{ + if (cparam == NULL) { + return; + } + debug_msg("destroy conn param"); + nng_free(cparam->pro_name.body, cparam->pro_name.len); + nng_free(cparam->clientid.body, cparam->clientid.len); + nng_free(cparam->will_topic.body, cparam->will_topic.len); + nng_free(cparam->will_msg.body, cparam->will_msg.len); + nng_free(cparam->username.body, cparam->username.len); + nng_free(cparam->password.body, cparam->password.len); + nng_free(cparam->auth_method.body, cparam->auth_method.len); + nng_free(cparam->auth_data.body, cparam->auth_data.len); + nng_free(cparam->user_property.key, cparam->user_property.len_key); + nng_free(cparam->user_property.val, cparam->user_property.len_val); + nng_free(cparam->content_type.body, cparam->content_type.len); + nng_free(cparam->resp_topic.body, cparam->resp_topic.len); + nng_free(cparam->corr_data.body, cparam->corr_data.len); + nng_free(cparam->payload_user_property.key, + cparam->payload_user_property.len_key); + nng_free(cparam->payload_user_property.val, + cparam->payload_user_property.len_val); + nng_free(cparam, sizeof(struct conn_param)); + cparam = NULL; +} + +void +init_conn_param(conn_param *cparam) +{ + cparam->pro_name.len = 0; + cparam->pro_name.body = NULL; + cparam->clientid.len = 0; + cparam->clientid.body = NULL; + cparam->will_topic.body = NULL; + cparam->will_topic.len = 0; + cparam->will_msg.body = NULL; + cparam->will_msg.len = 0; + cparam->username.body = NULL; + cparam->username.len = 0; + cparam->password.body = NULL; + cparam->password.len = 0; + cparam->auth_method.body = NULL; + cparam->auth_method.len = 0; + cparam->auth_data.body = NULL; + cparam->auth_data.len = 0; + cparam->user_property.key = NULL; + cparam->user_property.len_key = 0; + cparam->user_property.val = NULL; + cparam->user_property.len_val = 0; + cparam->content_type.body = NULL; + cparam->content_type.len = 0; + cparam->resp_topic.body = NULL; + cparam->resp_topic.len = 0; + cparam->corr_data.body = NULL; + cparam->corr_data.len = 0; + cparam->payload_user_property.key = NULL; + cparam->payload_user_property.len_key = 0; + cparam->payload_user_property.val = NULL; + cparam->payload_user_property.len_val = 0; +} + +uint32_t +DJBHash(char *str) +{ + unsigned int hash = 5381; + while (*str) { + hash = ((hash << 5) + hash) + (*str++); /* times 33 */ + } + hash &= ~(1 << 31); /* strip the highest bit */ + return hash; +} + +uint32_t +DJBHashn(char *str, uint16_t len) +{ + unsigned int hash = 5381; + uint16_t i = 0; + while (i < len) { + hash = ((hash << 5) + hash) + (*str++); /* times 33 */ + i++; + } + hash &= ~(1 << 31); /* strip the highest bit */ + return hash; +} + +uint64_t +nano_hash(char *str) +{ + uint64_t hash = 5381; + int c; + + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + // hash = hash * 33 + c; + return hash; +} + +void +nano_msg_set_dup(nng_msg *msg) +{ + uint8_t *header; + + header = nni_msg_header(msg); + *header = *header | 0x08; +} + +// alloc a publish msg according to the need +nng_msg * +nano_msg_composer( + uint8_t retain, uint8_t qos, mqtt_string *payload, mqtt_string *topic) +{ + size_t rlen; + uint8_t *ptr, buf[5] = { '\0' }; + uint32_t len; + nni_msg *msg; + + len = payload->len + topic->len + 2; + if (qos > 0) { + nni_msg_alloc(&msg, len + 2); + rlen = put_var_integer(buf + 1, len + 2); + nni_msg_set_remaining_len(msg, len + 2); + if (qos == 1) { + buf[0] = CMD_PUBLISH | 0x02; + } else if (qos == 2) { + buf[0] = CMD_PUBLISH | 0x04; + } else { + nni_println("ERROR: will msg qos invalid"); + return NULL; + } + } else { + nni_msg_alloc(&msg, len); + rlen = put_var_integer(buf + 1, len); + nni_msg_set_remaining_len(msg, len); + buf[0] = CMD_PUBLISH; + } + ptr = nni_msg_header(msg); + if (retain > 0) { + buf[0] = buf[0] | 0x01; + } + memcpy(ptr, buf, rlen + 1); + + ptr = nni_msg_body(msg); + NNI_PUT16(ptr, topic->len); + ptr = ptr + 2; + memcpy(ptr, topic->body, topic->len); + ptr += topic->len; + if (qos > 0) { + // Set pid? + NNI_PUT16(ptr, 0x10); + ptr = ptr + 2; + } + memcpy(ptr, payload->body, payload->len); + nni_msg_set_payload_ptr(msg, ptr); + + return msg; +} + +uint8_t +verify_connect(conn_param *cparam, conf *conf) +{ + int i, n = conf->auths.count; + char *username = cparam->username.body; + char *password = cparam->password.body; + + if (conf->auths.count == 0 || conf->allow_anonymous == true) { + debug_msg("WARNING: no valid entry in " + "etc/nanomq_auth_username.conf."); + return 0; + } + + if (cparam->username.len == 0 || cparam->password.len == 0) { + if (cparam->pro_ver == 5) { + return BAD_USER_NAME_OR_PASSWORD; + } else { + return 0x04; + } + } + + for (i = 0; i < n; i++) { + if (strcmp(username, conf->auths.usernames[i]) == 0 && + strcmp(password, conf->auths.passwords[i]) == 0) { + return 0; + } + } + if (cparam->pro_ver == 5) { + return BAD_USER_NAME_OR_PASSWORD; + } else { + return 0x05; + } +} + +nng_msg * +nano_msg_notify_disconnect(conn_param *cparam, uint8_t code) +{ + nni_msg * msg; + mqtt_string string, topic; + uint8_t buff[256]; + snprintf(buff, 256, DISCONNECT_MSG, cparam->username.body, + (uint64_t) nni_clock(), code, cparam->clientid.body); + string.body = buff; + string.len = strlen(string.body); + topic.body = DISCONNECT_TOPIC; + topic.len = strlen(DISCONNECT_TOPIC); + msg = nano_msg_composer(0, 0, &string, &topic); + return msg; +} + +nng_msg * +nano_msg_notify_connect(conn_param *cparam, uint8_t code) +{ + nni_msg * msg; + mqtt_string string, topic; + uint8_t buff[256]; + snprintf(buff, 256, CONNECT_MSG, cparam->username.body, + (uint64_t) nni_clock(), cparam->pro_name.body, cparam->keepalive_mqtt, code, cparam->pro_ver, cparam->clientid.body, cparam->clean_start); + string.body = buff; + string.len = strlen(string.body); + topic.body = CONNECT_TOPIC; + topic.len = strlen(CONNECT_TOPIC); + msg = nano_msg_composer(0, 0, &string, &topic); + return msg; +} \ No newline at end of file diff --git a/src/sp/protocol/reqrep0/CMakeLists.txt b/src/sp/protocol/reqrep0/CMakeLists.txt index a3cecfd03..d588034fe 100644 --- a/src/sp/protocol/reqrep0/CMakeLists.txt +++ b/src/sp/protocol/reqrep0/CMakeLists.txt @@ -15,8 +15,8 @@ nng_sources_if(NNG_PROTO_REQ0 req.c xreq.c) nng_headers_if(NNG_PROTO_REQ0 nng/protocol/reqrep0/req.h) nng_defines_if(NNG_PROTO_REQ0 NNG_HAVE_REQ0) -nng_sources_if(NNG_PROTO_REP0 rep.c xrep.c) -nng_headers_if(NNG_PROTO_REP0 nng/protocol/reqrep0/rep.h) +nng_sources_if(NNG_PROTO_REP0 rep.c xrep.c nano_tcp.c) +nng_headers_if(NNG_PROTO_REP0 nng/protocol/reqrep0/rep.h nng/protocol/mqtt/nano_tcp.h) nng_defines_if(NNG_PROTO_REP0 NNG_HAVE_REP0) nng_test(req_test) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c new file mode 100644 index 000000000..1698ea728 --- /dev/null +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -0,0 +1,1285 @@ +// +// Copyright 2020 NanoMQ Team, Inc. +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include +#include +#include +#include + +#include "core/nng_impl.h" +#include "core/sockimpl.h" +#include "nng/protocol/mqtt/mqtt_parser.h" +#include "nng/protocol/mqtt/nano_tcp.h" + +#include "nng/protocol/mqtt/mqtt.h" + +#include + +// TODO rewrite as nano_mq protocol with RPC support + +typedef struct nano_pipe nano_pipe; +typedef struct nano_sock nano_sock; +typedef struct nano_ctx nano_ctx; +typedef struct nano_clean_session nano_clean_session; +typedef struct cs_msg_list cs_msg_list; + +static void nano_pipe_send_cb(void *); +static void nano_pipe_recv_cb(void *); +static void nano_pipe_fini(void *); +static void nano_pipe_close(void *, uint8_t reason_code); +static inline void close_pipe(nano_pipe *p, uint8_t reason_code); +// static void nano_period_check(nano_sock *s, nni_list *sent_list, void *arg); +// static void nano_keepalive(nano_pipe *p, void *arg); + +// huge context/ dynamic context? +struct nano_ctx { + nano_sock *sock; + uint32_t pipe_id; + // uint32_t resend_count; + // uint32_t pipe_len; //record total length of pipe_id queue + // when resending + nano_pipe *spipe, *qos_pipe; // send pipe + nni_aio * saio; // send aio + nni_aio * raio; // recv aio + // uint32_t* rspipes;// pub resend pipe queue Qos 1/2 + // nni_list send_queue; // contexts waiting to send. + nni_list_node sqnode; + nni_list_node rqnode; + // nni_timer_node qos_timer; +}; + +// nano_sock is our per-socket protocol private structure. +struct nano_sock { + nni_mtx lk; + nni_atomic_int ttl; + nni_id_map pipes; + nni_id_map clean_session_db; + nni_list recvpipes; // list of pipes with data to receive + nni_list recvq; + nano_ctx ctx; // base socket + nni_pollable readable; + nni_pollable writable; + conf * conf; + void * db; +}; + +// nano_pipe is our per-pipe protocol private structure. +struct nano_pipe { + nni_mtx lk; + nni_pipe * pipe; + nano_sock * rep; + uint32_t id; + void * tree; // root node of db tree + nni_aio aio_send; + nni_aio aio_recv; + nni_aio aio_timer; + nni_list_node rnode; // receivable list linkage + nni_list sendq; // contexts waiting to send + bool busy; + bool closed; + bool kicked; + uint8_t reason_code; + uint8_t ka_refresh; + conn_param * conn_param; + nano_pipe_db *pipedb_root; + nni_lmq rlmq; +}; + +struct nano_clean_session { + client_ctx * cltx; + conn_param * cparam; + nni_id_map * msg_map; + nano_pipe_db *pipe_db; + uint32_t pipeid; // corresponding pipe id of nng + bool clean; +}; + +static void +nano_pipe_timer_cb(void *arg) +{ + nano_pipe *p = arg; + nni_msg * msg; + nni_time time; + nni_pipe * npipe = p->pipe; + uint16_t pid; + int qos_timer = p->rep->conf->qos_timer; + + if (nng_aio_result(&p->aio_timer) != 0) { + return; + } + nni_mtx_lock(&p->lk); + if (p->ka_refresh * (qos_timer) > p->conn_param->keepalive_mqtt) { + printf("Warning: close pipe & kick client due to KeepAlive " + "timeout!"); + // TODO check keepalived timer interval + nni_mtx_unlock(&p->lk); + nano_pipe_close(p,0x8D); + return; + } + p->ka_refresh++; + if (!p->busy) { + msg = nni_id_get_any(npipe->nano_qos_db, &pid); + + if (msg != NULL) { + time = nni_msg_get_timestamp(msg); + if ((nni_clock() - time) >= + (long unsigned) qos_timer * 1250) { + p->busy = true; + nni_msg_clone(msg); + nano_msg_set_dup(msg); + nni_aio_set_packetid(&p->aio_send, pid); + nni_aio_set_msg(&p->aio_send, msg); + debug_msg("resending qos msg!\n"); + nni_pipe_send(p->pipe, &p->aio_send); + nni_id_remove(npipe->nano_qos_db, pid); + } + } + } + + nni_mtx_unlock(&p->lk); + nni_sleep_aio(qos_timer * 1000, &p->aio_timer); + return; +} + +/* +static void +nano_keepalive(nano_pipe *p, void *arg) +{ + uint16_t interval; + + interval = conn_param_get_keepalive(p->conn_param); + debug_msg("KeepAlive: %d", interval); + //20% KeepAlive as buffer time for multi-threading + nni_timer_schedule(&p->ka_timer, nni_clock() + NNI_SECOND * interval * +0.8); +} +*/ + +static void +nano_ctx_close(void *arg) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + nni_aio * aio; + + debug_msg("nano_ctx_close"); + nni_mtx_lock(&s->lk); + if ((aio = ctx->saio) != NULL) { + // nano_pipe *pipe = ctx->spipe; + ctx->saio = NULL; + ctx->spipe = NULL; + ctx->qos_pipe = NULL; + nni_aio_finish_error(aio, NNG_ECLOSED); + } + if ((aio = ctx->raio) != NULL) { + nni_list_remove(&s->recvq, ctx); + ctx->raio = NULL; + nni_aio_finish_error(aio, NNG_ECLOSED); + } + nni_mtx_unlock(&s->lk); +} + +static void +nano_ctx_fini(void *arg) +{ + nano_ctx *ctx = arg; + + nano_ctx_close(ctx); + + // timer + debug_msg("========= nano_ctx_fini ========="); + // nni_timer_cancel(&ctx->qos_timer); + // nni_timer_fini(&ctx->qos_timer); +} + +static int +nano_ctx_init(void *carg, void *sarg) +{ + nano_sock *s = sarg; + nano_ctx * ctx = carg; + + debug_msg("&&&&&&&& nano_ctx_init %p &&&&&&&&&", ctx); + NNI_LIST_NODE_INIT(&ctx->sqnode); + NNI_LIST_NODE_INIT(&ctx->rqnode); + + // TODO send list?? + // ctx->pp_len = 0; + ctx->sock = s; + ctx->pipe_id = 0; + + return (0); +} + +static void +nano_ctx_cancel_send(nni_aio *aio, void *arg, int rv) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + + debug_msg("*********** nano_ctx_cancel_send ***********"); + nni_mtx_lock(&s->lk); + if (ctx->saio != aio) { + nni_mtx_unlock(&s->lk); + return; + } + nni_list_node_remove(&ctx->sqnode); + ctx->saio = NULL; + nni_mtx_unlock(&s->lk); + + nni_msg_header_clear(nni_aio_get_msg(aio)); // reset the headers + nni_aio_finish_error(aio, rv); +} + +static void +nano_ctx_send(void *arg, nni_aio *aio) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + nano_pipe *p; + nni_msg * msg; + int rv; + uint32_t pipe; + + msg = nni_aio_get_msg(aio); + + if (nni_aio_begin(aio) != 0) { + return; + } + + debug_msg("############### nano_ctx_send with ctx %p msg type %x " + "###############", + ctx, nni_msg_cmd_type(msg)); + + if ((pipe = nni_msg_get_pipe(msg)) != 0) { + nni_msg_set_pipe(msg, 0); + } else { + pipe = ctx->pipe_id; // reply to self + } + ctx->pipe_id = 0; // ensure connack/PING/DISCONNECT/PUBACK only sends once + + if (ctx == &s->ctx) { + nni_pollable_clear(&s->writable); + } + + nni_mtx_lock(&s->lk); + debug_msg("*************************** working with pipe id : %d " + "ctx***************************", pipe); + if ((p = nni_id_get(&s->pipes, pipe)) == NULL) { + // Pipe is gone. Make this look like a good send to avoid + // disrupting the state machine. We don't care if the peer + // lost interest in our reply. + nni_mtx_unlock(&s->lk); + nni_aio_set_msg(aio, NULL); + //TODO lastwill/SYS topic will trigger this (sub to the topic that publish to by itself) + debug_syslog("ERROR: pipe is gone, pub failed"); + nni_msg_free(msg); + return; + } + nni_mtx_unlock(&s->lk); + nni_mtx_lock(&p->lk); + if (!p->busy) { + p->busy = true; + nni_aio_set_msg(&p->aio_send, msg); + nni_pipe_send(p->pipe, &p->aio_send); + nni_mtx_unlock(&p->lk); + nni_aio_set_msg(aio, NULL); + return; + } + + if ((rv = nni_aio_schedule(aio, nano_ctx_cancel_send, ctx)) != 0) { + nni_msg_free(msg); + nni_mtx_unlock(&p->lk); + return; + } + debug_msg("WARNING: pipe %d occupied! resending in cb!", pipe); + if (nni_lmq_full(&p->rlmq)) { + // Make space for the new message. TODO add max limit of msgq len in conf + if (rv = nni_lmq_resize(&p->rlmq, nni_lmq_cap(&p->rlmq) * 2) != 0) { + debug_syslog("warning msg dropped!"); + nni_msg *old; + (void) nni_lmq_getq(&p->rlmq, &old); + nni_msg_free(old); + } + } + nni_lmq_putq(&p->rlmq, msg); + + nni_mtx_unlock(&p->lk); + nni_aio_set_msg(aio, NULL); + return; +} + +void +nano_clean_session_db_fini(nni_id_map *m) +{ + uint32_t key = 0; + nano_clean_session *cs = NULL; + while ((cs = nni_id_get_one(m, &key)) != NULL) { + conn_param *cparam = cs->cparam; + nni_id_map *msg_map = cs->msg_map; + + destroy_conn_param(cparam); + nni_id_iterate(msg_map, nni_id_msgfree_cb); + nni_id_map_fini(msg_map); + nng_free(msg_map, sizeof(struct nni_id_map)); + + nni_id_remove(m, key); + cs = NULL; + } + nni_id_map_fini(m); +} + +static void +nano_sock_fini(void *arg) +{ + nano_sock *s = arg; + + nni_id_map_fini(&s->pipes); + nano_clean_session_db_fini(&s->clean_session_db); + nano_ctx_fini(&s->ctx); + nni_pollable_fini(&s->writable); + nni_pollable_fini(&s->readable); + nni_mtx_fini(&s->lk); + + conf_fini(s->conf); +} + +static int +nano_sock_init(void *arg, nni_sock *sock) +{ + nano_sock *s = arg; + + NNI_ARG_UNUSED(sock); + + nni_mtx_init(&s->lk); + + nni_id_map_init(&s->pipes, 0, 0, false); + nni_id_map_init(&s->clean_session_db, 0, 0, false); + NNI_LIST_INIT(&s->recvq, nano_ctx, rqnode); + NNI_LIST_INIT(&s->recvpipes, nano_pipe, rnode); + + nni_atomic_init(&s->ttl); + nni_atomic_set(&s->ttl, 8); + + (void) nano_ctx_init(&s->ctx, s); + + debug_msg("************* nano_sock_init %p *************", s); + // We start off without being either readable or writable. + // Readability comes when there is something on the socket. + nni_pollable_init(&s->writable); + nni_pollable_init(&s->readable); + + return (0); +} + +static void +nano_sock_open(void *arg) +{ + NNI_ARG_UNUSED(arg); +} + +static void +nano_sock_close(void *arg) +{ + nano_sock *s = arg; + + nano_ctx_close(&s->ctx); +} + +static void +nano_pipe_stop(void *arg) +{ + nano_pipe *p = arg; + + debug_msg("##########nano_pipe_stop###############"); + nni_aio_stop(&p->aio_send); + nni_aio_stop(&p->aio_timer); + nni_aio_stop(&p->aio_recv); +} + +static void +nano_deep_copy_connparam(conn_param *new_cp, conn_param *cp) +{ + UPDATE_FIELD_INT(pro_ver, new_cp, cp); + UPDATE_FIELD_INT(con_flag, new_cp, cp); + UPDATE_FIELD_INT(keepalive_mqtt, new_cp, cp); + UPDATE_FIELD_INT(clean_start, new_cp, cp); + UPDATE_FIELD_INT(will_flag, new_cp, cp); + UPDATE_FIELD_INT(will_retain, new_cp, cp); + UPDATE_FIELD_INT(will_qos, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(pro_name, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(clientid, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(will_topic, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(will_msg, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(username, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(password, body, new_cp, cp); + UPDATE_FIELD_INT(session_expiry_interval, new_cp, cp); + UPDATE_FIELD_INT(rx_max, new_cp, cp); + UPDATE_FIELD_INT(max_packet_size, new_cp, cp); + UPDATE_FIELD_INT(topic_alias_max, new_cp, cp); + UPDATE_FIELD_INT(req_resp_info, new_cp, cp); + UPDATE_FIELD_INT(req_problem_info, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(auth_method, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(auth_data, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING_PAIR(user_property, key, val, new_cp, cp); + UPDATE_FIELD_INT(will_delay_interval, new_cp, cp); + UPDATE_FIELD_INT(payload_format_indicator, new_cp, cp); + UPDATE_FIELD_INT(msg_expiry_interval, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(content_type, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(resp_topic, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(corr_data, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING_PAIR( + payload_user_property, key, val, new_cp, cp); +} + +static void * +del_topic_clictx_from_tree(void *tree, topic_queue *tq, uint32_t pid) +{ + client_ctx *cli_ctx = NULL; + + while (tq) { + if (tq->topic) { + cli_ctx = search_and_delete(tree, tq->topic, pid); + } + debug_msg("delete pipe id [%d] topic: [%s]", pid, tq->topic); + del_sub_ctx(cli_ctx, tq->topic); + tq = tq->next; + } + + return cli_ctx; +} + +static void * +del_topic_from_tree(void *tree, topic_queue *tq, uint32_t pid) +{ + client_ctx *cli_ctx = NULL; + + while (tq) { + if (tq->topic) { + cli_ctx = search_and_delete(tree, tq->topic, pid); + } + debug_msg("delete pipe id [%d] topic: [%s]", pid, tq->topic); + tq = tq->next; + } + + return cli_ctx; +} + +static void +restore_topic_to_tree(void *tree, client_ctx *cli_ctx, char *client_id) +{ + topic_node *tn_t = cli_ctx->sub_pkt->node; + + while (tn_t) { + debug_msg("Now adding topic (from last session), body: [%s]", + tn_t->it->topic_filter.body); + search_and_insert(tree, tn_t->it->topic_filter.body, client_id, + cli_ctx, cli_ctx->pid.id); + tn_t = tn_t->next; + } +} + +static int +nano_session_restore(nano_pipe *p, nano_sock *s, uint8_t *flag) +{ + int ret; + conn_param * new_cparam = p->conn_param; + uint32_t key; + uint8_t clean_session_flag = new_cparam->clean_start; + nano_clean_session *cs; + + key = DJBHashn(new_cparam->clientid.body, new_cparam->clientid.len); + // TODO hash collision? + cs = nni_id_get(&s->clean_session_db, key); + + // no matter if client enabled cleansession. use clean-session-db for + // duplicate clientid verifying. + if (cs == NULL) { + if ((cs = nni_zalloc(sizeof(nano_clean_session) * 1)) == + NULL) { + return (NNG_ENOMEM); + } + // firts connection, store pipeid and hashed clientid + cs->pipeid = p->id; + if (clean_session_flag == 0) { + debug_msg("(CS=0) Session cannot restore, cannot find " + "cached information based " + "on the clientID given (eithe first connect " + "or lose the backup)"); + cs->clean = false; + ret = 0; + } else { + debug_msg("(CS=1) No need for restoring a session"); + cs->clean = true; + ret = 0; + } + if (nni_id_set(&s->clean_session_db, key, cs) != 0) { + debug_msg("(CS=0) UNEXPECTED: The nano_clean_session " + "structure is not set " + "as a new instance of hashtable"); + ret = NNG_ECONNABORTED; + } + return ret; + } else if (cs->pipeid != 0) { + // TODO kick prev connection or current one?(p or cs->pipeid) + p->kicked = true; + if (p->conn_param->pro_ver == 5) { + *(flag +1 ) = 0x8E; + } else { + *(flag +1 ) = 0x02; + } + return (NNG_ECONNABORTED); + } + + client_ctx * cltx = cs->cltx; + conn_param * cparam = cs->cparam; + nni_id_map * msgs = cs->msg_map; + nano_pipe_db *topics = cs->pipe_db; + nano_pipe_db *topic_node = topics; + + cs->pipeid = p->id; + if (clean_session_flag == 0) { + *flag = 0x01; //set session present flag + cs->clean = false; + // step 0 restore conn param + nano_deep_copy_connparam(new_cparam, cparam); + destroy_conn_param(cparam); + cparam = NULL; + // step 1 restore nano_qos_db + // TODO new coming message may use the existing packet id in + // one client nano_qos_db + nni_id_map_fini(p->pipe->nano_qos_db); + nng_free(p->pipe->nano_qos_db, sizeof(struct nni_id_map)); + p->pipe->nano_qos_db = msgs; + p->conn_param->nano_qos_db = msgs; + // step 2 restore cli_ctx and cached_topic_queue + if (cltx != NULL) + cltx->pid.id = p->id; + if (cached_check_id(key)) { + restore_topic_all(key, p->id); + restore_topic_to_tree( + p->tree, cltx, new_cparam->clientid.body); + } else { + debug_msg( + "(CS=0) UNEXPECTED: no stored cached topic queue"); + } + // step 3 restore topic in pipe_db + p->pipedb_root = topics; + cs->pipe_db = NULL; + // step 4 restore nano_pipe_db + while (topic_node->next) { + nni_id_set(&p->pipe->nano_db, + DJBHashn( + topic_node->topic, strlen(topic_node->topic)), + topic_node); + topic_node = topic_node->next; + } + debug_msg( + "(CS=0) All last session related information restored"); + } else { + cs->clean = true; + // step 0 remove conn param + destroy_conn_param(cparam); + cparam = NULL; + // step 1 remove nano_qos_db + nni_id_iterate(msgs, nni_id_msgfree_cb); + nni_id_map_fini(msgs); + nng_free(msgs, sizeof(struct nni_id_map)); + msgs = NULL; + // step 2 delete 2-1 cli_ctx and cached topic queue + if (cached_check_id(key)) { + topic_queue *tq = get_cached_topic(key); + while (tq) { + del_sub_ctx(cltx, tq->topic); + tq = tq->next; + } + del_cached_topic_all(key); + } else { + debug_msg( + "(CS=1) UNEXPECTED: no stored cached topic queue"); + } + // step 3 delete topics in pipe_db + nano_msg_free_pipedb(topics); + debug_msg( + "(CS=1) All last session related information disgarded"); + } + return 0; +} + +static int +nano_session_cache(nano_pipe *p, nano_clean_session *temp_cs, uint32_t key) +{ + conn_param * cp = p->conn_param; + nni_id_map * nano_qos_db = cp->nano_qos_db; + client_ctx * cli_ctx = NULL; + struct topic_queue *tq = NULL; + + // step 0 copy connection parameter + conn_param *new_cp; + if ((new_cp = nni_zalloc(sizeof(conn_param) * 1)) == NULL) { + return (NNG_ENOMEM); + } + init_conn_param(new_cp); + nano_deep_copy_connparam(new_cp, cp); + temp_cs->cparam = new_cp; + // step 1 move nano_qos_db to temp_cs struct (move pointer) + temp_cs->msg_map = nano_qos_db; + debug_msg("the nano_qos_db has an address: %p", nano_qos_db); + nano_qos_db = NULL; + // step 2-1 find cli_ctx and kept its pointer, but delete topic from + // tree step 2-2 move topic from topic map to cached topic map + // (hash.cc) + if (check_id(p->id)) { + tq = get_topic(p->id); + if ((cli_ctx = del_topic_from_tree(p->tree, tq, p->id)) != + NULL) { + cli_ctx->pid.id = 0; + temp_cs->cltx = cli_ctx; + } + cache_topic_all(p->id, key); + } else { + debug_msg("(CS=0) UNEXPECTED: no stored topic queue, tq lost " + "or client may not subed topic"); + } + // step 3 move nano_pipe_db to temp_cs struct (move pointer) + temp_cs->pipe_db = p->pipedb_root; + p->pipedb_root = NULL; + + debug_msg("(CS=0) Session cached, all this session related " + "information kept"); + return 0; +} + +static void +nano_sessiondb_clean(nano_pipe *p) +{ + conn_param * cp = p->conn_param; + nano_sock * s = p->rep; + uint32_t key; + nano_clean_session *temp_cs; + + key = DJBHashn(cp->clientid.body, cp->clientid.len); + // get temp_cs from clean_session_db + temp_cs = nni_id_get(&s->clean_session_db, key); + if (temp_cs != NULL) { + // temp_cs->pipeid indicates if current session existed. + if (p->closed == true && temp_cs->pipeid == p->id) { + temp_cs->pipeid = 0; + } + if (temp_cs->clean == true) { + // Do not kick the old one. + if (temp_cs->pipeid == 0) { + nni_id_remove(&s->clean_session_db, key); + nng_free(temp_cs, sizeof(nano_clean_session)); + } + } + } +} + +static void +nano_pipe_fini(void *arg) +{ + nano_pipe * p = arg; + nng_msg * msg; + uint32_t key; + nano_clean_session *temp_cs; + conn_param * cp = p->conn_param; + nano_sock * s = p->rep; + + debug_msg("########## nano_pipe_fini ###############"); + if ((msg = nni_aio_get_msg(&p->aio_recv)) != NULL) { + nni_aio_set_msg(&p->aio_recv, NULL); + nni_msg_free(msg); + } + + if ((msg = nni_aio_get_msg(&p->aio_send)) != NULL) { + nni_aio_set_msg(&p->aio_recv, NULL); + nni_msg_free(msg); + } + + key = DJBHashn(cp->clientid.body, cp->clientid.len); + // get temp_cs from clean_session_db + // TODO potential risk without lock + temp_cs = nni_id_get(&s->clean_session_db, key); + if (p->conn_param->clean_start == 0 && + temp_cs != NULL && + p->kicked != true) { + nano_session_cache(p, temp_cs, key); + } else { + // When clean_session is set to 1 + nni_id_map * nano_qos_db = p->conn_param->nano_qos_db; + client_ctx * cli_ctx = NULL; + struct topic_queue *tq = NULL; + + nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); + nni_id_map_fini(nano_qos_db); + nng_free(nano_qos_db, sizeof(struct nni_id_map)); + + if (check_id(p->id) && p->tree != NULL) { + tq = get_topic(p->id); + if ((cli_ctx = del_topic_clictx_from_tree( + p->tree, tq, p->id)) != NULL) { + debug_msg("(CS=1) Unexpected, not all topic " + "has been delete from sub_pkt"); + } + del_topic_all(p->id); + } else { + debug_msg("(CS=1) UNEXPECTED: no stored topic queue, " + "tq lost or maybe not subed any topic"); + } + nano_msg_free_pipedb(p->pipedb_root); + p->pipedb_root = NULL; + } + destroy_conn_param(p->conn_param); + + nni_mtx_fini(&p->lk); + nni_aio_fini(&p->aio_send); + nni_aio_fini(&p->aio_recv); + nni_aio_fini(&p->aio_timer); + nni_lmq_fini(&p->rlmq); +} + +static int +nano_pipe_init(void *arg, nni_pipe *pipe, void *s) +{ + nano_pipe *p = arg; + nano_sock *sock = s; + + debug_msg("##########nano_pipe_init###############"); + + nni_mtx_init(&p->lk); + nni_lmq_init(&p->rlmq, sock->conf->msq_len); + nni_aio_init(&p->aio_send, nano_pipe_send_cb, p); + //TODO move keepalive monitor to transport layer? + nni_aio_init(&p->aio_timer, nano_pipe_timer_cb, p); + nni_aio_init(&p->aio_recv, nano_pipe_recv_cb, p); + + // NNI_LIST_INIT(&p->sendq, nano_ctx, sqnode); + + p->reason_code = 0x00; + p->id = nni_pipe_id(pipe); + p->pipe = pipe; + p->rep = s; + p->ka_refresh = 0; + p->kicked = false; + p->conn_param = nni_pipe_get_conn_param(pipe); + p->tree = sock->db; + p->conn_param->nano_qos_db = p->pipe->nano_qos_db; + + return (0); +} + +/* +static int +nano_ctx_set_qsize( + void *arg, void *arg2, const void *buf, size_t sz, nni_type t) +{ + nano_ctx * ctx = arg; + nano_sock *sock = ctx->sock; + nano_pipe *p = arg2; + int val; + int rv; + + if ((rv = nni_copyin_int(&val, buf, sz, 1, 8192, t)) != 0) { + return (rv); + } + + nni_mtx_lock(&sock->lk); + if ((rv = nni_lmq_resize(&p->rlmq, (size_t) val)) != 0) { + nni_mtx_unlock(&sock->lk); + return (rv); + } + + nni_mtx_unlock(&sock->lk); + return (0); +} +*/ + +static int +nano_pipe_start(void *arg) +{ + nano_pipe *p = arg; + nano_sock *s = p->rep; + nni_msg * msg; + uint8_t rv, *reason; // reason code of CONNACK + uint8_t buf[4] = { 0x20, 0x02, 0x00, 0x00 }; + + debug_msg("##########nano_pipe_start################"); + /* + // TODO check peer protocol ver + if (nni_pipe_peer(p->pipe) != NNG_NANO_TCP_PEER) { + // Peer protocol mismatch. + return (NNG_EPROTO); + } + */ + nni_msg_alloc(&msg, 0); + nni_msg_header_append(msg, buf, 4); + reason = nni_msg_header(msg) + 2; + nni_mtx_lock(&s->lk); + // TODO replace pipe_id with hash key of client_id + // pipe_id is just random value of id_dyn_val with self-increment. + nni_id_set(&s->pipes, nni_pipe_id(p->pipe), p); + rv = verify_connect(p->conn_param, s->conf); + if (rv != 0) { + // TODO disconnect client && send connack with reason code 0x05 + debug_syslog("Invalid auth info."); + *(reason + 1) = rv; //set return code + } + rv = nano_session_restore(p, s, reason); + nni_mtx_unlock(&s->lk); + + // TODO MQTT V5 check return code + if (*(reason + 1) == 0) { + nni_sleep_aio(s->conf->qos_timer * 1500, &p->aio_timer); + } + nni_msg_set_cmd_type(msg, CMD_CONNACK); + nni_msg_set_conn_param(msg, p->conn_param); + // There is no need to check the state of aio_recv + // Since pipe_start is definetly the first cb to be excuted of pipe. + nni_aio_set_msg(&p->aio_recv, msg); + nni_aio_finish(&p->aio_recv, 0, nni_msg_len(msg)); + return (rv); +} + +static inline void +close_pipe(nano_pipe *p, uint8_t reason_code) +{ + nano_sock *s = p->rep; + nano_ctx * ctx; + + nni_aio_close(&p->aio_send); + nni_aio_close(&p->aio_recv); + nni_aio_close(&p->aio_timer); + + // nni_mtx_lock(&s->lk); + p->closed = true; + if (nni_list_active(&s->recvpipes, p)) { + nni_list_remove(&s->recvpipes, p); + } + nni_lmq_flush(&p->rlmq); + + //TODO delete + while ((ctx = nni_list_first(&p->sendq)) != NULL) { + nni_aio *aio; + nni_msg *msg; + nni_list_remove(&p->sendq, ctx); + aio = ctx->saio; + ctx->saio = NULL; + msg = nni_aio_get_msg(aio); + nni_aio_set_msg(aio, NULL); + nni_aio_finish(aio, 0, nni_msg_len(msg)); + nni_msg_free(msg); + } + nni_id_remove(&s->pipes, nni_pipe_id(p->pipe)); + nano_sessiondb_clean(p); +} + +static void +nano_pipe_close(void *arg, uint8_t reason_code) +{ + nano_pipe * p = arg; + nano_sock * s = p->rep; + nano_ctx * ctx; + conn_param *cparam; + nni_aio * aio = NULL; + nni_msg * msg; + + debug_msg("################# nano_pipe_close ##############"); + nni_mtx_lock(&s->lk); + close_pipe(p, reason_code); + // pub disconnect event + if ((ctx = nni_list_first(&s->recvq)) != NULL) { + msg = nano_msg_notify_disconnect(p->conn_param, reason_code); + if (msg == NULL) { + nni_mtx_unlock(&s->lk); + return; + } + nni_msg_set_conn_param(msg, p->conn_param); + nni_msg_set_cmd_type(msg, CMD_DISCONNECT_EV); + aio = ctx->raio; + ctx->raio = NULL; + nni_list_remove(&s->recvq, ctx); + nni_mtx_unlock(&s->lk); + nni_aio_set_msg(aio, msg); + nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); + return; + } else { + debug_msg("Warning: no ctx left!! faied to send disconnect notification"); + } + nni_mtx_unlock(&s->lk); +} + +static void +nano_pipe_send_cb(void *arg) +{ + nano_pipe *p = arg; + nni_msg * msg; + // uint32_t index = 0; + // uint32_t * pipes; + + debug_msg( + "################ nano_pipe_send_cb %d ################", p->id); + // retry here + if (nni_aio_result(&p->aio_send) != 0) { + nni_msg_free(nni_aio_get_msg(&p->aio_send)); + nni_aio_set_msg(&p->aio_send, NULL); + nni_pipe_close(p->pipe); + return; + } + nni_mtx_lock(&p->lk); + + nni_aio_set_packetid(&p->aio_send, 0); + if (nni_lmq_getq(&p->rlmq, &msg) == 0) { + nni_aio_set_msg(&p->aio_send, msg); + debug_msg("rlmq msg resending! %ld msgs left\n", + nni_lmq_len(&p->rlmq)); + nni_pipe_send(p->pipe, &p->aio_send); + nni_mtx_unlock(&p->lk); + return; + } + + p->busy = false; + nni_mtx_unlock(&p->lk); + return; +} + +static void +nano_cancel_recv(nni_aio *aio, void *arg, int rv) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + + debug_msg("*********** nano_cancel_recv ***********"); + nni_mtx_lock(&s->lk); + if (ctx->raio == aio) { + nni_list_remove(&s->recvq, ctx); + ctx->raio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&s->lk); +} + +static void +nano_ctx_recv(void *arg, nni_aio *aio) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + nano_pipe *p; + // size_t len; + nni_msg *msg; + + if (nni_aio_begin(aio) != 0) { + return; + } + debug_msg("nano_ctx_recv start %p", ctx); + nni_mtx_lock(&s->lk); + if ((p = nni_list_first(&s->recvpipes)) == NULL) { + int rv; + if ((rv = nni_aio_schedule(aio, nano_cancel_recv, ctx)) != 0) { + nni_mtx_unlock(&s->lk); + nni_aio_finish_error(aio, rv); + return; + } + if (ctx->raio != NULL) { + // Cannot have a second receive operation pending. + // This could be ESTATE, or we could cancel the first + // with ECANCELED. We elect the former. + debug_msg("ERROR: former aio not finish yet"); + nni_mtx_unlock(&s->lk); + nni_aio_finish_error(aio, NNG_ESTATE); + return; + } + ctx->raio = aio; + nni_list_append(&s->recvq, ctx); + nni_mtx_unlock(&s->lk); + return; + } + msg = nni_aio_get_msg(&p->aio_recv); + nni_aio_set_msg(&p->aio_recv, NULL); + nni_list_remove(&s->recvpipes, p); + if (nni_list_empty(&s->recvpipes)) { + nni_pollable_clear(&s->readable); + } + nni_pipe_recv(p->pipe, &p->aio_recv); + if ((ctx == &s->ctx) && !p->busy) { + nni_pollable_raise(&s->writable); + } + + // TODO MQTT 5 property + + ctx->pipe_id = nni_pipe_id(p->pipe); + debug_msg("nano_ctx_recv ends %p pipe: %p pipe_id: %d", ctx, p, + ctx->pipe_id); + nni_mtx_unlock(&s->lk); + + nni_aio_set_msg(aio, msg); + nni_aio_finish(aio, 0, nni_msg_len(msg)); +} + +static void +nano_pipe_recv_cb(void *arg) +{ + nano_pipe * p = arg; + nano_sock * s = p->rep; + nano_ctx * ctx; + nni_msg * msg; + nni_aio * aio; + nano_pipe_db *pipe_db; + nni_pipe * npipe = p->pipe; + uint8_t * ptr; + uint16_t ackid; + nni_msg * qos_msg; + + if (nni_aio_result(&p->aio_recv) != 0) { + //unexpected disconnect + nni_pipe_close(p->pipe); + return; + } + debug_msg("#########nano_pipe_recv_cb !############"); + p->ka_refresh = 0; + msg = nni_aio_get_msg(&p->aio_recv); + if (msg == NULL) { + goto end; + } + + // ttl = nni_atomic_get(&s->ttl); + nni_msg_set_pipe(msg, p->id); + // TODO HOOK + switch (nng_msg_cmd_type(msg)) { + case CMD_SUBSCRIBE: + // TODO only cache topic hash when it is above qos 1/2 + nni_mtx_lock(&p->lk); + pipe_db = nano_msg_get_subtopic(msg, + p->pipedb_root); // TODO potential memleak when sub failed + p->pipedb_root = pipe_db; + while (pipe_db) { + nni_id_set(&npipe->nano_db, DJBHash(pipe_db->topic), pipe_db); + pipe_db = pipe_db->next; + } + nni_mtx_unlock(&p->lk); + break; + case CMD_PUBLISH: + case CMD_DISCONNECT: + case CMD_UNSUBSCRIBE: + case CMD_CONNACK: + case CMD_CONNECT: + break; + case CMD_PUBACK: + case CMD_PUBCOMP: + nni_mtx_lock(&p->lk); + ptr = nni_msg_body(msg); + NNI_GET16(ptr, ackid); + if ((qos_msg = nni_id_get(npipe->nano_qos_db, ackid)) != + NULL) { + nni_msg_free(qos_msg); + nni_id_remove(npipe->nano_qos_db, ackid); + } else { + // shouldn't get here BUG TODO + debug_syslog("qos msg not found!"); + } + nni_mtx_unlock(&p->lk); + goto drop; + case CMD_PUBREC: + case CMD_PUBREL: + goto drop; + default: + goto drop; + } + + if (p->closed) { + // If we are closed, then we can't return data. + nni_aio_set_msg(&p->aio_recv, NULL); + nni_msg_free(msg); + debug_msg("ERROR: pipe is closed abruptly!!"); + return; + } + + nni_mtx_lock(&s->lk); + if ((ctx = nni_list_first(&s->recvq)) == NULL) { + // No one waiting to receive yet, holding pattern. + nni_list_append(&s->recvpipes, p); + nni_pollable_raise(&s->readable); + nni_mtx_unlock(&s->lk); + debug_msg("ERROR: no ctx found!! create more ctxs!"); + // nni_println("ERROR: no ctx found!! create more ctxs!"); + return; + } + + nni_list_remove(&s->recvq, ctx); + aio = ctx->raio; + ctx->raio = NULL; + nni_aio_set_msg(&p->aio_recv, NULL); + if ((ctx == &s->ctx) && !p->busy) { + nni_pollable_raise(&s->writable); + } + + // schedule another receive + nni_pipe_recv(p->pipe, &p->aio_recv); + + // ctx->pp_len = len; //TODO Rewrite mqtt header length + ctx->pipe_id = p->id; // use pipe id to identify which client is receving + debug_msg("currently processing pipe_id: %d", p->id); + + nni_mtx_unlock(&s->lk); + nni_aio_set_msg(aio, msg); + + nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); + debug_msg("end of nano_pipe_recv_cb %p", ctx); + return; + +drop: + nni_aio_set_msg(&p->aio_recv, NULL); + nni_msg_free(msg); +end: + nni_pipe_recv(p->pipe, &p->aio_recv); + debug_msg("Warning:dropping msg"); + return; +} + +static int +nano_sock_set_max_ttl(void *arg, const void *buf, size_t sz, nni_opt_type t) +{ + nano_sock *s = arg; + int ttl; + int rv; + + if ((rv = nni_copyin_int(&ttl, buf, sz, 1, NNI_MAX_MAX_TTL, t)) == 0) { + nni_atomic_set(&s->ttl, ttl); + } + return (rv); +} + +static int +nano_sock_get_max_ttl(void *arg, void *buf, size_t *szp, nni_opt_type t) +{ + nano_sock *s = arg; + + return (nni_copyout_int(nni_atomic_get(&s->ttl), buf, szp, t)); +} + +static int +nano_sock_get_sendfd(void *arg, void *buf, size_t *szp, nni_opt_type t) +{ + nano_sock *s = arg; + int rv; + int fd; + + if ((rv = nni_pollable_getfd(&s->writable, &fd)) != 0) { + return (rv); + } + return (nni_copyout_int(fd, buf, szp, t)); +} + +static int +nano_sock_get_recvfd(void *arg, void *buf, size_t *szp, nni_opt_type t) +{ + nano_sock *s = arg; + int rv; + int fd; + + if ((rv = nni_pollable_getfd(&s->readable, &fd)) != 0) { + return (rv); + } + + return (nni_copyout_int(fd, buf, szp, t)); +} + +static void +nano_sock_send(void *arg, nni_aio *aio) +{ + nano_sock *s = arg; + + nano_ctx_send(&s->ctx, aio); +} + +static void +nano_sock_recv(void *arg, nni_aio *aio) +{ + nano_sock *s = arg; + + nano_ctx_recv(&s->ctx, aio); +} + +static void +nano_sock_setdb(void *arg, void *data) +{ + nano_sock *s = arg; + conf * nano_conf = data; + + s->conf = nano_conf; + s->db = nano_conf->db_root; + + conf_auth_parser(s->conf); +} + +// This is the global protocol structure -- our linkage to the core. +// This should be the only global non-static symbol in this file. +static nni_proto_pipe_ops nano_pipe_ops = { + .pipe_size = sizeof(nano_pipe), + .pipe_init = nano_pipe_init, + .pipe_fini = nano_pipe_fini, + .pipe_start = nano_pipe_start, + .pipe_close = nano_pipe_close, + .pipe_stop = nano_pipe_stop, +}; + +static nni_proto_ctx_ops nano_ctx_ops = { + .ctx_size = sizeof(nano_ctx), + .ctx_init = nano_ctx_init, + .ctx_fini = nano_ctx_fini, + .ctx_send = nano_ctx_send, + .ctx_recv = nano_ctx_recv, +}; + +static nni_option nano_sock_options[] = { + { + .o_name = NNG_OPT_MAXTTL, + .o_get = nano_sock_get_max_ttl, + .o_set = nano_sock_set_max_ttl, + }, + { + .o_name = NNG_OPT_RECVFD, + .o_get = nano_sock_get_recvfd, + }, + { + .o_name = NNG_OPT_SENDFD, + .o_get = nano_sock_get_sendfd, + }, + { + .o_name = NULL, + }, +}; + +static nni_proto_sock_ops nano_sock_ops = { + .sock_size = sizeof(nano_sock), + .sock_init = nano_sock_init, + .sock_fini = nano_sock_fini, + .sock_open = nano_sock_open, + .sock_close = nano_sock_close, + .sock_options = nano_sock_options, + .sock_send = nano_sock_send, + .sock_recv = nano_sock_recv, +}; + +static nni_proto nano_tcp_proto = { + .proto_version = NNI_PROTOCOL_VERSION, + .proto_self = { NNG_NANO_TCP_SELF, NNG_NANO_TCP_SELF_NAME }, + .proto_peer = { NNG_NANO_TCP_PEER, NNG_NANO_TCP_PEER_NAME }, + .proto_flags = NNI_PROTO_FLAG_SNDRCV, + .proto_sock_ops = &nano_sock_ops, + .proto_pipe_ops = &nano_pipe_ops, + .proto_ctx_ops = &nano_ctx_ops, +}; + +int +nng_nano_tcp0_open(nng_socket *sidp) +{ + // TODO Global binary tree init here + return (nni_proto_mqtt_open(sidp, &nano_tcp_proto, nano_sock_setdb)); +} diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 3aa20f388..c201cc7f7 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -1,19 +1,19 @@ -// -// Copyright 2021 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// Copyright 2019 Devolutions -// -// This software is supplied under the terms of the MIT License, a -// copy of which should be located in the distribution where this -// file was obtained (LICENSE.txt). A copy of the license may also be -// found online at https://opensource.org/licenses/MIT. -// +// rewrite by Jaylin EMQ X for MQTT usage +// TODO Independent tcptran protocol +#include +#include +#include #include #include #include #include "core/nng_impl.h" +#include "core/sockimpl.h" +#include "nng/nng_debug.h" + +#include "nng/protocol/mqtt/mqtt.h" +#include "nng/protocol/mqtt/mqtt_parser.h" // TCP transport. Platform specific TCP operations must be // supplied as well. @@ -23,40 +23,47 @@ typedef struct tcptran_ep tcptran_ep; // tcp_pipe is one end of a TCP connection. struct tcptran_pipe { - nng_stream * conn; - nni_pipe * npipe; - uint16_t peer; - uint16_t proto; + nng_stream *conn; + nni_pipe * npipe; // for statitical + // uint16_t peer; //reserved for MQTT sdk version + // uint16_t proto; size_t rcvmax; - bool closed; - nni_list_node node; - tcptran_ep * ep; - nni_atomic_flag reaped; - nni_reap_node reap; - uint8_t txlen[sizeof(uint64_t)]; - uint8_t rxlen[sizeof(uint64_t)]; - size_t gottxhead; size_t gotrxhead; - size_t wanttxhead; size_t wantrxhead; - nni_list recvq; - nni_list sendq; + size_t qlength; // length of qos_buf + bool closed; + uint8_t cmd; + uint8_t txlen[NANO_MIN_PACKET_LEN]; + uint8_t rxlen[NNI_NANO_MAX_HEADER_SIZE]; + uint8_t * conn_buf; + uint8_t * qos_buf; nni_aio * txaio; nni_aio * rxaio; + nni_aio * qsaio; + nni_aio * rsaio; + nni_aio * rpaio; nni_aio * negoaio; - nni_msg * rxmsg; + nni_msg * rxmsg, *cnmsg; nni_mtx mtx; + conn_param * tcp_cparam; + nni_list recvq; + nni_list sendq; + nni_list_node node; + tcptran_ep * ep; + nni_atomic_flag reaped; + nni_reap_node reap; + // uint8_t sli_win[5]; //use aio multiple times instead of + // seperating 2 packets manually }; struct tcptran_ep { - nni_mtx mtx; - uint16_t proto; + nni_mtx mtx; + // uint16_t proto; size_t rcvmax; bool fini; bool started; bool closed; nng_url * url; - const char * host; // for dialers nng_sockaddr src; int refcnt; // active pipes nni_aio * useraio; @@ -66,9 +73,7 @@ struct tcptran_ep { nni_list waitpipes; // pipes waiting to match to socket nni_list negopipes; // pipes busy negotiating nni_reap_node reap; - nng_stream_dialer * dialer; nng_stream_listener *listener; - #ifdef NNG_ENABLE_STATS nni_stat_item st_rcv_max; #endif @@ -106,16 +111,21 @@ static void tcptran_pipe_close(void *arg) { tcptran_pipe *p = arg; + // nni_pipe * npipe = p->npipe; nni_mtx_lock(&p->mtx); p->closed = true; nni_mtx_unlock(&p->mtx); nni_aio_close(p->rxaio); + nni_aio_close(p->rpaio); nni_aio_close(p->txaio); + nni_aio_close(p->rsaio); + nni_aio_close(p->qsaio); nni_aio_close(p->negoaio); nng_stream_close(p->conn); + debug_syslog("tcptran_pipe_close\n"); } static void @@ -123,6 +133,9 @@ tcptran_pipe_stop(void *arg) { tcptran_pipe *p = arg; + nni_aio_stop(p->qsaio); + nni_aio_stop(p->rsaio); + nni_aio_stop(p->rpaio); nni_aio_stop(p->rxaio); nni_aio_stop(p->txaio); nni_aio_stop(p->negoaio); @@ -131,9 +144,13 @@ tcptran_pipe_stop(void *arg) static int tcptran_pipe_init(void *arg, nni_pipe *npipe) { + debug_msg("************tcptran_pipe_init************"); tcptran_pipe *p = arg; - p->npipe = npipe; + nni_pipe_set_conn_param(npipe, p->tcp_cparam); + p->npipe = npipe; + p->conn_buf = NULL; + p->qos_buf = nng_alloc(16 + NNI_NANO_MAX_PACKET_SIZE); return (0); } @@ -142,6 +159,7 @@ tcptran_pipe_fini(void *arg) { tcptran_pipe *p = arg; tcptran_ep * ep; + // nni_pipe * npipe = p->npipe; tcptran_pipe_stop(p); if ((ep = p->ep) != NULL) { @@ -154,6 +172,11 @@ tcptran_pipe_fini(void *arg) nni_mtx_unlock(&ep->mtx); } + nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); + // nng_free(p->tcp_cparam, sizeof(struct conn_param)); + nni_aio_free(p->qsaio); + nni_aio_free(p->rpaio); + nni_aio_free(p->rsaio); nni_aio_free(p->rxaio); nni_aio_free(p->txaio); nni_aio_free(p->negoaio); @@ -185,6 +208,9 @@ tcptran_pipe_alloc(tcptran_pipe **pipep) } nni_mtx_init(&p->mtx); if (((rv = nni_aio_alloc(&p->txaio, tcptran_pipe_send_cb, p)) != 0) || + ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rpaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rsaio, NULL, p)) != 0) || ((rv = nni_aio_alloc(&p->rxaio, tcptran_pipe_recv_cb, p)) != 0) || ((rv = nni_aio_alloc(&p->negoaio, tcptran_pipe_nego_cb, p)) != 0)) { @@ -218,6 +244,14 @@ tcptran_ep_match(tcptran_ep *ep) nni_aio_finish(aio, 0, 0); } +/** + * MQTT protocal negotiate + * deal with CONNECT packet + * Fixed header to variable header + * receive multiple times for complete data packet then reply ACK in protocol + * layer iov_len limits the length readv reads + * TODO independent with nng SP + */ static void tcptran_pipe_nego_cb(void *arg) { @@ -225,59 +259,87 @@ tcptran_pipe_nego_cb(void *arg) tcptran_ep * ep = p->ep; nni_aio * aio = p->negoaio; nni_aio * uaio; - int rv; + uint32_t len; + int rv, len_of_varint = 0; + debug_msg("start tcptran_pipe_nego_cb max len %ld pipe_addr %p\n", + NANO_CONNECT_PACKET_LEN, p); nni_mtx_lock(&ep->mtx); if ((rv = nni_aio_result(aio)) != 0) { goto error; } - // We start transmitting before we receive. - if (p->gottxhead < p->wanttxhead) { - p->gottxhead += nni_aio_count(aio); - } else if (p->gotrxhead < p->wantrxhead) { + // calculate number of bytes received + if (p->gotrxhead < p->wantrxhead) { p->gotrxhead += nni_aio_count(aio); } - if (p->gottxhead < p->wanttxhead) { + // recv fixed header + if (p->gotrxhead < NNI_NANO_MAX_HEADER_SIZE) { nni_iov iov; - iov.iov_len = p->wanttxhead - p->gottxhead; - iov.iov_buf = &p->txlen[p->gottxhead]; - // send it down... + iov.iov_len = NNI_NANO_MAX_HEADER_SIZE - p->gotrxhead; + iov.iov_buf = &p->rxlen[p->gotrxhead]; nni_aio_set_iov(aio, 1, &iov); - nng_stream_send(p->conn, aio); + nng_stream_recv(p->conn, aio); nni_mtx_unlock(&ep->mtx); return; } - if (p->gotrxhead < p->wantrxhead) { + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE && + p->wantrxhead == NANO_CONNECT_PACKET_LEN) { + if (p->rxlen[0] != CMD_CONNECT) { + debug_msg("CMD TYPE %x", p->rxlen[0]); + rv = NNG_EPROTO; + goto error; + } + len = + get_var_integer(p->rxlen + 1, (uint32_t *) &len_of_varint); + p->wantrxhead = len + 1 + len_of_varint; + } + + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE || + p->gotrxhead < p->wantrxhead) { nni_iov iov; iov.iov_len = p->wantrxhead - p->gotrxhead; - iov.iov_buf = &p->rxlen[p->gotrxhead]; + if (p->conn_buf == NULL) { + p->conn_buf = nng_alloc(p->wantrxhead); + memcpy(p->conn_buf, p->rxlen, p->gotrxhead); + } + iov.iov_buf = &p->conn_buf[p->gotrxhead]; nni_aio_set_iov(aio, 1, &iov); nng_stream_recv(p->conn, aio); nni_mtx_unlock(&ep->mtx); return; } - // We have both sent and received the headers. Lets check the - // receive side header. - if ((p->rxlen[0] != 0) || (p->rxlen[1] != 'S') || - (p->rxlen[2] != 'P') || (p->rxlen[3] != 0) || (p->rxlen[6] != 0) || - (p->rxlen[7] != 0)) { - rv = NNG_EPROTO; - goto error; - } - NNI_GET16(&p->rxlen[4], p->peer); + // We have both sent and received the CONNECT headers. + // CONNECT packet serialization - // We are all ready now. We put this in the wait list, and - // then try to run the matcher. - nni_list_remove(&ep->negopipes, p); - nni_list_append(&ep->waitpipes, p); + if (p->gotrxhead >= p->wantrxhead) { + if (p->tcp_cparam == NULL) { + p->tcp_cparam = nng_alloc(sizeof(struct conn_param)); + } + if (conn_handler(p->conn_buf, p->tcp_cparam) == 0) { + nng_free(p->conn_buf, p->wantrxhead); + p->conn_buf = NULL; + // we don't need to alloc a new msg, just use pipe. + // We are all ready now. We put this in the wait list, + // and then try to run the matcher. + nni_list_remove(&ep->negopipes, p); + nni_list_append(&ep->waitpipes, p); + tcptran_ep_match(ep); + nni_mtx_unlock(&ep->mtx); + return; + } else { + rv = NNG_EPROTO; + nng_free(p->conn_buf, p->wantrxhead); + nng_free(p->tcp_cparam, sizeof(struct conn_param)); + goto error; + } + } - tcptran_ep_match(ep); nni_mtx_unlock(&ep->mtx); - + debug_msg("^^^^^^^^^^end of tcptran_pipe_nego_cb^^^^^^^^^^\n"); return; error: @@ -289,6 +351,8 @@ tcptran_pipe_nego_cb(void *arg) } nni_mtx_unlock(&ep->mtx); tcptran_pipe_reap(p); + debug_msg("connect nego error rv: %d!", rv); + return; } static void @@ -297,6 +361,8 @@ tcptran_pipe_send_cb(void *arg) tcptran_pipe *p = arg; int rv; nni_aio * aio; + uint8_t * header; + uint8_t flag, cmd; size_t n; nni_msg * msg; nni_aio * txaio = p->txaio; @@ -304,13 +370,10 @@ tcptran_pipe_send_cb(void *arg) nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->sendq); + debug_msg("############### tcptran_pipe_send_cb ################"); + if ((rv = nni_aio_result(txaio)) != 0) { nni_pipe_bump_error(p->npipe, rv); - // Intentionally we do not queue up another transfer. - // There's an excellent chance that the pipe is no longer - // usable, with a partial transfer. - // The protocol should see this error, and close the - // pipe itself, we hope. nni_aio_list_remove(aio); nni_mtx_unlock(&p->mtx); nni_aio_finish_error(aio, rv); @@ -319,95 +382,264 @@ tcptran_pipe_send_cb(void *arg) n = nni_aio_count(txaio); nni_aio_iov_advance(txaio, n); + debug_msg( + "tcp socket sent %ld bytes iov %ld", n, nni_aio_iov_count(txaio)); + if (nni_aio_iov_count(txaio) > 0) { nng_stream_send(p->conn, txaio); nni_mtx_unlock(&p->mtx); return; } - nni_aio_list_remove(aio); tcptran_pipe_send_start(p); msg = nni_aio_get_msg(aio); n = nni_msg_len(msg); - nni_pipe_bump_tx(p->npipe, n); + cmd = nni_msg_cmd_type(msg); + if (cmd == CMD_CONNACK) { + header = nni_msg_header(msg); + flag = header[3]; + } + // nni_pipe_bump_tx(p->npipe, n); + // free qos buffer + if (p->qlength > 16 + NNI_NANO_MAX_PACKET_SIZE) { + nng_free(p->qos_buf, p->qlength); + p->qos_buf = nng_alloc(16 + NNI_NANO_MAX_PACKET_SIZE); + } nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, NULL); nni_msg_free(msg); - nni_aio_finish_sync(aio, 0, n); + if (cmd == CMD_CONNACK && flag != 0x00) { + nni_aio_finish_error(aio, NNG_ECLOSED); + } else { + nni_aio_finish_sync(aio, 0, n); + } } +/* + * deal with MQTT protocol + * insure read complete MQTT packet from socket + */ static void tcptran_pipe_recv_cb(void *arg) { - tcptran_pipe *p = arg; - nni_aio * aio; - int rv; + uint8_t *variable_ptr = NULL, *payload_ptr = NULL; + // uint8_t * header_ptr; + nni_aio *aio; + nni_iov iov; + uint8_t type; + // uint16_t fixed_header; + uint32_t len = 0, rv, pos = 1; size_t n; nni_msg * msg; + tcptran_pipe *p = arg; nni_aio * rxaio = p->rxaio; + conn_param * cparam; + uint32_t len_of_varint = 0; + debug_msg("tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); + aio = nni_list_first(&p->recvq); if ((rv = nni_aio_result(rxaio)) != 0) { + debug_msg("nni aio error!! %d\n", rv); goto recv_error; } n = nni_aio_count(rxaio); + p->gotrxhead += n; + nni_aio_iov_advance(rxaio, n); + // not receive enough bytes, deal with remaining length + len = get_var_integer(p->rxlen, &pos); + debug_msg("new %ld recevied %ld header %x %d pos: %d len : %d", n, + p->gotrxhead, p->rxlen[0], p->rxlen[1], pos, len); + debug_msg("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); + if (nni_aio_iov_count(rxaio) > 0) { + debug_msg("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], + strlen((char *) p->rxlen)); nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; + } else if (p->gotrxhead <= NNI_NANO_MAX_HEADER_SIZE && + p->rxlen[p->gotrxhead - 1] > 0x7f) { + // length error + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { + rv = NNG_EMSGSIZE; + goto recv_error; + } + // same packet, continue receving next byte of remaining length + iov.iov_buf = &p->rxlen[p->gotrxhead]; + iov.iov_len = 1; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } else if (len == 0 && n == 2) { + if ((p->rxlen[0] & 0XFF) == CMD_PINGREQ) { + nng_aio_wait(p->qsaio); + p->txlen[0] = CMD_PINGRESP; + p->txlen[1] = 0x00; + iov.iov_len = 2; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->qsaio, 1, &iov); + p->cmd = CMD_PINGRESP; + nng_stream_send(p->conn, p->qsaio); + goto notify; + } else if ((p->rxlen[0] & 0XFF) == CMD_DISCONNECT) { + } } - // If we don't have a message yet, we were reading the TCP message - // header, which is just the length. This tells us the size of the - // message to allocate and how much more to expect. - if (p->rxmsg == NULL) { - uint64_t len; - // We should have gotten a message header. - NNI_GET64(p->rxlen, len); + // finish fixed header + p->wantrxhead = len + p->gotrxhead; + cparam = p->tcp_cparam; + if (p->rxmsg == NULL) { + // We should have gotten a message header. len -> remaining + // length to define how many bytes left + debug_msg("pipe %p header got: %x %x %x %x %x, %ld!!\n", p, + p->rxlen[0], p->rxlen[1], p->rxlen[2], p->rxlen[3], + p->rxlen[4], p->wantrxhead); // Make sure the message payload is not too big. If it is // the caller will shut down the pipe. if ((len > p->rcvmax) && (p->rcvmax > 0)) { + debug_msg("size error\n"); rv = NNG_EMSGSIZE; goto recv_error; } if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + debug_syslog("mem error %ld\n", (size_t) len); goto recv_error; } - // Submit the rest of the data for a read -- we want to - // read the entire message now. + // Submit the rest of the data for a read -- seperate Fixed + // header with variable header and so on + // we want to read the entire message now. if (len != 0) { - nni_iov iov; iov.iov_buf = nni_msg_body(p->rxmsg); iov.iov_len = (size_t) len; nni_aio_set_iov(rxaio, 1, &iov); + // second recv action nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; } } - // We read a message completely. Let the user know the good news. - nni_aio_list_remove(aio); + // We read a message completely. Let the user know the good news. use + // as application message callback of users + nni_aio_list_remove(aio); // need this to align with nng msg = p->rxmsg; p->rxmsg = NULL; n = nni_msg_len(msg); + type = p->rxlen[0] & 0xf0; + + fixed_header_adaptor(p->rxlen, msg); + nni_msg_set_conn_param(msg, cparam); + nni_msg_set_remaining_len(msg, len); + nni_msg_set_cmd_type(msg, type); + debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", + len, cparam, cparam->clientid.body, cparam->username.body, + cparam->pro_ver); + variable_ptr = nni_msg_variable_ptr(msg); + + // set the payload pointer of msg according to packet_type + debug_msg("The type of msg is %x", type); + if (type == CMD_SUBSCRIBE) { + if (cparam->pro_ver == PROTOCOL_VERSION_v5) { + len_of_varint = 0; + len = + get_var_integer(variable_ptr + 2, &len_of_varint); + payload_ptr = variable_ptr + 2 + len + len_of_varint; + } else { + payload_ptr = variable_ptr + 2; + } + } else if (type == CMD_UNSUBSCRIBE) { + if (cparam->pro_ver == PROTOCOL_VERSION_v5) { + len_of_varint = 0; + len = + get_var_integer(variable_ptr + 2, &len_of_varint); + payload_ptr = variable_ptr + 2 + len + len_of_varint; + } else { + payload_ptr = variable_ptr + 2; + } + } else if (type == CMD_PUBLISH) { + uint8_t qos_pac; + uint16_t pid; + size_t tlen; + + NNI_GET16(variable_ptr, tlen); + qos_pac = nni_msg_get_pub_qos(msg); + if (cparam->pro_ver != PROTOCOL_VERSION_v5) { + payload_ptr = + variable_ptr + tlen + 2 + (qos_pac > 0 ? 2 : 0); + } + if (qos_pac > 0) { + nng_aio_wait(p->rsaio); + if (qos_pac == 1) { + p->txlen[0] = CMD_PUBACK; + } else if (qos_pac == 2) { + p->txlen[0] = CMD_PUBREC; + } + p->txlen[1] = 0x02; + pid = nni_msg_get_pub_pid(msg); + NNI_PUT16(p->txlen + 2, pid); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->rsaio, 1, &iov); + + p->cmd = CMD_PUBREC; + nng_stream_send(p->conn, p->rsaio); + } + } else if (type == CMD_PUBREC) { + // TODO + uint8_t *tmp; + nng_aio_wait(p->rpaio); + p->txlen[0] = 0X62; + p->txlen[1] = 0x02; + tmp = nni_msg_body(msg); + memcpy(p->txlen + 2, tmp, 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->rpaio, 1, &iov); + p->cmd = CMD_PUBREL; + nng_stream_send(p->conn, p->rpaio); + } else if (type == CMD_PUBREL) { + uint8_t *tmp; + nng_aio_wait(p->qsaio); + p->txlen[0] = CMD_PUBCOMP; + p->txlen[1] = 0x02; + tmp = nni_msg_body(msg); + memcpy(p->txlen + 2, tmp, 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->qsaio, 1, &iov); + p->cmd = CMD_PUBCOMP; + nng_stream_send(p->conn, p->qsaio); + } else if (type == CMD_PUBACK || type == CMD_PUBCOMP) { + //TODO move keepalive timer & ACK checker to transport layer + } else { + payload_ptr = NULL; + } + nni_msg_set_payload_ptr(msg, payload_ptr); - nni_pipe_bump_rx(p->npipe, n); + // keep connection & Schedule next receive + // nni_pipe_bump_rx(p->npipe, n); tcptran_pipe_recv_start(p); nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, n); + debug_msg("end of tcptran_pipe_recv_cb: synch! %p\n", p); return; recv_error: @@ -415,12 +647,21 @@ tcptran_pipe_recv_cb(void *arg) msg = p->rxmsg; p->rxmsg = NULL; nni_pipe_bump_error(p->npipe, rv); - // Intentionally, we do not queue up another receive. - // The protocol should notice this error and close the pipe. nni_mtx_unlock(&p->mtx); nni_msg_free(msg); nni_aio_finish_error(aio, rv); + debug_msg("tcptran_pipe_recv_cb: recv error rv: %d\n", rv); + return; +notify: + // nni_pipe_bump_rx(p->npipe, n); + nni_aio_list_remove(aio); + tcptran_pipe_recv_start(p); + nni_mtx_unlock(&p->mtx); + nni_aio_set_msg(aio, NULL); + nni_aio_finish(aio, 0, 0); //only finishes when we need + // PINGREQ event + return; } static void @@ -454,9 +695,9 @@ tcptran_pipe_send_start(tcptran_pipe *p) nni_aio *txaio; nni_msg *msg; int niov; - nni_iov iov[3]; - uint64_t len; + nni_iov iov[4]; + debug_msg("########### tcptran_pipe_send_start ###########"); if (p->closed) { while ((aio = nni_list_first(&p->sendq)) != NULL) { nni_list_remove(&p->sendq, aio); @@ -466,20 +707,153 @@ tcptran_pipe_send_start(tcptran_pipe *p) } if ((aio = nni_list_first(&p->sendq)) == NULL) { + debug_msg("aio not functioning"); return; } // This runs to send the message. msg = nni_aio_get_msg(aio); - len = nni_msg_len(msg) + nni_msg_header_len(msg); + if (msg == NULL) { + // TODO error handle + nni_println("ERROR: sending NULL msg!"); + return; + } - NNI_PUT64(p->txlen, len); + // never modify msg + if (nni_msg_header_len(msg) > 0 && + nni_msg_cmd_type(msg) == CMD_PUBLISH) { + uint8_t *body, *header, qos_pac; + uint8_t varheader[2], + fixheader[NNI_NANO_MAX_HEADER_SIZE] = { 0 }, + tmp[4] = { 0 }; + nni_pipe * pipe; + uint16_t pid; + size_t tlen, rlen; + nano_pipe_db *db; + + pipe = p->npipe; + body = nni_msg_body(msg); + header = nni_msg_header(msg); + p->qlength = 0; + NNI_GET16(body, tlen); + + if ((db = nni_id_get(&pipe->nano_db, + DJBHashn((char *) body + 2, tlen))) == NULL) { + // shouldn't get here BUG TODO + nni_println( + "ERROR: nano_db subscription topic missing!"); + goto send; + } + qos_pac = nni_msg_get_pub_qos(msg); + if (qos_pac == 0) { + // save time & space for QoS 0 publish + goto send; + } + + debug_msg("qos_pac %d sub %d\n", qos_pac, db->qos); + memcpy(fixheader, header, nni_msg_header_len(msg)); + + if (qos_pac > db->qos) { + if (db->qos == 1) { + // set qos to 1 + fixheader[0] = fixheader[0] & 0xF9; + fixheader[0] = fixheader[0] | 0x02; + rlen = nni_msg_header_len(msg) - 1; + } else { + // set qos to 0 + fixheader[0] = fixheader[0] & 0xF9; + // mdf remaining length TODO get remaining len + // from packet + rlen = put_var_integer( + tmp, nni_msg_remaining_len(msg) - 2); + memcpy(fixheader + 1, tmp, rlen); + } + } else if (qos_pac < db->qos) { + if (qos_pac == 1) { + // QoS 1 publish to Qos 2 + // TODO + rlen = nni_msg_header_len(msg) - 1; + } else { + // QoS 0 publish to QoS 1/2 nothing to do + goto send; + } + } else { + rlen = nni_msg_header_len(msg) - 1; + } + + txaio = p->txaio; + niov = 0; + // fixed header + p->qlength += rlen + 1; // strlen(fixheader) + // 1st part of variable header: topic + + p->qlength += tlen + 2; // get topic length + // packet id + if (db->qos > 0 && qos_pac > 0) { + // set pid + nni_msg *old; + pid = nni_aio_get_packetid(aio); + if (pid == 0) { // first time deal with "pid", it's not + // resending + pid = nni_pipe_inc_packetid(pipe); + // store msg for qos retrying + debug_msg( + "* processing QoS pubmsg with pipe: %p *", + p); + nni_msg_clone(msg); + if ((old = nni_id_get( + pipe->nano_qos_db, pid)) != NULL) { + // TODO packetid already exists. + // replace old with new one shouldn't + // get here BUG + nni_println( + "ERROR: packet id duplicates in " + "nano_qos_db"); + nni_msg_free(old); + // nni_id_remove(&pipe->nano_qos_db, + // pid); + } + nni_id_set(pipe->nano_qos_db, pid, msg); + } + NNI_PUT16(varheader, pid); + p->qlength += 2; + } + // TODO optimize the performance of QoS 1to1 2to2 by reduce the + // length of qlength + if (p->qlength > 16 + NNI_NANO_MAX_PACKET_SIZE) { + nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); + p->qos_buf = nng_alloc(sizeof(uint8_t) * (p->qlength)); + } + memcpy(p->qos_buf, fixheader, rlen + 1); + memcpy(p->qos_buf + rlen + 1, body, tlen + 2); + if (db->qos > 0 && qos_pac > 0) { + memcpy(p->qos_buf + rlen + tlen + 3, varheader, 2); + } + iov[niov].iov_buf = p->qos_buf; + iov[niov].iov_len = p->qlength; + niov++; + + // payload + if (nni_msg_len(msg) > 0 && + qos_pac > + 0) { // determine if it needs to skip packet id field + iov[niov].iov_buf = body + 2 + tlen + 2; + iov[niov].iov_len = nni_msg_len(msg) - 4 - tlen; + niov++; + } else if (nni_msg_len(msg) > 0) { + iov[niov].iov_buf = body + 2 + tlen; + iov[niov].iov_len = nni_msg_len(msg) - 2 - tlen; + niov++; + } + + nni_aio_set_iov(txaio, niov, iov); + nng_stream_send(p->conn, txaio); + return; + } +send: + txaio = p->txaio; + niov = 0; - txaio = p->txaio; - niov = 0; - iov[0].iov_buf = p->txlen; - iov[0].iov_len = sizeof(p->txlen); - niov++; if (nni_msg_header_len(msg) > 0) { iov[niov].iov_buf = nni_msg_header(msg); iov[niov].iov_len = nni_msg_header_len(msg); @@ -500,6 +874,7 @@ tcptran_pipe_send(void *arg, nni_aio *aio) tcptran_pipe *p = arg; int rv; + debug_msg("####################tcptran_pipe_send###########"); if (nni_aio_begin(aio) != 0) { return; } @@ -539,34 +914,6 @@ tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) nni_aio_finish_error(aio, rv); } -static void -tcptran_pipe_recv_start(tcptran_pipe *p) -{ - nni_aio *rxaio; - nni_iov iov; - NNI_ASSERT(p->rxmsg == NULL); - - if (p->closed) { - nni_aio *aio; - while ((aio = nni_list_first(&p->recvq)) != NULL) { - nni_list_remove(&p->recvq, aio); - nni_aio_finish_error(aio, NNG_ECLOSED); - } - return; - } - if (nni_list_empty(&p->recvq)) { - return; - } - - // Schedule a read of the header. - rxaio = p->rxaio; - iov.iov_buf = p->rxlen; - iov.iov_len = sizeof(p->rxlen); - nni_aio_set_iov(rxaio, 1, &iov); - - nng_stream_recv(p->conn, rxaio); -} - static void tcptran_pipe_recv(void *arg, nni_aio *aio) { @@ -583,20 +930,25 @@ tcptran_pipe_recv(void *arg, nni_aio *aio) return; } - nni_list_append(&p->recvq, aio); + if (nni_aio_list_active(aio) == 0) { + nni_list_append(&p->recvq, aio); + } + if (nni_list_first(&p->recvq) == aio) { tcptran_pipe_recv_start(p); } nni_mtx_unlock(&p->mtx); } +/* static uint16_t tcptran_pipe_peer(void *arg) { - tcptran_pipe *p = arg; + tcptran_pipe *p = arg; - return (p->peer); + return (p->peer); } +*/ static int tcptran_pipe_getopt( @@ -606,35 +958,64 @@ tcptran_pipe_getopt( return (nni_stream_get(p->conn, name, buf, szp, t)); } +static void +tcptran_pipe_recv_start(tcptran_pipe *p) +{ + nni_aio *rxaio; + nni_iov iov; + debug_msg("second oder! tcptran_pipe_recv_start\n"); + NNI_ASSERT(p->rxmsg == NULL); + + if (p->closed) { + nni_aio *aio; + while ((aio = nni_list_first(&p->recvq)) != NULL) { + nni_list_remove(&p->recvq, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + return; + } + if (nni_list_empty(&p->recvq)) { + return; + } + + // Schedule a read of the fixed header. + rxaio = p->rxaio; + p->gotrxhead = 0; + p->wantrxhead = NANO_MIN_FIXED_HEADER_LEN; + iov.iov_buf = p->rxlen; + iov.iov_len = NANO_MIN_FIXED_HEADER_LEN; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); +} + +// DEAL WITH CONNECT when PIPE INIT static void tcptran_pipe_start(tcptran_pipe *p, nng_stream *conn, tcptran_ep *ep) { nni_iov iov; + // nni_tcp_conn *c; ep->refcnt++; - p->conn = conn; - p->ep = ep; - p->proto = ep->proto; - - p->txlen[0] = 0; - p->txlen[1] = 'S'; - p->txlen[2] = 'P'; - p->txlen[3] = 0; - NNI_PUT16(&p->txlen[4], p->proto); - NNI_PUT16(&p->txlen[6], 0); + p->conn = conn; + p->ep = ep; + // p->proto = ep->proto; + debug_msg("tcptran_pipe_start!"); + // TODO abide with CONNECT header p->gotrxhead = 0; - p->gottxhead = 0; - p->wantrxhead = 8; - p->wanttxhead = 8; - iov.iov_len = 8; - iov.iov_buf = &p->txlen[0]; + p->wantrxhead = NANO_CONNECT_PACKET_LEN; // packet type 1 + remaining + // length 1 + protocal name 7 + // + flag 1 + keepalive 2 = 12 + iov.iov_len = NNI_NANO_MAX_HEADER_SIZE; // dynamic + iov.iov_buf = p->rxlen; + nni_aio_set_iov(p->negoaio, 1, &iov); nni_list_append(&ep->negopipes, p); - nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate - nng_stream_send(p->conn, p->negoaio); + nni_aio_set_timeout(p->negoaio, + 15 * 1000); // 15 sec timeout to negotiate abide with emqx + nng_stream_recv(p->conn, p->negoaio); } static void @@ -651,7 +1032,6 @@ tcptran_ep_fini(void *arg) nni_mtx_unlock(&ep->mtx); nni_aio_stop(ep->timeaio); nni_aio_stop(ep->connaio); - nng_stream_dialer_free(ep->dialer); nng_stream_listener_free(ep->listener); nni_aio_free(ep->timeaio); nni_aio_free(ep->connaio); @@ -668,11 +1048,9 @@ tcptran_ep_close(void *arg) nni_mtx_lock(&ep->mtx); + debug_syslog("tcptran_ep_close"); ep->closed = true; nni_aio_close(ep->timeaio); - if (ep->dialer != NULL) { - nng_stream_dialer_close(ep->dialer); - } if (ep->listener != NULL) { nng_stream_listener_close(ep->listener); } @@ -695,8 +1073,8 @@ tcptran_ep_close(void *arg) // This parses off the optional source address that this transport uses. // The special handling of this URL format is quite honestly an historical -// mistake, which we would remove if we could. -static int +// mistake, which we would remove if we could.static int +int tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl) { int af; @@ -718,7 +1096,7 @@ tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl) return (0); } - len = (size_t) (semi - url->u_hostname); + len = (size_t)(semi - url->u_hostname); url->u_hostname = semi + 1; if (strcmp(surl->u_scheme, "tcp") == 0) { @@ -759,6 +1137,7 @@ tcptran_timer_cb(void *arg) } } +// TCP accpet trigger static void tcptran_accept_cb(void *arg) { @@ -814,52 +1193,11 @@ tcptran_accept_cb(void *arg) nni_mtx_unlock(&ep->mtx); } -static void -tcptran_dial_cb(void *arg) -{ - tcptran_ep * ep = arg; - nni_aio * aio = ep->connaio; - tcptran_pipe *p; - int rv; - nng_stream * conn; - - if ((rv = nni_aio_result(aio)) != 0) { - goto error; - } - - conn = nni_aio_get_output(aio, 0); - if ((rv = tcptran_pipe_alloc(&p)) != 0) { - nng_stream_free(conn); - goto error; - } - nni_mtx_lock(&ep->mtx); - if (ep->closed) { - tcptran_pipe_fini(p); - nng_stream_free(conn); - rv = NNG_ECLOSED; - nni_mtx_unlock(&ep->mtx); - goto error; - } else { - tcptran_pipe_start(p, conn, ep); - } - nni_mtx_unlock(&ep->mtx); - return; - -error: - // Error connecting. We need to pass this straight back - // to the user. - nni_mtx_lock(&ep->mtx); - if ((aio = ep->useraio) != NULL) { - ep->useraio = NULL; - nni_aio_finish_error(aio, rv); - } - nni_mtx_unlock(&ep->mtx); -} - static int tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) { tcptran_ep *ep; + NNI_ARG_UNUSED(sock); if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); @@ -869,9 +1207,8 @@ tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) NNI_LIST_INIT(&ep->waitpipes, tcptran_pipe, node); NNI_LIST_INIT(&ep->negopipes, tcptran_pipe, node); - ep->proto = nni_sock_proto_id(sock); - ep->url = url; - + // ep->proto = nni_sock_proto_id(sock); + ep->url = url; #ifdef NNG_ENABLE_STATS static const nni_stat_info rcv_max_info = { .si_name = "rcv_max", @@ -887,53 +1224,6 @@ tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) return (0); } -static int -tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) -{ - tcptran_ep * ep; - int rv; - nng_sockaddr srcsa; - nni_sock * sock = nni_dialer_sock(ndialer); - nng_url myurl; - - // Check for invalid URL components. - if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { - return (NNG_EADDRINVAL); - } - if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || - (url->u_query != NULL) || (strlen(url->u_hostname) == 0) || - (strlen(url->u_port) == 0)) { - return (NNG_EADDRINVAL); - } - - if ((rv = tcptran_url_parse_source(&myurl, &srcsa, url)) != 0) { - return (rv); - } - - if ((rv = tcptran_ep_init(&ep, url, sock)) != 0) { - return (rv); - } - - if ((rv != 0) || - ((rv = nni_aio_alloc(&ep->connaio, tcptran_dial_cb, ep)) != 0) || - ((rv = nng_stream_dialer_alloc_url(&ep->dialer, &myurl)) != 0)) { - tcptran_ep_fini(ep); - return (rv); - } - if ((srcsa.s_family != NNG_AF_UNSPEC) && - ((rv = nni_stream_dialer_set(ep->dialer, NNG_OPT_LOCADDR, &srcsa, - sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) { - tcptran_ep_fini(ep); - return (rv); - } - -#ifdef NNG_ENABLE_STATS - nni_dialer_add_stat(ndialer, &ep->st_rcv_max); -#endif - *dp = ep; - return (0); -} - static int tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) { @@ -960,10 +1250,10 @@ tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) tcptran_ep_fini(ep); return (rv); } + #ifdef NNG_ENABLE_STATS nni_listener_add_stat(nlistener, &ep->st_rcv_max); #endif - *lp = ep; return (0); } @@ -980,37 +1270,7 @@ tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) nni_mtx_unlock(&ep->mtx); } -static void -tcptran_ep_connect(void *arg, nni_aio *aio) -{ - tcptran_ep *ep = arg; - int rv; - - if (nni_aio_begin(aio) != 0) { - return; - } - nni_mtx_lock(&ep->mtx); - if (ep->closed) { - nni_mtx_unlock(&ep->mtx); - nni_aio_finish_error(aio, NNG_ECLOSED); - return; - } - if (ep->useraio != NULL) { - nni_mtx_unlock(&ep->mtx); - nni_aio_finish_error(aio, NNG_EBUSY); - return; - } - if ((rv = nni_aio_schedule(aio, tcptran_ep_cancel, ep)) != 0) { - nni_mtx_unlock(&ep->mtx); - nni_aio_finish_error(aio, rv); - return; - } - ep->useraio = aio; - - nng_stream_dialer_dial(ep->dialer, ep->connaio); - nni_mtx_unlock(&ep->mtx); -} - +// TODO network interface bind static int tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) { @@ -1119,13 +1379,13 @@ tcptran_ep_accept(void *arg, nni_aio *aio) } static nni_sp_pipe_ops tcptran_pipe_ops = { - .p_init = tcptran_pipe_init, - .p_fini = tcptran_pipe_fini, - .p_stop = tcptran_pipe_stop, - .p_send = tcptran_pipe_send, - .p_recv = tcptran_pipe_recv, - .p_close = tcptran_pipe_close, - .p_peer = tcptran_pipe_peer, + .p_init = tcptran_pipe_init, + .p_fini = tcptran_pipe_fini, + .p_stop = tcptran_pipe_stop, + .p_send = tcptran_pipe_send, + .p_recv = tcptran_pipe_recv, + .p_close = tcptran_pipe_close, + //.p_peer = tcptran_pipe_peer, .p_getopt = tcptran_pipe_getopt, }; @@ -1145,34 +1405,6 @@ static const nni_option tcptran_ep_opts[] = { }, }; -static int -tcptran_dialer_getopt( - void *arg, const char *name, void *buf, size_t *szp, nni_type t) -{ - tcptran_ep *ep = arg; - int rv; - - rv = nni_stream_dialer_get(ep->dialer, name, buf, szp, t); - if (rv == NNG_ENOTSUP) { - rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t); - } - return (rv); -} - -static int -tcptran_dialer_setopt( - void *arg, const char *name, const void *buf, size_t sz, nni_type t) -{ - tcptran_ep *ep = arg; - int rv; - - rv = nni_stream_dialer_set(ep->dialer, name, buf, sz, t); - if (rv == NNG_ENOTSUP) { - rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t); - } - return (rv); -} - static int tcptran_listener_getopt( void *arg, const char *name, void *buf, size_t *szp, nni_type t) @@ -1201,15 +1433,6 @@ tcptran_listener_setopt( return (rv); } -static nni_sp_dialer_ops tcptran_dialer_ops = { - .d_init = tcptran_dialer_init, - .d_fini = tcptran_ep_fini, - .d_connect = tcptran_ep_connect, - .d_close = tcptran_ep_close, - .d_getopt = tcptran_dialer_getopt, - .d_setopt = tcptran_dialer_setopt, -}; - static nni_sp_listener_ops tcptran_listener_ops = { .l_init = tcptran_listener_init, .l_fini = tcptran_ep_fini, @@ -1220,27 +1443,24 @@ static nni_sp_listener_ops tcptran_listener_ops = { .l_setopt = tcptran_listener_setopt, }; -static nni_sp_tran tcp_tran = { +static nni_sp_tran tcp_tran_mqtt = { .tran_scheme = "tcp", - .tran_dialer = &tcptran_dialer_ops, .tran_listener = &tcptran_listener_ops, .tran_pipe = &tcptran_pipe_ops, .tran_init = tcptran_init, .tran_fini = tcptran_fini, }; -static nni_sp_tran tcp4_tran = { +static nni_sp_tran tcp4_tran_mqtt = { .tran_scheme = "tcp4", - .tran_dialer = &tcptran_dialer_ops, .tran_listener = &tcptran_listener_ops, .tran_pipe = &tcptran_pipe_ops, .tran_init = tcptran_init, .tran_fini = tcptran_fini, }; -static nni_sp_tran tcp6_tran = { +static nni_sp_tran tcp6_tran_mqtt = { .tran_scheme = "tcp6", - .tran_dialer = &tcptran_dialer_ops, .tran_listener = &tcptran_listener_ops, .tran_pipe = &tcptran_pipe_ops, .tran_init = tcptran_init, @@ -1250,8 +1470,8 @@ static nni_sp_tran tcp6_tran = { int nng_tcp_register(void) { - nni_sp_tran_register(&tcp_tran); - nni_sp_tran_register(&tcp4_tran); - nni_sp_tran_register(&tcp6_tran); + nni_sp_tran_register(&tcp_tran_mqtt); + nni_sp_tran_register(&tcp4_tran_mqtt); + nni_sp_tran_register(&tcp6_tran_mqtt); return (0); } From 4cdd582fa3ac3a82aaf5fc890df2e5d43b53c62a Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 1 Aug 2021 08:25:58 -0700 Subject: [PATCH 004/180] Fix premature transport registration. Mark it deprecated. Originally the idea was to better support having the transports be separate loadable modules. This isn't needed for the builtin transports, so we make the explicit initialization of them deprecated, and document it as such. --- docs/man/nng_inproc_register.3.adoc | 5 ++- docs/man/nng_ipc_register.3.adoc | 5 ++- docs/man/nng_tcp_register.3.adoc | 5 ++- docs/man/nng_ws_register.3.adoc | 5 ++- docs/man/nng_wss_register.3.adoc | 5 ++- docs/man/nng_zt_register.3.adoc | 5 ++- include/nng/transport/inproc/inproc.h | 5 ++- include/nng/transport/ipc/ipc.h | 4 +- include/nng/transport/tcp/tcp.h | 4 +- include/nng/transport/tls/tls.h | 2 + include/nng/transport/ws/websocket.h | 7 +-- include/nng/transport/zerotier/zerotier.h | 2 + src/sp/transport.c | 55 ++++++++++++----------- src/sp/transport/inproc/inproc.c | 15 +++++-- src/sp/transport/ipc/ipc.c | 11 ++++- src/sp/transport/tcp/tcp.c | 9 +++- src/sp/transport/tls/tls.c | 7 ++- src/sp/transport/ws/websocket.c | 30 +++++++------ src/sp/transport/zerotier/zerotier.c | 48 +++++++++++--------- 19 files changed, 147 insertions(+), 82 deletions(-) diff --git a/docs/man/nng_inproc_register.3.adoc b/docs/man/nng_inproc_register.3.adoc index cf9afce2f..8379a4e88 100644 --- a/docs/man/nng_inproc_register.3.adoc +++ b/docs/man/nng_inproc_register.3.adoc @@ -1,6 +1,6 @@ = nng_inproc_register(3) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -27,6 +27,9 @@ int nng_inproc_register(void); The `nng_inproc_register()` function registers the ((_inproc_ transport))(((transport, _inproc_))) for use. +NOTE: This function is deprecated, and may be removed from a future release. +It is no longer necessary to explicitly register transports. + == RETURN VALUES This function returns 0 on success, and non-zero otherwise. diff --git a/docs/man/nng_ipc_register.3.adoc b/docs/man/nng_ipc_register.3.adoc index cfdf823a9..64da4b00e 100644 --- a/docs/man/nng_ipc_register.3.adoc +++ b/docs/man/nng_ipc_register.3.adoc @@ -1,6 +1,6 @@ = nng_ipc_register(3) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -27,6 +27,9 @@ int nng_ipc_register(void); The `nng_ipc_register()` function registers the ((_ipc_ transport))(((transport, _ipc_))) for use. +NOTE: This function is deprecated, and may be removed from a future release. +It is no longer necessary to explicitly register transports. + == RETURN VALUES This function returns 0 on success, and non-zero otherwise. diff --git a/docs/man/nng_tcp_register.3.adoc b/docs/man/nng_tcp_register.3.adoc index 1a3a85817..3da671a9b 100644 --- a/docs/man/nng_tcp_register.3.adoc +++ b/docs/man/nng_tcp_register.3.adoc @@ -1,6 +1,6 @@ = nng_tcp_register(3) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -27,6 +27,9 @@ int nng_tcp_register(void); The `nng_tcp_register()` function registers the ((_tcp_ transport))(((transport, _tcp_))) for use. +NOTE: This function is deprecated, and may be removed from a future release. +It is no longer necessary to explicitly register transports. + == RETURN VALUES This function returns 0 on success, and non-zero otherwise. diff --git a/docs/man/nng_ws_register.3.adoc b/docs/man/nng_ws_register.3.adoc index a5f09d977..7a9cc1f30 100644 --- a/docs/man/nng_ws_register.3.adoc +++ b/docs/man/nng_ws_register.3.adoc @@ -1,6 +1,6 @@ = nng_ws_register(3) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -27,6 +27,9 @@ int nng_ws_register(void); The `nng_ws_register()` function registers the ((_ws_ transport))(((transport, _ws_))) for use. +NOTE: This function is deprecated, and may be removed from a future release. +It is no longer necessary to explicitly register transports. + == RETURN VALUES This function returns 0 on success, and non-zero otherwise. diff --git a/docs/man/nng_wss_register.3.adoc b/docs/man/nng_wss_register.3.adoc index 14f434d68..856fe1c0d 100644 --- a/docs/man/nng_wss_register.3.adoc +++ b/docs/man/nng_wss_register.3.adoc @@ -1,6 +1,6 @@ = nng_wss_register(3) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -27,6 +27,9 @@ int nng_wss_register(void); The `nng_wss_register()` function registers the ((_wss_ transport))(((transport, _wss_))) for use. +NOTE: This function is deprecated, and may be removed from a future release. +It is no longer necessary to explicitly register transports. + == RETURN VALUES This function returns 0 on success, and non-zero otherwise. diff --git a/docs/man/nng_zt_register.3.adoc b/docs/man/nng_zt_register.3.adoc index e3cc4060f..9c4a4ac42 100644 --- a/docs/man/nng_zt_register.3.adoc +++ b/docs/man/nng_zt_register.3.adoc @@ -1,6 +1,6 @@ = nng_zt_register(3) // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This document is supplied under the terms of the MIT License, a @@ -27,6 +27,9 @@ int nng_zt_register(void); The `nng_zt_register()` function registers the ((_zt_ transport))(((transport, _zt_))) for use. +NOTE: This function is deprecated, and may be removed from a future release. +It is no longer necessary to explicitly register transports. + == RETURN VALUES This function returns 0 on success, and non-zero otherwise. diff --git a/include/nng/transport/inproc/inproc.h b/include/nng/transport/inproc/inproc.h index 80a83883d..0c633620a 100644 --- a/include/nng/transport/inproc/inproc.h +++ b/include/nng/transport/inproc/inproc.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2017 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -18,8 +18,9 @@ extern "C" { #endif // inproc transport. This is used for intra-process communication. - +#ifndef NNG_ELIDE_DEPRECATED NNG_DECL int nng_inproc_register(void); +#endif #ifdef __cplusplus } diff --git a/include/nng/transport/ipc/ipc.h b/include/nng/transport/ipc/ipc.h index 18d2046db..cccef9a1a 100644 --- a/include/nng/transport/ipc/ipc.h +++ b/include/nng/transport/ipc/ipc.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -20,7 +20,9 @@ extern "C" { // ipc transport. This is used for inter-process communication on // the same host computer. +#ifndef NNG_ELIDE_DEPRECATED NNG_DECL int nng_ipc_register(void); +#endif #ifdef __cplusplus } diff --git a/include/nng/transport/tcp/tcp.h b/include/nng/transport/tcp/tcp.h index 2ca40b708..e236c2710 100644 --- a/include/nng/transport/tcp/tcp.h +++ b/include/nng/transport/tcp/tcp.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2017 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -19,7 +19,9 @@ extern "C" { // TCP transport. This is used for communication over TCP/IP. +#ifndef NNG_ELIDE_DEPRECATED NNG_DECL int nng_tcp_register(void); +#endif #ifdef __cplusplus } diff --git a/include/nng/transport/tls/tls.h b/include/nng/transport/tls/tls.h index 700d5fffe..5e99372bd 100644 --- a/include/nng/transport/tls/tls.h +++ b/include/nng/transport/tls/tls.h @@ -19,7 +19,9 @@ extern "C" { // TLS transport. This is used for communication via TLS v1.2 over TCP/IP. +#ifndef NNG_ELIDE_DEPRECATED NNG_DECL int nng_tls_register(void); +#endif #ifdef __cplusplus } diff --git a/include/nng/transport/ws/websocket.h b/include/nng/transport/ws/websocket.h index 695771077..a5f97d468 100644 --- a/include/nng/transport/ws/websocket.h +++ b/include/nng/transport/ws/websocket.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -19,13 +19,14 @@ extern "C" { // WebSocket transport. This is used for communication via WebSocket. -NNG_DECL int nng_ws_register(void); - // These aliases are for WSS naming consistency. #define NNG_OPT_WSS_REQUEST_HEADERS NNG_OPT_WS_REQUEST_HEADERS #define NNG_OPT_WSS_RESPONSE_HEADERS NNG_OPT_WS_RESPONSE_HEADERS +#ifndef NNG_ELIDE_DEPRECATED +NNG_DECL int nng_ws_register(void); NNG_DECL int nng_wss_register(void); +#endif #ifdef __cplusplus } diff --git a/include/nng/transport/zerotier/zerotier.h b/include/nng/transport/zerotier/zerotier.h index ea73fea72..b8745dbdc 100644 --- a/include/nng/transport/zerotier/zerotier.h +++ b/include/nng/transport/zerotier/zerotier.h @@ -150,7 +150,9 @@ enum nng_zt_status { NNG_ZT_STATUS_UNKNOWN, }; +#ifndef NNG_ELIDE_DEPRECATED NNG_DECL int nng_zt_register(void); +#endif #ifdef __cplusplus } diff --git a/src/sp/transport.c b/src/sp/transport.c index dba530e0a..13961eaaf 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -11,25 +11,6 @@ #include "core/nng_impl.h" -#ifdef NNG_TRANSPORT_INPROC -#include "nng/transport/inproc/inproc.h" -#endif -#ifdef NNG_TRANSPORT_IPC -#include "nng/transport/ipc/ipc.h" -#endif -#ifdef NNG_TRANSPORT_TCP -#include "nng/transport/tcp/tcp.h" -#endif -#ifdef NNG_TRANSPORT_TLS -#include "nng/transport/tls/tls.h" -#endif -#ifdef NNG_TRANSPORT_WS -#include "nng/transport/ws/websocket.h" -#endif -#ifdef NNG_TRANSPORT_ZEROTIER -#include "nng/transport/zerotier/zerotier.h" -#endif - #include #include @@ -67,6 +48,28 @@ nni_sp_tran_find(nni_url *url) // nni_sp_tran_sys_init initializes the entire transport subsystem, including // each individual transport. +#ifdef NNG_TRANSPORT_INPROC +extern void nni_sp_inproc_register(void); +#endif +#ifdef NNG_TRANSPORT_IPC +extern void nni_sp_ipc_register(void); +#endif +#ifdef NNG_TRANSPORT_TCP +extern void nni_sp_tcp_register(void); +#endif +#ifdef NNG_TRANSPORT_TLS +extern void nni_sp_tls_register(void); +#endif +#ifdef NNG_TRANSPORT_WS +extern void nni_sp_ws_register(void); +#endif +#ifdef NNG_TRANSPORT_WSS +extern void nni_sp_wss_register(void); +#endif +#ifdef NNG_TRANSPORT_ZEROTIER +extern void nni_sp_zt_register(void); +#endif + int nni_sp_tran_sys_init(void) { @@ -74,25 +77,25 @@ nni_sp_tran_sys_init(void) nni_rwlock_init(&sp_tran_lk); #ifdef NNG_TRANSPORT_INPROC - nng_inproc_register(); + nni_sp_inproc_register(); #endif #ifdef NNG_TRANSPORT_IPC - nng_ipc_register(); + nni_sp_ipc_register(); #endif #ifdef NNG_TRANSPORT_TCP - nng_tcp_register(); + nni_sp_tcp_register(); #endif #ifdef NNG_TRANSPORT_TLS - nng_tls_register(); + nni_sp_tls_register(); #endif #ifdef NNG_TRANSPORT_WS - nng_ws_register(); + nni_sp_ws_register(); #endif #ifdef NNG_TRANSPORT_WSS - nng_wss_register(); + nni_sp_wss_register(); #endif #ifdef NNG_TRANSPORT_ZEROTIER - nng_zt_register(); + nni_sp_zt_register(); #endif return (0); } diff --git a/src/sp/transport/inproc/inproc.c b/src/sp/transport/inproc/inproc.c index a67d6d183..971b88774 100644 --- a/src/sp/transport/inproc/inproc.c +++ b/src/sp/transport/inproc/inproc.c @@ -313,9 +313,9 @@ inproc_listener_init(void **epp, nni_url *url, nni_listener *nlistener) } nni_mtx_init(&ep->mtx); - ep->listener = true; - ep->proto = nni_sock_proto_id(sock); - ep->rcvmax = 0; + ep->listener = true; + ep->proto = nni_sock_proto_id(sock); + ep->rcvmax = 0; NNI_LIST_INIT(&ep->clients, inproc_ep, node); nni_aio_list_init(&ep->aios); @@ -683,9 +683,16 @@ struct nni_sp_tran nni_inproc_tran = { .tran_fini = inproc_fini, }; +#ifndef NNG_ELIDE_DEPRECATED int nng_inproc_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_sp_inproc_register(void) { nni_sp_tran_register(&nni_inproc_tran); - return (0); } diff --git a/src/sp/transport/ipc/ipc.c b/src/sp/transport/ipc/ipc.c index 502943a50..8ed4ac942 100644 --- a/src/sp/transport/ipc/ipc.c +++ b/src/sp/transport/ipc/ipc.c @@ -1148,8 +1148,17 @@ static nni_sp_tran ipc_tran_abstract = { }; #endif + +#ifndef NNG_ELIDE_DEPRECATED int nng_ipc_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_sp_ipc_register(void) { nni_sp_tran_register(&ipc_tran); #ifdef NNG_PLATFORM_POSIX @@ -1158,6 +1167,4 @@ nng_ipc_register(void) #ifdef NNG_HAVE_ABSTRACT_SOCKETS nni_sp_tran_register(&ipc_tran_abstract); #endif - - return (0); } diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index c201cc7f7..9b12f6d0e 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -1467,11 +1467,18 @@ static nni_sp_tran tcp6_tran_mqtt = { .tran_fini = tcptran_fini, }; +#ifndef NNG_ELIDE_DEPRECATED int nng_tcp_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_sp_tcp_register(void) { nni_sp_tran_register(&tcp_tran_mqtt); nni_sp_tran_register(&tcp4_tran_mqtt); nni_sp_tran_register(&tcp6_tran_mqtt); - return (0); } diff --git a/src/sp/transport/tls/tls.c b/src/sp/transport/tls/tls.c index 91c0f1c9d..75858839f 100644 --- a/src/sp/transport/tls/tls.c +++ b/src/sp/transport/tls/tls.c @@ -1278,9 +1278,14 @@ static nni_sp_tran tls6_tran = { int nng_tls_register(void) +{ + return (nni_init()); +} + +void +nni_sp_tls_register(void) { nni_sp_tran_register(&tls_tran); nni_sp_tran_register(&tls4_tran); nni_sp_tran_register(&tls6_tran); - return (0); } diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index a3f2cd267..7cf9949f1 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -667,14 +667,26 @@ static nni_sp_tran ws6_tran = { .tran_fini = wstran_fini, }; +#ifndef NNG_ELIDE_DEPRECATED int nng_ws_register(void) +{ + return (nni_init()); +} + +int +nng_wss_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_sp_ws_register(void) { nni_sp_tran_register(&ws_tran); nni_sp_tran_register(&ws4_tran); nni_sp_tran_register(&ws6_tran); - - return (0); } #ifdef NNG_TRANSPORT_WSS @@ -706,22 +718,12 @@ static nni_sp_tran wss6_tran = { .tran_fini = wstran_fini, }; -int -nng_wss_register(void) +void +nni_sp_wss_register(void) { nni_sp_tran_register(&wss_tran); nni_sp_tran_register(&wss4_tran); nni_sp_tran_register(&wss6_tran); - - return (0); -} - -#else - -int -nng_wss_register(void) -{ - return (0); } #endif // NNG_TRANSPORT_WSS diff --git a/src/sp/transport/zerotier/zerotier.c b/src/sp/transport/zerotier/zerotier.c index 15c0fe9f5..5658fb18e 100644 --- a/src/sp/transport/zerotier/zerotier.c +++ b/src/sp/transport/zerotier/zerotier.c @@ -58,18 +58,17 @@ typedef struct zt_node zt_node; typedef struct zt_frag zt_frag; typedef struct zt_fraglist zt_fraglist; - // Port numbers are stored as 24-bit values in network byte order. -#define ZT_GET24(ptr, v) \ - v = (((uint32_t)((uint8_t)(ptr)[0])) << 16) + \ - (((uint32_t)((uint8_t)(ptr)[1])) << 8) + \ - (((uint32_t)(uint8_t)(ptr)[2])) - -#define ZT_PUT24(ptr, u) \ - do { \ - (ptr)[0] = (uint8_t)(((uint32_t)(u)) >> 16); \ - (ptr)[1] = (uint8_t)(((uint32_t)(u)) >> 8); \ - (ptr)[2] = (uint8_t)((uint32_t)(u)); \ +#define ZT_GET24(ptr, v) \ + v = (((uint32_t) ((uint8_t) (ptr)[0])) << 16) + \ + (((uint32_t) ((uint8_t) (ptr)[1])) << 8) + \ + (((uint32_t) (uint8_t) (ptr)[2])) + +#define ZT_PUT24(ptr, u) \ + do { \ + (ptr)[0] = (uint8_t) (((uint32_t) (u)) >> 16); \ + (ptr)[1] = (uint8_t) (((uint32_t) (u)) >> 8); \ + (ptr)[2] = (uint8_t) ((uint32_t) (u)); \ } while (0) static const uint16_t zt_ethertype = 0x901; @@ -455,7 +454,7 @@ zt_node_to_mac(uint64_t node, uint64_t nwid) // multicast and set local administration -- this is the first // octet of the 48 bit mac address. We also avoid 0x52, which // is known to be used in KVM, libvirt, etc. - mac = ((uint8_t)(nwid & 0xfe) | 0x02); + mac = ((uint8_t) (nwid & 0xfe) | 0x02); if (mac == 0x52) { mac = 0x32; } @@ -907,7 +906,7 @@ zt_pipe_recv_data(zt_pipe *p, const uint8_t *data, size_t len) return; } - bit = (uint8_t)(1 << (fragno % 8)); + bit = (uint8_t) (1 << (fragno % 8)); if ((fl->fl_missing[fragno / 8] & bit) == 0) { // We've already got this fragment, ignore it. We don't // bother to check for changed data. @@ -1714,8 +1713,8 @@ zt_pipe_fini(void *arg) } static nni_reap_list zt_reap_list = { - .rl_offset = offsetof(zt_pipe, zp_reap), - .rl_func = zt_pipe_fini, + .rl_offset = offsetof(zt_pipe, zp_reap), + .rl_func = zt_pipe_fini, }; static void @@ -1841,15 +1840,15 @@ zt_pipe_send(void *arg, nni_aio *aio) NNI_ASSERT(fragsz < 0x10000); // Because zp_mtu is 16 bits msg_header_len = nni_msg_header_len(m); - msg_len = nni_msg_len(m); - bytes = msg_header_len + msg_len; + msg_len = nni_msg_len(m); + bytes = msg_header_len + msg_len; if (bytes >= (0xfffe * fragsz)) { nni_aio_finish_error(aio, NNG_EMSGSIZE); nni_mtx_unlock(&zt_lk); return; } // above check means nfrags will fit in 16-bits. - nfrags = (uint16_t)((bytes + (fragsz - 1)) / fragsz); + nfrags = (uint16_t) ((bytes + (fragsz - 1)) / fragsz); // get the next message ID, but skip 0 if ((id = p->zp_next_msgid++) == 0) { @@ -1865,7 +1864,7 @@ zt_pipe_send(void *arg, nni_aio *aio) size_t len; // Prepend the header first. - if ( (!offset) && (msg_header_len > 0)) { + if ((!offset) && (msg_header_len > 0)) { if (msg_header_len > fragsz) { // This shouldn't happen! SP headers are // supposed to be quite small. @@ -1895,7 +1894,7 @@ zt_pipe_send(void *arg, nni_aio *aio) fragno++; zt_send(p->zp_ztn, p->zp_nwid, zt_op_data, p->zp_raddr, p->zp_laddr, data, fraglen + zt_offset_data_data); - } while (msg_header_len + msg_len -offset != 0); + } while (msg_header_len + msg_len - offset != 0); nni_mtx_unlock(&zt_lk); // NB, We never bothered to call nn_aio_sched, because we run this @@ -3240,9 +3239,16 @@ static struct nni_tran zt_tran = { .tran_fini = zt_tran_fini, }; +#ifndef NNG_ELIDE_DEPRECATED int nng_zt_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_sp_zt_register(void) { nni_tran_register(&zt_tran); - return (0); } From f716cca63fad9d82d2e05b3c965bbf8cc9ebd6ea Mon Sep 17 00:00:00 2001 From: JaylinYu <64823539+JaylinYu@users.noreply.github.com> Date: Tue, 10 Aug 2021 06:43:50 +0800 Subject: [PATCH 005/180] * FIX #1486 by waking up latest aio each time. (#1487) --- src/core/aio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/aio.c b/src/core/aio.c index 75b340789..1817dc18f 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -530,9 +530,8 @@ nni_aio_expire_add(nni_aio *aio) } eq->eq_list[eq->eq_len++] = aio; - if (eq->eq_len == 1) { - nni_cv_wake(&eq->eq_cv); - } + // Fire the latest aio, but it cames with performance punishment + nni_cv_wake(&eq->eq_cv); } static void From f244123c12b621dde89dd9a1a6f2ea10dc45d780 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 9 Aug 2021 16:13:16 -0700 Subject: [PATCH 006/180] fixes #1478 mbedTLS 3.0 is not API compatible with 2.x --- cmake/FindmbedTLS.cmake | 62 +++++++++++++------------ src/supplemental/tls/mbedtls/tls.c | 42 ++++++++++++++--- src/supplemental/tls/tls_common.c | 2 +- src/supplemental/tls/tls_test.c | 6 ++- tests/tls.c | 73 ++++++++++++++++++------------ tests/trantest.h | 2 +- 6 files changed, 121 insertions(+), 66 deletions(-) diff --git a/cmake/FindmbedTLS.cmake b/cmake/FindmbedTLS.cmake index 8c25ec9c4..f01039d6c 100644 --- a/cmake/FindmbedTLS.cmake +++ b/cmake/FindmbedTLS.cmake @@ -31,50 +31,56 @@ set(_MBEDTLS_ROOT_HINTS ${MBEDTLS_ROOT_DIR} ENV MBEDTLS_ROOT_DIR) include(FindPackageHandleStandardArgs) find_path(MBEDTLS_INCLUDE_DIR - NAMES mbedtls/ssl.h - HINTS ${_MBEDTLS_ROOT_HINTS} - PATHS /usr/local - PATH_SUFFIXES include) + NAMES mbedtls/ssl.h + HINTS ${_MBEDTLS_ROOT_HINTS} + PATHS /usr/local + PATH_SUFFIXES include) find_library(MBEDTLS_CRYPTO_LIBRARY - NAMES mbedcrypto - HINTS ${_MBEDTLS_ROOT_HINTS} - PATHS /usr/local - PATH_SUFFIXES lib) + NAMES mbedcrypto + HINTS ${_MBEDTLS_ROOT_HINTS} + PATHS /usr/local + PATH_SUFFIXES lib) find_library(MBEDTLS_X509_LIBRARY - NAMES mbedx509 - HINTS ${_MBEDTLS_ROOT_HINTS} - PATHS /usr/local - PATH_SUFFIXES lib) + NAMES mbedx509 + HINTS ${_MBEDTLS_ROOT_HINTS} + PATHS /usr/local + PATH_SUFFIXES lib) find_library(MBEDTLS_TLS_LIBRARY - NAMES mbedtls - HINTS ${_MBEDTLS_ROOT_HINTS} - PATHS /usr/local - PATH_SUFFIXES lib) + NAMES mbedtls + HINTS ${_MBEDTLS_ROOT_HINTS} + PATHS /usr/local + PATH_SUFFIXES lib) set(MBEDTLS_LIBRARIES - ${MBEDTLS_TLS_LIBRARY} - ${MBEDTLS_X509_LIBRARY} - ${MBEDTLS_CRYPTO_LIBRARY}) + ${MBEDTLS_TLS_LIBRARY} + ${MBEDTLS_X509_LIBRARY} + ${MBEDTLS_CRYPTO_LIBRARY}) if (${MBEDTLS_TLS_LIBRARY-NOTFOUND}) message(FATAL_ERROR "Failed to find Mbed TLS library") -endif() +endif () mark_as_advanced( - MBEDSSL_INCLUDE_DIR - MBEDTLS_LIBRARIES - MBEDTLS_CRYPTO_LIBRARY - MBEDTLS_X509_LIBRARY - MBEDTLS_TLS_LIBRARY) + MBEDSSL_INCLUDE_DIR + MBEDTLS_LIBRARIES + MBEDTLS_CRYPTO_LIBRARY + MBEDTLS_X509_LIBRARY + MBEDTLS_TLS_LIBRARY) # Extract the version from the header... hopefully it matches the library. -file(STRINGS ${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h _MBEDTLS_VERLINE - REGEX "^#define[ \t]+MBEDTLS_VERSION_STRING[\t ].*") +if (EXISTS ${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h) + file(STRINGS ${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h _MBEDTLS_VERLINE + REGEX "^#define[ \t]+MBEDTLS_VERSION_STRING[\t ].*") +else () + file(STRINGS ${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h _MBEDTLS_VERLINE + REGEX "^#define[ \t]+MBEDTLS_VERSION_STRING[\t ].*") +endif () + string(REGEX REPLACE ".*MBEDTLS_VERSION_STRING[\t ]+\"(.*)\"" "\\1" MBEDTLS_VERSION ${_MBEDTLS_VERLINE}) find_package_handle_standard_args(mbedTLS - REQUIRED_VARS MBEDTLS_TLS_LIBRARY MBEDTLS_CRYPTO_LIBRARY MBEDTLS_X509_LIBRARY MBEDTLS_INCLUDE_DIR VERSION_VAR MBEDTLS_VERSION) + REQUIRED_VARS MBEDTLS_TLS_LIBRARY MBEDTLS_CRYPTO_LIBRARY MBEDTLS_X509_LIBRARY MBEDTLS_INCLUDE_DIR VERSION_VAR MBEDTLS_VERSION) diff --git a/src/supplemental/tls/mbedtls/tls.c b/src/supplemental/tls/mbedtls/tls.c index 1f9453c18..a216b3a69 100644 --- a/src/supplemental/tls/mbedtls/tls.c +++ b/src/supplemental/tls/mbedtls/tls.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2019 Devolutions // @@ -44,13 +44,13 @@ static nni_mtx rng_lock; #endif struct nng_tls_engine_conn { - void * tls; // parent conn + void *tls; // parent conn mbedtls_ssl_context ctx; }; struct nng_tls_engine_config { mbedtls_ssl_config cfg_ctx; - char * server_name; + char *server_name; mbedtls_x509_crt ca_certs; mbedtls_x509_crl crl; int min_ver; @@ -104,14 +104,29 @@ static struct { int tls; int nng; } tls_errs[] = { +#ifdef MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE { MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE, NNG_EPEERAUTH }, +#endif +#ifdef MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED { MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED, NNG_EPEERAUTH }, +#endif +#ifdef MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED { MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED, NNG_EPEERAUTH }, +#endif +#ifdef MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE { MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE, NNG_EPEERAUTH }, +#endif { MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY, NNG_ECONNREFUSED }, { MBEDTLS_ERR_SSL_ALLOC_FAILED, NNG_ENOMEM }, { MBEDTLS_ERR_SSL_TIMEOUT, NNG_ETIMEDOUT }, { MBEDTLS_ERR_SSL_CONN_EOF, NNG_ECLOSED }, +// MbedTLS 3.0 error codes +#ifdef MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE + { MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE, NNG_EPEERAUTH }, +#endif +#ifdef MBEDTLS_ERR_SSL_BAD_CERTIFICATE + { MBEDTLS_ERR_SSL_BAD_CERTIFICATE, NNG_EPEERAUTH }, +#endif // terminator { 0, 0 }, }; @@ -337,7 +352,7 @@ config_server_name(nng_tls_engine_config *cfg, const char *name) if ((dup = nni_strdup(name)) == NULL) { return (NNG_ENOMEM); } - if (cfg->server_name) { + if (cfg->server_name != NULL) { nni_strfree(cfg->server_name); } cfg->server_name = dup; @@ -395,7 +410,7 @@ config_own_cert(nng_tls_engine_config *cfg, const char *cert, const char *key, { size_t len; const uint8_t *pem; - pair * p; + pair *p; int rv; if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { @@ -413,8 +428,13 @@ config_own_cert(nng_tls_engine_config *cfg, const char *cert, const char *key, pem = (const uint8_t *) key; len = strlen(key) + 1; - rv = mbedtls_pk_parse_key(&p->key, pem, len, (const uint8_t *) pass, - pass != NULL ? strlen(pass) : 0); +#if MBEDTLS_VERSION_MAJOR < 3 + rv = mbedtls_pk_parse_key(&p->key, pem, len, (const uint8_t *) pass, + pass != NULL ? strlen(pass) : 0); +#else + rv = mbedtls_pk_parse_key(&p->key, pem, len, (const uint8_t *) pass, + pass != NULL ? strlen(pass) : 0, tls_random, NULL); +#endif if (rv != 0) { rv = tls_mk_err(rv); goto err; @@ -448,12 +468,16 @@ config_version(nng_tls_engine_config *cfg, nng_tls_version min_ver, return (NNG_ENOTSUP); } switch (min_ver) { +#ifdef MBEDTLS_SSL_MINOR_VERSION_1 case NNG_TLS_1_0: v1 = MBEDTLS_SSL_MINOR_VERSION_1; break; +#endif +#ifdef MBEDTLS_SSL_MINOR_VERSION_2 case NNG_TLS_1_1: v1 = MBEDTLS_SSL_MINOR_VERSION_2; break; +#endif case NNG_TLS_1_2: v1 = MBEDTLS_SSL_MINOR_VERSION_3; break; @@ -462,12 +486,16 @@ config_version(nng_tls_engine_config *cfg, nng_tls_version min_ver, } switch (max_ver) { +#ifdef MBEDTLS_SSL_MINOR_VERSION_1 case NNG_TLS_1_0: v2 = MBEDTLS_SSL_MINOR_VERSION_1; break; +#endif +#ifdef MBEDTLS_SSL_MINOR_VERSION_2 case NNG_TLS_1_1: v2 = MBEDTLS_SSL_MINOR_VERSION_2; break; +#endif case NNG_TLS_1_2: case NNG_TLS_1_3: // We lack support for 1.3, so treat as 1.2. v2 = MBEDTLS_SSL_MINOR_VERSION_3; diff --git a/src/supplemental/tls/tls_common.c b/src/supplemental/tls/tls_common.c index 2ae50f157..404a8cf76 100644 --- a/src/supplemental/tls/tls_common.c +++ b/src/supplemental/tls/tls_common.c @@ -1374,7 +1374,7 @@ nng_tls_config_alloc(nng_tls_config **cfg_p, nng_tls_mode mode) return (NNG_ENOTSUP); } - size = NNI_ALIGN_UP(sizeof(*cfg) + eng->config_ops->size); + size = NNI_ALIGN_UP(sizeof(*cfg)) + eng->config_ops->size; if ((cfg = nni_zalloc(size)) == NULL) { return (NNG_ENOMEM); diff --git a/src/supplemental/tls/tls_test.c b/src/supplemental/tls/tls_test.c index 244f68ca9..96d95fb63 100644 --- a/src/supplemental/tls/tls_test.c +++ b/src/supplemental/tls/tls_test.c @@ -28,7 +28,10 @@ test_tls_config_version(void) NUTS_FAIL(nng_tls_config_version(cfg, NNG_TLS_1_0, NNG_TLS_1_3 + 1), NNG_ENOTSUP); - // Verify that we *can* configure some various ranges. + // Verify that we *can* configure some various ranges starting with + // TLS v1.2. Note that some libraries no longer support TLS 1.0 + // and TLS 1.1, so we don't test for them. +#if 0 NUTS_PASS(nng_tls_config_version(cfg, NNG_TLS_1_0, NNG_TLS_1_0)); NUTS_PASS(nng_tls_config_version(cfg, NNG_TLS_1_0, NNG_TLS_1_1)); NUTS_PASS(nng_tls_config_version(cfg, NNG_TLS_1_0, NNG_TLS_1_2)); @@ -36,6 +39,7 @@ test_tls_config_version(void) NUTS_PASS(nng_tls_config_version(cfg, NNG_TLS_1_1, NNG_TLS_1_1)); NUTS_PASS(nng_tls_config_version(cfg, NNG_TLS_1_1, NNG_TLS_1_2)); NUTS_PASS(nng_tls_config_version(cfg, NNG_TLS_1_1, NNG_TLS_1_3)); +#endif NUTS_PASS(nng_tls_config_version(cfg, NNG_TLS_1_2, NNG_TLS_1_2)); NUTS_PASS(nng_tls_config_version(cfg, NNG_TLS_1_2, NNG_TLS_1_3)); diff --git a/tests/tls.c b/tests/tls.c index c6d5da6e4..6eaa002c8 100644 --- a/tests/tls.c +++ b/tests/tls.c @@ -27,40 +27,57 @@ // The certificate is valid for 100 years, because I don't want to // have to regenerate it ever again. The CN is 127.0.0.1, and self-signed. // -// Generated using openssl: -// -// % openssl ecparam -name secp224r1 -genkey -out key.key -// % openssl req -new -key key.key -out cert.csr -sha256 -// % openssl x509 -req -in cert.csr -days 36500 -out cert.crt -// -signkey key.key -sha256 -// -// Secp224r1 chosen as a least common denominator recommended by NIST-800. -// -// static const char cert[] = "-----BEGIN CERTIFICATE-----\n" - "MIIBzDCCAXkCCQCNJMf8eYUHxTAKBggqhkjOPQQDAjB2MQswCQYDVQQGEwJVUzEL\n" - "MAkGA1UECAwCQ0ExEjAQBgNVBAcMCVNhbiBEaWVnbzEUMBIGA1UECgwLbmFub21z\n" - "Zy5vcmcxHDAaBgNVBAsME1NhbXBsZSBDZXJ0aWZpY2F0ZXMxEjAQBgNVBAMMCWxv\n" - "Y2FsaG9zdDAgFw0yMDAyMjMxODMwMDZaGA8yMTIwMDEzMDE4MzAwNlowdjELMAkG\n" - "A1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTYW4gRGllZ28xFDASBgNV\n" - "BAoMC25hbm9tc2cub3JnMRwwGgYDVQQLDBNTYW1wbGUgQ2VydGlmaWNhdGVzMRIw\n" - "EAYDVQQDDAlsb2NhbGhvc3QwTjAQBgcqhkjOPQIBBgUrgQQAIQM6AAS9hA5gYo10\n" - "jx+gzJdzYbxHzigJYXawdHtyoAud/TT/dUCt0ycpOzTMiO3CoDNxep+/mkmgxjfp\n" - "ujAKBggqhkjOPQQDAgNBADA+Ah0A9b+GcfbhzzmI2NcYb4auE6XTYJPkPzHt6Adi\n" - "fwIdAMJO2LEr6WHH6JGLlishVqjF78TtkuB5t+kzneQ=\n" + "MIIDRzCCAi8CFCOIJGs6plMawgBYdDuCRV7UuJuyMA0GCSqGSIb3DQEBCwUAMF8x\n" + "CzAJBgNVBAYTAlhYMQ8wDQYDVQQIDAZVdG9waWExETAPBgNVBAcMCFBhcmFkaXNl\n" + "MRgwFgYDVQQKDA9OTkcgVGVzdHMsIEluYy4xEjAQBgNVBAMMCWxvY2FsaG9zdDAg\n" + "Fw0yMDA1MjMyMzMxMTlaGA8yMTIwMDQyOTIzMzExOVowXzELMAkGA1UEBhMCWFgx\n" + "DzANBgNVBAgMBlV0b3BpYTERMA8GA1UEBwwIUGFyYWRpc2UxGDAWBgNVBAoMD05O\n" + "RyBUZXN0cywgSW5jLjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B\n" + "AQEFAAOCAQ8AMIIBCgKCAQEAyPdnRbMrQj9902TGQsmMbG6xTSl9XKbJr55BcnyZ\n" + "ifsrqA7BbNSkndVw9Qq+OJQIDBTfRhGdG+o9j3h6SDVvIb62fWtwJ5Fe0eUmeYwP\n" + "c1PKQzOmMFlMYekXiZsx60yu5LeuUhGlb84+csImH+m3NbutInPJcStSq0WfSV6V\n" + "Nk6DN3535ex66zV2Ms6ikys1vCC434YqIpe1VxUh+IC2widJcLDCxmmJt3TOlx5f\n" + "9OcKMkxuH4fMAzgjIEpIrUjdb19CGNVvsNrEEB2CShBMgBdqMaAnKFxpKgfzS0JF\n" + "ulxRGNtpsrweki+j+a4sJXTv40kELkRQS6uB6wWZNjcPywIDAQABMA0GCSqGSIb3\n" + "DQEBCwUAA4IBAQA86Fqrd4aiih6R3fwiMLwV6IQJv+u5rQeqA4D0xu6v6siP42SJ\n" + "YMaI2DkNGrWdSFVSHUK/efceCrhnMlW7VM8I1cyl2F/qKMfnT72cxqqquiKtQKdT\n" + "NDTzv61QMUP9n86HxMzGS7jg0Pknu55BsIRNK6ndDvI3D/K/rzZs4xbqWSSfNfQs\n" + "fNFBbOuDrkS6/1h3p8SY1uPM18WLVv3GO2T3aeNMHn7YJAKSn+sfaxzAPyPIK3UT\n" + "W8ecGQSHOqBJJQELyUfMu7lx/FCYKUhN7/1uhU5Qf1pCR8hkIMegtqr64yVBNMOn\n" + "248fuiHbs9BRknuA/PqjxIDDZTwtDrfVSO/S\n" "-----END CERTIFICATE-----\n"; static const char key[] = - "-----BEGIN EC PARAMETERS-----\n" - "gUrgQQAIQ==\n" - "-----END EC PARAMETERS-----\n" - "-----BEGIN EC PRIVATE KEY-----\n" - "MGgCAQEEHChK068x8MWcBzhpO7qANvW4iTo7E0yzMYFXGn+gBwYFK4EEACGhPAM6\n" - "AAS9hA5gYo10jx+gzJdzYbxHzigJYXawdHtyoAud/TT/dUCt0ycpOzTMiO3CoDNx\n" - "ep+/mkmgxjfpug==\n" - "-----END EC PRIVATE KEY-----\n"; + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEAyPdnRbMrQj9902TGQsmMbG6xTSl9XKbJr55BcnyZifsrqA7B\n" + "bNSkndVw9Qq+OJQIDBTfRhGdG+o9j3h6SDVvIb62fWtwJ5Fe0eUmeYwPc1PKQzOm\n" + "MFlMYekXiZsx60yu5LeuUhGlb84+csImH+m3NbutInPJcStSq0WfSV6VNk6DN353\n" + "5ex66zV2Ms6ikys1vCC434YqIpe1VxUh+IC2widJcLDCxmmJt3TOlx5f9OcKMkxu\n" + "H4fMAzgjIEpIrUjdb19CGNVvsNrEEB2CShBMgBdqMaAnKFxpKgfzS0JFulxRGNtp\n" + "srweki+j+a4sJXTv40kELkRQS6uB6wWZNjcPywIDAQABAoIBAQCGSUsot+BgFCzv\n" + "5JbWafb7Pbwb421xS8HZJ9Zzue6e1McHNVTqc+zLyqQAGX2iMMhvykKnf32L+anJ\n" + "BKgxOANaeSVYCUKYLfs+JfDfp0druMGexhR2mjT/99FSkfF5WXREQLiq/j+dxiLU\n" + "bActq+5QaWf3bYddp6VF7O/TBvCNqBfD0+S0o0wtBdvxXItrKPTD5iKr9JfLWdAt\n" + "YNAk2QgFywFtY5zc2wt4queghF9GHeBzzZCuVj9QvPA4WdVq0mePaPTmvTYQUD0j\n" + "GT6X5j9JhqCwfh7trb/HfkmLHwwc62zPDFps+Dxao80+vss5b/EYZ4zY3S/K3vpG\n" + "f/e42S2BAoGBAP51HQYFJGC/wsNtOcX8RtXnRo8eYmyboH6MtBFrZxWl6ERigKCN\n" + "5Tjni7EI3nwi3ONg0ENPFkoQ8h0bcVFS7iW5kz5te73WaOFtpkU9rmuFDUz37eLP\n" + "d+JLZ5Kwfn2FM9HoiSAZAHowE0MIlmmIEXSnFtqA2zzorPQLO/4QlR+VAoGBAMov\n" + "R0yaHg3qPlxmCNyLXKiGaGNzvsvWjYw825uCGmVZfhzDhOiCFMaMb51BS5Uw/gwm\n" + "zHxmJjoqak8JjxaQ1qKPoeY1TJ5ps1+TRq9Wzm2/zGqJHOXnRPlqwBQ6AFllAMgt\n" + "Rlp5uqb8QJ+YEo6/1kdGhw9kZWCZEEue6MNQjxnfAoGARLkUkZ+p54di7qz9QX+V\n" + "EghYgibOpk6R1hviNiIvwSUByhZgbvxjwC6pB7NBg31W8wIevU8K0g4plbrnq/Md\n" + "5opsPhwLo4XY5albkq/J/7f7k6ISWYN2+WMsIe4Q+42SJUsMXeLiwh1h1mTnWrEp\n" + "JbxK69CJZbXhoDe4iDGqVNECgYAjlgS3n9ywWE1XmAHxR3osk1OmRYYMfJv3VfLV\n" + "QSYCNqkyyNsIzXR4qdkvVYHHJZNhcibFsnkB/dsuRCFyOFX+0McPLMxqiXIv3U0w\n" + "qVe2C28gRTfX40fJmpdqN/c9xMBJe2aJoClRIM8DCBIkG/HMI8a719DcGrS6iqKv\n" + "VeuKAwKBgEgD+KWW1KtoSjCBlS0NP8HjC/Rq7j99YhKE6b9h2slIa7JTO8RZKCa0\n" + "qbuomdUeJA3R8h+5CFkEKWqO2/0+dUdLNOjG+CaTFHaUJevzHOzIjpn+VsfCLV13\n" + "yupGzHG+tGtdrWgLn9Dzdp67cDfSnsSh+KODPECAAFfo+wPvD8DS\n" + "-----END RSA PRIVATE KEY-----\n"; static int check_props_v4(nng_msg *msg) diff --git a/tests/trantest.h b/tests/trantest.h index 93f902dad..e56d755d1 100644 --- a/tests/trantest.h +++ b/tests/trantest.h @@ -232,7 +232,7 @@ trantest_listen_accept(trantest *tt) So(trantest_listen(tt, &l) == 0); So(nng_listener_id(l) > 0); - nng_msleep(200); + nng_msleep(500); So(trantest_dial(tt, &d) == 0); So(nng_dialer_id(d) > 0); So(nng_dialer_id(d0) < 0); From 457e208bb9ee7006c25434fcf2eea53157715443 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 9 Aug 2021 22:39:46 -0700 Subject: [PATCH 007/180] fixes #1488 aio expiration list performance work needed There were several problems with the array implementation, both from performance and from correctness. This corrects those errors (hopefully) and restores the expiration lists as linked lists. --- src/core/aio.c | 198 ++++++++++++++++++++++-------------------------- src/core/aio.h | 11 +-- src/core/defs.h | 7 +- 3 files changed, 102 insertions(+), 114 deletions(-) diff --git a/src/core/aio.c b/src/core/aio.c index 1817dc18f..bc4816d6b 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -13,14 +13,13 @@ #include struct nni_aio_expire_q { - nni_mtx eq_mtx; - nni_cv eq_cv; - nni_aio **eq_list; - uint32_t eq_len; - uint32_t eq_cap; - nni_aio * eq_aio; // currently expiring (task dispatch) - nni_thr eq_thr; - bool eq_exit; + nni_mtx eq_mtx; + nni_cv eq_cv; + nni_list eq_list; + uint32_t eq_len; + nni_thr eq_thr; + nni_time eq_next; // next expiration + bool eq_exit; }; static nni_aio_expire_q **nni_aio_expire_q_list; @@ -119,7 +118,7 @@ void nni_aio_fini(nni_aio *aio) { nni_aio_cancel_fn fn; - void * arg; + void *arg; nni_aio_expire_q *eq = aio->a_expire_q; // This is like aio_close, but we don't want to dispatch @@ -128,10 +127,10 @@ nni_aio_fini(nni_aio *aio) // We also wait if the aio is being expired. nni_mtx_lock(&eq->eq_mtx); aio->a_stop = true; - nni_aio_expire_rm(aio); - while (eq->eq_aio == aio) { + while (aio->a_expiring) { nni_cv_wait(&eq->eq_cv); } + nni_aio_expire_rm(aio); fn = aio->a_cancel_fn; arg = aio->a_cancel_arg; aio->a_cancel_fn = NULL; @@ -205,7 +204,7 @@ nni_aio_stop(nni_aio *aio) { if (aio != NULL) { nni_aio_cancel_fn fn; - void * arg; + void *arg; nni_aio_expire_q *eq = aio->a_expire_q; nni_mtx_lock(&eq->eq_mtx); @@ -230,7 +229,7 @@ nni_aio_close(nni_aio *aio) { if (aio != NULL) { nni_aio_cancel_fn fn; - void * arg; + void *arg; nni_aio_expire_q *eq = aio->a_expire_q; nni_mtx_lock(&eq->eq_mtx); @@ -414,7 +413,7 @@ void nni_aio_abort(nni_aio *aio, int rv) { nni_aio_cancel_fn fn; - void * arg; + void *arg; nni_aio_expire_q *eq = aio->a_expire_q; nni_mtx_lock(&eq->eq_mtx); @@ -518,125 +517,114 @@ static void nni_aio_expire_add(nni_aio *aio) { nni_aio_expire_q *eq = aio->a_expire_q; - if (eq->eq_len >= eq->eq_cap) { - nni_aio **new_list = - nni_zalloc(eq->eq_cap * 2 * sizeof(nni_aio *)); - for (uint32_t i = 0; i < eq->eq_len; i++) { - new_list[i] = eq->eq_list[i]; - } - nni_free(eq->eq_list, eq->eq_cap * sizeof(nni_aio *)); - eq->eq_list = new_list; - eq->eq_cap *= 2; - } - eq->eq_list[eq->eq_len++] = aio; - // Fire the latest aio, but it cames with performance punishment - nni_cv_wake(&eq->eq_cv); + nni_list_append(&eq->eq_list, aio); + + if (eq->eq_next > aio->a_expire) { + eq->eq_next = aio->a_expire; + nni_cv_wake(&eq->eq_cv); + } } static void nni_aio_expire_rm(nni_aio *aio) { - nni_aio_expire_q *eq = aio->a_expire_q; - - for (uint32_t i = 0; i < eq->eq_len; i++) { - if (aio == eq->eq_list[i]) { - eq->eq_list[i] = eq->eq_list[eq->eq_len - 1]; - eq->eq_len--; - break; - } - } + nni_list_node_remove(&aio->a_expire_node); - if (eq->eq_len < eq->eq_cap / 4 && eq->eq_cap > NNI_EXPIRE_Q_SIZE) { - nni_aio **new_list = - nni_zalloc(eq->eq_cap * sizeof(nni_aio *) / 4); - for (uint32_t i = 0; i < eq->eq_len; i++) { - new_list[i] = eq->eq_list[i]; - } - nni_free(eq->eq_list, eq->eq_cap * sizeof(nni_aio *)); - eq->eq_list = new_list; - eq->eq_cap /= 4; - } + // If this item is the one that is going to wake the loop, + // don't worry about it. It will wake up normally, or when we + // add a new aio to it. Worst case is just one spurious wake up, + // which we'd need to do anyway. } static void nni_aio_expire_loop(void *arg) { nni_aio_expire_q *q = arg; - nni_mtx * mtx = &q->eq_mtx; - nni_cv * cv = &q->eq_cv; - nni_aio ** list; + nni_mtx *mtx = &q->eq_mtx; + nni_cv *cv = &q->eq_cv; nni_time now; - uint32_t aio_idx; + uint32_t exp_idx; + nni_aio *expires[NNI_EXPIRE_BATCH]; nni_thr_set_name(NULL, "nng:aio:expire"); - now = nni_clock(); nni_mtx_lock(mtx); for (;;) { nni_aio *aio; int rv; - - if (q->eq_len == 0) { - - if (q->eq_exit) { - nni_mtx_unlock(mtx); - return; - } - - nni_cv_wait(cv); - - now = nni_clock(); + nni_time next; + + next = q->eq_next; + now = nni_clock(); + + // Each time we wake up, we scan the entire list of elements. + // We scan forward, moving up to NNI_EXPIRE_Q_SIZE elements + // (a batch) to a saved array of things we are going to cancel. + // This mostly runs in O(n), provided you don't have many + // elements (> NNI_EXPIRE_Q_SIZE) all expiring simultaneously. + aio = nni_list_first(&q->eq_list); + if ((aio == NULL) && (q->eq_exit)) { + nni_mtx_unlock(mtx); + return; + } + if (now < next) { + // Early wake up (just to reschedule), no need to + // rescan the list. This is an optimization. + nni_cv_until(cv, next); continue; } - - // Find the timer with min expire time. - list = q->eq_list; - aio_idx = 0; - aio = list[aio_idx]; - for (uint32_t i = 0; i < q->eq_len; i++) { - if (list[i]->a_expire < aio->a_expire) { - aio = list[i]; - aio_idx = i; + q->eq_next = NNI_TIME_NEVER; + exp_idx = 0; + while (aio != NULL) { + if ((aio->a_expire < now) && + (exp_idx < NNI_EXPIRE_BATCH)) { + nni_aio *nxt; + + // This one is expiring. + expires[exp_idx++] = aio; + // save the next node + nxt = nni_list_next(&q->eq_list, aio); + nni_list_remove(&q->eq_list, aio); + // Place a temporary hold on the aio. + // This prevents it from being destroyed. + aio->a_expiring = true; + aio = nxt; + continue; } - } - if (now < aio->a_expire) { - // Unexpired; we just wait for the next expired aio. - nni_cv_until(cv, aio->a_expire); - now = nni_clock(); - continue; + if (aio->a_expire < q->eq_next) { + q->eq_next = aio->a_expire; + } + aio = nni_list_next(&q->eq_list, aio); } - // The time has come for this aio. Expire it, canceling any - // outstanding I/O. - list[aio_idx] = list[q->eq_len - 1]; - q->eq_len--; - rv = aio->a_expire_ok ? 0 : NNG_ETIMEDOUT; + for (uint32_t i = 0; i < exp_idx; i++) { + aio = expires[i]; + rv = aio->a_expire_ok ? 0 : NNG_ETIMEDOUT; - nni_aio_cancel_fn cancel_fn = aio->a_cancel_fn; - void * cancel_arg = aio->a_cancel_arg; + nni_aio_cancel_fn cancel_fn = aio->a_cancel_fn; + void *cancel_arg = aio->a_cancel_arg; - aio->a_cancel_fn = NULL; - aio->a_cancel_arg = NULL; - // Place a temporary hold on the aio. This prevents it - // from being destroyed. - q->eq_aio = aio; + aio->a_cancel_fn = NULL; + aio->a_cancel_arg = NULL; - // We let the cancel function handle the completion. - // If there is no cancellation function, then we cannot - // terminate the aio - we've tried, but it has to run - // to it's natural conclusion. - nni_mtx_unlock(mtx); - cancel_fn(aio, cancel_arg, rv); - - // Get updated time before reacquiring lock. - now = nni_clock(); - - nni_mtx_lock(mtx); - - q->eq_aio = NULL; + // We let the cancel function handle the completion. + // If there is no cancellation function, then we cannot + // terminate the aio - we've tried, but it has to run + // to its natural conclusion. + if (cancel_fn != NULL) { + nni_mtx_unlock(mtx); + cancel_fn(aio, cancel_arg, rv); + nni_mtx_lock(mtx); + } + aio->a_expiring = false; + } nni_cv_wake(cv); + + if (now < q->eq_next) { + nni_cv_until(cv, q->eq_next); + } } } @@ -766,7 +754,6 @@ nni_aio_expire_q_free(nni_aio_expire_q *eq) nni_mtx_unlock(&eq->eq_mtx); } - nni_free(eq->eq_list, eq->eq_cap * sizeof(nni_aio *)); nni_thr_fini(&eq->eq_thr); nni_cv_fini(&eq->eq_cv); nni_mtx_fini(&eq->eq_mtx); @@ -783,9 +770,8 @@ nni_aio_expire_q_alloc(void) } nni_mtx_init(&eq->eq_mtx); nni_cv_init(&eq->eq_cv, &eq->eq_mtx); - eq->eq_cap = NNI_EXPIRE_Q_SIZE; - eq->eq_len = 0; - eq->eq_list = nni_zalloc(eq->eq_cap * sizeof(nni_aio *)); + NNI_LIST_INIT(&eq->eq_list, nni_aio, a_expire_node); + eq->eq_next = NNI_TIME_NEVER; eq->eq_exit = false; if (nni_thr_init(&eq->eq_thr, nni_aio_expire_loop, eq) != 0) { diff --git a/src/core/aio.h b/src/core/aio.h index 2e0d6bab2..944a48ec1 100644 --- a/src/core/aio.h +++ b/src/core/aio.h @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -177,10 +177,10 @@ extern void nni_aio_set_packetid(nni_aio *aio, uint16_t id); typedef struct nni_aio_expire_q nni_aio_expire_q; -// An nni_aio is an async I/O handle. The details of this aio structure +// nng_aio is an async I/O handle. The details of this aio structure // are private to the AIO framework. The structure has the public name // (nng_aio) so that we minimize the pollution in the public API namespace. -// It is a coding error for anything out side of the AIO framework to access +// It is a coding error for anything outside the AIO framework to access // any of these members -- the definition is provided here to facilitate // inlining, but that should be the only use. struct nng_aio { @@ -191,6 +191,7 @@ struct nng_aio { bool a_stop; // Shutting down (no new operations) bool a_sleep; // Sleeping with no action bool a_expire_ok; // Expire from sleep is ok + bool a_expiring; // Expiration in progress nni_task a_task; // Read/write operations. @@ -208,9 +209,9 @@ struct nng_aio { // Provider-use fields. nni_aio_cancel_fn a_cancel_fn; - void * a_cancel_arg; + void *a_cancel_arg; nni_list_node a_prov_node; // Linkage on provider list. - void * a_prov_extra[2]; // Extra data used by provider + void *a_prov_extra[2]; // Extra data used by provider nni_aio_expire_q *a_expire_q; nni_list_node a_expire_node; // Expiration node diff --git a/src/core/defs.h b/src/core/defs.h index 584335fa2..f07e9c0b8 100644 --- a/src/core/defs.h +++ b/src/core/defs.h @@ -185,9 +185,10 @@ typedef struct conn_propt nano_conn_propt; #define NNI_NANO_MAX_HEADER_SIZE sizeof(uint8_t) * 5 // ONLY FIXED HEADER #endif -// NNI_EXPIRE_Q_SIZE is the default size of aio expire queue -#ifndef NNI_EXPIRE_Q_SIZE -#define NNI_EXPIRE_Q_SIZE 256 +// NNI_EXPIRE_BATCH lets us handle expiration in batches, +// reducing the number of traverses of the expiration list we perform. +#ifndef NNI_EXPIRE_BATCH +#define NNI_EXPIRE_BATCH 100 #endif From 1ae437df62a420cadbd290ed0a4d178e9441353c Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Tue, 10 Aug 2021 17:09:53 -0700 Subject: [PATCH 008/180] Bump version v1.5.2 --- include/nng/nng.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index 11591507e..beaf625dc 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -49,9 +49,9 @@ extern "C" { // We use SemVer, and these versions are about the API, and // may not necessarily match the ABI versions. #define NNG_MAJOR_VERSION 1 -#define NNG_MINOR_VERSION 4 -#define NNG_PATCH_VERSION 0 -#define NNG_RELEASE_SUFFIX "DEV" // if non-empty, this is a pre-release +#define NNG_MINOR_VERSION 5 +#define NNG_PATCH_VERSION 2 +#define NNG_RELEASE_SUFFIX "" // if non-empty, this is a pre-release // Maximum length of a socket address. This includes the terminating NUL. // This limit is built into other implementations, so do not change it. From 4a41148f8d856bfdc8a31aeb7056a2a4bd93e925 Mon Sep 17 00:00:00 2001 From: Jaylin Date: Sun, 15 Aug 2021 14:06:24 +0800 Subject: [PATCH 009/180] * FIX [mqtt_parser] band-aid fix for issue #200 --- include/nng/protocol/mqtt/mqtt_parser.h | 4 ++-- src/sp/protocol/mqtt/mqtt_parser.c | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 0977a5ae5..aaa08e2e8 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -9,10 +9,10 @@ #define DISCONNECT_MSG \ "{\"username\":\"%s\"," \ - "\"ts\":%lu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" + "\"ts\":%llu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" #define CONNECT_MSG \ "{\"username\":\"%s\", " \ - "\"ts\":%lu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":\"%x\",\"proto_ver\":%d,\"client_id\":\"%s\", \"clean_start\":%d}" + "\"ts\":%llu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":\"%x\",\"proto_ver\":%d,\"client_id\":\"%s\", \"clean_start\":%d}" #define DISCONNECT_TOPIC "$SYS/brokers/disconnected" #define CONNECT_TOPIC "$SYS/brokers/connected" diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 0ed6ec84c..ce9776cfd 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -796,13 +796,13 @@ nano_msg_notify_disconnect(conn_param *cparam, uint8_t code) nni_msg * msg; mqtt_string string, topic; uint8_t buff[256]; - snprintf(buff, 256, DISCONNECT_MSG, cparam->username.body, - (uint64_t) nni_clock(), code, cparam->clientid.body); + snprintf(buff, 256, DISCONNECT_MSG, cparam->username.body, nni_clock(), + code, cparam->clientid.body); string.body = buff; string.len = strlen(string.body); - topic.body = DISCONNECT_TOPIC; - topic.len = strlen(DISCONNECT_TOPIC); - msg = nano_msg_composer(0, 0, &string, &topic); + topic.body = DISCONNECT_TOPIC; + topic.len = strlen(DISCONNECT_TOPIC); + msg = nano_msg_composer(0, 0, &string, &topic); return msg; } @@ -812,12 +812,13 @@ nano_msg_notify_connect(conn_param *cparam, uint8_t code) nni_msg * msg; mqtt_string string, topic; uint8_t buff[256]; - snprintf(buff, 256, CONNECT_MSG, cparam->username.body, - (uint64_t) nni_clock(), cparam->pro_name.body, cparam->keepalive_mqtt, code, cparam->pro_ver, cparam->clientid.body, cparam->clean_start); + snprintf(buff, 256, CONNECT_MSG, cparam->username.body, nni_clock(), + cparam->pro_name.body, cparam->keepalive_mqtt, code, + cparam->pro_ver, cparam->clientid.body, cparam->clean_start); string.body = buff; string.len = strlen(string.body); - topic.body = CONNECT_TOPIC; - topic.len = strlen(CONNECT_TOPIC); - msg = nano_msg_composer(0, 0, &string, &topic); + topic.body = CONNECT_TOPIC; + topic.len = strlen(CONNECT_TOPIC); + msg = nano_msg_composer(0, 0, &string, &topic); return msg; } \ No newline at end of file From 59afa54fc77666de39b28152fdb55c33ebeb3504 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 7 Aug 2021 17:41:19 -0700 Subject: [PATCH 010/180] Remove separate protocol initialization step. Nothing is using this, but it adds complexity and also requires additional lock activity each time a socket is opened. --- src/core/init.c | 2 -- src/core/protocol.c | 79 ++++----------------------------------------- src/core/protocol.h | 21 ++---------- 3 files changed, 9 insertions(+), 93 deletions(-) diff --git a/src/core/init.c b/src/core/init.c index 564c01a90..9f39490a1 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -47,7 +47,6 @@ nni_init_helper(void) ((rv = nni_dialer_sys_init()) != 0) || ((rv = nni_pipe_sys_init()) != 0) || ((rv = nni_tls_sys_init()) != 0) || - ((rv = nni_proto_sys_init()) != 0) || ((rv = nni_sp_tran_sys_init()) != 0)) { nni_fini(); } @@ -81,7 +80,6 @@ nni_fini(void) nni_mtx_unlock(&nni_init_mtx); } nni_sp_tran_sys_fini(); - nni_proto_sys_fini(); nni_tls_sys_fini(); nni_pipe_sys_fini(); nni_dialer_sys_fini(); diff --git a/src/core/protocol.c b/src/core/protocol.c index 6d07f6473..993f0826a 100644 --- a/src/core/protocol.c +++ b/src/core/protocol.c @@ -1,5 +1,5 @@ // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -12,59 +12,20 @@ #include "core/nng_impl.h" -// Protocol related stuff - generically. -typedef struct nni_protocol nni_protocol; -struct nni_protocol { - const nni_proto *p_proto; - nni_list_node p_link; -}; - -static nni_mtx nni_proto_lk; -static nni_list nni_proto_list; -static int nni_proto_inited = 0; - -static int -nni_proto_init(const nni_proto *proto) -{ - nni_protocol *p; - int rv; - - nni_mtx_lock(&nni_proto_lk); - NNI_LIST_FOREACH (&nni_proto_list, p) { - if (p->p_proto == proto) { - nni_mtx_unlock(&nni_proto_lk); - return (0); - } - } - if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { - nni_mtx_unlock(&nni_proto_lk); - return (NNG_ENOMEM); - } - NNI_LIST_NODE_INIT(&p->p_link); - p->p_proto = proto; - if ((proto->proto_init != NULL) && ((rv = proto->proto_init()) != 0)) { - NNI_FREE_STRUCT(p); - nni_mtx_unlock(&nni_proto_lk); - return (rv); - } - nni_list_append(&nni_proto_list, p); - nni_mtx_unlock(&nni_proto_lk); - return (0); -} int -nni_proto_open(nng_socket *sockidp, const nni_proto *proto) +nni_proto_open(nng_socket *sip, const nni_proto *proto) { int rv; nni_sock *sock; - if (((rv = nni_init()) != 0) || ((rv = nni_proto_init(proto)) != 0)) { + if ((rv = nni_init()) != 0) { return (rv); } if ((rv = nni_sock_open(&sock, proto)) == 0) { nng_socket s; s.id = nni_sock_id(sock); // Keep socket held open. - *sockidp = s; + *sip = s; } return (rv); } @@ -76,7 +37,7 @@ nni_proto_mqtt_open(nng_socket *sockidp, const nni_proto *proto, int rv; nni_sock *sock; - if (((rv = nni_init()) != 0) || ((rv = nni_proto_init(proto)) != 0)) { + if ((rv = nni_init()) != 0) { return (rv); } if ((rv = nni_sock_open(&sock, proto)) == 0) { @@ -84,32 +45,4 @@ nni_proto_mqtt_open(nng_socket *sockidp, const nni_proto *proto, sock_setdb(nni_sock_proto_data(sock), sockidp->data); } return (rv); -} - -int -nni_proto_sys_init(void) -{ - NNI_LIST_INIT(&nni_proto_list, nni_protocol, p_link); - nni_mtx_init(&nni_proto_lk); - nni_proto_inited = 1; - return (0); -} - -void -nni_proto_sys_fini(void) -{ - if (nni_proto_inited) { - nni_protocol *p; - nni_mtx_lock(&nni_proto_lk); - while ((p = nni_list_first(&nni_proto_list)) != NULL) { - nni_list_remove(&nni_proto_list, p); - if (p->p_proto->proto_fini != NULL) { - p->p_proto->proto_fini(); - } - NNI_FREE_STRUCT(p); - } - nni_mtx_unlock(&nni_proto_lk); - } - nni_proto_inited = 0; - nni_mtx_fini(&nni_proto_lk); -} +} \ No newline at end of file diff --git a/src/core/protocol.h b/src/core/protocol.h index 9c6c49354..a50b0e32b 100644 --- a/src/core/protocol.h +++ b/src/core/protocol.h @@ -52,7 +52,7 @@ struct nni_proto_pipe_ops { // pipe_stop is called during finalization, to ensure that // the protocol is absolutely finished with the pipe. It should // wait if necessary to ensure that the pipe is not referenced - // anymore by the protocol. It should not destroy resources. + // any more by the protocol. It should not destroy resources. void (*pipe_stop)(void *); }; @@ -125,15 +125,6 @@ struct nni_proto { const nni_proto_sock_ops *proto_sock_ops; // Per-socket operations const nni_proto_pipe_ops *proto_pipe_ops; // Per-pipe operations const nni_proto_ctx_ops * proto_ctx_ops; // Context operations - - // proto_init, if not NULL, provides a function that initializes - // global values. The main purpose of this may be to initialize - // protocol option values. - int (*proto_init)(void); - - // proto_fini, if not NULL, is called at shutdown, to release - // any resources allocated at proto_init time. - void (*proto_fini)(void); }; // We quite intentionally use a signature where the upper word is nonzero, @@ -144,8 +135,8 @@ struct nni_proto { // during the life of the project. If we add a new version, please keep // the old version around -- it may be possible to automatically convert // older versions in the future. -#define NNI_PROTOCOL_V2 0x50520002u // "pr\0\2" -#define NNI_PROTOCOL_VERSION NNI_PROTOCOL_V2 +#define NNI_PROTOCOL_V3 0x50520003u // "pr\0\3" +#define NNI_PROTOCOL_VERSION NNI_PROTOCOL_V3 // These flags determine which operations make sense. We use them so that // we can reject attempts to create notification fds for operations that make @@ -194,12 +185,6 @@ extern int nni_proto_open(nng_socket *, const nni_proto *); // STARv0 100 0 star mangos only, experimental // -extern int nni_proto_sys_init(void); -extern void nni_proto_sys_fini(void); - -// For Nanomq - extern int nni_proto_mqtt_open(nng_socket *, const nni_proto *, void (*sock_setdb)(void *, void *)); - #endif // CORE_PROTOCOL_H From 312fcfce34f892fe94a12ca9edc87ebbe75fcb32 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Tue, 17 Aug 2021 19:17:50 +0800 Subject: [PATCH 011/180] * FIX [nng/tcp] mqtt CONNECT length protection #203 --- src/sp/protocol/mqtt/mqtt_parser.c | 4 ++-- src/sp/transport/tcp/tcp.c | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index ce9776cfd..57e686f11 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -309,7 +309,7 @@ sizeof(struct conn_param)); /** * only use in nego_cb !!! - * + * TODO CONNECT packet validation */ int32_t conn_handler(uint8_t *packet, conn_param *cparam) @@ -325,7 +325,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) return rv; } else { pos++; - } + } init_conn_param(cparam); // remaining length diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 9b12f6d0e..031c4444b 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -285,8 +285,7 @@ tcptran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); return; } - if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE && - p->wantrxhead == NANO_CONNECT_PACKET_LEN) { + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { if (p->rxlen[0] != CMD_CONNECT) { debug_msg("CMD TYPE %x", p->rxlen[0]); rv = NNG_EPROTO; @@ -295,10 +294,13 @@ tcptran_pipe_nego_cb(void *arg) len = get_var_integer(p->rxlen + 1, (uint32_t *) &len_of_varint); p->wantrxhead = len + 1 + len_of_varint; + rv = (p->wantrxhead >= NANO_CONNECT_PACKET_LEN)? 0 : NNG_EPROTO; + if (rv !=0) { + goto error; + } } - if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE || - p->gotrxhead < p->wantrxhead) { + if (p->gotrxhead < p->wantrxhead) { nni_iov iov; iov.iov_len = p->wantrxhead - p->gotrxhead; if (p->conn_buf == NULL) { @@ -963,7 +965,7 @@ tcptran_pipe_recv_start(tcptran_pipe *p) { nni_aio *rxaio; nni_iov iov; - debug_msg("second oder! tcptran_pipe_recv_start\n"); + debug_msg("*** tcptran_pipe_recv_start ***\n"); NNI_ASSERT(p->rxmsg == NULL); if (p->closed) { From 956a72fa3a2303dadee269bb0be2e028d5585e2c Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 27 Aug 2021 19:02:40 +0800 Subject: [PATCH 012/180] * NEW [NNG/WS] add mqtt over websocket support - modify transport layer for mqtt 1.CONNECT --- src/sp/transport/ws/websocket.c | 133 +++++++++++++++++++++++++++----- 1 file changed, 113 insertions(+), 20 deletions(-) diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 7cf9949f1..ce6721f20 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -19,6 +19,10 @@ #include #include +#include "nng/nng_debug.h" +#include "nng/protocol/mqtt/mqtt.h" +#include "nng/protocol/mqtt/mqtt_parser.h" + typedef struct ws_dialer ws_dialer; typedef struct ws_listener ws_listener; typedef struct ws_pipe ws_pipe; @@ -45,10 +49,17 @@ struct ws_pipe { nni_mtx mtx; bool closed; uint16_t peer; + size_t gotrxhead; + size_t wantrxhead; + nni_msg * tmp_msg; nni_aio * user_txaio; nni_aio * user_rxaio; + nni_aio * ep_aio; nni_aio * txaio; nni_aio * rxaio; + nni_pipe * npipe; + uint8_t * qos_buf; + conn_param *ws_param; nng_stream *ws; }; @@ -78,27 +89,103 @@ wstran_pipe_send_cb(void *arg) static void wstran_pipe_recv_cb(void *arg) { - ws_pipe *p = arg; + ws_pipe *p = arg; + uint32_t len = 0, rv, pos = 1; nni_aio *raio = p->rxaio; nni_aio *uaio; - int rv; nni_mtx_lock(&p->mtx); - uaio = p->user_rxaio; - p->user_rxaio = NULL; + uaio = p->user_rxaio; + // p->user_rxaio = NULL; + // process scatterd msgs if ((rv = nni_aio_result(raio)) != 0) { - if (uaio != NULL) { - nni_aio_finish_error(uaio, rv); + goto reset; + } + nni_msg *msg = nni_aio_get_msg(raio); + uint8_t *ptr = nni_msg_body(msg); + uint8_t *hdr = nni_msg_header(msg); + p->gotrxhead += nni_msg_len(msg); + debug_msg("#### wstran_pipe_recv_cb got %d msg: %p %x %p %x %d", + p->gotrxhead, *hdr, ptr, *ptr, nni_msg_len(msg)); + // first we collect complete Fixheader + if (p->tmp_msg == NULL) { + if ((rv = nni_msg_alloc(&p->tmp_msg, 0)) != 0) { + debug_syslog("mem error %ld\n", (size_t) len); + goto reset; } - } else { - nni_msg *msg = nni_aio_get_msg(raio); - if (uaio != NULL) { - nni_aio_finish_msg(uaio, msg); + } + nni_msg_append(p->tmp_msg, ptr, nni_msg_len(msg)); + ptr = nni_msg_body(p->tmp_msg); // packet might be sticky? + + if (p->wantrxhead == 0) { + if (p->gotrxhead == 1) { + goto recv; + } + len = get_var_integer(ptr, &pos); + if (*(ptr + pos) > 0x7f) { // continue to next byte of + // remaining length + if (p->gotrxhead >= NNI_NANO_MAX_HEADER_SIZE) { + // length error + rv = NNG_EMSGSIZE; + goto reset; + } + // goto recv; } else { - nni_msg_free(msg); + // Fixed header finished + p->wantrxhead = len + pos; + nni_msg_set_cmd_type(p->tmp_msg, *ptr & 0xf0); + // goto recv; } } + if (p->gotrxhead >= p->wantrxhead) { + p->gotrxhead = 0; + goto done; + } + debug_msg("?????????????? len : %d", len); + +recv: + nni_msg_free(msg); + nng_stream_recv(p->ws, raio); nni_mtx_unlock(&p->mtx); + return; +done: + if (uaio == NULL) { + uaio = p->ep_aio; + } + if (uaio != NULL) { + p->gotrxhead = 0; + p->wantrxhead = 0; + nni_msg_free(msg); + if (nni_msg_cmd_type(p->tmp_msg) == CMD_CONNECT) { + // end of nego + if (p->ws_param == NULL) { + p->ws_param = + nng_alloc(sizeof(struct conn_param)); + } + if (conn_handler( + nni_msg_body(p->tmp_msg), p->ws_param) == 0) { + nni_msg_set_conn_param( + p->tmp_msg, p->ws_param); + } + } + nni_aio_set_msg(uaio, p->tmp_msg); + nni_aio_set_output(uaio, 0, p); + nni_aio_finish(uaio, 0, nni_msg_len(p->tmp_msg)); + p->tmp_msg = NULL; + } + nni_mtx_unlock(&p->mtx); + return; +reset: + // reset the connection, remember to free the message before enter here + p->gotrxhead = 0; + p->wantrxhead = 0; + if (uaio != NULL) { + nni_aio_finish_error(uaio, rv); + } else if (p->ep_aio != NULL) { + nni_aio_finish_error(p->ep_aio, rv); + } + nni_mtx_unlock(&p->mtx); + return; } static void @@ -186,8 +273,15 @@ wstran_pipe_stop(void *arg) static int wstran_pipe_init(void *arg, nni_pipe *pipe) { - NNI_ARG_UNUSED(arg); - NNI_ARG_UNUSED(pipe); + debug_msg("************wstran_pipe_init************"); + ws_pipe *p = arg; + + nni_pipe_set_conn_param(pipe, p->ws_param); + p->npipe = pipe; + p->gotrxhead = 0; + p->wantrxhead = 0; + // p->qos_buf = nng_alloc(16 + NNI_NANO_MAX_PACKET_SIZE); + p->ep_aio = NULL; return (0); } @@ -469,12 +563,12 @@ wstran_accept_cb(void *arg) nni_aio_finish_error(uaio, rv); } else { p->peer = l->peer; - - nni_aio_set_output(uaio, 0, p); - nni_aio_finish(uaio, 0, 0); + ws_pipe_start(p, p->ws); + p->ep_aio = uaio; } } } + if (!nni_list_empty(&l->aios)) { nng_stream_listener_accept(l->listener, aaio); } @@ -498,8 +592,7 @@ wstran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) d->peer = nni_sock_peer_id(s); - snprintf( - name, sizeof(name), "%s.sp.nanomsg.org", nni_sock_peer_name(s)); + snprintf(name, sizeof(name), "mqtt"); if (((rv = nni_ws_dialer_alloc(&d->dialer, url)) != 0) || ((rv = nni_aio_alloc(&d->connaio, wstran_connect_cb, d)) != 0) || @@ -515,6 +608,7 @@ wstran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) return (0); } +// TODO proto name modify static int wstran_listener_init(void **lp, nng_url *url, nni_listener *listener) { @@ -532,8 +626,7 @@ wstran_listener_init(void **lp, nng_url *url, nni_listener *listener) l->peer = nni_sock_peer_id(s); - snprintf( - name, sizeof(name), "%s.sp.nanomsg.org", nni_sock_proto_name(s)); + snprintf(name, sizeof(name), "mqtt"); if (((rv = nni_ws_listener_alloc(&l->listener, url)) != 0) || ((rv = nni_aio_alloc(&l->accaio, wstran_accept_cb, l)) != 0) || From 6c1aae5c7878bc346ae12fdc4e425eb003b52bba Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 27 Aug 2021 19:05:00 +0800 Subject: [PATCH 013/180] * NEW [nng/sp] add ws_pipe_start func --- src/sp/transport/ws/websocket.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index ce6721f20..553f28729 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -537,6 +537,16 @@ wstran_listener_close(void *arg) nng_stream_listener_close(l->listener); } +static void +ws_pipe_start(ws_pipe *pipe, nng_stream *conn) +{ + ws_pipe *p = pipe; + int rv; + debug_msg("ws_pipe_start!"); + + nng_stream_recv(p->ws, p->rxaio); +} + static void wstran_accept_cb(void *arg) { From 96f845c4677d42a4c78d8237796bcc5711c1c9a8 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Sat, 28 Aug 2021 15:15:42 +0800 Subject: [PATCH 014/180] * NEW [nng/ws] add support for mqtt over websocket 2. PINGREQ/PINGRESQ --- src/sp/protocol/mqtt/mqtt_parser.c | 8 +++++--- src/sp/protocol/reqrep0/nano_tcp.c | 1 + src/sp/transport/tcp/tcp.c | 2 +- src/sp/transport/ws/websocket.c | 29 +++++++++++++++-------------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 57e686f11..c903617d1 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -270,16 +270,18 @@ get_variable_binary(uint8_t **dest, const uint8_t *src) return len; } +//set header & remaining length of msg int fixed_header_adaptor(uint8_t *packet, nng_msg *dst) { nni_msg *m; int rv; + uint32_t len; size_t pos = 1; - m = (nni_msg *) dst; - get_var_integer(packet, (uint32_t *) &pos); - + m = (nni_msg *) dst; + len = get_var_integer(packet, (uint32_t *) &pos); + nni_msg_set_remaining_len(m, len); rv = nni_msg_header_append(m, packet, pos); return rv; } diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 1698ea728..763e6bcfb 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -1069,6 +1069,7 @@ nano_pipe_recv_cb(void *arg) case CMD_UNSUBSCRIBE: case CMD_CONNACK: case CMD_CONNECT: + case CMD_PINGREQ: break; case CMD_PUBACK: case CMD_PUBCOMP: diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 031c4444b..8eaf69786 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -544,7 +544,7 @@ tcptran_pipe_recv_cb(void *arg) fixed_header_adaptor(p->rxlen, msg); nni_msg_set_conn_param(msg, cparam); - nni_msg_set_remaining_len(msg, len); + nni_msg_set_remaining_len(msg, len); //duplicated with fixed_header_adaptor nni_msg_set_cmd_type(msg, type); debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", len, cparam, cparam->clientid.body, cparam->username.body, diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 553f28729..46e6a69af 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -74,6 +74,7 @@ wstran_pipe_send_cb(void *arg) taio = p->txaio; uaio = p->user_txaio; p->user_txaio = NULL; + p->tmp_msg = NULL; if (uaio != NULL) { int rv; @@ -92,11 +93,13 @@ wstran_pipe_recv_cb(void *arg) ws_pipe *p = arg; uint32_t len = 0, rv, pos = 1; nni_aio *raio = p->rxaio; - nni_aio *uaio; + nni_aio *uaio = NULL; nni_mtx_lock(&p->mtx); - uaio = p->user_rxaio; - // p->user_rxaio = NULL; + //only sets uaio at first time + if (p->user_rxaio != NULL) { + uaio = p->user_rxaio; + } // process scatterd msgs if ((rv = nni_aio_result(raio)) != 0) { goto reset; @@ -129,19 +132,16 @@ wstran_pipe_recv_cb(void *arg) rv = NNG_EMSGSIZE; goto reset; } - // goto recv; } else { // Fixed header finished p->wantrxhead = len + pos; nni_msg_set_cmd_type(p->tmp_msg, *ptr & 0xf0); - // goto recv; + nni_msg_set_payload_ptr(p->tmp_msg, ptr + pos); } } if (p->gotrxhead >= p->wantrxhead) { - p->gotrxhead = 0; goto done; } - debug_msg("?????????????? len : %d", len); recv: nni_msg_free(msg); @@ -159,19 +159,20 @@ wstran_pipe_recv_cb(void *arg) if (nni_msg_cmd_type(p->tmp_msg) == CMD_CONNECT) { // end of nego if (p->ws_param == NULL) { - p->ws_param = - nng_alloc(sizeof(struct conn_param)); + p->ws_param = nng_alloc(sizeof(struct conn_param)); } - if (conn_handler( - nni_msg_body(p->tmp_msg), p->ws_param) == 0) { - nni_msg_set_conn_param( - p->tmp_msg, p->ws_param); + if (conn_handler(nni_msg_body(p->tmp_msg), p->ws_param) != 0) { + goto reset; } + } else { + fixed_header_adaptor(nni_msg_body(p->tmp_msg), p->tmp_msg); + nni_msg_set_conn_param(p->tmp_msg, p->ws_param); } nni_aio_set_msg(uaio, p->tmp_msg); nni_aio_set_output(uaio, 0, p); nni_aio_finish(uaio, 0, nni_msg_len(p->tmp_msg)); - p->tmp_msg = NULL; + } else { + goto reset; } nni_mtx_unlock(&p->mtx); return; From d6f27d404e667ebeb20e840ba6d91ad9fc0e9526 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 30 Aug 2021 14:52:02 +0800 Subject: [PATCH 015/180] * RM [nng/api] remove duplicated variable_ptr api. --- include/nng/nng.h | 1 - src/core/message.c | 6 ------ src/core/message.h | 1 - src/nng.c | 6 ------ src/sp/transport/tcp/tcp.c | 2 +- src/sp/transport/ws/websocket.c | 3 ++- 6 files changed, 3 insertions(+), 16 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index beaf625dc..4c425efa5 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1291,7 +1291,6 @@ NNG_DECL int nng_msg_cmd_type(nng_msg *msg); NNG_DECL void * nng_msg_get_conn_param(nng_msg *msg); NNG_DECL size_t nng_msg_remaining_len(nng_msg *msg); NNG_DECL uint8_t *nng_msg_header_ptr(nng_msg *msg); -NNG_DECL uint8_t *nng_msg_variable_ptr(nng_msg *msg); NNG_DECL uint8_t *nng_msg_payload_ptr(nng_msg *msg); NNG_DECL void nng_msg_set_payload_ptr(nng_msg *msg, uint8_t *ptr); NNG_DECL void nng_msg_set_remaining_len(nng_msg *msg, size_t len); diff --git a/src/core/message.c b/src/core/message.c index 099ab0ea9..f88fa1fee 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -658,12 +658,6 @@ nni_msg_header_ptr(const nni_msg *m) return ((uint8_t *) m->m_header_buf); } -uint8_t * -nni_msg_variable_ptr(const nni_msg *m) -{ - return (m->m_body.ch_ptr); -} - uint8_t * nni_msg_payload_ptr(const nni_msg *m) { diff --git a/src/core/message.h b/src/core/message.h index ec2a3eeb5..00287f05d 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -69,7 +69,6 @@ extern nni_time nni_msg_get_timestamp(nni_msg *m); extern void nni_msg_set_timestamp(nni_msg *m, nni_time time); extern int nni_msg_cmd_type(nni_msg *m); extern uint8_t * nni_msg_header_ptr(const nni_msg *m); -extern uint8_t * nni_msg_variable_ptr(const nni_msg *m); extern uint8_t * nni_msg_payload_ptr(const nni_msg *m); extern uint8_t nni_msg_get_pub_qos(nni_msg *m); extern size_t nni_msg_remaining_len(const nni_msg *m); diff --git a/src/nng.c b/src/nng.c index f52b84dac..d8437c343 100644 --- a/src/nng.c +++ b/src/nng.c @@ -1927,12 +1927,6 @@ nng_msg_header_ptr(nng_msg *msg) return (nni_msg_header_ptr(msg)); } -uint8_t * -nng_msg_variable_ptr(nng_msg *msg) -{ - return (nni_msg_variable_ptr(msg)); -} - uint8_t * nng_msg_payload_ptr(nng_msg *msg) { diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 8eaf69786..2c911e86b 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -549,7 +549,7 @@ tcptran_pipe_recv_cb(void *arg) debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", len, cparam, cparam->clientid.body, cparam->username.body, cparam->pro_ver); - variable_ptr = nni_msg_variable_ptr(msg); + variable_ptr = nni_msg_body(msg); // set the payload pointer of msg according to packet_type debug_msg("The type of msg is %x", type); diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 46e6a69af..87de55458 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -165,7 +165,8 @@ wstran_pipe_recv_cb(void *arg) goto reset; } } else { - fixed_header_adaptor(nni_msg_body(p->tmp_msg), p->tmp_msg); + ptr = nni_msg_body(p->tmp_msg); + fixed_header_adaptor(ptr, p->tmp_msg); nni_msg_set_conn_param(p->tmp_msg, p->ws_param); } nni_aio_set_msg(uaio, p->tmp_msg); From 68052639e26e5b0ad95e5a8af944b1300eed3e3c Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 30 Aug 2021 19:36:30 +0800 Subject: [PATCH 016/180] * NEW [nng] move msg ptr related logic out from transport layer. --- include/nng/protocol/mqtt/mqtt_parser.h | 1 + src/sp/protocol/mqtt/mqtt_parser.c | 23 ++++++++++++++++ src/sp/protocol/reqrep0/nano_tcp.c | 36 ++++++++++++++++++++----- src/sp/transport/tcp/tcp.c | 16 +---------- src/sp/transport/ws/websocket.c | 28 ++++++++++++------- 5 files changed, 72 insertions(+), 32 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index aaa08e2e8..5bd5ba5bf 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -26,6 +26,7 @@ int32_t conn_handler(uint8_t *packet, conn_param *conn_param); void init_conn_param(conn_param *cparam); void destroy_conn_param(conn_param *cparam); int fixed_header_adaptor(uint8_t *packet, nng_msg *dst); +int ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst); // parser NNG_DECL uint8_t put_var_integer(uint8_t *dest, uint32_t value); diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index c903617d1..b49d7fc67 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -285,7 +285,30 @@ fixed_header_adaptor(uint8_t *packet, nng_msg *dst) rv = nni_msg_header_append(m, packet, pos); return rv; } +/** + * @brief copy packet (original msg suppose have full MQTT bytes in payload) to dst msg (new empty one) + * + * @param packet + * @param dst assume it as an empty message + * @return int + */ +int +ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst) +{ + nni_msg *m; + int rv; + uint32_t len; + uint8_t *ptr; + size_t pos = 1; + m = (nni_msg *) dst; + len = get_var_integer(packet, (uint32_t *) &pos); + nni_msg_set_cmd_type(m, *packet & 0xf0); + nni_msg_set_remaining_len(m, len); + rv = nni_msg_header_append(m, packet, pos); + nni_msg_append(m, packet + pos, len); + return rv; +} /* int variable_header_adaptor(uint8_t *packet, nni_msg *dst) { diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 763e6bcfb..c4d45d986 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -1028,13 +1028,12 @@ nano_pipe_recv_cb(void *arg) nano_pipe * p = arg; nano_sock * s = p->rep; nano_ctx * ctx; - nni_msg * msg; + nni_msg * msg, *qos_msg; nni_aio * aio; nano_pipe_db *pipe_db; nni_pipe * npipe = p->pipe; - uint8_t * ptr; - uint16_t ackid; - nni_msg * qos_msg; + uint8_t * ptr; + uint16_t ackid; if (nni_aio_result(&p->aio_recv) != 0) { //unexpected disconnect @@ -1050,21 +1049,45 @@ nano_pipe_recv_cb(void *arg) // ttl = nni_atomic_get(&s->ttl); nni_msg_set_pipe(msg, p->id); + //nni_msg_set_conn_param(msg, p->conn_param); + ptr = nni_msg_body(msg); // TODO HOOK switch (nng_msg_cmd_type(msg)) { + conn_param *cparam; + uint32_t len, len_of_varint = 0; + uint8_t qos_pac; + size_t tlen; case CMD_SUBSCRIBE: // TODO only cache topic hash when it is above qos 1/2 nni_mtx_lock(&p->lk); + cparam = p->conn_param; + if (cparam->pro_ver == PROTOCOL_VERSION_v5) { + len = get_var_integer(ptr + 2, &len_of_varint); + nni_msg_set_payload_ptr( + msg, ptr + 2 + len + len_of_varint); + } else { + nni_msg_set_payload_ptr(msg, ptr + 2); + } pipe_db = nano_msg_get_subtopic(msg, p->pipedb_root); // TODO potential memleak when sub failed p->pipedb_root = pipe_db; while (pipe_db) { - nni_id_set(&npipe->nano_db, DJBHash(pipe_db->topic), pipe_db); + nni_id_set( + &npipe->nano_db, DJBHash(pipe_db->topic), pipe_db); pipe_db = pipe_db->next; } nni_mtx_unlock(&p->lk); break; case CMD_PUBLISH: + NNI_GET16(ptr, tlen); + cparam = p->conn_param; + qos_pac = nni_msg_get_pub_qos(msg); + if (cparam->pro_ver != PROTOCOL_VERSION_v5) { + nni_msg_set_payload_ptr( + msg, ptr + tlen + 2 + (qos_pac > 0 ? 2 : 0)); + } else { + } + break; case CMD_DISCONNECT: case CMD_UNSUBSCRIBE: case CMD_CONNACK: @@ -1073,8 +1096,7 @@ nano_pipe_recv_cb(void *arg) break; case CMD_PUBACK: case CMD_PUBCOMP: - nni_mtx_lock(&p->lk); - ptr = nni_msg_body(msg); + nni_mtx_lock(&p->lk); NNI_GET16(ptr, ackid); if ((qos_msg = nni_id_get(npipe->nano_qos_db, ackid)) != NULL) { diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 2c911e86b..bde19cd4b 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -553,16 +553,7 @@ tcptran_pipe_recv_cb(void *arg) // set the payload pointer of msg according to packet_type debug_msg("The type of msg is %x", type); - if (type == CMD_SUBSCRIBE) { - if (cparam->pro_ver == PROTOCOL_VERSION_v5) { - len_of_varint = 0; - len = - get_var_integer(variable_ptr + 2, &len_of_varint); - payload_ptr = variable_ptr + 2 + len + len_of_varint; - } else { - payload_ptr = variable_ptr + 2; - } - } else if (type == CMD_UNSUBSCRIBE) { + if (type == CMD_UNSUBSCRIBE) { if (cparam->pro_ver == PROTOCOL_VERSION_v5) { len_of_varint = 0; len = @@ -576,12 +567,7 @@ tcptran_pipe_recv_cb(void *arg) uint16_t pid; size_t tlen; - NNI_GET16(variable_ptr, tlen); qos_pac = nni_msg_get_pub_qos(msg); - if (cparam->pro_ver != PROTOCOL_VERSION_v5) { - payload_ptr = - variable_ptr + tlen + 2 + (qos_pac > 0 ? 2 : 0); - } if (qos_pac > 0) { nng_aio_wait(p->rsaio); if (qos_pac == 1) { diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 87de55458..93c07f1fa 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -92,6 +92,8 @@ wstran_pipe_recv_cb(void *arg) { ws_pipe *p = arg; uint32_t len = 0, rv, pos = 1; + uint8_t *ptr; + nni_msg *smsg, *msg; nni_aio *raio = p->rxaio; nni_aio *uaio = NULL; @@ -104,12 +106,11 @@ wstran_pipe_recv_cb(void *arg) if ((rv = nni_aio_result(raio)) != 0) { goto reset; } - nni_msg *msg = nni_aio_get_msg(raio); - uint8_t *ptr = nni_msg_body(msg); - uint8_t *hdr = nni_msg_header(msg); + msg = nni_aio_get_msg(raio); + ptr = nni_msg_body(msg); p->gotrxhead += nni_msg_len(msg); - debug_msg("#### wstran_pipe_recv_cb got %d msg: %p %x %p %x %d", - p->gotrxhead, *hdr, ptr, *ptr, nni_msg_len(msg)); + debug_msg("#### wstran_pipe_recv_cb got %d msg: %p %x %d", + p->gotrxhead, ptr, *ptr, nni_msg_len(msg)); // first we collect complete Fixheader if (p->tmp_msg == NULL) { if ((rv = nni_msg_alloc(&p->tmp_msg, 0)) != 0) { @@ -125,8 +126,7 @@ wstran_pipe_recv_cb(void *arg) goto recv; } len = get_var_integer(ptr, &pos); - if (*(ptr + pos) > 0x7f) { // continue to next byte of - // remaining length + if (*(ptr + pos) > 0x7f) { // continue to next byte of remaining length if (p->gotrxhead >= NNI_NANO_MAX_HEADER_SIZE) { // length error rv = NNG_EMSGSIZE; @@ -136,7 +136,6 @@ wstran_pipe_recv_cb(void *arg) // Fixed header finished p->wantrxhead = len + pos; nni_msg_set_cmd_type(p->tmp_msg, *ptr & 0xf0); - nni_msg_set_payload_ptr(p->tmp_msg, ptr + pos); } } if (p->gotrxhead >= p->wantrxhead) { @@ -165,13 +164,18 @@ wstran_pipe_recv_cb(void *arg) goto reset; } } else { - ptr = nni_msg_body(p->tmp_msg); - fixed_header_adaptor(ptr, p->tmp_msg); + if (nni_msg_alloc(&smsg, 0) != 0) { + goto reset; + } + ws_fixed_header_adaptor(ptr, smsg); + nni_msg_free(p->tmp_msg); + p->tmp_msg = smsg; nni_msg_set_conn_param(p->tmp_msg, p->ws_param); } nni_aio_set_msg(uaio, p->tmp_msg); nni_aio_set_output(uaio, 0, p); nni_aio_finish(uaio, 0, nni_msg_len(p->tmp_msg)); + p->tmp_msg = NULL; } else { goto reset; } @@ -186,6 +190,10 @@ wstran_pipe_recv_cb(void *arg) } else if (p->ep_aio != NULL) { nni_aio_finish_error(p->ep_aio, rv); } + if (p->tmp_msg != NULL) { + nni_msg_free(p->tmp_msg); + p->tmp_msg = NULL; + } nni_mtx_unlock(&p->mtx); return; } From f8661a670d1f02c10ecb6cc4a376d58269ad34af Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Tue, 31 Aug 2021 18:28:44 +0800 Subject: [PATCH 017/180] * MDF [message/mqtt_parser] move nano_msg_get_subtopic API out from message.c --- include/nng/protocol/mqtt/mqtt_parser.h | 1 + src/core/message.c | 88 --------------------- src/core/message.h | 1 - src/sp/protocol/mqtt/mqtt_parser.c | 101 +++++++++++++++++++++++- 4 files changed, 101 insertions(+), 90 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 5bd5ba5bf..d0ef43502 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -52,5 +52,6 @@ NNG_DECL nng_msg *nano_msg_composer( uint8_t retain, uint8_t qos, mqtt_string *payload, mqtt_string *topic); NNG_DECL nng_msg *nano_msg_notify_disconnect(conn_param *cparam, uint8_t code); NNG_DECL nng_msg *nano_msg_notify_connect(conn_param *cparam, uint8_t code); +NNG_DECL nano_pipe_db * nano_msg_get_subtopic(nng_msg *msg, nano_pipe_db *root, conn_param *cparam); #endif // NNG_MQTT_H diff --git a/src/core/message.c b/src/core/message.c index f88fa1fee..ae8b90f1b 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -736,94 +736,6 @@ nni_msg_get_timestamp(nni_msg *m) return m->times; } -nano_pipe_db * -nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root) -{ - char *topic; - nano_pipe_db *db = NULL, *tmp = NULL, *iter = NULL; - uint8_t len_of_topic = 0, *payload_ptr; - size_t bpos = 0, remain = 0; - bool repeat = false; - - payload_ptr = (char *) nni_msg_payload_ptr(msg); - remain = nni_msg_remaining_len(msg) - 2; - - if (nni_msg_cmd_type(msg) != 0x80) - return NULL; - - if (root != NULL) { - db = root; - while (db->next != NULL) { - db = db->next; - } - } - - while (bpos < remain) { - NNI_GET16(payload_ptr + bpos, len_of_topic); - - if (len_of_topic != 0) { - - debug_msg("The current process topic is %s", - payload_ptr + bpos + 2); - iter = root; - while (iter) { - if (strlen(iter->topic) == len_of_topic && - !strncmp(payload_ptr + bpos + 2, - iter->topic, len_of_topic)) { - repeat = true; - bpos += (2 + len_of_topic); - if (iter->qos != - *(payload_ptr + bpos)) { - iter->qos = - *(payload_ptr + bpos); - } - bpos += 1; - } - iter = iter->next; - } - - if (repeat) { - repeat = false; - continue; - } - - if (NULL != db) { - tmp = db; - db = db->next; - } - db = nng_alloc(sizeof(nano_pipe_db)); - topic = nng_alloc(len_of_topic + 1); - db->prev = tmp; - if (bpos == 0 && root == NULL) { - root = db; - } else { - tmp->next = db; - } - db->root = root; - if (topic == NULL || db == NULL) { - NNI_ASSERT("ERROR: nng_alloc"); - return NULL; - } else { - bpos += 2; - } - strncpy( - topic, (char *) payload_ptr + bpos, len_of_topic); - topic[len_of_topic] = 0x00; - db->topic = topic; - bpos += len_of_topic; - } else { - NNI_ASSERT("ERROR : topic length error."); - return NULL; - } - db->qos = *(payload_ptr + bpos); - db->next = NULL; - debug_msg("sub topic: %s qos : %x\n", db->topic, db->qos); - bpos += 1; - } - - return root; -} - void nano_msg_free_pipedb(nano_pipe_db *db) { diff --git a/src/core/message.h b/src/core/message.h index 00287f05d..f72ff27a3 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -76,7 +76,6 @@ extern void nni_msg_set_payload_ptr(nni_msg *m, uint8_t *ptr); extern void nni_msg_set_remaining_len(nni_msg *m, size_t len); extern void nni_msg_set_cmd_type(nni_msg *m, uint8_t cmd); extern void nni_msg_set_conn_param(nni_msg *m, void *ptr); -extern nano_pipe_db *nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root); extern void nano_msg_free_pipedb(nano_pipe_db *db); extern void nano_msg_ubsub_free(nano_pipe_db *db); extern uint8_t nni_msg_get_preset_qos(nni_msg *m); diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index b49d7fc67..c3cfde638 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -306,7 +306,11 @@ ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst) nni_msg_set_cmd_type(m, *packet & 0xf0); nni_msg_set_remaining_len(m, len); rv = nni_msg_header_append(m, packet, pos); - nni_msg_append(m, packet + pos, len); + printf("len !!!! 2 %d\n", len); + if (len > 0) { + nni_msg_append(m, packet + pos, len); + } + return rv; } /* @@ -846,4 +850,99 @@ nano_msg_notify_connect(conn_param *cparam, uint8_t code) topic.len = strlen(CONNECT_TOPIC); msg = nano_msg_composer(0, 0, &string, &topic); return msg; +} + + +nano_pipe_db * +nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) +{ + char *topic; + nano_pipe_db *db = NULL, *tmp = NULL, *iter = NULL; + uint8_t len_of_topic = 0, *payload_ptr; + uint32_t len, len_of_varint; + size_t bpos = 0, remain = 0; + bool repeat = false; + + if (nni_msg_cmd_type(msg) != CMD_SUBSCRIBE) + return NULL; + + if (root != NULL) { + db = root; + while (db->next != NULL) { + db = db->next; + } + } + + if (cparam->pro_ver == PROTOCOL_VERSION_v5) { + len = get_var_integer(nni_msg_body(msg) + 2, &len_of_varint); + payload_ptr = nni_msg_body(msg) + 2 + len + len_of_varint; + } else { + payload_ptr = nni_msg_body(msg) + 2; + } + remain = nni_msg_remaining_len(msg) - 2; + + while (bpos < remain) { + NNI_GET16(payload_ptr + bpos, len_of_topic); + + if (len_of_topic != 0) { + + debug_msg("The current process topic is %s", + payload_ptr + bpos + 2); + iter = root; + while (iter) { + if (strlen(iter->topic) == len_of_topic && + !strncmp(payload_ptr + bpos + 2, + iter->topic, len_of_topic)) { + repeat = true; + bpos += (2 + len_of_topic); + if (iter->qos != + *(payload_ptr + bpos)) { + iter->qos = + *(payload_ptr + bpos); + } + bpos += 1; + } + iter = iter->next; + } + + if (repeat) { + repeat = false; + continue; + } + + if (NULL != db) { + tmp = db; + db = db->next; + } + db = nng_alloc(sizeof(nano_pipe_db)); + topic = nng_alloc(len_of_topic + 1); + db->prev = tmp; + if (bpos == 0 && root == NULL) { + root = db; + } else { + tmp->next = db; + } + db->root = root; + if (topic == NULL || db == NULL) { + NNI_ASSERT("ERROR: nng_alloc"); + return NULL; + } else { + bpos += 2; + } + strncpy( + topic, (char *) payload_ptr + bpos, len_of_topic); + topic[len_of_topic] = 0x00; + db->topic = topic; + bpos += len_of_topic; + } else { + NNI_ASSERT("ERROR : topic length error."); + return NULL; + } + db->qos = *(payload_ptr + bpos); + db->next = NULL; + debug_msg("sub topic: %s qos : %x\n", db->topic, db->qos); + bpos += 1; + } + + return root; } \ No newline at end of file From c1748cc7defe5b2de3bcaeeed3f6d4f853f59186 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Tue, 31 Aug 2021 18:39:03 +0800 Subject: [PATCH 018/180] * MDF [nano_tcp/tcp] set payload ptr at protocol layer --- src/sp/protocol/reqrep0/nano_tcp.c | 27 ++++++++++++++------------- src/sp/transport/tcp/tcp.c | 11 +---------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index c4d45d986..b24f18090 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -1040,7 +1040,7 @@ nano_pipe_recv_cb(void *arg) nni_pipe_close(p->pipe); return; } - debug_msg("#########nano_pipe_recv_cb !############"); + debug_msg("######### nano_pipe_recv_cb ############"); p->ka_refresh = 0; msg = nni_aio_get_msg(&p->aio_recv); if (msg == NULL) { @@ -1049,8 +1049,8 @@ nano_pipe_recv_cb(void *arg) // ttl = nni_atomic_get(&s->ttl); nni_msg_set_pipe(msg, p->id); - //nni_msg_set_conn_param(msg, p->conn_param); ptr = nni_msg_body(msg); + // TODO HOOK switch (nng_msg_cmd_type(msg)) { conn_param *cparam; @@ -1061,6 +1061,14 @@ nano_pipe_recv_cb(void *arg) // TODO only cache topic hash when it is above qos 1/2 nni_mtx_lock(&p->lk); cparam = p->conn_param; + pipe_db = nano_msg_get_subtopic(msg, p->pipedb_root, cparam); // TODO potential memleak when sub failed + p->pipedb_root = pipe_db; + while (pipe_db) { + nni_id_set(&npipe->nano_db, DJBHash(pipe_db->topic), pipe_db); + pipe_db = pipe_db->next; + } + nni_mtx_unlock(&p->lk); + case CMD_UNSUBSCRIBE: if (cparam->pro_ver == PROTOCOL_VERSION_v5) { len = get_var_integer(ptr + 2, &len_of_varint); nni_msg_set_payload_ptr( @@ -1068,15 +1076,7 @@ nano_pipe_recv_cb(void *arg) } else { nni_msg_set_payload_ptr(msg, ptr + 2); } - pipe_db = nano_msg_get_subtopic(msg, - p->pipedb_root); // TODO potential memleak when sub failed - p->pipedb_root = pipe_db; - while (pipe_db) { - nni_id_set( - &npipe->nano_db, DJBHash(pipe_db->topic), pipe_db); - pipe_db = pipe_db->next; - } - nni_mtx_unlock(&p->lk); + //TODO remove topic from pipe_db break; case CMD_PUBLISH: NNI_GET16(ptr, tlen); @@ -1089,9 +1089,9 @@ nano_pipe_recv_cb(void *arg) } break; case CMD_DISCONNECT: - case CMD_UNSUBSCRIBE: + nni_pipe_close(p->pipe); + break; case CMD_CONNACK: - case CMD_CONNECT: case CMD_PINGREQ: break; case CMD_PUBACK: @@ -1110,6 +1110,7 @@ nano_pipe_recv_cb(void *arg) goto drop; case CMD_PUBREC: case CMD_PUBREL: + case CMD_CONNECT: goto drop; default: goto drop; diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index bde19cd4b..ecef8d951 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -553,16 +553,7 @@ tcptran_pipe_recv_cb(void *arg) // set the payload pointer of msg according to packet_type debug_msg("The type of msg is %x", type); - if (type == CMD_UNSUBSCRIBE) { - if (cparam->pro_ver == PROTOCOL_VERSION_v5) { - len_of_varint = 0; - len = - get_var_integer(variable_ptr + 2, &len_of_varint); - payload_ptr = variable_ptr + 2 + len + len_of_varint; - } else { - payload_ptr = variable_ptr + 2; - } - } else if (type == CMD_PUBLISH) { + if (type == CMD_PUBLISH) { uint8_t qos_pac; uint16_t pid; size_t tlen; From 72a775ad4395798d18dad195e62f873fd7d1fb41 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Tue, 31 Aug 2021 19:02:18 +0800 Subject: [PATCH 019/180] * NEW [websocket] support SUBSCRIBE & UNSUBSCRIBE MQTT over websocket --- src/sp/protocol/reqrep0/nano_tcp.c | 26 -------------------------- src/sp/transport/ws/websocket.c | 27 ++++++++++++++++++--------- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index b24f18090..b1abc29b6 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -775,32 +775,6 @@ nano_pipe_init(void *arg, nni_pipe *pipe, void *s) return (0); } -/* -static int -nano_ctx_set_qsize( - void *arg, void *arg2, const void *buf, size_t sz, nni_type t) -{ - nano_ctx * ctx = arg; - nano_sock *sock = ctx->sock; - nano_pipe *p = arg2; - int val; - int rv; - - if ((rv = nni_copyin_int(&val, buf, sz, 1, 8192, t)) != 0) { - return (rv); - } - - nni_mtx_lock(&sock->lk); - if ((rv = nni_lmq_resize(&p->rlmq, (size_t) val)) != 0) { - nni_mtx_unlock(&sock->lk); - return (rv); - } - - nni_mtx_unlock(&sock->lk); - return (0); -} -*/ - static int nano_pipe_start(void *arg) { diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 93c07f1fa..04a0707d0 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -74,7 +74,6 @@ wstran_pipe_send_cb(void *arg) taio = p->txaio; uaio = p->user_txaio; p->user_txaio = NULL; - p->tmp_msg = NULL; if (uaio != NULL) { int rv; @@ -112,12 +111,13 @@ wstran_pipe_recv_cb(void *arg) debug_msg("#### wstran_pipe_recv_cb got %d msg: %p %x %d", p->gotrxhead, ptr, *ptr, nni_msg_len(msg)); // first we collect complete Fixheader - if (p->tmp_msg == NULL) { + if (p->tmp_msg == NULL && p->gotrxhead > 0) { if ((rv = nni_msg_alloc(&p->tmp_msg, 0)) != 0) { debug_syslog("mem error %ld\n", (size_t) len); goto reset; } } + //TODO use IOV instead of appending msg nni_msg_append(p->tmp_msg, ptr, nni_msg_len(msg)); ptr = nni_msg_body(p->tmp_msg); // packet might be sticky? @@ -126,7 +126,7 @@ wstran_pipe_recv_cb(void *arg) goto recv; } len = get_var_integer(ptr, &pos); - if (*(ptr + pos) > 0x7f) { // continue to next byte of remaining length + if (*(ptr + pos - 1) > 0x7f) { // continue to next byte of remaining length if (p->gotrxhead >= NNI_NANO_MAX_HEADER_SIZE) { // length error rv = NNG_EMSGSIZE; @@ -151,7 +151,7 @@ wstran_pipe_recv_cb(void *arg) if (uaio == NULL) { uaio = p->ep_aio; } - if (uaio != NULL) { + if (uaio != NULL) { p->gotrxhead = 0; p->wantrxhead = 0; nni_msg_free(msg); @@ -163,18 +163,25 @@ wstran_pipe_recv_cb(void *arg) if (conn_handler(nni_msg_body(p->tmp_msg), p->ws_param) != 0) { goto reset; } + nni_msg_free(p->tmp_msg); + p->tmp_msg = NULL; + nni_aio_set_msg(uaio, smsg); + nni_aio_set_output(uaio, 0, p); + nni_aio_finish(uaio, 0, 0); + nni_mtx_unlock(&p->mtx); + return; } else { if (nni_msg_alloc(&smsg, 0) != 0) { goto reset; } ws_fixed_header_adaptor(ptr, smsg); nni_msg_free(p->tmp_msg); - p->tmp_msg = smsg; - nni_msg_set_conn_param(p->tmp_msg, p->ws_param); + p->tmp_msg = NULL; + nni_msg_set_conn_param(smsg, p->ws_param); } - nni_aio_set_msg(uaio, p->tmp_msg); + nni_aio_set_msg(uaio, smsg); nni_aio_set_output(uaio, 0, p); - nni_aio_finish(uaio, 0, nni_msg_len(p->tmp_msg)); + nni_aio_finish(uaio, 0, nni_msg_len(smsg)); p->tmp_msg = NULL; } else { goto reset; @@ -191,7 +198,8 @@ wstran_pipe_recv_cb(void *arg) nni_aio_finish_error(p->ep_aio, rv); } if (p->tmp_msg != NULL) { - nni_msg_free(p->tmp_msg); + smsg = p->tmp_msg; + nni_msg_free(smsg); p->tmp_msg = NULL; } nni_mtx_unlock(&p->mtx); @@ -304,6 +312,7 @@ wstran_pipe_fini(void *arg) nni_aio_free(p->txaio); nng_stream_free(p->ws); + nni_msg_free(p->tmp_msg); nni_mtx_fini(&p->mtx); NNI_FREE_STRUCT(p); } From 802aaed1af77a2a1eea0d9c568d56dfb8bf73a6b Mon Sep 17 00:00:00 2001 From: JaylinYu <64823539+JaylinYu@users.noreply.github.com> Date: Tue, 31 Aug 2021 19:22:14 +0800 Subject: [PATCH 020/180] Update README.adoc --- README.adoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.adoc b/README.adoc index ceec42683..37bb72255 100644 --- a/README.adoc +++ b/README.adoc @@ -1,3 +1,8 @@ +This is NNG repo of NanoMQ project. I have updated it to support MQTT protocol. + + + + ifdef::env-github[] :note-caption: :information_source: :important-caption: :heavy_exclamation_mark: From 0e4fe9a6b5b62f259c95895323d57090109f4e27 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Tue, 31 Aug 2021 23:32:01 +0800 Subject: [PATCH 021/180] * MDF [nng/core] move MQTT oriented API out from core part of nng in order to be compatible --- include/nng/protocol/mqtt/mqtt_parser.h | 14 ++++--- src/core/message.c | 49 ----------------------- src/core/message.h | 2 - src/sp/protocol/mqtt/mqtt_parser.c | 53 ++++++++++++++++++++++++- src/sp/transport/ws/websocket.c | 19 +++++---- 5 files changed, 71 insertions(+), 66 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index d0ef43502..7981a11c4 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -7,12 +7,13 @@ #include #include -#define DISCONNECT_MSG \ +#define DISCONNECT_MSG \ "{\"username\":\"%s\"," \ "\"ts\":%llu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" -#define CONNECT_MSG \ - "{\"username\":\"%s\", " \ - "\"ts\":%llu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":\"%x\",\"proto_ver\":%d,\"client_id\":\"%s\", \"clean_start\":%d}" +#define CONNECT_MSG \ + "{\"username\":\"%s\", " \ + "\"ts\":%llu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":" \ + "\"%x\",\"proto_ver\":%d,\"client_id\":\"%s\", \"clean_start\":%d}" #define DISCONNECT_TOPIC "$SYS/brokers/disconnected" #define CONNECT_TOPIC "$SYS/brokers/connected" @@ -52,6 +53,9 @@ NNG_DECL nng_msg *nano_msg_composer( uint8_t retain, uint8_t qos, mqtt_string *payload, mqtt_string *topic); NNG_DECL nng_msg *nano_msg_notify_disconnect(conn_param *cparam, uint8_t code); NNG_DECL nng_msg *nano_msg_notify_connect(conn_param *cparam, uint8_t code); -NNG_DECL nano_pipe_db * nano_msg_get_subtopic(nng_msg *msg, nano_pipe_db *root, conn_param *cparam); +NNG_DECL nano_pipe_db *nano_msg_get_subtopic( + nng_msg *msg, nano_pipe_db *root, conn_param *cparam); +NNG_DECL void nano_msg_free_pipedb(nano_pipe_db *db); +NNG_DECL void nano_msg_ubsub_free(nano_pipe_db *db); #endif // NNG_MQTT_H diff --git a/src/core/message.c b/src/core/message.c index ae8b90f1b..6a4bc8c23 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -735,52 +735,3 @@ nni_msg_get_timestamp(nni_msg *m) { return m->times; } - -void -nano_msg_free_pipedb(nano_pipe_db *db) -{ - uint8_t len; - nano_pipe_db *db_next; - - if (NULL == db) { - return; - } - db = db->root; - - while (db) { - len = strlen(db->topic); - nng_free(db->topic, len); - db_next = db->next; - nng_free(db, sizeof(nano_pipe_db)); - db = db_next; - } - return; -} - -void -nano_msg_ubsub_free(nano_pipe_db *db) -{ - nano_pipe_db *ptr, *tmp; - uint8_t len; - - if (NULL == db) { - return; - } - if (db == db->root) { - ptr = db; - tmp = db->next; - while (ptr) { - ptr->root = tmp; - ptr = ptr->next; - } - } else { - tmp = db->prev; - tmp->next = db->next; - db->next->prev = tmp; - } - - len = strlen(db->topic); - nng_free(db->topic, len); - nng_free(db, sizeof(nano_pipe_db)); - return; -} diff --git a/src/core/message.h b/src/core/message.h index f72ff27a3..492375dc5 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -76,8 +76,6 @@ extern void nni_msg_set_payload_ptr(nni_msg *m, uint8_t *ptr); extern void nni_msg_set_remaining_len(nni_msg *m, size_t len); extern void nni_msg_set_cmd_type(nni_msg *m, uint8_t cmd); extern void nni_msg_set_conn_param(nni_msg *m, void *ptr); -extern void nano_msg_free_pipedb(nano_pipe_db *db); -extern void nano_msg_ubsub_free(nano_pipe_db *db); extern uint8_t nni_msg_get_preset_qos(nni_msg *m); extern uint16_t nni_msg_get_pub_pid(nni_msg *m); diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index c3cfde638..157f5e46d 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -306,7 +306,7 @@ ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst) nni_msg_set_cmd_type(m, *packet & 0xf0); nni_msg_set_remaining_len(m, len); rv = nni_msg_header_append(m, packet, pos); - printf("len !!!! 2 %d\n", len); + if (len > 0) { nni_msg_append(m, packet + pos, len); } @@ -945,4 +945,53 @@ nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) } return root; -} \ No newline at end of file +} + +void +nano_msg_free_pipedb(nano_pipe_db *db) +{ + uint8_t len; + nano_pipe_db *db_next; + + if (NULL == db) { + return; + } + db = db->root; + + while (db) { + len = strlen(db->topic); + nng_free(db->topic, len); + db_next = db->next; + nng_free(db, sizeof(nano_pipe_db)); + db = db_next; + } + return; +} + +void +nano_msg_ubsub_free(nano_pipe_db *db) +{ + nano_pipe_db *ptr, *tmp; + uint8_t len; + + if (NULL == db) { + return; + } + if (db == db->root) { + ptr = db; + tmp = db->next; + while (ptr) { + ptr->root = tmp; + ptr = ptr->next; + } + } else { + tmp = db->prev; + tmp->next = db->next; + db->next->prev = tmp; + } + + len = strlen(db->topic); + nng_free(db->topic, len); + nng_free(db, sizeof(nano_pipe_db)); + return; +} diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 04a0707d0..1b530cef9 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -92,12 +92,12 @@ wstran_pipe_recv_cb(void *arg) ws_pipe *p = arg; uint32_t len = 0, rv, pos = 1; uint8_t *ptr; - nni_msg *smsg, *msg; + nni_msg *smsg, *msg; nni_aio *raio = p->rxaio; nni_aio *uaio = NULL; nni_mtx_lock(&p->mtx); - //only sets uaio at first time + // only sets uaio at first time if (p->user_rxaio != NULL) { uaio = p->user_rxaio; } @@ -117,7 +117,7 @@ wstran_pipe_recv_cb(void *arg) goto reset; } } - //TODO use IOV instead of appending msg + // TODO use IOV instead of appending msg nni_msg_append(p->tmp_msg, ptr, nni_msg_len(msg)); ptr = nni_msg_body(p->tmp_msg); // packet might be sticky? @@ -126,7 +126,8 @@ wstran_pipe_recv_cb(void *arg) goto recv; } len = get_var_integer(ptr, &pos); - if (*(ptr + pos - 1) > 0x7f) { // continue to next byte of remaining length + if (*(ptr + pos - 1) > + 0x7f) { // continue to next byte of remaining length if (p->gotrxhead >= NNI_NANO_MAX_HEADER_SIZE) { // length error rv = NNG_EMSGSIZE; @@ -151,16 +152,18 @@ wstran_pipe_recv_cb(void *arg) if (uaio == NULL) { uaio = p->ep_aio; } - if (uaio != NULL) { + if (uaio != NULL) { p->gotrxhead = 0; p->wantrxhead = 0; nni_msg_free(msg); if (nni_msg_cmd_type(p->tmp_msg) == CMD_CONNECT) { // end of nego if (p->ws_param == NULL) { - p->ws_param = nng_alloc(sizeof(struct conn_param)); + p->ws_param = + nng_alloc(sizeof(struct conn_param)); } - if (conn_handler(nni_msg_body(p->tmp_msg), p->ws_param) != 0) { + if (conn_handler( + nni_msg_body(p->tmp_msg), p->ws_param) != 0) { goto reset; } nni_msg_free(p->tmp_msg); @@ -169,7 +172,7 @@ wstran_pipe_recv_cb(void *arg) nni_aio_set_output(uaio, 0, p); nni_aio_finish(uaio, 0, 0); nni_mtx_unlock(&p->mtx); - return; + return; } else { if (nni_msg_alloc(&smsg, 0) != 0) { goto reset; From 0452cf0443220ae1bbf0bf0adf193c88967f6fe3 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Thu, 2 Sep 2021 18:38:57 +0800 Subject: [PATCH 022/180] Resolved compile warning --- include/nng/protocol/mqtt/mqtt_parser.h | 11 +++--- src/sp/protocol/mqtt/mqtt_parser.c | 23 ++++++------ src/sp/protocol/reqrep0/nano_tcp.c | 48 ++++++++++++++----------- src/sp/transport/tcp/tcp.c | 5 +-- src/sp/transport/ws/websocket.c | 2 +- 5 files changed, 47 insertions(+), 42 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 7981a11c4..18decdc58 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -9,12 +9,15 @@ #define DISCONNECT_MSG \ "{\"username\":\"%s\"," \ - "\"ts\":%llu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" -#define CONNECT_MSG \ - "{\"username\":\"%s\", " \ - "\"ts\":%llu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":" \ + "\"ts\":%lu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" + +#define CONNECT_MSG \ + "{\"username\":\"%s\", " \ + "\"ts\":%lu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":" \ "\"%x\",\"proto_ver\":%d,\"client_id\":\"%s\", \"clean_start\":%d}" + #define DISCONNECT_TOPIC "$SYS/brokers/disconnected" + #define CONNECT_TOPIC "$SYS/brokers/connected" // Variables & Structs diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 157f5e46d..9ac5bf938 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -298,7 +298,6 @@ ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst) nni_msg *m; int rv; uint32_t len; - uint8_t *ptr; size_t pos = 1; m = (nni_msg *) dst; @@ -344,9 +343,9 @@ int32_t conn_handler(uint8_t *packet, conn_param *cparam) { - uint32_t len, tmp, pos = 0, len_of_properties = 0; - int len_of_str = 0, len_of_var = 0; - int32_t rv = 0; + uint32_t len, tmp, pos = 0, len_of_properties = 0, len_of_var = 0; + int len_of_str = 0; + int32_t rv = 0; uint8_t property_id; if (packet[pos] != CMD_CONNECT) { @@ -354,7 +353,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) return rv; } else { pos++; - } + } init_conn_param(cparam); // remaining length @@ -789,8 +788,8 @@ uint8_t verify_connect(conn_param *cparam, conf *conf) { int i, n = conf->auths.count; - char *username = cparam->username.body; - char *password = cparam->password.body; + char *username = (char *) cparam->username.body; + char *password = (char *) cparam->password.body; if (conf->auths.count == 0 || conf->allow_anonymous == true) { debug_msg("WARNING: no valid entry in " @@ -824,9 +823,9 @@ nano_msg_notify_disconnect(conn_param *cparam, uint8_t code) { nni_msg * msg; mqtt_string string, topic; - uint8_t buff[256]; - snprintf(buff, 256, DISCONNECT_MSG, cparam->username.body, nni_clock(), - code, cparam->clientid.body); + char buff[256]; + snprintf(buff, 256, DISCONNECT_MSG, (char *) cparam->username.body, + nni_clock(), code, (char *) cparam->clientid.body); string.body = buff; string.len = strlen(string.body); topic.body = DISCONNECT_TOPIC; @@ -840,7 +839,7 @@ nano_msg_notify_connect(conn_param *cparam, uint8_t code) { nni_msg * msg; mqtt_string string, topic; - uint8_t buff[256]; + char buff[256]; snprintf(buff, 256, CONNECT_MSG, cparam->username.body, nni_clock(), cparam->pro_name.body, cparam->keepalive_mqtt, code, cparam->pro_ver, cparam->clientid.body, cparam->clean_start); @@ -891,7 +890,7 @@ nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) iter = root; while (iter) { if (strlen(iter->topic) == len_of_topic && - !strncmp(payload_ptr + bpos + 2, + !strncmp((char *)(payload_ptr + bpos + 2), iter->topic, len_of_topic)) { repeat = true; bpos += (2 + len_of_topic); diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index b1abc29b6..03ba2394d 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -17,7 +17,6 @@ #include "core/sockimpl.h" #include "nng/protocol/mqtt/mqtt_parser.h" #include "nng/protocol/mqtt/nano_tcp.h" - #include "nng/protocol/mqtt/mqtt.h" #include @@ -33,8 +32,8 @@ typedef struct cs_msg_list cs_msg_list; static void nano_pipe_send_cb(void *); static void nano_pipe_recv_cb(void *); static void nano_pipe_fini(void *); -static void nano_pipe_close(void *, uint8_t reason_code); -static inline void close_pipe(nano_pipe *p, uint8_t reason_code); +static void nano_pipe_close(void *); +static inline void close_pipe(nano_pipe *p); // static void nano_period_check(nano_sock *s, nni_list *sent_list, void *arg); // static void nano_keepalive(nano_pipe *p, void *arg); @@ -120,7 +119,8 @@ nano_pipe_timer_cb(void *arg) "timeout!"); // TODO check keepalived timer interval nni_mtx_unlock(&p->lk); - nano_pipe_close(p,0x8D); + p->reason_code = 0x8D; + nano_pipe_close(p); return; } p->ka_refresh++; @@ -301,7 +301,7 @@ nano_ctx_send(void *arg, nni_aio *aio) debug_msg("WARNING: pipe %d occupied! resending in cb!", pipe); if (nni_lmq_full(&p->rlmq)) { // Make space for the new message. TODO add max limit of msgq len in conf - if (rv = nni_lmq_resize(&p->rlmq, nni_lmq_cap(&p->rlmq) * 2) != 0) { + if ((rv = nni_lmq_resize(&p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { debug_syslog("warning msg dropped!"); nni_msg *old; (void) nni_lmq_getq(&p->rlmq, &old); @@ -822,7 +822,7 @@ nano_pipe_start(void *arg) } static inline void -close_pipe(nano_pipe *p, uint8_t reason_code) +close_pipe(nano_pipe *p) { nano_sock *s = p->rep; nano_ctx * ctx; @@ -855,21 +855,21 @@ close_pipe(nano_pipe *p, uint8_t reason_code) } static void -nano_pipe_close(void *arg, uint8_t reason_code) +nano_pipe_close(void *arg) { nano_pipe * p = arg; nano_sock * s = p->rep; nano_ctx * ctx; - conn_param *cparam; + // conn_param *cparam; nni_aio * aio = NULL; nni_msg * msg; debug_msg("################# nano_pipe_close ##############"); nni_mtx_lock(&s->lk); - close_pipe(p, reason_code); + close_pipe(p); // pub disconnect event if ((ctx = nni_list_first(&s->recvq)) != NULL) { - msg = nano_msg_notify_disconnect(p->conn_param, reason_code); + msg = nano_msg_notify_disconnect(p->conn_param, p->reason_code); if (msg == NULL) { nni_mtx_unlock(&s->lk); return; @@ -1025,24 +1025,30 @@ nano_pipe_recv_cb(void *arg) nni_msg_set_pipe(msg, p->id); ptr = nni_msg_body(msg); + conn_param *cparam; + uint32_t len, len_of_varint = 0; + uint8_t qos_pac; + size_t tlen; + // TODO HOOK switch (nng_msg_cmd_type(msg)) { - conn_param *cparam; - uint32_t len, len_of_varint = 0; - uint8_t qos_pac; - size_t tlen; + case CMD_UNSUBSCRIBE: + goto unsub; case CMD_SUBSCRIBE: // TODO only cache topic hash when it is above qos 1/2 nni_mtx_lock(&p->lk); - cparam = p->conn_param; - pipe_db = nano_msg_get_subtopic(msg, p->pipedb_root, cparam); // TODO potential memleak when sub failed + cparam = p->conn_param; + pipe_db = nano_msg_get_subtopic(msg, p->pipedb_root, + cparam); // TODO potential memleak when sub failed p->pipedb_root = pipe_db; - while (pipe_db) { - nni_id_set(&npipe->nano_db, DJBHash(pipe_db->topic), pipe_db); - pipe_db = pipe_db->next; + for (; pipe_db != NULL; pipe_db = pipe_db->next) { + nni_id_set( + &npipe->nano_db, DJBHash(pipe_db->topic), pipe_db); } nni_mtx_unlock(&p->lk); - case CMD_UNSUBSCRIBE: + + // __attribute__((fallthrough)) + unsub: if (cparam->pro_ver == PROTOCOL_VERSION_v5) { len = get_var_integer(ptr + 2, &len_of_varint); nni_msg_set_payload_ptr( @@ -1050,7 +1056,7 @@ nano_pipe_recv_cb(void *arg) } else { nni_msg_set_payload_ptr(msg, ptr + 2); } - //TODO remove topic from pipe_db + // TODO remove topic from pipe_db break; case CMD_PUBLISH: NNI_GET16(ptr, tlen); diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index ecef8d951..30a1a73ab 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -426,7 +426,7 @@ tcptran_pipe_send_cb(void *arg) static void tcptran_pipe_recv_cb(void *arg) { - uint8_t *variable_ptr = NULL, *payload_ptr = NULL; + uint8_t *payload_ptr = NULL; // uint8_t * header_ptr; nni_aio *aio; nni_iov iov; @@ -438,7 +438,6 @@ tcptran_pipe_recv_cb(void *arg) tcptran_pipe *p = arg; nni_aio * rxaio = p->rxaio; conn_param * cparam; - uint32_t len_of_varint = 0; debug_msg("tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); @@ -549,14 +548,12 @@ tcptran_pipe_recv_cb(void *arg) debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", len, cparam, cparam->clientid.body, cparam->username.body, cparam->pro_ver); - variable_ptr = nni_msg_body(msg); // set the payload pointer of msg according to packet_type debug_msg("The type of msg is %x", type); if (type == CMD_PUBLISH) { uint8_t qos_pac; uint16_t pid; - size_t tlen; qos_pac = nni_msg_get_pub_qos(msg); if (qos_pac > 0) { diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 1b530cef9..e74798a71 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -562,8 +562,8 @@ wstran_listener_close(void *arg) static void ws_pipe_start(ws_pipe *pipe, nng_stream *conn) { + NNI_ARG_UNUSED(conn); ws_pipe *p = pipe; - int rv; debug_msg("ws_pipe_start!"); nng_stream_recv(p->ws, p->rxaio); From f8ed1714573f4b224233e6f01f18a3416e9fc8a0 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 3 Sep 2021 10:49:47 +0800 Subject: [PATCH 023/180] * MDF [nano_tcp] reply PUBACK/PUBREL/PUBCOMP in protocol layer --- src/core/aio.h | 2 +- src/sp/protocol/mqtt/mqtt_parser.c | 10 +++- src/sp/protocol/reqrep0/nano_tcp.c | 84 ++++++++++++++++++++++++++---- src/sp/transport/tcp/tcp.c | 60 +-------------------- src/sp/transport/ws/websocket.c | 2 +- 5 files changed, 86 insertions(+), 72 deletions(-) diff --git a/src/core/aio.h b/src/core/aio.h index 944a48ec1..6a371d93f 100644 --- a/src/core/aio.h +++ b/src/core/aio.h @@ -217,7 +217,7 @@ struct nng_aio { nni_list_node a_expire_node; // Expiration node nni_reap_node a_reap_node; // NanoMQ var - uint16_t packet_id; + uint16_t packet_id; //indicates message id + qos? }; #endif // CORE_AIO_H diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 9ac5bf938..b4db3ae97 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -851,7 +851,14 @@ nano_msg_notify_connect(conn_param *cparam, uint8_t code) return msg; } - +/** + * @brief + * + * @param msg SUB/UNSUB packet + * @param root root node of nano_pipe_db linked table + * @param cparam connection param + * @return nano_pipe_db* pointer of newly added pipe_db + */ nano_pipe_db * nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) { @@ -878,6 +885,7 @@ nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) } else { payload_ptr = nni_msg_body(msg) + 2; } + nni_msg_set_payload_ptr(msg, payload_ptr); remain = nni_msg_remaining_len(msg) - 2; while (bpos < remain) { diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 03ba2394d..1b02e45e9 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -1001,6 +1001,10 @@ nano_pipe_recv_cb(void *arg) { nano_pipe * p = arg; nano_sock * s = p->rep; + conn_param * cparam; + uint32_t len, len_of_varint = 0; + uint8_t qos_pac, buf[4]; + size_t tlen; nano_ctx * ctx; nni_msg * msg, *qos_msg; nni_aio * aio; @@ -1025,11 +1029,6 @@ nano_pipe_recv_cb(void *arg) nni_msg_set_pipe(msg, p->id); ptr = nni_msg_body(msg); - conn_param *cparam; - uint32_t len, len_of_varint = 0; - uint8_t qos_pac; - size_t tlen; - // TODO HOOK switch (nng_msg_cmd_type(msg)) { case CMD_UNSUBSCRIBE: @@ -1060,20 +1059,87 @@ nano_pipe_recv_cb(void *arg) break; case CMD_PUBLISH: NNI_GET16(ptr, tlen); - cparam = p->conn_param; + cparam = p->conn_param; qos_pac = nni_msg_get_pub_qos(msg); if (cparam->pro_ver != PROTOCOL_VERSION_v5) { nni_msg_set_payload_ptr( msg, ptr + tlen + 2 + (qos_pac > 0 ? 2 : 0)); } else { } + + if (qos_pac > 0) { + nni_msg_alloc(&qos_msg, 0); + if (qos_pac == 1) { + buf[0] = CMD_PUBACK; + } else if (qos_pac == 2) { + buf[0] = CMD_PUBREC; + } + buf[1] = 0x02; + + ackid = nni_msg_get_pub_pid(msg); + NNI_PUT16(buf+2, ackid); + nni_msg_header_append(qos_msg, buf, 4); + } + if (qos_msg != NULL) { + nni_mtx_lock(&p->lk); + if (!p->busy) { + p->busy = true; + nni_aio_set_msg(&p->aio_send, qos_msg); + nni_pipe_send(p->pipe, &p->aio_send); + } else { + if (nni_lmq_full(&p->rlmq)) { + // Make space for the new message. TODO add max + // limit of msgq len in conf + debug_syslog("warning msg dropped!"); + nni_msg *old; + (void) nni_lmq_getq(&p->rlmq, &old); + nni_msg_free(old); + } + nni_lmq_putq(&p->rlmq, qos_msg); + } + nni_mtx_unlock(&p->lk); + } break; case CMD_DISCONNECT: nni_pipe_close(p->pipe); break; case CMD_CONNACK: case CMD_PINGREQ: - break; + //TODO check if this is necessary? + break; + case CMD_PUBREC: + case CMD_PUBREL: + nni_msg_header_clear(msg); + if (nni_msg_cmd_type(msg) == CMD_PUBREC) { + buf[0] = 0X62; + } else if (nni_msg_cmd_type(msg) == CMD_PUBREL) { + buf[0] = CMD_PUBCOMP; + } + buf[1] = 0x02; + ptr = nni_msg_body(msg); + memcpy(buf + 2, ptr, 2); + nni_msg_clear(msg); + nni_msg_header_append(msg, buf, 4); + if (msg != NULL) { + nni_mtx_lock(&p->lk); + if (!p->busy) { + p->busy = true; + nni_aio_set_msg(&p->aio_send, msg); + nni_pipe_send(p->pipe, &p->aio_send); + } else { + if (nni_lmq_full(&p->rlmq)) { + // Make space for the new message. TODO add max + // limit of msgq len in conf + debug_syslog("warning msg dropped!"); + nni_msg *old; + (void) nni_lmq_getq(&p->rlmq, &old); + nni_msg_free(old); + } + nni_lmq_putq(&p->rlmq, msg); + } + nni_mtx_unlock(&p->lk); + } + goto end; case CMD_PUBACK: case CMD_PUBCOMP: nni_mtx_lock(&p->lk); @@ -1088,8 +1154,6 @@ nano_pipe_recv_cb(void *arg) } nni_mtx_unlock(&p->lk); goto drop; - case CMD_PUBREC: - case CMD_PUBREL: case CMD_CONNECT: goto drop; default: @@ -1138,9 +1202,9 @@ nano_pipe_recv_cb(void *arg) return; drop: - nni_aio_set_msg(&p->aio_recv, NULL); nni_msg_free(msg); end: + nni_aio_set_msg(&p->aio_recv, NULL); nni_pipe_recv(p->pipe, &p->aio_recv); debug_msg("Warning:dropping msg"); return; diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 30a1a73ab..190a8f1d8 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -32,7 +32,6 @@ struct tcptran_pipe { size_t wantrxhead; size_t qlength; // length of qos_buf bool closed; - uint8_t cmd; uint8_t txlen[NANO_MIN_PACKET_LEN]; uint8_t rxlen[NNI_NANO_MAX_HEADER_SIZE]; uint8_t * conn_buf; @@ -488,7 +487,6 @@ tcptran_pipe_recv_cb(void *arg) iov.iov_buf = &p->txlen; // send it down... nni_aio_set_iov(p->qsaio, 1, &iov); - p->cmd = CMD_PINGRESP; nng_stream_send(p->conn, p->qsaio); goto notify; } else if ((p->rxlen[0] & 0XFF) == CMD_DISCONNECT) { @@ -551,61 +549,6 @@ tcptran_pipe_recv_cb(void *arg) // set the payload pointer of msg according to packet_type debug_msg("The type of msg is %x", type); - if (type == CMD_PUBLISH) { - uint8_t qos_pac; - uint16_t pid; - - qos_pac = nni_msg_get_pub_qos(msg); - if (qos_pac > 0) { - nng_aio_wait(p->rsaio); - if (qos_pac == 1) { - p->txlen[0] = CMD_PUBACK; - } else if (qos_pac == 2) { - p->txlen[0] = CMD_PUBREC; - } - p->txlen[1] = 0x02; - pid = nni_msg_get_pub_pid(msg); - NNI_PUT16(p->txlen + 2, pid); - iov.iov_len = 4; - iov.iov_buf = &p->txlen; - // send it down... - nni_aio_set_iov(p->rsaio, 1, &iov); - - p->cmd = CMD_PUBREC; - nng_stream_send(p->conn, p->rsaio); - } - } else if (type == CMD_PUBREC) { - // TODO - uint8_t *tmp; - nng_aio_wait(p->rpaio); - p->txlen[0] = 0X62; - p->txlen[1] = 0x02; - tmp = nni_msg_body(msg); - memcpy(p->txlen + 2, tmp, 2); - iov.iov_len = 4; - iov.iov_buf = &p->txlen; - // send it down... - nni_aio_set_iov(p->rpaio, 1, &iov); - p->cmd = CMD_PUBREL; - nng_stream_send(p->conn, p->rpaio); - } else if (type == CMD_PUBREL) { - uint8_t *tmp; - nng_aio_wait(p->qsaio); - p->txlen[0] = CMD_PUBCOMP; - p->txlen[1] = 0x02; - tmp = nni_msg_body(msg); - memcpy(p->txlen + 2, tmp, 2); - iov.iov_len = 4; - iov.iov_buf = &p->txlen; - // send it down... - nni_aio_set_iov(p->qsaio, 1, &iov); - p->cmd = CMD_PUBCOMP; - nng_stream_send(p->conn, p->qsaio); - } else if (type == CMD_PUBACK || type == CMD_PUBCOMP) { - //TODO move keepalive timer & ACK checker to transport layer - } else { - payload_ptr = NULL; - } nni_msg_set_payload_ptr(msg, payload_ptr); // keep connection & Schedule next receive @@ -635,8 +578,7 @@ tcptran_pipe_recv_cb(void *arg) tcptran_pipe_recv_start(p); nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, NULL); - nni_aio_finish(aio, 0, 0); //only finishes when we need - // PINGREQ event + nni_aio_finish(aio, 0, 0); return; } diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index e74798a71..9b8f0a3e7 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -192,9 +192,9 @@ wstran_pipe_recv_cb(void *arg) nni_mtx_unlock(&p->mtx); return; reset: - // reset the connection, remember to free the message before enter here p->gotrxhead = 0; p->wantrxhead = 0; + nng_stream_close(p->ws); if (uaio != NULL) { nni_aio_finish_error(uaio, rv); } else if (p->ep_aio != NULL) { From cad6958316449494165a9daccd1906a4e0fbc100 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Fri, 3 Sep 2021 11:07:48 +0800 Subject: [PATCH 024/180] Resolved warning in mqtt_parser.c --- src/sp/protocol/mqtt/mqtt_parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 9ac5bf938..9dae2bfab 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -695,7 +695,7 @@ DJBHash(char *str) while (*str) { hash = ((hash << 5) + hash) + (*str++); /* times 33 */ } - hash &= ~(1 << 31); /* strip the highest bit */ + hash &= ~(1U << 31); /* strip the highest bit */ return hash; } @@ -858,7 +858,7 @@ nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) char *topic; nano_pipe_db *db = NULL, *tmp = NULL, *iter = NULL; uint8_t len_of_topic = 0, *payload_ptr; - uint32_t len, len_of_varint; + uint32_t len, len_of_varint = 0; size_t bpos = 0, remain = 0; bool repeat = false; From 424eaf5a6f76b94703eefa93538303863b1388ed Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 3 Sep 2021 11:23:05 +0800 Subject: [PATCH 025/180] * MDF [tcp/nano_tcp] remove useless variables & format code --- src/sp/protocol/reqrep0/nano_tcp.c | 158 +++++++++++++++-------------- src/sp/transport/tcp/tcp.c | 15 --- 2 files changed, 82 insertions(+), 91 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 1b02e45e9..c4f772d9a 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -15,9 +15,9 @@ #include "core/nng_impl.h" #include "core/sockimpl.h" +#include "nng/protocol/mqtt/mqtt.h" #include "nng/protocol/mqtt/mqtt_parser.h" #include "nng/protocol/mqtt/nano_tcp.h" -#include "nng/protocol/mqtt/mqtt.h" #include @@ -262,7 +262,8 @@ nano_ctx_send(void *arg, nni_aio *aio) } else { pipe = ctx->pipe_id; // reply to self } - ctx->pipe_id = 0; // ensure connack/PING/DISCONNECT/PUBACK only sends once + ctx->pipe_id = + 0; // ensure connack/PING/DISCONNECT/PUBACK only sends once if (ctx == &s->ctx) { nni_pollable_clear(&s->writable); @@ -270,14 +271,16 @@ nano_ctx_send(void *arg, nni_aio *aio) nni_mtx_lock(&s->lk); debug_msg("*************************** working with pipe id : %d " - "ctx***************************", pipe); + "ctx***************************", + pipe); if ((p = nni_id_get(&s->pipes, pipe)) == NULL) { // Pipe is gone. Make this look like a good send to avoid // disrupting the state machine. We don't care if the peer // lost interest in our reply. nni_mtx_unlock(&s->lk); nni_aio_set_msg(aio, NULL); - //TODO lastwill/SYS topic will trigger this (sub to the topic that publish to by itself) + // TODO lastwill/SYS topic will trigger this (sub to the topic + // that publish to by itself) debug_syslog("ERROR: pipe is gone, pub failed"); nni_msg_free(msg); return; @@ -300,8 +303,10 @@ nano_ctx_send(void *arg, nni_aio *aio) } debug_msg("WARNING: pipe %d occupied! resending in cb!", pipe); if (nni_lmq_full(&p->rlmq)) { - // Make space for the new message. TODO add max limit of msgq len in conf - if ((rv = nni_lmq_resize(&p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { + // Make space for the new message. TODO add max limit of msgq + // len in conf + if ((rv = nni_lmq_resize( + &p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { debug_syslog("warning msg dropped!"); nni_msg *old; (void) nni_lmq_getq(&p->rlmq, &old); @@ -530,9 +535,9 @@ nano_session_restore(nano_pipe *p, nano_sock *s, uint8_t *flag) // TODO kick prev connection or current one?(p or cs->pipeid) p->kicked = true; if (p->conn_param->pro_ver == 5) { - *(flag +1 ) = 0x8E; + *(flag + 1) = 0x8E; } else { - *(flag +1 ) = 0x02; + *(flag + 1) = 0x02; } return (NNG_ECONNABORTED); } @@ -545,7 +550,7 @@ nano_session_restore(nano_pipe *p, nano_sock *s, uint8_t *flag) cs->pipeid = p->id; if (clean_session_flag == 0) { - *flag = 0x01; //set session present flag + *flag = 0x01; // set session present flag cs->clean = false; // step 0 restore conn param nano_deep_copy_connparam(new_cparam, cparam); @@ -707,8 +712,7 @@ nano_pipe_fini(void *arg) // get temp_cs from clean_session_db // TODO potential risk without lock temp_cs = nni_id_get(&s->clean_session_db, key); - if (p->conn_param->clean_start == 0 && - temp_cs != NULL && + if (p->conn_param->clean_start == 0 && temp_cs != NULL && p->kicked != true) { nano_session_cache(p, temp_cs, key); } else { @@ -756,13 +760,13 @@ nano_pipe_init(void *arg, nni_pipe *pipe, void *s) nni_mtx_init(&p->lk); nni_lmq_init(&p->rlmq, sock->conf->msq_len); nni_aio_init(&p->aio_send, nano_pipe_send_cb, p); - //TODO move keepalive monitor to transport layer? + // TODO move keepalive monitor to transport layer? nni_aio_init(&p->aio_timer, nano_pipe_timer_cb, p); nni_aio_init(&p->aio_recv, nano_pipe_recv_cb, p); // NNI_LIST_INIT(&p->sendq, nano_ctx, sqnode); - p->reason_code = 0x00; + p->reason_code = 0x00; p->id = nni_pipe_id(pipe); p->pipe = pipe; p->rep = s; @@ -778,8 +782,8 @@ nano_pipe_init(void *arg, nni_pipe *pipe, void *s) static int nano_pipe_start(void *arg) { - nano_pipe *p = arg; - nano_sock *s = p->rep; + nano_pipe *p = arg; + nano_sock *s = p->rep; nni_msg * msg; uint8_t rv, *reason; // reason code of CONNACK uint8_t buf[4] = { 0x20, 0x02, 0x00, 0x00 }; @@ -803,7 +807,7 @@ nano_pipe_start(void *arg) if (rv != 0) { // TODO disconnect client && send connack with reason code 0x05 debug_syslog("Invalid auth info."); - *(reason + 1) = rv; //set return code + *(reason + 1) = rv; // set return code } rv = nano_session_restore(p, s, reason); nni_mtx_unlock(&s->lk); @@ -838,7 +842,7 @@ close_pipe(nano_pipe *p) } nni_lmq_flush(&p->rlmq); - //TODO delete + // TODO delete while ((ctx = nni_list_first(&p->sendq)) != NULL) { nni_aio *aio; nni_msg *msg; @@ -857,19 +861,20 @@ close_pipe(nano_pipe *p) static void nano_pipe_close(void *arg) { - nano_pipe * p = arg; - nano_sock * s = p->rep; - nano_ctx * ctx; + nano_pipe *p = arg; + nano_sock *s = p->rep; + nano_ctx * ctx; // conn_param *cparam; - nni_aio * aio = NULL; - nni_msg * msg; + nni_aio *aio = NULL; + nni_msg *msg; debug_msg("################# nano_pipe_close ##############"); nni_mtx_lock(&s->lk); close_pipe(p); // pub disconnect event if ((ctx = nni_list_first(&s->recvq)) != NULL) { - msg = nano_msg_notify_disconnect(p->conn_param, p->reason_code); + msg = + nano_msg_notify_disconnect(p->conn_param, p->reason_code); if (msg == NULL) { nni_mtx_unlock(&s->lk); return; @@ -884,7 +889,8 @@ nano_pipe_close(void *arg) nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); return; } else { - debug_msg("Warning: no ctx left!! faied to send disconnect notification"); + debug_msg("Warning: no ctx left!! faied to send disconnect " + "notification"); } nni_mtx_unlock(&s->lk); } @@ -1014,7 +1020,7 @@ nano_pipe_recv_cb(void *arg) uint16_t ackid; if (nni_aio_result(&p->aio_recv) != 0) { - //unexpected disconnect + // unexpected disconnect nni_pipe_close(p->pipe); return; } @@ -1075,74 +1081,74 @@ nano_pipe_recv_cb(void *arg) buf[0] = CMD_PUBREC; } buf[1] = 0x02; - - ackid = nni_msg_get_pub_pid(msg); - NNI_PUT16(buf+2, ackid); + + ackid = nni_msg_get_pub_pid(msg); + NNI_PUT16(buf + 2, ackid); nni_msg_header_append(qos_msg, buf, 4); } - if (qos_msg != NULL) { - nni_mtx_lock(&p->lk); - if (!p->busy) { - p->busy = true; - nni_aio_set_msg(&p->aio_send, qos_msg); - nni_pipe_send(p->pipe, &p->aio_send); - } else { - if (nni_lmq_full(&p->rlmq)) { - // Make space for the new message. TODO add max - // limit of msgq len in conf - debug_syslog("warning msg dropped!"); - nni_msg *old; - (void) nni_lmq_getq(&p->rlmq, &old); - nni_msg_free(old); + if (qos_msg != NULL) { + nni_mtx_lock(&p->lk); + if (!p->busy) { + p->busy = true; + nni_aio_set_msg(&p->aio_send, qos_msg); + nni_pipe_send(p->pipe, &p->aio_send); + } else { + if (nni_lmq_full(&p->rlmq)) { + // Make space for the new message. TODO + // add max limit of msgq len in conf + debug_syslog("warning msg dropped!"); + nni_msg *old; + (void) nni_lmq_getq(&p->rlmq, &old); + nni_msg_free(old); + } + nni_lmq_putq(&p->rlmq, qos_msg); } - nni_lmq_putq(&p->rlmq, qos_msg); + nni_mtx_unlock(&p->lk); } - nni_mtx_unlock(&p->lk); - } break; case CMD_DISCONNECT: nni_pipe_close(p->pipe); break; case CMD_CONNACK: case CMD_PINGREQ: - //TODO check if this is necessary? - break; + // TODO check if this is necessary? + break; case CMD_PUBREC: case CMD_PUBREL: nni_msg_header_clear(msg); - if (nni_msg_cmd_type(msg) == CMD_PUBREC) { - buf[0] = 0X62; - } else if (nni_msg_cmd_type(msg) == CMD_PUBREL) { - buf[0] = CMD_PUBCOMP; - } - buf[1] = 0x02; - ptr = nni_msg_body(msg); - memcpy(buf + 2, ptr, 2); - nni_msg_clear(msg); - nni_msg_header_append(msg, buf, 4); + if (nni_msg_cmd_type(msg) == CMD_PUBREC) { + buf[0] = 0X62; + } else if (nni_msg_cmd_type(msg) == CMD_PUBREL) { + buf[0] = CMD_PUBCOMP; + } + buf[1] = 0x02; + ptr = nni_msg_body(msg); + memcpy(buf + 2, ptr, 2); + nni_msg_clear(msg); + nni_msg_header_append(msg, buf, 4); if (msg != NULL) { - nni_mtx_lock(&p->lk); - if (!p->busy) { - p->busy = true; - nni_aio_set_msg(&p->aio_send, msg); - nni_pipe_send(p->pipe, &p->aio_send); - } else { - if (nni_lmq_full(&p->rlmq)) { - // Make space for the new message. TODO add max - // limit of msgq len in conf - debug_syslog("warning msg dropped!"); - nni_msg *old; - (void) nni_lmq_getq(&p->rlmq, &old); - nni_msg_free(old); + nni_mtx_lock(&p->lk); + if (!p->busy) { + p->busy = true; + nni_aio_set_msg(&p->aio_send, msg); + nni_pipe_send(p->pipe, &p->aio_send); + } else { + if (nni_lmq_full(&p->rlmq)) { + // Make space for the new message. TODO + // add max limit of msgq len in conf + debug_syslog("warning msg dropped!"); + nni_msg *old; + (void) nni_lmq_getq(&p->rlmq, &old); + nni_msg_free(old); + } + nni_lmq_putq(&p->rlmq, msg); } - nni_lmq_putq(&p->rlmq, msg); + nni_mtx_unlock(&p->lk); } - nni_mtx_unlock(&p->lk); - } goto end; case CMD_PUBACK: case CMD_PUBCOMP: - nni_mtx_lock(&p->lk); + nni_mtx_lock(&p->lk); NNI_GET16(ptr, ackid); if ((qos_msg = nni_id_get(npipe->nano_qos_db, ackid)) != NULL) { @@ -1191,7 +1197,7 @@ nano_pipe_recv_cb(void *arg) nni_pipe_recv(p->pipe, &p->aio_recv); // ctx->pp_len = len; //TODO Rewrite mqtt header length - ctx->pipe_id = p->id; // use pipe id to identify which client is receving + ctx->pipe_id = p->id; debug_msg("currently processing pipe_id: %d", p->id); nni_mtx_unlock(&s->lk); @@ -1204,7 +1210,7 @@ nano_pipe_recv_cb(void *arg) drop: nni_msg_free(msg); end: - nni_aio_set_msg(&p->aio_recv, NULL); + nni_aio_set_msg(&p->aio_recv, NULL); nni_pipe_recv(p->pipe, &p->aio_recv); debug_msg("Warning:dropping msg"); return; diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 190a8f1d8..bc4360347 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -39,8 +39,6 @@ struct tcptran_pipe { nni_aio * txaio; nni_aio * rxaio; nni_aio * qsaio; - nni_aio * rsaio; - nni_aio * rpaio; nni_aio * negoaio; nni_msg * rxmsg, *cnmsg; nni_mtx mtx; @@ -117,9 +115,7 @@ tcptran_pipe_close(void *arg) nni_mtx_unlock(&p->mtx); nni_aio_close(p->rxaio); - nni_aio_close(p->rpaio); nni_aio_close(p->txaio); - nni_aio_close(p->rsaio); nni_aio_close(p->qsaio); nni_aio_close(p->negoaio); @@ -133,8 +129,6 @@ tcptran_pipe_stop(void *arg) tcptran_pipe *p = arg; nni_aio_stop(p->qsaio); - nni_aio_stop(p->rsaio); - nni_aio_stop(p->rpaio); nni_aio_stop(p->rxaio); nni_aio_stop(p->txaio); nni_aio_stop(p->negoaio); @@ -158,7 +152,6 @@ tcptran_pipe_fini(void *arg) { tcptran_pipe *p = arg; tcptran_ep * ep; - // nni_pipe * npipe = p->npipe; tcptran_pipe_stop(p); if ((ep = p->ep) != NULL) { @@ -172,10 +165,7 @@ tcptran_pipe_fini(void *arg) } nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); - // nng_free(p->tcp_cparam, sizeof(struct conn_param)); nni_aio_free(p->qsaio); - nni_aio_free(p->rpaio); - nni_aio_free(p->rsaio); nni_aio_free(p->rxaio); nni_aio_free(p->txaio); nni_aio_free(p->negoaio); @@ -208,8 +198,6 @@ tcptran_pipe_alloc(tcptran_pipe **pipep) nni_mtx_init(&p->mtx); if (((rv = nni_aio_alloc(&p->txaio, tcptran_pipe_send_cb, p)) != 0) || ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || - ((rv = nni_aio_alloc(&p->rpaio, NULL, p)) != 0) || - ((rv = nni_aio_alloc(&p->rsaio, NULL, p)) != 0) || ((rv = nni_aio_alloc(&p->rxaio, tcptran_pipe_recv_cb, p)) != 0) || ((rv = nni_aio_alloc(&p->negoaio, tcptran_pipe_nego_cb, p)) != 0)) { @@ -425,8 +413,6 @@ tcptran_pipe_send_cb(void *arg) static void tcptran_pipe_recv_cb(void *arg) { - uint8_t *payload_ptr = NULL; - // uint8_t * header_ptr; nni_aio *aio; nni_iov iov; uint8_t type; @@ -549,7 +535,6 @@ tcptran_pipe_recv_cb(void *arg) // set the payload pointer of msg according to packet_type debug_msg("The type of msg is %x", type); - nni_msg_set_payload_ptr(msg, payload_ptr); // keep connection & Schedule next receive // nni_pipe_bump_rx(p->npipe, n); From ce4764a62cef86a28185362eaedea34dca2a867e Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 3 Sep 2021 18:44:42 +0800 Subject: [PATCH 026/180] * NEW [websocket/qos1] support QoS 1 MQTT over Websocket --- src/sp/protocol/reqrep0/nano_tcp.c | 83 ++---------------------------- src/sp/transport/tcp/tcp.c | 76 +++++++++++++++++++++++---- src/sp/transport/ws/websocket.c | 31 +++++++++++ 3 files changed, 102 insertions(+), 88 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index c4f772d9a..8beb2ac41 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -1063,89 +1063,13 @@ nano_pipe_recv_cb(void *arg) } // TODO remove topic from pipe_db break; - case CMD_PUBLISH: - NNI_GET16(ptr, tlen); - cparam = p->conn_param; - qos_pac = nni_msg_get_pub_qos(msg); - if (cparam->pro_ver != PROTOCOL_VERSION_v5) { - nni_msg_set_payload_ptr( - msg, ptr + tlen + 2 + (qos_pac > 0 ? 2 : 0)); - } else { - } - - if (qos_pac > 0) { - nni_msg_alloc(&qos_msg, 0); - if (qos_pac == 1) { - buf[0] = CMD_PUBACK; - } else if (qos_pac == 2) { - buf[0] = CMD_PUBREC; - } - buf[1] = 0x02; - - ackid = nni_msg_get_pub_pid(msg); - NNI_PUT16(buf + 2, ackid); - nni_msg_header_append(qos_msg, buf, 4); - } - if (qos_msg != NULL) { - nni_mtx_lock(&p->lk); - if (!p->busy) { - p->busy = true; - nni_aio_set_msg(&p->aio_send, qos_msg); - nni_pipe_send(p->pipe, &p->aio_send); - } else { - if (nni_lmq_full(&p->rlmq)) { - // Make space for the new message. TODO - // add max limit of msgq len in conf - debug_syslog("warning msg dropped!"); - nni_msg *old; - (void) nni_lmq_getq(&p->rlmq, &old); - nni_msg_free(old); - } - nni_lmq_putq(&p->rlmq, qos_msg); - } - nni_mtx_unlock(&p->lk); - } - break; case CMD_DISCONNECT: nni_pipe_close(p->pipe); - break; case CMD_CONNACK: + case CMD_PUBLISH: case CMD_PINGREQ: - // TODO check if this is necessary? + // Websocket need to reply PINGREQ in application layer break; - case CMD_PUBREC: - case CMD_PUBREL: - nni_msg_header_clear(msg); - if (nni_msg_cmd_type(msg) == CMD_PUBREC) { - buf[0] = 0X62; - } else if (nni_msg_cmd_type(msg) == CMD_PUBREL) { - buf[0] = CMD_PUBCOMP; - } - buf[1] = 0x02; - ptr = nni_msg_body(msg); - memcpy(buf + 2, ptr, 2); - nni_msg_clear(msg); - nni_msg_header_append(msg, buf, 4); - if (msg != NULL) { - nni_mtx_lock(&p->lk); - if (!p->busy) { - p->busy = true; - nni_aio_set_msg(&p->aio_send, msg); - nni_pipe_send(p->pipe, &p->aio_send); - } else { - if (nni_lmq_full(&p->rlmq)) { - // Make space for the new message. TODO - // add max limit of msgq len in conf - debug_syslog("warning msg dropped!"); - nni_msg *old; - (void) nni_lmq_getq(&p->rlmq, &old); - nni_msg_free(old); - } - nni_lmq_putq(&p->rlmq, msg); - } - nni_mtx_unlock(&p->lk); - } - goto end; case CMD_PUBACK: case CMD_PUBCOMP: nni_mtx_lock(&p->lk); @@ -1159,8 +1083,9 @@ nano_pipe_recv_cb(void *arg) debug_syslog("qos msg not found!"); } nni_mtx_unlock(&p->lk); - goto drop; case CMD_CONNECT: + case CMD_PUBREC: + case CMD_PUBREL: goto drop; default: goto drop; diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index bc4360347..1b019f4ed 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -39,6 +39,8 @@ struct tcptran_pipe { nni_aio * txaio; nni_aio * rxaio; nni_aio * qsaio; + nni_aio * rsaio; + nni_aio * rpaio; nni_aio * negoaio; nni_msg * rxmsg, *cnmsg; nni_mtx mtx; @@ -115,7 +117,9 @@ tcptran_pipe_close(void *arg) nni_mtx_unlock(&p->mtx); nni_aio_close(p->rxaio); + nni_aio_close(p->rpaio); nni_aio_close(p->txaio); + nni_aio_close(p->rsaio); nni_aio_close(p->qsaio); nni_aio_close(p->negoaio); @@ -129,6 +133,8 @@ tcptran_pipe_stop(void *arg) tcptran_pipe *p = arg; nni_aio_stop(p->qsaio); + nni_aio_stop(p->rsaio); + nni_aio_stop(p->rpaio); nni_aio_stop(p->rxaio); nni_aio_stop(p->txaio); nni_aio_stop(p->negoaio); @@ -165,7 +171,10 @@ tcptran_pipe_fini(void *arg) } nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); + // nng_free(p->tcp_cparam, sizeof(struct conn_param)); nni_aio_free(p->qsaio); + nni_aio_free(p->rpaio); + nni_aio_free(p->rsaio); nni_aio_free(p->rxaio); nni_aio_free(p->txaio); nni_aio_free(p->negoaio); @@ -198,6 +207,8 @@ tcptran_pipe_alloc(tcptran_pipe **pipep) nni_mtx_init(&p->mtx); if (((rv = nni_aio_alloc(&p->txaio, tcptran_pipe_send_cb, p)) != 0) || ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rpaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rsaio, NULL, p)) != 0) || ((rv = nni_aio_alloc(&p->rxaio, tcptran_pipe_recv_cb, p)) != 0) || ((rv = nni_aio_alloc(&p->negoaio, tcptran_pipe_nego_cb, p)) != 0)) { @@ -281,8 +292,9 @@ tcptran_pipe_nego_cb(void *arg) len = get_var_integer(p->rxlen + 1, (uint32_t *) &len_of_varint); p->wantrxhead = len + 1 + len_of_varint; - rv = (p->wantrxhead >= NANO_CONNECT_PACKET_LEN)? 0 : NNG_EPROTO; - if (rv !=0) { + rv = (p->wantrxhead >= NANO_CONNECT_PACKET_LEN) ? 0 + : NNG_EPROTO; + if (rv != 0) { goto error; } } @@ -413,10 +425,9 @@ tcptran_pipe_send_cb(void *arg) static void tcptran_pipe_recv_cb(void *arg) { - nni_aio *aio; - nni_iov iov; - uint8_t type; - // uint16_t fixed_header; + nni_aio * aio; + nni_iov iov; + uint8_t type; uint32_t len = 0, rv, pos = 1; size_t n; nni_msg * msg; @@ -475,7 +486,6 @@ tcptran_pipe_recv_cb(void *arg) nni_aio_set_iov(p->qsaio, 1, &iov); nng_stream_send(p->conn, p->qsaio); goto notify; - } else if ((p->rxlen[0] & 0XFF) == CMD_DISCONNECT) { } } @@ -519,7 +529,7 @@ tcptran_pipe_recv_cb(void *arg) // We read a message completely. Let the user know the good news. use // as application message callback of users - nni_aio_list_remove(aio); // need this to align with nng + nni_aio_list_remove(aio); msg = p->rxmsg; p->rxmsg = NULL; n = nni_msg_len(msg); @@ -527,7 +537,8 @@ tcptran_pipe_recv_cb(void *arg) fixed_header_adaptor(p->rxlen, msg); nni_msg_set_conn_param(msg, cparam); - nni_msg_set_remaining_len(msg, len); //duplicated with fixed_header_adaptor + nni_msg_set_remaining_len( + msg, len); // duplicated with fixed_header_adaptor nni_msg_set_cmd_type(msg, type); debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", len, cparam, cparam->clientid.body, cparam->username.body, @@ -535,6 +546,53 @@ tcptran_pipe_recv_cb(void *arg) // set the payload pointer of msg according to packet_type debug_msg("The type of msg is %x", type); + if (type == CMD_PUBLISH) { + uint8_t qos_pac; + uint16_t pid; + + qos_pac = nni_msg_get_pub_qos(msg); + if (qos_pac > 0) { + nng_aio_wait(p->rsaio); + if (qos_pac == 1) { + p->txlen[0] = CMD_PUBACK; + } else if (qos_pac == 2) { + p->txlen[0] = CMD_PUBREC; + } + p->txlen[1] = 0x02; + pid = nni_msg_get_pub_pid(msg); + NNI_PUT16(p->txlen + 2, pid); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->rsaio, 1, &iov); + nng_stream_send(p->conn, p->rsaio); + } + } else if (type == CMD_PUBREC) { + // TODO + uint8_t *tmp; + nng_aio_wait(p->rpaio); + p->txlen[0] = 0X62; + p->txlen[1] = 0x02; + tmp = nni_msg_body(msg); + memcpy(p->txlen + 2, tmp, 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->rpaio, 1, &iov); + nng_stream_send(p->conn, p->rpaio); + } else if (type == CMD_PUBREL) { + uint8_t *tmp; + nng_aio_wait(p->qsaio); + p->txlen[0] = CMD_PUBCOMP; + p->txlen[1] = 0x02; + tmp = nni_msg_body(msg); + memcpy(p->txlen + 2, tmp, 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->qsaio, 1, &iov); + nng_stream_send(p->conn, p->qsaio); + } // keep connection & Schedule next receive // nni_pipe_bump_rx(p->npipe, n); diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 9b8f0a3e7..03f4b3f5b 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -48,6 +48,7 @@ struct ws_listener { struct ws_pipe { nni_mtx mtx; bool closed; + uint8_t txlen[NANO_MIN_PACKET_LEN]; uint16_t peer; size_t gotrxhead; size_t wantrxhead; @@ -57,6 +58,7 @@ struct ws_pipe { nni_aio * ep_aio; nni_aio * txaio; nni_aio * rxaio; + nni_aio * qsaio; nni_pipe * npipe; uint8_t * qos_buf; conn_param *ws_param; @@ -95,6 +97,7 @@ wstran_pipe_recv_cb(void *arg) nni_msg *smsg, *msg; nni_aio *raio = p->rxaio; nni_aio *uaio = NULL; + nni_iov iov; nni_mtx_lock(&p->mtx); // only sets uaio at first time @@ -182,6 +185,30 @@ wstran_pipe_recv_cb(void *arg) p->tmp_msg = NULL; nni_msg_set_conn_param(smsg, p->ws_param); } + + if (nni_msg_cmd_type(smsg) == CMD_PUBLISH) { + uint8_t qos_pac; + uint16_t pid; + nni_msg * qos_msg; + + qos_pac = nni_msg_get_pub_qos(smsg); + if (qos_pac > 0) { + nng_aio_wait(p->qsaio); + if (qos_pac == 1) { + p->txlen[0] = CMD_PUBACK; + } else if (qos_pac == 2) { + p->txlen[0] = CMD_PUBREC; + } + p->txlen[1] = 0x02; + pid = nni_msg_get_pub_pid(smsg); + NNI_PUT16(p->txlen + 2, pid); + nni_msg_alloc(&qos_msg, 0); + nni_msg_header_append(qos_msg, p->txlen, 4); + nni_aio_set_msg(p->qsaio, qos_msg); + nng_stream_send(p->ws, p->qsaio); + } + } + nni_aio_set_msg(uaio, smsg); nni_aio_set_output(uaio, 0, p); nni_aio_finish(uaio, 0, nni_msg_len(smsg)); @@ -289,6 +316,7 @@ wstran_pipe_stop(void *arg) nni_aio_stop(p->rxaio); nni_aio_stop(p->txaio); + nni_aio_stop(p->qsaio); } static int @@ -313,6 +341,7 @@ wstran_pipe_fini(void *arg) nni_aio_free(p->rxaio); nni_aio_free(p->txaio); + nni_aio_free(p->qsaio); nng_stream_free(p->ws); nni_msg_free(p->tmp_msg); @@ -326,6 +355,7 @@ wstran_pipe_close(void *arg) ws_pipe *p = arg; nni_aio_close(p->rxaio); + nni_aio_close(p->qsaio); nni_aio_close(p->txaio); nni_mtx_lock(&p->mtx); @@ -346,6 +376,7 @@ wstran_pipe_alloc(ws_pipe **pipep, void *ws) // Initialize AIOs. if (((rv = nni_aio_alloc(&p->txaio, wstran_pipe_send_cb, p)) != 0) || + ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || ((rv = nni_aio_alloc(&p->rxaio, wstran_pipe_recv_cb, p)) != 0)) { wstran_pipe_fini(p); return (rv); From f8fea9557e65b87a8f24a89390d3200e79fe7a82 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 6 Sep 2021 11:02:36 +0800 Subject: [PATCH 027/180] New nng API for get/set prov_extra; New pub_extra structure and releated API; --- include/nng/nng.h | 3 + include/nng/protocol/mqtt/mqtt_parser.h | 8 +++ src/nng.c | 15 +++++ src/sp/protocol/mqtt/mqtt_parser.c | 68 ++++++++++++++++---- src/sp/protocol/reqrep0/nano_tcp.c | 85 +++++++++++++------------ src/sp/transport/tcp/tcp.c | 46 +++++++------ src/sp/transport/ws/websocket.c | 4 +- 7 files changed, 157 insertions(+), 72 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index 4c425efa5..d316332cd 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -548,6 +548,9 @@ NNG_DECL int nng_aio_set_output(nng_aio *, unsigned, void *); // nng_aio_get_output retrieves the output result at the given index. NNG_DECL void *nng_aio_get_output(nng_aio *, unsigned); +NNG_DECL void nng_aio_set_prov_extra(nng_aio *, unsigned , void *); +NNG_DECL void *nng_aio_get_prov_extra(nng_aio *, unsigned ); + // nng_aio_set_timeout sets a timeout on the AIO. This should be called for // operations that should time out after a period. The timeout should be // either a positive number of milliseconds, or NNG_DURATION_INFINITE to diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 18decdc58..1b9444c1e 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -21,10 +21,18 @@ #define CONNECT_TOPIC "$SYS/brokers/connected" // Variables & Structs +typedef struct pub_extra pub_extra; // int hex_to_oct(char *str); // uint32_t htoi(char *str); +extern pub_extra *pub_extra_alloc(pub_extra *); +extern void pub_extra_free(pub_extra *pub_extra); +extern uint8_t pub_extra_get_qos(pub_extra *pub_extra); +extern uint16_t pub_extra_get_packet_id(pub_extra *pub_extra); +extern void pub_extra_set_qos(pub_extra *pub_extra, uint8_t qos); +extern void pub_extra_set_packet_id(pub_extra *pub_extra, uint16_t packet_id); + // MQTT CONNECT int32_t conn_handler(uint8_t *packet, conn_param *conn_param); void init_conn_param(conn_param *cparam); diff --git a/src/nng.c b/src/nng.c index d8437c343..0e97d3822 100644 --- a/src/nng.c +++ b/src/nng.c @@ -1858,6 +1858,21 @@ nng_aio_get_output(nng_aio *aio, unsigned index) return (nni_aio_get_output(aio, index)); } +void *nng_aio_get_prov_extra(nng_aio *aio, unsigned index){ + if(index < 2) { + return nni_aio_get_prov_extra(aio, index); + }else { + return NULL; + } +} + +void +nng_aio_set_prov_extra(nng_aio *aio, unsigned index, void *data){ + if(index < 2) { + nni_aio_set_prov_extra(aio, index ,data); + } +} + void nng_aio_finish(nng_aio *aio, int rv) { diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 07a29abff..93f7507ef 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -16,9 +16,52 @@ #include #include +struct pub_extra { + uint8_t qos; + uint16_t packet_id; +}; + static uint8_t get_value_size(uint64_t value); static uint64_t power(uint64_t x, uint32_t n); +pub_extra * +pub_extra_alloc(pub_extra *extra) +{ + return NNI_ALLOC_STRUCT(extra); +} + +void +pub_extra_free(pub_extra *pub_extra) +{ + if (pub_extra) { + NNI_FREE_STRUCT(pub_extra); + } +} + +uint8_t +pub_extra_get_qos(pub_extra *pub_extra) +{ + return pub_extra->qos; +} + +uint16_t +pub_extra_get_packet_id(pub_extra *pub_extra) +{ + return pub_extra->packet_id; +} + +void +pub_extra_set_qos(pub_extra *pub_extra, uint8_t qos) +{ + pub_extra->qos = qos; +} + +void +pub_extra_set_packet_id(pub_extra *pub_extra, uint16_t packet_id) +{ + pub_extra->packet_id = packet_id; +} + static uint64_t power(uint64_t x, uint32_t n) { @@ -98,7 +141,7 @@ get_var_integer(const uint8_t *buf, uint32_t *pos) do { temp = *(buf + p); - result = result + (uint32_t)(temp & 0x7f) * (power(0x80, i)); + result = result + (uint32_t) (temp & 0x7f) * (power(0x80, i)); p++; } while ((temp & 0x80) > 0 && i++ < 4); *pos = p; @@ -270,7 +313,7 @@ get_variable_binary(uint8_t **dest, const uint8_t *src) return len; } -//set header & remaining length of msg +// set header & remaining length of msg int fixed_header_adaptor(uint8_t *packet, nng_msg *dst) { @@ -286,11 +329,12 @@ fixed_header_adaptor(uint8_t *packet, nng_msg *dst) return rv; } /** - * @brief copy packet (original msg suppose have full MQTT bytes in payload) to dst msg (new empty one) - * - * @param packet + * @brief copy packet (original msg suppose have full MQTT bytes in payload) to + * dst msg (new empty one) + * + * @param packet * @param dst assume it as an empty message - * @return int + * @return int */ int ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst) @@ -852,17 +896,17 @@ nano_msg_notify_connect(conn_param *cparam, uint8_t code) } /** - * @brief - * + * @brief + * * @param msg SUB/UNSUB packet * @param root root node of nano_pipe_db linked table * @param cparam connection param - * @return nano_pipe_db* pointer of newly added pipe_db + * @return nano_pipe_db* pointer of newly added pipe_db */ nano_pipe_db * nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) { - char *topic; + char * topic; nano_pipe_db *db = NULL, *tmp = NULL, *iter = NULL; uint8_t len_of_topic = 0, *payload_ptr; uint32_t len, len_of_varint = 0; @@ -886,7 +930,7 @@ nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) payload_ptr = nni_msg_body(msg) + 2; } nni_msg_set_payload_ptr(msg, payload_ptr); - remain = nni_msg_remaining_len(msg) - 2; + remain = nni_msg_remaining_len(msg) - 2; while (bpos < remain) { NNI_GET16(payload_ptr + bpos, len_of_topic); @@ -898,7 +942,7 @@ nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) iter = root; while (iter) { if (strlen(iter->topic) == len_of_topic && - !strncmp((char *)(payload_ptr + bpos + 2), + !strncmp((char *) (payload_ptr + bpos + 2), iter->topic, len_of_topic)) { repeat = true; bpos += (2 + len_of_topic); diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 8beb2ac41..ee5830c91 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -15,6 +15,7 @@ #include "core/nng_impl.h" #include "core/sockimpl.h" +#include "nng/nng.h" #include "nng/protocol/mqtt/mqtt.h" #include "nng/protocol/mqtt/mqtt_parser.h" #include "nng/protocol/mqtt/nano_tcp.h" @@ -71,33 +72,33 @@ struct nano_sock { // nano_pipe is our per-pipe protocol private structure. struct nano_pipe { - nni_mtx lk; - nni_pipe * pipe; - nano_sock * rep; - uint32_t id; - void * tree; // root node of db tree - nni_aio aio_send; - nni_aio aio_recv; - nni_aio aio_timer; - nni_list_node rnode; // receivable list linkage - nni_list sendq; // contexts waiting to send - bool busy; - bool closed; - bool kicked; - uint8_t reason_code; - uint8_t ka_refresh; - conn_param * conn_param; - nano_pipe_db *pipedb_root; - nni_lmq rlmq; + nni_mtx lk; + nni_pipe * pipe; + nano_sock * rep; + uint32_t id; + void * tree; // root node of db tree + nni_aio aio_send; + nni_aio aio_recv; + nni_aio aio_timer; + nni_list_node rnode; // receivable list linkage + nni_list sendq; // contexts waiting to send + bool busy; + bool closed; + bool kicked; + uint8_t reason_code; + uint8_t ka_refresh; + nano_conn_param *conn_param; + nano_pipe_db * pipedb_root; + nni_lmq rlmq; }; struct nano_clean_session { - client_ctx * cltx; - conn_param * cparam; - nni_id_map * msg_map; - nano_pipe_db *pipe_db; - uint32_t pipeid; // corresponding pipe id of nng - bool clean; + client_ctx * cltx; + nano_conn_param *cparam; + nni_id_map * msg_map; + nano_pipe_db * pipe_db; + uint32_t pipeid; // corresponding pipe id of nng + bool clean; }; static void @@ -289,6 +290,12 @@ nano_ctx_send(void *arg, nni_aio *aio) nni_mtx_lock(&p->lk); if (!p->busy) { p->busy = true; + pub_extra *pub_extra_info = + (pub_extra *) nni_aio_get_prov_extra(aio, 0); + if (pub_extra_info) { + nni_aio_set_prov_extra( + &p->aio_send, 0, pub_extra_info); + } nni_aio_set_msg(&p->aio_send, msg); nni_pipe_send(p->pipe, &p->aio_send); nni_mtx_unlock(&p->lk); @@ -326,8 +333,8 @@ nano_clean_session_db_fini(nni_id_map *m) uint32_t key = 0; nano_clean_session *cs = NULL; while ((cs = nni_id_get_one(m, &key)) != NULL) { - conn_param *cparam = cs->cparam; - nni_id_map *msg_map = cs->msg_map; + nano_conn_param *cparam = cs->cparam; + nni_id_map * msg_map = cs->msg_map; destroy_conn_param(cparam); nni_id_iterate(msg_map, nni_id_msgfree_cb); @@ -1005,19 +1012,19 @@ nano_ctx_recv(void *arg, nni_aio *aio) static void nano_pipe_recv_cb(void *arg) { - nano_pipe * p = arg; - nano_sock * s = p->rep; - conn_param * cparam; - uint32_t len, len_of_varint = 0; - uint8_t qos_pac, buf[4]; - size_t tlen; - nano_ctx * ctx; - nni_msg * msg, *qos_msg; - nni_aio * aio; - nano_pipe_db *pipe_db; - nni_pipe * npipe = p->pipe; - uint8_t * ptr; - uint16_t ackid; + nano_pipe * p = arg; + nano_sock * s = p->rep; + nano_conn_param *cparam = NULL; + uint32_t len, len_of_varint = 0; + uint8_t qos_pac = 0, buf[4]; + size_t tlen; + nano_ctx * ctx; + nni_msg * msg, *qos_msg = NULL; + nni_aio * aio; + nano_pipe_db * pipe_db; + nni_pipe * npipe = p->pipe; + uint8_t * ptr; + uint16_t ackid; if (nni_aio_result(&p->aio_recv) != 0) { // unexpected disconnect diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 1b019f4ed..64897f21c 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -293,7 +293,7 @@ tcptran_pipe_nego_cb(void *arg) get_var_integer(p->rxlen + 1, (uint32_t *) &len_of_varint); p->wantrxhead = len + 1 + len_of_varint; rv = (p->wantrxhead >= NANO_CONNECT_PACKET_LEN) ? 0 - : NNG_EPROTO; + : NNG_EPROTO; if (rv != 0) { goto error; } @@ -537,8 +537,8 @@ tcptran_pipe_recv_cb(void *arg) fixed_header_adaptor(p->rxlen, msg); nni_msg_set_conn_param(msg, cparam); - nni_msg_set_remaining_len( - msg, len); // duplicated with fixed_header_adaptor + // duplicated with fixed_header_adaptor + nni_msg_set_remaining_len(msg, len); nni_msg_set_cmd_type(msg, type); debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", len, cparam, cparam->clientid.body, cparam->username.body, @@ -687,10 +687,9 @@ tcptran_pipe_send_start(tcptran_pipe *p) uint8_t varheader[2], fixheader[NNI_NANO_MAX_HEADER_SIZE] = { 0 }, tmp[4] = { 0 }; - nni_pipe * pipe; - uint16_t pid; - size_t tlen, rlen; - nano_pipe_db *db; + nni_pipe *pipe; + uint16_t pid; + size_t tlen, rlen; pipe = p->npipe; body = nni_msg_body(msg); @@ -698,24 +697,33 @@ tcptran_pipe_send_start(tcptran_pipe *p) p->qlength = 0; NNI_GET16(body, tlen); - if ((db = nni_id_get(&pipe->nano_db, - DJBHashn((char *) body + 2, tlen))) == NULL) { - // shouldn't get here BUG TODO - nni_println( - "ERROR: nano_db subscription topic missing!"); + pub_extra *pub_extra_info = + (pub_extra *) nni_aio_get_prov_extra(aio, 0); + + if (pub_extra_info == NULL) { goto send; } + + debug_msg("get pub_extra :%p", pub_extra_info); + debug_msg("get pub_extra, qos: %d, packet id: %d", + pub_extra_get_qos(pub_extra_info), + pub_extra_get_packet_id(pub_extra_info)); + + uint8_t qos = pub_extra_get_qos(pub_extra_info); + + pub_extra_free(pub_extra_info); + qos_pac = nni_msg_get_pub_qos(msg); if (qos_pac == 0) { // save time & space for QoS 0 publish goto send; } - debug_msg("qos_pac %d sub %d\n", qos_pac, db->qos); + debug_msg("qos_pac %d sub %d\n", qos_pac, qos); memcpy(fixheader, header, nni_msg_header_len(msg)); - if (qos_pac > db->qos) { - if (db->qos == 1) { + if (qos_pac > qos) { + if (qos == 1) { // set qos to 1 fixheader[0] = fixheader[0] & 0xF9; fixheader[0] = fixheader[0] | 0x02; @@ -729,7 +737,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) tmp, nni_msg_remaining_len(msg) - 2); memcpy(fixheader + 1, tmp, rlen); } - } else if (qos_pac < db->qos) { + } else if (qos_pac < qos) { if (qos_pac == 1) { // QoS 1 publish to Qos 2 // TODO @@ -750,7 +758,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) p->qlength += tlen + 2; // get topic length // packet id - if (db->qos > 0 && qos_pac > 0) { + if (qos > 0 && qos_pac > 0) { // set pid nni_msg *old; pid = nni_aio_get_packetid(aio); @@ -787,7 +795,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) } memcpy(p->qos_buf, fixheader, rlen + 1); memcpy(p->qos_buf + rlen + 1, body, tlen + 2); - if (db->qos > 0 && qos_pac > 0) { + if (qos > 0 && qos_pac > 0) { memcpy(p->qos_buf + rlen + tlen + 3, varheader, 2); } iov[niov].iov_buf = p->qos_buf; @@ -1057,7 +1065,7 @@ tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl) return (0); } - len = (size_t)(semi - url->u_hostname); + len = (size_t) (semi - url->u_hostname); url->u_hostname = semi + 1; if (strcmp(surl->u_scheme, "tcp") == 0) { diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 03f4b3f5b..593dafb04 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -94,7 +94,7 @@ wstran_pipe_recv_cb(void *arg) ws_pipe *p = arg; uint32_t len = 0, rv, pos = 1; uint8_t *ptr; - nni_msg *smsg, *msg; + nni_msg *smsg = NULL, *msg = NULL; nni_aio *raio = p->rxaio; nni_aio *uaio = NULL; nni_iov iov; @@ -111,7 +111,7 @@ wstran_pipe_recv_cb(void *arg) msg = nni_aio_get_msg(raio); ptr = nni_msg_body(msg); p->gotrxhead += nni_msg_len(msg); - debug_msg("#### wstran_pipe_recv_cb got %d msg: %p %x %d", + debug_msg("#### wstran_pipe_recv_cb got %ld msg: %p %x %ld", p->gotrxhead, ptr, *ptr, nni_msg_len(msg)); // first we collect complete Fixheader if (p->tmp_msg == NULL && p->gotrxhead > 0) { From 6d4afd3ced0120c8952c421a4e7cefb53c5643cc Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Tue, 7 Sep 2021 14:41:34 +0800 Subject: [PATCH 028/180] Add a field "msg" to pub_extra & releated API --- include/nng/protocol/mqtt/mqtt_parser.h | 2 + src/sp/protocol/mqtt/mqtt_parser.c | 23 +++++++-- src/sp/protocol/reqrep0/nano_tcp.c | 67 +++++++++++++++++-------- 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 1b9444c1e..03aaf9617 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -31,6 +31,8 @@ extern void pub_extra_free(pub_extra *pub_extra); extern uint8_t pub_extra_get_qos(pub_extra *pub_extra); extern uint16_t pub_extra_get_packet_id(pub_extra *pub_extra); extern void pub_extra_set_qos(pub_extra *pub_extra, uint8_t qos); +extern void * pub_extra_get_msg(pub_extra *pub_extra); +extern void pub_extra_set_msg(pub_extra *pub_extra, void *msg); extern void pub_extra_set_packet_id(pub_extra *pub_extra, uint16_t packet_id); // MQTT CONNECT diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 93f7507ef..388c5ef31 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -19,6 +19,7 @@ struct pub_extra { uint8_t qos; uint16_t packet_id; + void * msg; }; static uint8_t get_value_size(uint64_t value); @@ -44,6 +45,12 @@ pub_extra_get_qos(pub_extra *pub_extra) return pub_extra->qos; } +void +pub_extra_set_qos(pub_extra *pub_extra, uint8_t qos) +{ + pub_extra->qos = qos; +} + uint16_t pub_extra_get_packet_id(pub_extra *pub_extra) { @@ -51,15 +58,21 @@ pub_extra_get_packet_id(pub_extra *pub_extra) } void -pub_extra_set_qos(pub_extra *pub_extra, uint8_t qos) +pub_extra_set_packet_id(pub_extra *pub_extra, uint16_t packet_id) { - pub_extra->qos = qos; + pub_extra->packet_id = packet_id; +} + +void * +pub_extra_get_msg(pub_extra *pub_extra) +{ + return pub_extra->msg; } void -pub_extra_set_packet_id(pub_extra *pub_extra, uint16_t packet_id) +pub_extra_set_msg(pub_extra *pub_extra, void *msg) { - pub_extra->packet_id = packet_id; + pub_extra->msg = msg; } static uint64_t @@ -752,7 +765,7 @@ DJBHashn(char *str, uint16_t len) hash = ((hash << 5) + hash) + (*str++); /* times 33 */ i++; } - hash &= ~(1 << 31); /* strip the highest bit */ + hash &= ~(1U << 31); /* strip the highest bit */ return hash; } diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index ee5830c91..1d9d45890 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -15,6 +15,7 @@ #include "core/nng_impl.h" #include "core/sockimpl.h" +#include "nano_lmq.h" #include "nng/nng.h" #include "nng/protocol/mqtt/mqtt.h" #include "nng/protocol/mqtt/mqtt_parser.h" @@ -89,7 +90,7 @@ struct nano_pipe { uint8_t ka_refresh; nano_conn_param *conn_param; nano_pipe_db * pipedb_root; - nni_lmq rlmq; + nano_lmq rlmq; }; struct nano_clean_session { @@ -287,11 +288,16 @@ nano_ctx_send(void *arg, nni_aio *aio) return; } nni_mtx_unlock(&s->lk); + nni_mtx_lock(&p->lk); + + pub_extra *pub_extra_info = + (pub_extra *) nni_aio_get_prov_extra(aio, 0); + + debug_msg("pub_extra_info: %p", pub_extra_info); + if (!p->busy) { p->busy = true; - pub_extra *pub_extra_info = - (pub_extra *) nni_aio_get_prov_extra(aio, 0); if (pub_extra_info) { nni_aio_set_prov_extra( &p->aio_send, 0, pub_extra_info); @@ -309,18 +315,30 @@ nano_ctx_send(void *arg, nni_aio *aio) return; } debug_msg("WARNING: pipe %d occupied! resending in cb!", pipe); - if (nni_lmq_full(&p->rlmq)) { + if (nano_lmq_full(&p->rlmq)) { // Make space for the new message. TODO add max limit of msgq // len in conf - if ((rv = nni_lmq_resize( - &p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { - debug_syslog("warning msg dropped!"); - nni_msg *old; - (void) nni_lmq_getq(&p->rlmq, &old); - nni_msg_free(old); + if ((rv = nano_lmq_resize_with_cb(&p->rlmq, + nano_lmq_cap(&p->rlmq) * 2, + (nano_lmq_free) nni_msg_free, + (nano_lmq_get_sub_msg) pub_extra_get_msg)) != 0) { + debug_msg("warning msg dropped!"); + pub_extra *old; + if (nano_lmq_getq(&p->rlmq, (void **) &old) == 0) { + nni_msg *old_msg = + (nni_msg *) pub_extra_get_msg(old); + nni_msg_free(old_msg); + pub_extra_free(old); + } + } else { + debug_msg("nano_lmq_resize error: %d", rv); } } - nni_lmq_putq(&p->rlmq, msg); + + pub_extra_set_msg(pub_extra_info, msg); + rv = nano_lmq_putq(&p->rlmq, pub_extra_info); + + debug_msg("nano_lmq_putq %p, %d", pub_extra_info, rv); nni_mtx_unlock(&p->lk); nni_aio_set_msg(aio, NULL); @@ -753,7 +771,9 @@ nano_pipe_fini(void *arg) nni_aio_fini(&p->aio_send); nni_aio_fini(&p->aio_recv); nni_aio_fini(&p->aio_timer); - nni_lmq_fini(&p->rlmq); + + nano_lmq_fini_with_cb(&p->rlmq, (nano_lmq_free) nni_msg_free, + (nano_lmq_get_sub_msg) pub_extra_get_msg); } static int @@ -765,7 +785,7 @@ nano_pipe_init(void *arg, nni_pipe *pipe, void *s) debug_msg("##########nano_pipe_init###############"); nni_mtx_init(&p->lk); - nni_lmq_init(&p->rlmq, sock->conf->msq_len); + nano_lmq_init(&p->rlmq, sock->conf->msq_len); nni_aio_init(&p->aio_send, nano_pipe_send_cb, p); // TODO move keepalive monitor to transport layer? nni_aio_init(&p->aio_timer, nano_pipe_timer_cb, p); @@ -847,7 +867,9 @@ close_pipe(nano_pipe *p) if (nni_list_active(&s->recvpipes, p)) { nni_list_remove(&s->recvpipes, p); } - nni_lmq_flush(&p->rlmq); + // nni_lmq_flush(&p->rlmq); + nano_lmq_flush_with_cb(&p->rlmq, (nano_lmq_free) nni_msg_free, + (nano_lmq_get_sub_msg) pub_extra_get_msg); // TODO delete while ((ctx = nni_list_first(&p->sendq)) != NULL) { @@ -906,9 +928,7 @@ static void nano_pipe_send_cb(void *arg) { nano_pipe *p = arg; - nni_msg * msg; - // uint32_t index = 0; - // uint32_t * pipes; + pub_extra *extra; debug_msg( "################ nano_pipe_send_cb %d ################", p->id); @@ -922,13 +942,20 @@ nano_pipe_send_cb(void *arg) nni_mtx_lock(&p->lk); nni_aio_set_packetid(&p->aio_send, 0); - if (nni_lmq_getq(&p->rlmq, &msg) == 0) { + int rv = nano_lmq_getq(&p->rlmq, (void **) &extra); + if (rv == 0) { + nni_msg *msg = (nni_msg *) pub_extra_get_msg(extra); + debug_msg("get nng_msg from pub_extra: %p", msg); + nni_aio_set_prov_extra(&p->aio_send, 0, extra); nni_aio_set_msg(&p->aio_send, msg); + debug_msg("rlmq msg resending! %ld msgs left\n", - nni_lmq_len(&p->rlmq)); + nano_lmq_len(&p->rlmq)); nni_pipe_send(p->pipe, &p->aio_send); nni_mtx_unlock(&p->lk); return; + } else { + debug_msg("nano_lmq_getq error: %d", rv); } p->busy = false; @@ -1016,8 +1043,6 @@ nano_pipe_recv_cb(void *arg) nano_sock * s = p->rep; nano_conn_param *cparam = NULL; uint32_t len, len_of_varint = 0; - uint8_t qos_pac = 0, buf[4]; - size_t tlen; nano_ctx * ctx; nni_msg * msg, *qos_msg = NULL; nni_aio * aio; From 47d75c7df60868b235bc4aea4386d1eab16b8399 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Tue, 7 Sep 2021 18:11:18 +0800 Subject: [PATCH 029/180] Collate code --- include/nng/protocol/mqtt/mqtt_parser.h | 14 +++++++------- src/sp/protocol/reqrep0/nano_tcp.c | 14 +++----------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 03aaf9617..2700cfca4 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -27,13 +27,13 @@ typedef struct pub_extra pub_extra; // uint32_t htoi(char *str); extern pub_extra *pub_extra_alloc(pub_extra *); -extern void pub_extra_free(pub_extra *pub_extra); -extern uint8_t pub_extra_get_qos(pub_extra *pub_extra); -extern uint16_t pub_extra_get_packet_id(pub_extra *pub_extra); -extern void pub_extra_set_qos(pub_extra *pub_extra, uint8_t qos); -extern void * pub_extra_get_msg(pub_extra *pub_extra); -extern void pub_extra_set_msg(pub_extra *pub_extra, void *msg); -extern void pub_extra_set_packet_id(pub_extra *pub_extra, uint16_t packet_id); +extern void pub_extra_free(pub_extra *); +extern uint8_t pub_extra_get_qos(pub_extra *); +extern uint16_t pub_extra_get_packet_id(pub_extra *); +extern void pub_extra_set_qos(pub_extra *, uint8_t); +extern void * pub_extra_get_msg(pub_extra *); +extern void pub_extra_set_msg(pub_extra *, void *); +extern void pub_extra_set_packet_id(pub_extra *, uint16_t); // MQTT CONNECT int32_t conn_handler(uint8_t *packet, conn_param *conn_param); diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 1d9d45890..f206a4fbc 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -294,14 +294,10 @@ nano_ctx_send(void *arg, nni_aio *aio) pub_extra *pub_extra_info = (pub_extra *) nni_aio_get_prov_extra(aio, 0); - debug_msg("pub_extra_info: %p", pub_extra_info); - if (!p->busy) { p->busy = true; - if (pub_extra_info) { - nni_aio_set_prov_extra( - &p->aio_send, 0, pub_extra_info); - } + nni_aio_set_prov_extra(&p->aio_send, 0, pub_extra_info); + nni_aio_set_msg(&p->aio_send, msg); nni_pipe_send(p->pipe, &p->aio_send); nni_mtx_unlock(&p->lk); @@ -330,15 +326,11 @@ nano_ctx_send(void *arg, nni_aio *aio) nni_msg_free(old_msg); pub_extra_free(old); } - } else { - debug_msg("nano_lmq_resize error: %d", rv); } } pub_extra_set_msg(pub_extra_info, msg); - rv = nano_lmq_putq(&p->rlmq, pub_extra_info); - - debug_msg("nano_lmq_putq %p, %d", pub_extra_info, rv); + nano_lmq_putq(&p->rlmq, pub_extra_info); nni_mtx_unlock(&p->lk); nni_aio_set_msg(aio, NULL); From ed1a1acfb4957ddef9064683f1fd8f29dc1dc050 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Thu, 2 Sep 2021 12:13:11 +0800 Subject: [PATCH 030/180] * NEW [nano_tcp] move clean session to broker layer --- include/nng/nng.h | 2 + include/nng/protocol/mqtt/mqtt_parser.h | 2 + src/nng.c | 17 ++- src/sp/protocol/mqtt/mqtt_parser.c | 47 +++++++ src/sp/protocol/reqrep0/nano_tcp.c | 169 ++++++------------------ 5 files changed, 104 insertions(+), 133 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index d316332cd..59caf5bc2 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1321,6 +1321,8 @@ NNG_DECL uint8_t conn_param_get_will_qos(conn_param *cparam); NNG_DECL uint8_t conn_param_get_will_retain(conn_param *cparam); NNG_DECL uint16_t conn_param_get_keepalive(conn_param *cparam); NNG_DECL uint8_t conn_param_get_protover(conn_param *cparam); +NNG_DECL void * conn_param_get_qos_db(conn_param *cparam); +NNG_DECL void conn_param_set_qos_db(conn_param *cparam, void *); NNG_DECL void nng_taskq_setter (int num_taskq_threads, int max_taskq_threads); #ifdef __cplusplus diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 2700cfca4..2c881f3d1 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -37,8 +37,10 @@ extern void pub_extra_set_packet_id(pub_extra *, uint16_t); // MQTT CONNECT int32_t conn_handler(uint8_t *packet, conn_param *conn_param); +int new_conn_param(conn_param **cparam); void init_conn_param(conn_param *cparam); void destroy_conn_param(conn_param *cparam); +void deep_copy_conn_param(conn_param *new_cp, conn_param *cp); int fixed_header_adaptor(uint8_t *packet, nng_msg *dst); int ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst); diff --git a/src/nng.c b/src/nng.c index 0e97d3822..60fffa592 100644 --- a/src/nng.c +++ b/src/nng.c @@ -2077,10 +2077,19 @@ conn_param_get_keepalive(conn_param *cparam) uint8_t conn_param_get_protover(conn_param *cparam) { - if (NULL == cparam) - return 0; - else - return cparam->pro_ver; + return cparam->pro_ver; +} + +void * +conn_param_get_qos_db(conn_param *cparam) +{ + return (void *)(cparam->nano_qos_db); +} + +void +conn_param_set_qos_db(conn_param *cparam, void * qos) +{ + cparam->nano_qos_db = qos; } void diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 388c5ef31..96a0f100a 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -13,6 +13,7 @@ #include "nng/protocol/mqtt/mqtt.h" #include +#include #include #include @@ -682,6 +683,17 @@ conn_handler(uint8_t *packet, conn_param *cparam) return rv; } +int +new_conn_param(conn_param **cparamp) +{ + conn_param * new_cp; + if ((new_cp = nng_alloc(sizeof(conn_param))) == NULL) { + return (NNG_ENOMEM); + } + *cparamp = new_cp; + return 0; +} + void destroy_conn_param(conn_param *cparam) { @@ -745,6 +757,41 @@ init_conn_param(conn_param *cparam) cparam->payload_user_property.len_val = 0; } +void +deep_copy_conn_param(conn_param *new_cp, conn_param *cp) +{ +// UPDATE_FIELD_INT(pro_ver, new_cp, cp); +// UPDATE_FIELD_INT(con_flag, new_cp, cp); +// UPDATE_FIELD_INT(keepalive_mqtt, new_cp, cp); +// UPDATE_FIELD_INT(clean_start, new_cp, cp); + UPDATE_FIELD_INT(will_flag, new_cp, cp); + UPDATE_FIELD_INT(will_retain, new_cp, cp); + UPDATE_FIELD_INT(will_qos, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(pro_name, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(clientid, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(will_topic, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(will_msg, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(username, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(password, body, new_cp, cp); + UPDATE_FIELD_INT(session_expiry_interval, new_cp, cp); + UPDATE_FIELD_INT(rx_max, new_cp, cp); + UPDATE_FIELD_INT(max_packet_size, new_cp, cp); + UPDATE_FIELD_INT(topic_alias_max, new_cp, cp); + UPDATE_FIELD_INT(req_resp_info, new_cp, cp); + UPDATE_FIELD_INT(req_problem_info, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(auth_method, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(auth_data, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING_PAIR(user_property, key, val, new_cp, cp); + UPDATE_FIELD_INT(will_delay_interval, new_cp, cp); + UPDATE_FIELD_INT(payload_format_indicator, new_cp, cp); + UPDATE_FIELD_INT(msg_expiry_interval, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(content_type, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(resp_topic, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING(corr_data, body, new_cp, cp); + UPDATE_FIELD_MQTT_STRING_PAIR( + payload_user_property, key, val, new_cp, cp); +} + uint32_t DJBHash(char *str) { diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index f206a4fbc..f18c9abc4 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -28,7 +28,7 @@ typedef struct nano_pipe nano_pipe; typedef struct nano_sock nano_sock; typedef struct nano_ctx nano_ctx; -typedef struct nano_clean_session nano_clean_session; +// typedef struct nano_clean_session nano_clean_session; typedef struct cs_msg_list cs_msg_list; static void nano_pipe_send_cb(void *); @@ -93,15 +93,6 @@ struct nano_pipe { nano_lmq rlmq; }; -struct nano_clean_session { - client_ctx * cltx; - nano_conn_param *cparam; - nni_id_map * msg_map; - nano_pipe_db * pipe_db; - uint32_t pipeid; // corresponding pipe id of nng - bool clean; -}; - static void nano_pipe_timer_cb(void *arg) { @@ -264,8 +255,7 @@ nano_ctx_send(void *arg, nni_aio *aio) } else { pipe = ctx->pipe_id; // reply to self } - ctx->pipe_id = - 0; // ensure connack/PING/DISCONNECT/PUBACK only sends once + ctx->pipe_id = 0; // ensure connack/PING/DISCONNECT/PUBACK only sends once if (ctx == &s->ctx) { nni_pollable_clear(&s->writable); @@ -343,8 +333,8 @@ nano_clean_session_db_fini(nni_id_map *m) uint32_t key = 0; nano_clean_session *cs = NULL; while ((cs = nni_id_get_one(m, &key)) != NULL) { - nano_conn_param *cparam = cs->cparam; - nni_id_map * msg_map = cs->msg_map; + conn_param *cparam = cs->cparam; + nni_id_map *msg_map = (nni_id_map *)cs->msg_map; destroy_conn_param(cparam); nni_id_iterate(msg_map, nni_id_msgfree_cb); @@ -425,88 +415,7 @@ nano_pipe_stop(void *arg) nni_aio_stop(&p->aio_recv); } -static void -nano_deep_copy_connparam(conn_param *new_cp, conn_param *cp) -{ - UPDATE_FIELD_INT(pro_ver, new_cp, cp); - UPDATE_FIELD_INT(con_flag, new_cp, cp); - UPDATE_FIELD_INT(keepalive_mqtt, new_cp, cp); - UPDATE_FIELD_INT(clean_start, new_cp, cp); - UPDATE_FIELD_INT(will_flag, new_cp, cp); - UPDATE_FIELD_INT(will_retain, new_cp, cp); - UPDATE_FIELD_INT(will_qos, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(pro_name, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(clientid, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(will_topic, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(will_msg, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(username, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(password, body, new_cp, cp); - UPDATE_FIELD_INT(session_expiry_interval, new_cp, cp); - UPDATE_FIELD_INT(rx_max, new_cp, cp); - UPDATE_FIELD_INT(max_packet_size, new_cp, cp); - UPDATE_FIELD_INT(topic_alias_max, new_cp, cp); - UPDATE_FIELD_INT(req_resp_info, new_cp, cp); - UPDATE_FIELD_INT(req_problem_info, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(auth_method, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(auth_data, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING_PAIR(user_property, key, val, new_cp, cp); - UPDATE_FIELD_INT(will_delay_interval, new_cp, cp); - UPDATE_FIELD_INT(payload_format_indicator, new_cp, cp); - UPDATE_FIELD_INT(msg_expiry_interval, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(content_type, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(resp_topic, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(corr_data, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING_PAIR( - payload_user_property, key, val, new_cp, cp); -} - -static void * -del_topic_clictx_from_tree(void *tree, topic_queue *tq, uint32_t pid) -{ - client_ctx *cli_ctx = NULL; - - while (tq) { - if (tq->topic) { - cli_ctx = search_and_delete(tree, tq->topic, pid); - } - debug_msg("delete pipe id [%d] topic: [%s]", pid, tq->topic); - del_sub_ctx(cli_ctx, tq->topic); - tq = tq->next; - } - - return cli_ctx; -} - -static void * -del_topic_from_tree(void *tree, topic_queue *tq, uint32_t pid) -{ - client_ctx *cli_ctx = NULL; - - while (tq) { - if (tq->topic) { - cli_ctx = search_and_delete(tree, tq->topic, pid); - } - debug_msg("delete pipe id [%d] topic: [%s]", pid, tq->topic); - tq = tq->next; - } - - return cli_ctx; -} - -static void -restore_topic_to_tree(void *tree, client_ctx *cli_ctx, char *client_id) -{ - topic_node *tn_t = cli_ctx->sub_pkt->node; - - while (tn_t) { - debug_msg("Now adding topic (from last session), body: [%s]", - tn_t->it->topic_filter.body); - search_and_insert(tree, tn_t->it->topic_filter.body, client_id, - cli_ctx, cli_ctx->pid.id); - tn_t = tn_t->next; - } -} - +/* static int nano_session_restore(nano_pipe *p, nano_sock *s, uint8_t *flag) { @@ -523,8 +432,7 @@ nano_session_restore(nano_pipe *p, nano_sock *s, uint8_t *flag) // no matter if client enabled cleansession. use clean-session-db for // duplicate clientid verifying. if (cs == NULL) { - if ((cs = nni_zalloc(sizeof(nano_clean_session) * 1)) == - NULL) { + if ((cs = nni_zalloc(sizeof(nano_clean_session))) == NULL) { return (NNG_ENOMEM); } // firts connection, store pipeid and hashed clientid @@ -703,6 +611,7 @@ nano_sessiondb_clean(nano_pipe *p) } } } +*/ static void nano_pipe_fini(void *arg) @@ -725,39 +634,40 @@ nano_pipe_fini(void *arg) nni_msg_free(msg); } - key = DJBHashn(cp->clientid.body, cp->clientid.len); - // get temp_cs from clean_session_db // TODO potential risk without lock - temp_cs = nni_id_get(&s->clean_session_db, key); - if (p->conn_param->clean_start == 0 && temp_cs != NULL && - p->kicked != true) { - nano_session_cache(p, temp_cs, key); - } else { - // When clean_session is set to 1 - nni_id_map * nano_qos_db = p->conn_param->nano_qos_db; - client_ctx * cli_ctx = NULL; - struct topic_queue *tq = NULL; - - nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); - nni_id_map_fini(nano_qos_db); - nng_free(nano_qos_db, sizeof(struct nni_id_map)); - - if (check_id(p->id) && p->tree != NULL) { - tq = get_topic(p->id); - if ((cli_ctx = del_topic_clictx_from_tree( - p->tree, tq, p->id)) != NULL) { - debug_msg("(CS=1) Unexpected, not all topic " - "has been delete from sub_pkt"); +/* + if (p->conn_param->clean_start == 0) { + } +*/ + + // When clean_session is set to 1 +// nni_id_map * nano_qos_db = p->conn_param->nano_qos_db; + + nni_id_map * nano_qos_db = p->pipe->nano_qos_db; + +// nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); + nni_id_map_fini(nano_qos_db); + nng_free(nano_qos_db, sizeof(struct nni_id_map)); +/* + if (check_id(p->id) && p->tree != NULL) { + tq = get_topic(p->id); + while (tq) { + if (tq->topic) { + cli_ctx = search_and_delete(p->tree, tq->topic, p->id); } - del_topic_all(p->id); - } else { - debug_msg("(CS=1) UNEXPECTED: no stored topic queue, " - "tq lost or maybe not subed any topic"); + debug_msg("delete pipe id [%d] topic: [%s]", p->id, tq->topic); + del_sub_ctx(cli_ctx, tq->topic); + tq = tq->next; } - nano_msg_free_pipedb(p->pipedb_root); - p->pipedb_root = NULL; + del_topic_all(p->id); + } else { + debug_msg("Clean session. no stored topic queue"); } - destroy_conn_param(p->conn_param); +*/ + + nano_msg_free_pipedb(p->pipedb_root); + p->pipedb_root = NULL; +// destroy_conn_param(p->conn_param); nni_mtx_fini(&p->lk); nni_aio_fini(&p->aio_send); @@ -828,7 +738,7 @@ nano_pipe_start(void *arg) debug_syslog("Invalid auth info."); *(reason + 1) = rv; // set return code } - rv = nano_session_restore(p, s, reason); +// rv = nano_session_restore(p, s, reason); nni_mtx_unlock(&s->lk); // TODO MQTT V5 check return code @@ -876,7 +786,7 @@ close_pipe(nano_pipe *p) nni_msg_free(msg); } nni_id_remove(&s->pipes, nni_pipe_id(p->pipe)); - nano_sessiondb_clean(p); +// nano_sessiondb_clean(p); } static void @@ -902,6 +812,7 @@ nano_pipe_close(void *arg) } nni_msg_set_conn_param(msg, p->conn_param); nni_msg_set_cmd_type(msg, CMD_DISCONNECT_EV); + nni_msg_set_pipe(msg, p->id); aio = ctx->raio; ctx->raio = NULL; nni_list_remove(&s->recvq, ctx); From 3f04a3ac35144d379932955667633d01c5b9eccc Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Sat, 4 Sep 2021 13:46:49 +0800 Subject: [PATCH 031/180] * FIX [nano_tcp] fix the memory leak due to no enough ctx. --- src/sp/protocol/reqrep0/nano_tcp.c | 54 +++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index f18c9abc4..3cdfc574b 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -61,7 +61,8 @@ struct nano_sock { nni_mtx lk; nni_atomic_int ttl; nni_id_map pipes; - nni_id_map clean_session_db; +// nni_id_map clean_session_db; + nni_lmq waitlmq; nni_list recvpipes; // list of pipes with data to receive nni_list recvq; nano_ctx ctx; // base socket @@ -327,6 +328,7 @@ nano_ctx_send(void *arg, nni_aio *aio) return; } +/* void nano_clean_session_db_fini(nni_id_map *m) { @@ -346,6 +348,7 @@ nano_clean_session_db_fini(nni_id_map *m) } nni_id_map_fini(m); } +*/ static void nano_sock_fini(void *arg) @@ -353,7 +356,10 @@ nano_sock_fini(void *arg) nano_sock *s = arg; nni_id_map_fini(&s->pipes); +/* nano_clean_session_db_fini(&s->clean_session_db); +*/ + nni_lmq_fini(&s->waitlmq); nano_ctx_fini(&s->ctx); nni_pollable_fini(&s->writable); nni_pollable_fini(&s->readable); @@ -372,7 +378,8 @@ nano_sock_init(void *arg, nni_sock *sock) nni_mtx_init(&s->lk); nni_id_map_init(&s->pipes, 0, 0, false); - nni_id_map_init(&s->clean_session_db, 0, 0, false); +// nni_id_map_init(&s->clean_session_db, 0, 0, false); + nni_lmq_init(&s->waitlmq, 256); NNI_LIST_INIT(&s->recvq, nano_ctx, rqnode); NNI_LIST_INIT(&s->recvpipes, nano_pipe, rnode); @@ -802,17 +809,19 @@ nano_pipe_close(void *arg) debug_msg("################# nano_pipe_close ##############"); nni_mtx_lock(&s->lk); close_pipe(p); - // pub disconnect event + + // create disconnect event msg + msg = nano_msg_notify_disconnect(p->conn_param, reason_code); + if (msg == NULL) { + nni_mtx_unlock(&s->lk); + return; + } + nni_msg_set_conn_param(msg, p->conn_param); + nni_msg_set_cmd_type(msg, CMD_DISCONNECT_EV); + nni_msg_set_pipe(msg, p->id); + + // expose disconnect event if ((ctx = nni_list_first(&s->recvq)) != NULL) { - msg = - nano_msg_notify_disconnect(p->conn_param, p->reason_code); - if (msg == NULL) { - nni_mtx_unlock(&s->lk); - return; - } - nni_msg_set_conn_param(msg, p->conn_param); - nni_msg_set_cmd_type(msg, CMD_DISCONNECT_EV); - nni_msg_set_pipe(msg, p->id); aio = ctx->raio; ctx->raio = NULL; nni_list_remove(&s->recvq, ctx); @@ -821,8 +830,13 @@ nano_pipe_close(void *arg) nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); return; } else { - debug_msg("Warning: no ctx left!! faied to send disconnect " - "notification"); + // no enough ctx, so cache to waitlmq + if (nni_lmq_full(&s->waitlmq)) { + if (nni_lmq_resize(&s->waitlmq, nni_lmq_cap(&s->waitlmq) * 2) != 0) { + debug_msg("wait lmq resize failed."); + } + } + nni_lmq_putq(&s->waitlmq, msg); } nni_mtx_unlock(&s->lk); } @@ -889,13 +903,23 @@ nano_ctx_recv(void *arg, nni_aio *aio) nano_sock *s = ctx->sock; nano_pipe *p; // size_t len; - nni_msg *msg; + nni_msg *msg = NULL; if (nni_aio_begin(aio) != 0) { return; } + debug_msg("nano_ctx_recv start %p", ctx); nni_mtx_lock(&s->lk); + + if (nni_lmq_getq(&s->waitlmq, &msg) == 0) { + nni_mtx_unlock(&s->lk); + debug_msg("handle msg in waitlmq."); + nni_aio_set_msg(aio, msg); + nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); + return; + } + if ((p = nni_list_first(&s->recvpipes)) == NULL) { int rv; if ((rv = nni_aio_schedule(aio, nano_cancel_recv, ctx)) != 0) { From e33c77b275785ac5da294570125936d747932490 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Sun, 5 Sep 2021 14:32:37 +0800 Subject: [PATCH 032/180] * FIX [nano_tcp] remove code (comment or not) about clean session. --- src/sp/protocol/reqrep0/nano_tcp.c | 256 +---------------------------- 1 file changed, 1 insertion(+), 255 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 3cdfc574b..e42a84004 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -28,7 +28,6 @@ typedef struct nano_pipe nano_pipe; typedef struct nano_sock nano_sock; typedef struct nano_ctx nano_ctx; -// typedef struct nano_clean_session nano_clean_session; typedef struct cs_msg_list cs_msg_list; static void nano_pipe_send_cb(void *); @@ -61,7 +60,6 @@ struct nano_sock { nni_mtx lk; nni_atomic_int ttl; nni_id_map pipes; -// nni_id_map clean_session_db; nni_lmq waitlmq; nni_list recvpipes; // list of pipes with data to receive nni_list recvq; @@ -328,37 +326,12 @@ nano_ctx_send(void *arg, nni_aio *aio) return; } -/* -void -nano_clean_session_db_fini(nni_id_map *m) -{ - uint32_t key = 0; - nano_clean_session *cs = NULL; - while ((cs = nni_id_get_one(m, &key)) != NULL) { - conn_param *cparam = cs->cparam; - nni_id_map *msg_map = (nni_id_map *)cs->msg_map; - - destroy_conn_param(cparam); - nni_id_iterate(msg_map, nni_id_msgfree_cb); - nni_id_map_fini(msg_map); - nng_free(msg_map, sizeof(struct nni_id_map)); - - nni_id_remove(m, key); - cs = NULL; - } - nni_id_map_fini(m); -} -*/ - static void nano_sock_fini(void *arg) { nano_sock *s = arg; nni_id_map_fini(&s->pipes); -/* - nano_clean_session_db_fini(&s->clean_session_db); -*/ nni_lmq_fini(&s->waitlmq); nano_ctx_fini(&s->ctx); nni_pollable_fini(&s->writable); @@ -378,7 +351,6 @@ nano_sock_init(void *arg, nni_sock *sock) nni_mtx_init(&s->lk); nni_id_map_init(&s->pipes, 0, 0, false); -// nni_id_map_init(&s->clean_session_db, 0, 0, false); nni_lmq_init(&s->waitlmq, 256); NNI_LIST_INIT(&s->recvq, nano_ctx, rqnode); NNI_LIST_INIT(&s->recvpipes, nano_pipe, rnode); @@ -422,204 +394,6 @@ nano_pipe_stop(void *arg) nni_aio_stop(&p->aio_recv); } -/* -static int -nano_session_restore(nano_pipe *p, nano_sock *s, uint8_t *flag) -{ - int ret; - conn_param * new_cparam = p->conn_param; - uint32_t key; - uint8_t clean_session_flag = new_cparam->clean_start; - nano_clean_session *cs; - - key = DJBHashn(new_cparam->clientid.body, new_cparam->clientid.len); - // TODO hash collision? - cs = nni_id_get(&s->clean_session_db, key); - - // no matter if client enabled cleansession. use clean-session-db for - // duplicate clientid verifying. - if (cs == NULL) { - if ((cs = nni_zalloc(sizeof(nano_clean_session))) == NULL) { - return (NNG_ENOMEM); - } - // firts connection, store pipeid and hashed clientid - cs->pipeid = p->id; - if (clean_session_flag == 0) { - debug_msg("(CS=0) Session cannot restore, cannot find " - "cached information based " - "on the clientID given (eithe first connect " - "or lose the backup)"); - cs->clean = false; - ret = 0; - } else { - debug_msg("(CS=1) No need for restoring a session"); - cs->clean = true; - ret = 0; - } - if (nni_id_set(&s->clean_session_db, key, cs) != 0) { - debug_msg("(CS=0) UNEXPECTED: The nano_clean_session " - "structure is not set " - "as a new instance of hashtable"); - ret = NNG_ECONNABORTED; - } - return ret; - } else if (cs->pipeid != 0) { - // TODO kick prev connection or current one?(p or cs->pipeid) - p->kicked = true; - if (p->conn_param->pro_ver == 5) { - *(flag + 1) = 0x8E; - } else { - *(flag + 1) = 0x02; - } - return (NNG_ECONNABORTED); - } - - client_ctx * cltx = cs->cltx; - conn_param * cparam = cs->cparam; - nni_id_map * msgs = cs->msg_map; - nano_pipe_db *topics = cs->pipe_db; - nano_pipe_db *topic_node = topics; - - cs->pipeid = p->id; - if (clean_session_flag == 0) { - *flag = 0x01; // set session present flag - cs->clean = false; - // step 0 restore conn param - nano_deep_copy_connparam(new_cparam, cparam); - destroy_conn_param(cparam); - cparam = NULL; - // step 1 restore nano_qos_db - // TODO new coming message may use the existing packet id in - // one client nano_qos_db - nni_id_map_fini(p->pipe->nano_qos_db); - nng_free(p->pipe->nano_qos_db, sizeof(struct nni_id_map)); - p->pipe->nano_qos_db = msgs; - p->conn_param->nano_qos_db = msgs; - // step 2 restore cli_ctx and cached_topic_queue - if (cltx != NULL) - cltx->pid.id = p->id; - if (cached_check_id(key)) { - restore_topic_all(key, p->id); - restore_topic_to_tree( - p->tree, cltx, new_cparam->clientid.body); - } else { - debug_msg( - "(CS=0) UNEXPECTED: no stored cached topic queue"); - } - // step 3 restore topic in pipe_db - p->pipedb_root = topics; - cs->pipe_db = NULL; - // step 4 restore nano_pipe_db - while (topic_node->next) { - nni_id_set(&p->pipe->nano_db, - DJBHashn( - topic_node->topic, strlen(topic_node->topic)), - topic_node); - topic_node = topic_node->next; - } - debug_msg( - "(CS=0) All last session related information restored"); - } else { - cs->clean = true; - // step 0 remove conn param - destroy_conn_param(cparam); - cparam = NULL; - // step 1 remove nano_qos_db - nni_id_iterate(msgs, nni_id_msgfree_cb); - nni_id_map_fini(msgs); - nng_free(msgs, sizeof(struct nni_id_map)); - msgs = NULL; - // step 2 delete 2-1 cli_ctx and cached topic queue - if (cached_check_id(key)) { - topic_queue *tq = get_cached_topic(key); - while (tq) { - del_sub_ctx(cltx, tq->topic); - tq = tq->next; - } - del_cached_topic_all(key); - } else { - debug_msg( - "(CS=1) UNEXPECTED: no stored cached topic queue"); - } - // step 3 delete topics in pipe_db - nano_msg_free_pipedb(topics); - debug_msg( - "(CS=1) All last session related information disgarded"); - } - return 0; -} - -static int -nano_session_cache(nano_pipe *p, nano_clean_session *temp_cs, uint32_t key) -{ - conn_param * cp = p->conn_param; - nni_id_map * nano_qos_db = cp->nano_qos_db; - client_ctx * cli_ctx = NULL; - struct topic_queue *tq = NULL; - - // step 0 copy connection parameter - conn_param *new_cp; - if ((new_cp = nni_zalloc(sizeof(conn_param) * 1)) == NULL) { - return (NNG_ENOMEM); - } - init_conn_param(new_cp); - nano_deep_copy_connparam(new_cp, cp); - temp_cs->cparam = new_cp; - // step 1 move nano_qos_db to temp_cs struct (move pointer) - temp_cs->msg_map = nano_qos_db; - debug_msg("the nano_qos_db has an address: %p", nano_qos_db); - nano_qos_db = NULL; - // step 2-1 find cli_ctx and kept its pointer, but delete topic from - // tree step 2-2 move topic from topic map to cached topic map - // (hash.cc) - if (check_id(p->id)) { - tq = get_topic(p->id); - if ((cli_ctx = del_topic_from_tree(p->tree, tq, p->id)) != - NULL) { - cli_ctx->pid.id = 0; - temp_cs->cltx = cli_ctx; - } - cache_topic_all(p->id, key); - } else { - debug_msg("(CS=0) UNEXPECTED: no stored topic queue, tq lost " - "or client may not subed topic"); - } - // step 3 move nano_pipe_db to temp_cs struct (move pointer) - temp_cs->pipe_db = p->pipedb_root; - p->pipedb_root = NULL; - - debug_msg("(CS=0) Session cached, all this session related " - "information kept"); - return 0; -} - -static void -nano_sessiondb_clean(nano_pipe *p) -{ - conn_param * cp = p->conn_param; - nano_sock * s = p->rep; - uint32_t key; - nano_clean_session *temp_cs; - - key = DJBHashn(cp->clientid.body, cp->clientid.len); - // get temp_cs from clean_session_db - temp_cs = nni_id_get(&s->clean_session_db, key); - if (temp_cs != NULL) { - // temp_cs->pipeid indicates if current session existed. - if (p->closed == true && temp_cs->pipeid == p->id) { - temp_cs->pipeid = 0; - } - if (temp_cs->clean == true) { - // Do not kick the old one. - if (temp_cs->pipeid == 0) { - nni_id_remove(&s->clean_session_db, key); - nng_free(temp_cs, sizeof(nano_clean_session)); - } - } - } -} -*/ - static void nano_pipe_fini(void *arg) { @@ -641,40 +415,14 @@ nano_pipe_fini(void *arg) nni_msg_free(msg); } - // TODO potential risk without lock -/* - if (p->conn_param->clean_start == 0) { - } -*/ - - // When clean_session is set to 1 -// nni_id_map * nano_qos_db = p->conn_param->nano_qos_db; - nni_id_map * nano_qos_db = p->pipe->nano_qos_db; // nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); nni_id_map_fini(nano_qos_db); nng_free(nano_qos_db, sizeof(struct nni_id_map)); -/* - if (check_id(p->id) && p->tree != NULL) { - tq = get_topic(p->id); - while (tq) { - if (tq->topic) { - cli_ctx = search_and_delete(p->tree, tq->topic, p->id); - } - debug_msg("delete pipe id [%d] topic: [%s]", p->id, tq->topic); - del_sub_ctx(cli_ctx, tq->topic); - tq = tq->next; - } - del_topic_all(p->id); - } else { - debug_msg("Clean session. no stored topic queue"); - } -*/ nano_msg_free_pipedb(p->pipedb_root); p->pipedb_root = NULL; -// destroy_conn_param(p->conn_param); nni_mtx_fini(&p->lk); nni_aio_fini(&p->aio_send); @@ -745,7 +493,6 @@ nano_pipe_start(void *arg) debug_syslog("Invalid auth info."); *(reason + 1) = rv; // set return code } -// rv = nano_session_restore(p, s, reason); nni_mtx_unlock(&s->lk); // TODO MQTT V5 check return code @@ -793,7 +540,6 @@ close_pipe(nano_pipe *p) nni_msg_free(msg); } nni_id_remove(&s->pipes, nni_pipe_id(p->pipe)); -// nano_sessiondb_clean(p); } static void @@ -811,7 +557,7 @@ nano_pipe_close(void *arg) close_pipe(p); // create disconnect event msg - msg = nano_msg_notify_disconnect(p->conn_param, reason_code); + msg = nano_msg_notify_disconnect(p->conn_param, p->reason_code); if (msg == NULL) { nni_mtx_unlock(&s->lk); return; From cfaa1cf845a4e942f7b50113f2fa53ee9c6207cc Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 10 Sep 2021 19:15:02 +0800 Subject: [PATCH 033/180] * FIX [nano_tcp] remove nano_clean_session var --- src/sp/protocol/reqrep0/nano_tcp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index e42a84004..5fff4cb5f 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -400,7 +400,6 @@ nano_pipe_fini(void *arg) nano_pipe * p = arg; nng_msg * msg; uint32_t key; - nano_clean_session *temp_cs; conn_param * cp = p->conn_param; nano_sock * s = p->rep; From 0d450f3c36b09724204bc4257573e030970dbe58 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Fri, 10 Sep 2021 13:44:41 +0800 Subject: [PATCH 034/180] * FIX [mqtt_parser] function nano_msg_composer supports reuse msg --- include/nng/protocol/mqtt/mqtt_parser.h | 2 +- src/sp/protocol/mqtt/mqtt_parser.c | 20 +++++++++++++------- src/sp/protocol/reqrep0/nano_tcp.c | 3 --- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 2c881f3d1..d1e18e9cc 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -65,7 +65,7 @@ NNG_DECL uint8_t verify_connect(conn_param *cparam, conf *conf); // repack NNG_DECL void nano_msg_set_dup(nng_msg *msg); NNG_DECL nng_msg *nano_msg_composer( - uint8_t retain, uint8_t qos, mqtt_string *payload, mqtt_string *topic); + nng_msg **, uint8_t retain, uint8_t qos, mqtt_string *payload, mqtt_string *topic); NNG_DECL nng_msg *nano_msg_notify_disconnect(conn_param *cparam, uint8_t code); NNG_DECL nng_msg *nano_msg_notify_connect(conn_param *cparam, uint8_t code); NNG_DECL nano_pipe_db *nano_msg_get_subtopic( diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 96a0f100a..c8fb5d25b 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -840,7 +840,7 @@ nano_msg_set_dup(nng_msg *msg) // alloc a publish msg according to the need nng_msg * nano_msg_composer( - uint8_t retain, uint8_t qos, mqtt_string *payload, mqtt_string *topic) + nng_msg ** msgp, uint8_t retain, uint8_t qos, mqtt_string *payload, mqtt_string *topic) { size_t rlen; uint8_t *ptr, buf[5] = { '\0' }; @@ -848,8 +848,15 @@ nano_msg_composer( nni_msg *msg; len = payload->len + topic->len + 2; + + msg = *msgp; + if (msg == NULL) { + nni_msg_alloc(&msg, len + (qos>0?2:0)); + } else { + nni_msg_realloc(msg, len + (qos>0?2:0)); + } + if (qos > 0) { - nni_msg_alloc(&msg, len + 2); rlen = put_var_integer(buf + 1, len + 2); nni_msg_set_remaining_len(msg, len + 2); if (qos == 1) { @@ -861,7 +868,6 @@ nano_msg_composer( return NULL; } } else { - nni_msg_alloc(&msg, len); rlen = put_var_integer(buf + 1, len); nni_msg_set_remaining_len(msg, len); buf[0] = CMD_PUBLISH; @@ -925,7 +931,7 @@ verify_connect(conn_param *cparam, conf *conf) nng_msg * nano_msg_notify_disconnect(conn_param *cparam, uint8_t code) { - nni_msg * msg; + nni_msg * msg = NULL; mqtt_string string, topic; char buff[256]; snprintf(buff, 256, DISCONNECT_MSG, (char *) cparam->username.body, @@ -934,14 +940,14 @@ nano_msg_notify_disconnect(conn_param *cparam, uint8_t code) string.len = strlen(string.body); topic.body = DISCONNECT_TOPIC; topic.len = strlen(DISCONNECT_TOPIC); - msg = nano_msg_composer(0, 0, &string, &topic); + msg = nano_msg_composer(&msg, 0, 0, &string, &topic); return msg; } nng_msg * nano_msg_notify_connect(conn_param *cparam, uint8_t code) { - nni_msg * msg; + nni_msg * msg = NULL; mqtt_string string, topic; char buff[256]; snprintf(buff, 256, CONNECT_MSG, cparam->username.body, nni_clock(), @@ -951,7 +957,7 @@ nano_msg_notify_connect(conn_param *cparam, uint8_t code) string.len = strlen(string.body); topic.body = CONNECT_TOPIC; topic.len = strlen(CONNECT_TOPIC); - msg = nano_msg_composer(0, 0, &string, &topic); + msg = nano_msg_composer(&msg, 0, 0, &string, &topic); return msg; } diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 5fff4cb5f..bcbf742a7 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -399,9 +399,6 @@ nano_pipe_fini(void *arg) { nano_pipe * p = arg; nng_msg * msg; - uint32_t key; - conn_param * cp = p->conn_param; - nano_sock * s = p->rep; debug_msg("########## nano_pipe_fini ###############"); if ((msg = nni_aio_get_msg(&p->aio_recv)) != NULL) { From 955cb8c1dd1447b2526a9fcf76d03dc9f56138ac Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Sat, 11 Sep 2021 15:06:45 +0800 Subject: [PATCH 035/180] * NEW [mqtt_parser] add refcnt parameter in conn_param & rename interface about conn_param. --- include/nng/protocol/mqtt/mqtt_parser.h | 8 +-- src/core/message.c | 3 +- src/core/message.h | 1 + src/sp/protocol/mqtt/mqtt_parser.c | 85 +++++++++++++++---------- src/sp/transport/tcp/tcp.c | 4 +- 5 files changed, 58 insertions(+), 43 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index d1e18e9cc..cb91b7016 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -37,10 +37,10 @@ extern void pub_extra_set_packet_id(pub_extra *, uint16_t); // MQTT CONNECT int32_t conn_handler(uint8_t *packet, conn_param *conn_param); -int new_conn_param(conn_param **cparam); -void init_conn_param(conn_param *cparam); -void destroy_conn_param(conn_param *cparam); -void deep_copy_conn_param(conn_param *new_cp, conn_param *cp); +int conn_param_alloc(conn_param **cparam); +void conn_param_free(conn_param *cparam); +void conn_param_clone(conn_param *cparam); +// void deep_copy_conn_param(conn_param *new_cp, conn_param *cp); int fixed_header_adaptor(uint8_t *packet, nng_msg *dst); int ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst); diff --git a/src/core/message.c b/src/core/message.c index 6a4bc8c23..d60ead80e 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -27,8 +27,7 @@ typedef struct { // Underlying message structure. // TODO independent nano_msg struct nng_msg { - uint8_t - m_header_buf[NNI_NANO_MAX_HEADER_SIZE + 1]; // only Fixed header + uint8_t m_header_buf[NNI_NANO_MAX_HEADER_SIZE + 1]; // only Fixed header size_t m_header_len; nni_chunk m_body; // equal to variable header + payload uint32_t m_pipe; // set on receive diff --git a/src/core/message.h b/src/core/message.h index 492375dc5..1b89b2be1 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -100,6 +100,7 @@ struct pipe_db { // TODO use ZALLOC later struct conn_param { + nni_atomic_int refcnt; uint8_t pro_ver; uint8_t con_flag; uint16_t keepalive_mqtt; diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index c8fb5d25b..b301111ab 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -400,7 +400,6 @@ sizeof(struct conn_param)); int32_t conn_handler(uint8_t *packet, conn_param *cparam) { - uint32_t len, tmp, pos = 0, len_of_properties = 0, len_of_var = 0; int len_of_str = 0; int32_t rv = 0; @@ -413,7 +412,6 @@ conn_handler(uint8_t *packet, conn_param *cparam) pos++; } - init_conn_param(cparam); // remaining length len = (uint32_t) get_var_integer(packet + pos, &len_of_var); pos += len_of_var; @@ -683,23 +681,64 @@ conn_handler(uint8_t *packet, conn_param *cparam) return rv; } +static void +conn_param_init(conn_param *cparam) +{ + cparam->pro_name.len = 0; + cparam->pro_name.body = NULL; + cparam->clientid.len = 0; + cparam->clientid.body = NULL; + cparam->will_topic.body = NULL; + cparam->will_topic.len = 0; + cparam->will_msg.body = NULL; + cparam->will_msg.len = 0; + cparam->username.body = NULL; + cparam->username.len = 0; + cparam->password.body = NULL; + cparam->password.len = 0; + cparam->auth_method.body = NULL; + cparam->auth_method.len = 0; + cparam->auth_data.body = NULL; + cparam->auth_data.len = 0; + cparam->user_property.key = NULL; + cparam->user_property.len_key = 0; + cparam->user_property.val = NULL; + cparam->user_property.len_val = 0; + cparam->content_type.body = NULL; + cparam->content_type.len = 0; + cparam->resp_topic.body = NULL; + cparam->resp_topic.len = 0; + cparam->corr_data.body = NULL; + cparam->corr_data.len = 0; + cparam->payload_user_property.key = NULL; + cparam->payload_user_property.len_key = 0; + cparam->payload_user_property.val = NULL; + cparam->payload_user_property.len_val = 0; +} + int -new_conn_param(conn_param **cparamp) +conn_param_alloc(conn_param **cparamp) { conn_param * new_cp; if ((new_cp = nng_alloc(sizeof(conn_param))) == NULL) { return (NNG_ENOMEM); } + nni_atomic_init(&new_cp->refcnt); + nni_atomic_set(&new_cp->refcnt, 1); + conn_param_init(new_cp); *cparamp = new_cp; return 0; } void -destroy_conn_param(conn_param *cparam) +conn_param_free(conn_param *cparam) { if (cparam == NULL) { return; } + if (nni_atomic_dec_nv(&cparam->refcnt) != 0) { + return; + } debug_msg("destroy conn param"); nng_free(cparam->pro_name.body, cparam->pro_name.len); nng_free(cparam->clientid.body, cparam->clientid.len); @@ -723,40 +762,15 @@ destroy_conn_param(conn_param *cparam) } void -init_conn_param(conn_param *cparam) +conn_param_clone(conn_param * cparam) { - cparam->pro_name.len = 0; - cparam->pro_name.body = NULL; - cparam->clientid.len = 0; - cparam->clientid.body = NULL; - cparam->will_topic.body = NULL; - cparam->will_topic.len = 0; - cparam->will_msg.body = NULL; - cparam->will_msg.len = 0; - cparam->username.body = NULL; - cparam->username.len = 0; - cparam->password.body = NULL; - cparam->password.len = 0; - cparam->auth_method.body = NULL; - cparam->auth_method.len = 0; - cparam->auth_data.body = NULL; - cparam->auth_data.len = 0; - cparam->user_property.key = NULL; - cparam->user_property.len_key = 0; - cparam->user_property.val = NULL; - cparam->user_property.len_val = 0; - cparam->content_type.body = NULL; - cparam->content_type.len = 0; - cparam->resp_topic.body = NULL; - cparam->resp_topic.len = 0; - cparam->corr_data.body = NULL; - cparam->corr_data.len = 0; - cparam->payload_user_property.key = NULL; - cparam->payload_user_property.len_key = 0; - cparam->payload_user_property.val = NULL; - cparam->payload_user_property.len_val = 0; + if (cparam == NULL) { + return; + } + nni_atomic_inc(&cparam->refcnt); } +/* void deep_copy_conn_param(conn_param *new_cp, conn_param *cp) { @@ -791,6 +805,7 @@ deep_copy_conn_param(conn_param *new_cp, conn_param *cp) UPDATE_FIELD_MQTT_STRING_PAIR( payload_user_property, key, val, new_cp, cp); } +*/ uint32_t DJBHash(char *str) diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 64897f21c..a9bb626f6 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -318,7 +318,7 @@ tcptran_pipe_nego_cb(void *arg) if (p->gotrxhead >= p->wantrxhead) { if (p->tcp_cparam == NULL) { - p->tcp_cparam = nng_alloc(sizeof(struct conn_param)); + conn_param_alloc(&p->tcp_cparam); } if (conn_handler(p->conn_buf, p->tcp_cparam) == 0) { nng_free(p->conn_buf, p->wantrxhead); @@ -334,7 +334,7 @@ tcptran_pipe_nego_cb(void *arg) } else { rv = NNG_EPROTO; nng_free(p->conn_buf, p->wantrxhead); - nng_free(p->tcp_cparam, sizeof(struct conn_param)); + conn_param_free(p->tcp_cparam); goto error; } } From 6b77679ba6f01393874d8e529d80e0fd4b04d3bb Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 21 Aug 2021 16:11:54 -0700 Subject: [PATCH 036/180] Move protocol.c into SP tree (it is SP specific.) Also, remove an extraneous initialization call. --- src/core/CMakeLists.txt | 1 - src/sp/CMakeLists.txt | 1 + src/{core => sp}/protocol.c | 3 --- 3 files changed, 1 insertion(+), 4 deletions(-) rename src/{core => sp}/protocol.c (95%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3783dbd3c..0e751f3b2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -50,7 +50,6 @@ nng_sources( pipe.c pipe.h platform.h - protocol.c protocol.h reap.c reap.h diff --git a/src/sp/CMakeLists.txt b/src/sp/CMakeLists.txt index aa790c090..4704f8021 100644 --- a/src/sp/CMakeLists.txt +++ b/src/sp/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(protocol) add_subdirectory(transport) nng_sources( + protocol.c transport.c transport.h ) diff --git a/src/core/protocol.c b/src/sp/protocol.c similarity index 95% rename from src/core/protocol.c rename to src/sp/protocol.c index 993f0826a..5436addb2 100644 --- a/src/core/protocol.c +++ b/src/sp/protocol.c @@ -19,9 +19,6 @@ nni_proto_open(nng_socket *sip, const nni_proto *proto) int rv; nni_sock *sock; - if ((rv = nni_init()) != 0) { - return (rv); - } if ((rv = nni_sock_open(&sock, proto)) == 0) { nng_socket s; s.id = nni_sock_id(sock); // Keep socket held open. From cc4e70871ead1ba0d631801edc25a73cc1a11ad3 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 21 Aug 2021 16:36:06 -0700 Subject: [PATCH 037/180] Remove unused prototypes. --- src/core/socket.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/socket.h b/src/core/socket.h index b06f4d47e..e653329b4 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -1,5 +1,5 @@ // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -33,8 +33,6 @@ extern int nni_sock_setopt( nni_sock *, const char *, const void *, size_t, nni_opt_type); extern int nni_sock_getopt( nni_sock *, const char *, void *, size_t *, nni_opt_type); -extern int nni_sock_recvmsg(nni_sock *, nni_msg **, int); -extern int nni_sock_sendmsg(nni_sock *, nni_msg *, int); extern void nni_sock_send(nni_sock *, nni_aio *); extern void nni_sock_recv(nni_sock *, nni_aio *); extern uint32_t nni_sock_id(nni_sock *); From 7f6b6a39adc97057704e2b4174bb395721f9c0e3 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 21 Aug 2021 16:43:16 -0700 Subject: [PATCH 038/180] Minor cleanups. --- src/core/socket.h | 10 +++++----- src/core/sockimpl.h | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/core/socket.h b/src/core/socket.h index e653329b4..57a776814 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -41,11 +41,11 @@ extern uint32_t nni_sock_id(nni_sock *); // Note that each of these should be called without any locks held, since // the socket can reenter the protocol. -// nni_socket_sendq obtains the upper writeq. The protocol should +// nni_socket_sendq obtains the upper write queue. The protocol should // receive messages from this, and place them on the appropriate pipe. extern nni_msgq *nni_sock_sendq(nni_sock *); -// nni_socket_recvq obtains the upper readq. The protocol should +// nni_socket_recvq obtains the upper read queue. The protocol should // inject incoming messages from pipes to it. extern nni_msgq *nni_sock_recvq(nni_sock *); @@ -54,7 +54,7 @@ extern nni_msgq *nni_sock_recvq(nni_sock *); extern uint32_t nni_sock_flags(nni_sock *); // This function is used by the public API to set callbacks. It is -// one of the only cases (the only?) where the socket core understands +// one of the few cases (the only?) where the socket core understands // the public data types. (Other solutions might exist, but they require // keeping extra state to support conversion between public and internal // types.) The second argument is a mask of events for which the callback @@ -90,10 +90,10 @@ extern void nni_ctx_close(nni_ctx *); // nni_ctx_id returns the context ID, which can be used with nni_ctx_find. extern uint32_t nni_ctx_id(nni_ctx *); -// nni_ctx_recv is an asychronous receive. +// nni_ctx_recv receives asynchronously. extern void nni_ctx_recv(nni_ctx *, nni_aio *); -// nni_ctx_send is an asychronous receive. +// nni_ctx_send sends asynchronously. extern void nni_ctx_send(nni_ctx *, nni_aio *); // nni_ctx_getopt is used to get a context option. diff --git a/src/core/sockimpl.h b/src/core/sockimpl.h index ff1c4aba7..1670330c8 100644 --- a/src/core/sockimpl.h +++ b/src/core/sockimpl.h @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -36,7 +36,6 @@ struct nni_dialer { nni_duration d_maxrtime; // maximum time for reconnect nni_duration d_currtime; // current time for reconnect nni_duration d_inirtime; // initial time for reconnect - nni_time d_conntime; // time of last good connect nni_reap_node d_reap; #ifdef NNG_ENABLE_STATS From b967e5a8f1f6d3660507a2daf34e70be49bbf10c Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 4 Sep 2021 17:27:54 -0700 Subject: [PATCH 039/180] fixes #1498 Endpoint close/shutdown could be synchronous (#1499) --- src/core/dialer.c | 58 ++++++++--------- src/core/listener.c | 43 ++++++------- src/core/socket.c | 153 ++++++++++++-------------------------------- src/core/sockimpl.h | 38 +++++------ src/nng.c | 8 +-- 5 files changed, 105 insertions(+), 195 deletions(-) diff --git a/src/core/dialer.c b/src/core/dialer.c index a96742264..4c3e563d4 100644 --- a/src/core/dialer.c +++ b/src/core/dialer.c @@ -225,15 +225,20 @@ nni_dialer_bump_error(nni_dialer *d, int err) #endif } +// nni_dialer_create creates a dialer on the socket. +// The caller should have a hold on the socket, and on success +// the dialer inherits the callers hold. (If the caller wants +// an additional hold, it should get an extra hold before calling this +// function.) int -nni_dialer_create(nni_dialer **dp, nni_sock *s, const char *urlstr) +nni_dialer_create(nni_dialer **dp, nni_sock *s, const char *url_str) { - nni_sp_tran * tran; - nni_dialer *d; - int rv; - nni_url * url; + nni_sp_tran *tran; + nni_dialer *d; + int rv; + nni_url *url; - if ((rv = nni_url_parse(&url, urlstr)) != 0) { + if ((rv = nni_url_parse(&url, url_str)) != 0) { return (rv); } if (((tran = nni_sp_tran_find(url)) == NULL) || @@ -246,13 +251,12 @@ nni_dialer_create(nni_dialer **dp, nni_sock *s, const char *urlstr) nni_url_free(url); return (NNG_ENOMEM); } - d->d_url = url; - d->d_closed = false; - d->d_closing = false; - d->d_data = NULL; - d->d_ref = 1; - d->d_sock = s; - d->d_tran = tran; + d->d_url = url; + d->d_closed = false; + d->d_data = NULL; + d->d_ref = 1; + d->d_sock = s; + d->d_tran = tran; nni_atomic_flag_reset(&d->d_started); // Make a copy of the endpoint operations. This allows us to @@ -341,22 +345,6 @@ nni_dialer_rele(nni_dialer *d) } } -void -nni_dialer_close_rele(nni_dialer *d) -{ - nni_mtx_lock(&dialers_lk); - if (d->d_closed) { - nni_mtx_unlock(&dialers_lk); - nni_dialer_rele(d); - return; - } - d->d_closed = true; - nni_id_remove(&dialers, d->d_id); - nni_mtx_unlock(&dialers_lk); - - nni_dialer_rele(d); -} - void nni_dialer_close(nni_dialer *d) { @@ -389,8 +377,8 @@ static void dialer_connect_cb(void *arg) { nni_dialer *d = arg; - nni_aio * aio = &d->d_con_aio; - nni_aio * user_aio; + nni_aio *aio = &d->d_con_aio; + nni_aio *user_aio; int rv; nni_mtx_lock(&d->d_mtx); @@ -465,6 +453,14 @@ nni_dialer_start(nni_dialer *d, unsigned flags) return (rv); } +void +nni_dialer_stop(nni_dialer *d) +{ + nni_aio_stop(&d->d_tmo_aio); + nni_aio_stop(&d->d_con_aio); + d->d_ops.d_close(d->d_data); +} + nni_sock * nni_dialer_sock(nni_dialer *d) { diff --git a/src/core/listener.c b/src/core/listener.c index c2a5863de..410988f6a 100644 --- a/src/core/listener.c +++ b/src/core/listener.c @@ -50,9 +50,7 @@ nni_listener_id(nni_listener *l) void nni_listener_destroy(nni_listener *l) { - nni_aio_stop(&l->l_acc_aio); - nni_aio_stop(&l->l_tmo_aio); - + // NB: both these will have already been stopped. nni_aio_fini(&l->l_acc_aio); nni_aio_fini(&l->l_tmo_aio); @@ -216,13 +214,18 @@ nni_listener_bump_error(nni_listener *l, int err) #endif } +// nni_listener_create creates a listener on the socket. +// The caller should have a hold on the socket, and on success +// the listener inherits the callers hold. (If the caller wants +// an additional hold, it should get an extra hold before calling this +// function.) int nni_listener_create(nni_listener **lp, nni_sock *s, const char *url_str) { - nni_sp_tran * tran; + nni_sp_tran *tran; nni_listener *l; int rv; - nni_url * url; + nni_url *url; if ((rv = nni_url_parse(&url, url_str)) != 0) { return (rv); @@ -239,7 +242,6 @@ nni_listener_create(nni_listener **lp, nni_sock *s, const char *url_str) } l->l_url = url; l->l_closed = false; - l->l_closing = false; l->l_data = NULL; l->l_ref = 1; l->l_sock = s; @@ -344,24 +346,7 @@ nni_listener_close(nni_listener *l) nni_listener_shutdown(l); - nni_listener_rele(l); // This will trigger a reap if id count is zero. -} - -void -nni_listener_close_rele(nni_listener *l) -{ - // Listener should already be shutdown. The socket lock may be held. - nni_mtx_lock(&listeners_lk); - if (l->l_closed) { - nni_mtx_unlock(&listeners_lk); - nni_listener_rele(l); - return; - } - l->l_closed = true; - nni_id_remove(&listeners, l->l_id); - nni_mtx_unlock(&listeners_lk); - - nni_listener_rele(l); // This will trigger a reap if id count is zero. + nni_listener_rele(l); // This will reap if reference count is zero. } static void @@ -378,7 +363,7 @@ static void listener_accept_cb(void *arg) { nni_listener *l = arg; - nni_aio * aio = &l->l_acc_aio; + nni_aio *aio = &l->l_acc_aio; int rv; switch ((rv = nni_aio_result(aio))) { @@ -440,6 +425,14 @@ nni_listener_start(nni_listener *l, int flags) return (0); } +void +nni_listener_stop(nni_listener *l) +{ + nni_aio_stop(&l->l_tmo_aio); + nni_aio_stop(&l->l_acc_aio); + l->l_ops.l_close(l->l_data); +} + nni_sock * nni_listener_sock(nni_listener *l) { diff --git a/src/core/socket.c b/src/core/socket.c index e170289d6..e8b1211f5 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -109,9 +109,6 @@ struct nni_socket { static void nni_ctx_destroy(nni_ctx *); -static void dialer_shutdown_locked(nni_dialer *); -static void listener_shutdown_locked(nni_listener *); - #define SOCK(s) ((nni_sock *) (s)) static int @@ -693,15 +690,21 @@ nni_sock_shutdown(nni_sock *sock) // Mark us closing, so no more EPs or changes can occur. sock->s_closing = true; - // Close the EPs. This prevents new connections from forming - // but but allows existing ones to drain. - NNI_LIST_FOREACH (&sock->s_listeners, l) { - listener_shutdown_locked(l); - } - NNI_LIST_FOREACH (&sock->s_dialers, d) { - dialer_shutdown_locked(d); + while ((l = nni_list_first(&sock->s_listeners)) != NULL) { + nni_listener_hold(l); + nni_list_node_remove(&l->l_node); + nni_mtx_unlock(&sock->s_mx); + nni_listener_close(l); + nni_mtx_lock(&sock->s_mx); } + while ((d = nni_list_first(&sock->s_dialers)) != NULL) { + nni_dialer_hold(d); + nni_list_node_remove(&d->d_node); + nni_mtx_unlock(&sock->s_mx); + nni_dialer_close(d); + nni_mtx_lock(&sock->s_mx); + } nni_mtx_unlock(&sock->s_mx); // We now mark any owned contexts as closing. @@ -738,41 +741,21 @@ nni_sock_shutdown(nni_sock *sock) // At this point, we've done everything we politely can to // give the protocol a chance to flush its write side. Now - // its time to be a little more insistent. + // it is time to be a little more insistent. // Close the upper queues immediately. This can happen // safely while we hold the lock. nni_msgq_close(sock->s_urq); nni_msgq_close(sock->s_uwq); - // Go through the dialers and listeners, attempting to close them. - // We might already have a close in progress, in which case - // we skip past it; it will be removed from another thread. - NNI_LIST_FOREACH (&sock->s_listeners, l) { - if (nni_listener_hold(l) == 0) { - nni_listener_close_rele(l); - } - } - NNI_LIST_FOREACH (&sock->s_dialers, d) { - if (nni_dialer_hold(d) == 0) { - nni_dialer_close_rele(d); - } - } - // For each pipe, arrange for it to teardown hard. We would - // expect there not to be any here. However, it is possible for - // a pipe to have been added by an endpoint due to racing conditions - // in the shutdown. Therefore it is important that we shutdown pipes - // *last*. + // expect there not to be any here. NNI_LIST_FOREACH (&sock->s_pipes, pipe) { nni_pipe_close(pipe); } - // We have to wait for *both* endpoints and pipes to be - // removed. - while ((!nni_list_empty(&sock->s_pipes)) || - (!nni_list_empty(&sock->s_listeners)) || - (!nni_list_empty(&sock->s_dialers))) { + // We have to wait for pipes to be removed. + while (!nni_list_empty(&sock->s_pipes)) { nni_cv_wait(&sock->s_cv); } @@ -1453,11 +1436,7 @@ static void dialer_timer_start_locked(nni_dialer *d) { nni_duration back_off; - nni_sock * sock = d->d_sock; - if (d->d_closing || sock->s_closed) { - return; - } back_off = d->d_currtime; if (d->d_maxrtime > 0) { d->d_currtime *= 2; @@ -1494,11 +1473,6 @@ nni_dialer_add_pipe(nni_dialer *d, void *tpipe) nni_mtx_lock(&s->s_mx); - if (s->s_closed || d->d_closing) { - d->d_tran->tran_pipe->p_fini(tpipe); - nni_mtx_unlock(&s->s_mx); - return; - } if (nni_pipe_create_dialer(&p, d, tpipe) != 0) { nni_mtx_unlock(&s->s_mx); return; @@ -1544,38 +1518,23 @@ nni_dialer_add_pipe(nni_dialer *d, void *tpipe) nni_pipe_rele(p); } -static void -dialer_shutdown_impl(nni_dialer *d) +void +nni_dialer_shutdown(nni_dialer *d) { + nni_sock *s = d->d_sock; nni_pipe *p; - // Abort any remaining in-flight operations. - nni_aio_close(&d->d_con_aio); - nni_aio_close(&d->d_tmo_aio); + if (nni_atomic_flag_test_and_set(&d->d_closing)) { + return; + } - // Stop the underlying transport. - d->d_ops.d_close(d->d_data); + nni_dialer_stop(d); + nni_mtx_lock(&s->s_mx); NNI_LIST_FOREACH (&d->d_pipes, p) { nni_pipe_close(p); } -} - -static void -dialer_shutdown_locked(nni_dialer *d) -{ - if (!d->d_closing) { - d->d_closing = true; - dialer_shutdown_impl(d); - } -} - -void -nni_dialer_shutdown(nni_dialer *d) -{ - nni_sock *s = d->d_sock; - nni_mtx_lock(&s->s_mx); - dialer_shutdown_locked(d); + nni_list_node_remove(&d->d_node); nni_mtx_unlock(&s->s_mx); } @@ -1592,9 +1551,6 @@ dialer_reap(void *arg) nni_dialer *d = arg; nni_sock * s = d->d_sock; - nni_aio_stop(&d->d_tmo_aio); - nni_aio_stop(&d->d_con_aio); - #ifdef NNG_ENABLE_STATS nni_stat_unregister(&d->st_root); #endif @@ -1612,13 +1568,12 @@ dialer_reap(void *arg) return; } - nni_list_remove(&s->s_dialers, d); - if ((s->s_closing) && (nni_list_empty(&s->s_dialers))) { - nni_cv_wake(&s->s_cv); - } + nni_list_node_remove(&d->d_node); nni_mtx_unlock(&s->s_mx); + nni_sock_rele(s); + nni_dialer_destroy(d); } @@ -1635,12 +1590,6 @@ nni_listener_add_pipe(nni_listener *l, void *tpipe) nni_pipe *p; nni_mtx_lock(&s->s_mx); - if (s->s_closed || l->l_closing) { - l->l_tran->tran_pipe->p_fini(tpipe); - nni_mtx_unlock(&s->s_mx); - return; - } - if (nni_pipe_create_listener(&p, l, tpipe) != 0) { nni_mtx_unlock(&s->s_mx); return; @@ -1684,39 +1633,22 @@ nni_listener_add_pipe(nni_listener *l, void *tpipe) nni_pipe_rele(p); } -static void -listener_shutdown_impl(nni_listener *l) +void +nni_listener_shutdown(nni_listener *l) { + nni_sock *s = l->l_sock; nni_pipe *p; - // Abort any remaining in-flight accepts. - nni_aio_close(&l->l_acc_aio); - nni_aio_close(&l->l_tmo_aio); + if (nni_atomic_flag_test_and_set(&l->l_closing)) { + return; + } - // Stop the underlying transport. - l->l_ops.l_close(l->l_data); + nni_listener_stop(l); + nni_mtx_lock(&s->s_mx); NNI_LIST_FOREACH (&l->l_pipes, p) { nni_pipe_close(p); } -} - -static void -listener_shutdown_locked(nni_listener *l) -{ - if (!l->l_closing) { - l->l_closing = true; - listener_shutdown_impl(l); - } -} - -void -nni_listener_shutdown(nni_listener *l) -{ - nni_sock *s = l->l_sock; - - nni_mtx_lock(&s->s_mx); - listener_shutdown_locked(l); nni_mtx_unlock(&s->s_mx); } @@ -1733,9 +1665,6 @@ listener_reap(void *arg) nni_listener *l = arg; nni_sock * s = l->l_sock; - nni_aio_stop(&l->l_tmo_aio); - nni_aio_stop(&l->l_acc_aio); - #ifdef NNG_ENABLE_STATS nni_stat_unregister(&l->st_root); #endif @@ -1753,13 +1682,11 @@ listener_reap(void *arg) return; } - nni_list_remove(&s->s_listeners, l); - if ((s->s_closing) && (nni_list_empty(&s->s_listeners))) { - nni_cv_wake(&s->s_cv); - } - + nni_list_node_remove(&l->l_node); nni_mtx_unlock(&s->s_mx); + nni_sock_rele(s); + nni_listener_destroy(l); } diff --git a/src/core/sockimpl.h b/src/core/sockimpl.h index 1670330c8..37dc1eaac 100644 --- a/src/core/sockimpl.h +++ b/src/core/sockimpl.h @@ -17,20 +17,20 @@ struct nni_dialer { nni_sp_dialer_ops d_ops; // transport ops - nni_sp_tran * d_tran; // transport pointer - void * d_data; // transport private + nni_sp_tran *d_tran; // transport pointer + void *d_data; // transport private uint32_t d_id; // endpoint id nni_list_node d_node; // per socket list - nni_sock * d_sock; - nni_url * d_url; - nni_pipe * d_pipe; // active pipe (for re-dialer) + nni_sock *d_sock; + nni_url *d_url; + nni_pipe *d_pipe; // active pipe (for re-dialer) int d_ref; bool d_closed; // full shutdown - bool d_closing; + nni_atomic_flag d_closing; nni_atomic_flag d_started; nni_mtx d_mtx; nni_list d_pipes; - nni_aio * d_user_aio; + nni_aio *d_user_aio; nni_aio d_con_aio; nni_aio d_tmo_aio; // backoff timer nni_duration d_maxrtime; // maximum time for reconnect @@ -59,15 +59,15 @@ struct nni_dialer { struct nni_listener { nni_sp_listener_ops l_ops; // transport ops - nni_sp_tran * l_tran; // transport pointer - void * l_data; // transport private + nni_sp_tran *l_tran; // transport pointer + void *l_data; // transport private uint32_t l_id; // endpoint id nni_list_node l_node; // per socket list - nni_sock * l_sock; - nni_url * l_url; + nni_sock *l_sock; + nni_url *l_url; int l_ref; bool l_closed; // full shutdown - bool l_closing; // close started (shutdown) + nni_atomic_flag l_closing; // close started (shutdown) nni_atomic_flag l_started; nni_list l_pipes; nni_aio l_acc_aio; @@ -97,13 +97,13 @@ struct nni_pipe { nni_sp_pipe_ops p_tran_ops; nni_proto_pipe_ops p_proto_ops; size_t p_size; - void * p_tran_data; - void * p_proto_data; + void *p_tran_data; + void *p_proto_data; nni_list_node p_sock_node; nni_list_node p_ep_node; - nni_sock * p_sock; - nni_dialer * p_dialer; - nni_listener * p_listener; + nni_sock *p_sock; + nni_dialer *p_dialer; + nni_listener *p_listener; bool p_closed; nni_atomic_flag p_stop; bool p_cbs; @@ -138,13 +138,13 @@ extern void nni_dialer_shutdown(nni_dialer *); extern void nni_dialer_reap(nni_dialer *); extern void nni_dialer_destroy(nni_dialer *); extern void nni_dialer_timer_start(nni_dialer *); -extern void nni_dialer_close_rele(nni_dialer *); +extern void nni_dialer_stop(nni_dialer *); extern void nni_listener_add_pipe(nni_listener *, void *); extern void nni_listener_shutdown(nni_listener *); extern void nni_listener_reap(nni_listener *); extern void nni_listener_destroy(nni_listener *); -extern void nni_listener_close_rele(nni_listener *); +extern void nni_listener_stop(nni_listener *); extern void nni_pipe_remove(nni_pipe *); extern void nni_pipe_run_cb(nni_pipe *, nng_pipe_ev); diff --git a/src/nng.c b/src/nng.c index 60fffa592..9f1314535 100644 --- a/src/nng.c +++ b/src/nng.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -484,7 +484,6 @@ nng_dial(nng_socket sid, const char *addr, nng_dialer *dp, int flags) } if ((rv = nni_dialer_start(d, flags)) != 0) { nni_dialer_close(d); - nni_sock_rele(s); return (rv); } if (dp != NULL) { @@ -493,7 +492,6 @@ nng_dial(nng_socket sid, const char *addr, nng_dialer *dp, int flags) *dp = did; } nni_dialer_rele(d); - nni_sock_rele(s); return (0); } @@ -513,7 +511,6 @@ nng_listen(nng_socket sid, const char *addr, nng_listener *lp, int flags) } if ((rv = nni_listener_start(l, flags)) != 0) { nni_listener_close(l); - nni_sock_rele(s); return (rv); } @@ -523,7 +520,6 @@ nng_listen(nng_socket sid, const char *addr, nng_listener *lp, int flags) *lp = lid; } nni_listener_rele(l); - nni_sock_rele(s); return (rv); } @@ -545,7 +541,6 @@ nng_listener_create(nng_listener *lp, nng_socket sid, const char *addr) lid.id = nni_listener_id(l); *lp = lid; nni_listener_rele(l); - nni_sock_rele(s); return (0); } @@ -587,7 +582,6 @@ nng_dialer_create(nng_dialer *dp, nng_socket sid, const char *addr) did.id = nni_dialer_id(d); *dp = did; nni_dialer_rele(d); - nni_sock_rele(s); return (0); } From fa3beb33da086dca8c805ba1dd32199c121c4692 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 6 Sep 2021 12:01:26 -0700 Subject: [PATCH 040/180] SP initialization cannot fail. --- src/core/dialer.c | 4 +--- src/core/dialer.h | 4 ++-- src/core/init.c | 17 ++++++++++------- src/core/listener.c | 4 +--- src/core/listener.h | 4 ++-- src/core/pipe.c | 6 ++---- src/core/pipe.h | 7 +++---- src/core/socket.c | 3 +-- src/core/socket.h | 4 ++-- src/sp/transport.c | 3 +-- src/sp/transport.h | 2 +- 11 files changed, 26 insertions(+), 32 deletions(-) diff --git a/src/core/dialer.c b/src/core/dialer.c index 4c3e563d4..3a7490859 100644 --- a/src/core/dialer.c +++ b/src/core/dialer.c @@ -23,13 +23,11 @@ static void dialer_timer_cb(void *); static nni_id_map dialers; static nni_mtx dialers_lk; -int +void nni_dialer_sys_init(void) { nni_id_map_init(&dialers, 1, 0x7fffffff, false); nni_mtx_init(&dialers_lk); - - return (0); } void diff --git a/src/core/dialer.h b/src/core/dialer.h index df9232091..b6ba657b5 100644 --- a/src/core/dialer.h +++ b/src/core/dialer.h @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2018 Devolutions // @@ -12,7 +12,7 @@ #ifndef CORE_DIALER_H #define CORE_DIALER_H -extern int nni_dialer_sys_init(void); +extern void nni_dialer_sys_init(void); extern void nni_dialer_sys_fini(void); extern int nni_dialer_find(nni_dialer **, uint32_t); extern int nni_dialer_hold(nni_dialer *); diff --git a/src/core/init.c b/src/core/init.c index 9f39490a1..c923fdf0f 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -42,16 +42,19 @@ nni_init_helper(void) ((rv = nni_reap_sys_init()) != 0) || ((rv = nni_timer_sys_init()) != 0) || ((rv = nni_aio_sys_init()) != 0) || - ((rv = nni_sock_sys_init()) != 0) || - ((rv = nni_listener_sys_init()) != 0) || - ((rv = nni_dialer_sys_init()) != 0) || - ((rv = nni_pipe_sys_init()) != 0) || - ((rv = nni_tls_sys_init()) != 0) || - ((rv = nni_sp_tran_sys_init()) != 0)) { + ((rv = nni_tls_sys_init()) != 0)) { nni_fini(); + return (rv); } - return (rv); + // following never fail + nni_sock_sys_init(); + nni_listener_sys_init(); + nni_dialer_sys_init(); + nni_pipe_sys_init(); + nni_sp_tran_sys_init(); + + return (0); } int diff --git a/src/core/listener.c b/src/core/listener.c index 410988f6a..74e5e22b8 100644 --- a/src/core/listener.c +++ b/src/core/listener.c @@ -24,13 +24,11 @@ static void listener_timer_cb(void *); static nni_id_map listeners; static nni_mtx listeners_lk; -int +void nni_listener_sys_init(void) { nni_id_map_init(&listeners, 1, 0x7fffffff, false); nni_mtx_init(&listeners_lk); - - return (0); } void diff --git a/src/core/listener.h b/src/core/listener.h index ef87a9306..9b1ad907b 100644 --- a/src/core/listener.h +++ b/src/core/listener.h @@ -1,5 +1,5 @@ // -// Copyright 2018 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2018 Devolutions // @@ -12,7 +12,7 @@ #ifndef CORE_LISTENER_H #define CORE_LISTENER_H -extern int nni_listener_sys_init(void); +extern void nni_listener_sys_init(void); extern void nni_listener_sys_fini(void); extern int nni_listener_find(nni_listener **, uint32_t); extern int nni_listener_hold(nni_listener *); diff --git a/src/core/pipe.c b/src/core/pipe.c index b55e2fd61..a1d76665a 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2018 Devolutions // @@ -29,7 +29,7 @@ static nni_reap_list pipe_reap_list = { .rl_func = pipe_destroy, }; -int +void nni_pipe_sys_init(void) { nni_mtx_init(&pipes_lk); @@ -37,8 +37,6 @@ nni_pipe_sys_init(void) // Pipe IDs needs to have high order bit clear, and we want // them to start at a random value. nni_id_map_init(&pipes, 1, 0x7fffffff, true); - - return (0); } void diff --git a/src/core/pipe.h b/src/core/pipe.h index dee21799c..740b6073b 100644 --- a/src/core/pipe.h +++ b/src/core/pipe.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -12,14 +12,14 @@ #define CORE_PIPE_H // NB: This structure is supplied here for use by the CORE. Use of this -// OUSIDE of the core is STRICTLY VERBOTEN. NO DIRECT ACCESS BY PROTOCOLS OR +// OUTSIDE of the core is STRICTLY VERBOTEN. NO DIRECT ACCESS BY PROTOCOLS OR // TRANSPORTS. #include "core/defs.h" #include "core/thread.h" #include "sp/transport.h" -extern int nni_pipe_sys_init(void); +extern void nni_pipe_sys_init(void); extern void nni_pipe_sys_fini(void); // AIO @@ -34,7 +34,6 @@ extern uint32_t nni_pipe_id(nni_pipe *); // actual pipe will be reaped asynchronously. extern void nni_pipe_close(nni_pipe *); -extern uint16_t nni_pipe_proto(nni_pipe *); extern uint16_t nni_pipe_peer(nni_pipe *); // nni_pipe_getopt looks up the option. The last argument is the type, diff --git a/src/core/socket.c b/src/core/socket.c index e8b1211f5..e376b773e 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -608,7 +608,7 @@ nni_sock_create(nni_sock **sp, const nni_proto *proto) return (rv); } -int +void nni_sock_sys_init(void) { NNI_LIST_INIT(&sock_list, nni_sock, s_node); @@ -617,7 +617,6 @@ nni_sock_sys_init(void) nni_id_map_init(&sock_ids, 1, 0x7fffffff, false); nni_id_map_init(&ctx_ids, 1, 0x7fffffff, false); inited = true; - return (0); } void diff --git a/src/core/socket.h b/src/core/socket.h index 57a776814..59ceffa87 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -11,7 +11,7 @@ #ifndef CORE_SOCKET_H #define CORE_SOCKET_H -extern int nni_sock_sys_init(void); +extern void nni_sock_sys_init(void); extern void nni_sock_sys_fini(void); extern int nni_sock_find(nni_sock **, uint32_t); @@ -24,7 +24,7 @@ extern uint16_t nni_sock_proto_id(nni_sock *); extern uint16_t nni_sock_peer_id(nni_sock *); extern const char *nni_sock_proto_name(nni_sock *); extern const char *nni_sock_peer_name(nni_sock *); -extern void * nni_sock_proto_data(nni_sock *); +extern void *nni_sock_proto_data(nni_sock *); extern void nni_sock_add_stat(nni_sock *, nni_stat_item *); extern struct nni_proto_pipe_ops *nni_sock_proto_pipe_ops(nni_sock *); diff --git a/src/sp/transport.c b/src/sp/transport.c index 13961eaaf..ed27ebeb1 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -70,7 +70,7 @@ extern void nni_sp_wss_register(void); extern void nni_sp_zt_register(void); #endif -int +void nni_sp_tran_sys_init(void) { NNI_LIST_INIT(&sp_tran_list, nni_sp_tran, tran_link); @@ -97,7 +97,6 @@ nni_sp_tran_sys_init(void) #ifdef NNG_TRANSPORT_ZEROTIER nni_sp_zt_register(); #endif - return (0); } // nni_sp_tran_sys_fini finalizes the entire transport system, including all diff --git a/src/sp/transport.h b/src/sp/transport.h index 08f169bcb..76d8d36ab 100644 --- a/src/sp/transport.h +++ b/src/sp/transport.h @@ -169,7 +169,7 @@ struct nni_sp_tran { // These APIs are used by the framework internally, and not for use by // transport implementations. extern nni_sp_tran *nni_sp_tran_find(nni_url *); -extern int nni_sp_tran_sys_init(void); +extern void nni_sp_tran_sys_init(void); extern void nni_sp_tran_sys_fini(void); extern void nni_sp_tran_register(nni_sp_tran *); From c704ede41a5ffbca400ccd5f993c0636d54a8293 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Fri, 17 Sep 2021 12:24:30 +0800 Subject: [PATCH 041/180] * FIX [mqtt_parser] remove function unused. --- include/nng/protocol/mqtt/mqtt_parser.h | 1 - src/sp/protocol/mqtt/mqtt_parser.c | 41 ------------------------- src/sp/transport/ws/websocket.c | 1 - 3 files changed, 43 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index cb91b7016..a2d40f4ca 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -40,7 +40,6 @@ int32_t conn_handler(uint8_t *packet, conn_param *conn_param); int conn_param_alloc(conn_param **cparam); void conn_param_free(conn_param *cparam); void conn_param_clone(conn_param *cparam); -// void deep_copy_conn_param(conn_param *new_cp, conn_param *cp); int fixed_header_adaptor(uint8_t *packet, nng_msg *dst); int ws_fixed_header_adaptor(uint8_t *packet, nng_msg *dst); diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index b301111ab..453cfa165 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -386,10 +386,6 @@ auto_id_prefix_len) char *client_id; return client_id; } - -conn_param * copy_conn_param(conn_param * des, conn_param * src){ - return (conn_param *)memcpy((void *)des, (const void *)src, -sizeof(struct conn_param)); } */ @@ -770,43 +766,6 @@ conn_param_clone(conn_param * cparam) nni_atomic_inc(&cparam->refcnt); } -/* -void -deep_copy_conn_param(conn_param *new_cp, conn_param *cp) -{ -// UPDATE_FIELD_INT(pro_ver, new_cp, cp); -// UPDATE_FIELD_INT(con_flag, new_cp, cp); -// UPDATE_FIELD_INT(keepalive_mqtt, new_cp, cp); -// UPDATE_FIELD_INT(clean_start, new_cp, cp); - UPDATE_FIELD_INT(will_flag, new_cp, cp); - UPDATE_FIELD_INT(will_retain, new_cp, cp); - UPDATE_FIELD_INT(will_qos, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(pro_name, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(clientid, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(will_topic, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(will_msg, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(username, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(password, body, new_cp, cp); - UPDATE_FIELD_INT(session_expiry_interval, new_cp, cp); - UPDATE_FIELD_INT(rx_max, new_cp, cp); - UPDATE_FIELD_INT(max_packet_size, new_cp, cp); - UPDATE_FIELD_INT(topic_alias_max, new_cp, cp); - UPDATE_FIELD_INT(req_resp_info, new_cp, cp); - UPDATE_FIELD_INT(req_problem_info, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(auth_method, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(auth_data, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING_PAIR(user_property, key, val, new_cp, cp); - UPDATE_FIELD_INT(will_delay_interval, new_cp, cp); - UPDATE_FIELD_INT(payload_format_indicator, new_cp, cp); - UPDATE_FIELD_INT(msg_expiry_interval, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(content_type, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(resp_topic, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING(corr_data, body, new_cp, cp); - UPDATE_FIELD_MQTT_STRING_PAIR( - payload_user_property, key, val, new_cp, cp); -} -*/ - uint32_t DJBHash(char *str) { diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 593dafb04..21d7000cd 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -97,7 +97,6 @@ wstran_pipe_recv_cb(void *arg) nni_msg *smsg = NULL, *msg = NULL; nni_aio *raio = p->rxaio; nni_aio *uaio = NULL; - nni_iov iov; nni_mtx_lock(&p->mtx); // only sets uaio at first time From 2ba946dc80d824c8ac6c86adae4633551364c78f Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Sat, 18 Sep 2021 12:09:15 +0800 Subject: [PATCH 042/180] * FIX [aio_qos] rever #216, Fix #222 --- src/sp/protocol/reqrep0/nano_tcp.c | 59 +++++++++--------------------- src/sp/transport/tcp/tcp.c | 19 ++-------- 2 files changed, 20 insertions(+), 58 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index bcbf742a7..c1ff09710 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -15,7 +15,6 @@ #include "core/nng_impl.h" #include "core/sockimpl.h" -#include "nano_lmq.h" #include "nng/nng.h" #include "nng/protocol/mqtt/mqtt.h" #include "nng/protocol/mqtt/mqtt_parser.h" @@ -89,7 +88,7 @@ struct nano_pipe { uint8_t ka_refresh; nano_conn_param *conn_param; nano_pipe_db * pipedb_root; - nano_lmq rlmq; + nni_lmq rlmq; }; static void @@ -261,9 +260,7 @@ nano_ctx_send(void *arg, nni_aio *aio) } nni_mtx_lock(&s->lk); - debug_msg("*************************** working with pipe id : %d " - "ctx***************************", - pipe); + debug_msg(" ******** working with pipe id : %d ctx ********", pipe); if ((p = nni_id_get(&s->pipes, pipe)) == NULL) { // Pipe is gone. Make this look like a good send to avoid // disrupting the state machine. We don't care if the peer @@ -277,16 +274,10 @@ nano_ctx_send(void *arg, nni_aio *aio) return; } nni_mtx_unlock(&s->lk); - nni_mtx_lock(&p->lk); - pub_extra *pub_extra_info = - (pub_extra *) nni_aio_get_prov_extra(aio, 0); - if (!p->busy) { p->busy = true; - nni_aio_set_prov_extra(&p->aio_send, 0, pub_extra_info); - nni_aio_set_msg(&p->aio_send, msg); nni_pipe_send(p->pipe, &p->aio_send); nni_mtx_unlock(&p->lk); @@ -300,26 +291,19 @@ nano_ctx_send(void *arg, nni_aio *aio) return; } debug_msg("WARNING: pipe %d occupied! resending in cb!", pipe); - if (nano_lmq_full(&p->rlmq)) { + if (nni_lmq_full(&p->rlmq)) { // Make space for the new message. TODO add max limit of msgq // len in conf - if ((rv = nano_lmq_resize_with_cb(&p->rlmq, - nano_lmq_cap(&p->rlmq) * 2, - (nano_lmq_free) nni_msg_free, - (nano_lmq_get_sub_msg) pub_extra_get_msg)) != 0) { - debug_msg("warning msg dropped!"); - pub_extra *old; - if (nano_lmq_getq(&p->rlmq, (void **) &old) == 0) { - nni_msg *old_msg = - (nni_msg *) pub_extra_get_msg(old); - nni_msg_free(old_msg); - pub_extra_free(old); - } + if ((rv = nni_lmq_resize( + &p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { + debug_syslog("warning msg dropped!"); + nni_msg *old; + (void) nni_lmq_getq(&p->rlmq, &old); + nni_msg_free(old); } } - pub_extra_set_msg(pub_extra_info, msg); - nano_lmq_putq(&p->rlmq, pub_extra_info); + nni_lmq_putq(&p->rlmq, msg); nni_mtx_unlock(&p->lk); nni_aio_set_msg(aio, NULL); @@ -424,9 +408,7 @@ nano_pipe_fini(void *arg) nni_aio_fini(&p->aio_send); nni_aio_fini(&p->aio_recv); nni_aio_fini(&p->aio_timer); - - nano_lmq_fini_with_cb(&p->rlmq, (nano_lmq_free) nni_msg_free, - (nano_lmq_get_sub_msg) pub_extra_get_msg); + nni_lmq_fini(&p->rlmq); } static int @@ -438,7 +420,7 @@ nano_pipe_init(void *arg, nni_pipe *pipe, void *s) debug_msg("##########nano_pipe_init###############"); nni_mtx_init(&p->lk); - nano_lmq_init(&p->rlmq, sock->conf->msq_len); + nni_lmq_init(&p->rlmq, sock->conf->msq_len); nni_aio_init(&p->aio_send, nano_pipe_send_cb, p); // TODO move keepalive monitor to transport layer? nni_aio_init(&p->aio_timer, nano_pipe_timer_cb, p); @@ -519,9 +501,7 @@ close_pipe(nano_pipe *p) if (nni_list_active(&s->recvpipes, p)) { nni_list_remove(&s->recvpipes, p); } - // nni_lmq_flush(&p->rlmq); - nano_lmq_flush_with_cb(&p->rlmq, (nano_lmq_free) nni_msg_free, - (nano_lmq_get_sub_msg) pub_extra_get_msg); + nni_lmq_flush(&p->rlmq); // TODO delete while ((ctx = nni_list_first(&p->sendq)) != NULL) { @@ -587,7 +567,7 @@ static void nano_pipe_send_cb(void *arg) { nano_pipe *p = arg; - pub_extra *extra; + nni_msg * msg; debug_msg( "################ nano_pipe_send_cb %d ################", p->id); @@ -601,20 +581,15 @@ nano_pipe_send_cb(void *arg) nni_mtx_lock(&p->lk); nni_aio_set_packetid(&p->aio_send, 0); - int rv = nano_lmq_getq(&p->rlmq, (void **) &extra); - if (rv == 0) { - nni_msg *msg = (nni_msg *) pub_extra_get_msg(extra); - debug_msg("get nng_msg from pub_extra: %p", msg); - nni_aio_set_prov_extra(&p->aio_send, 0, extra); + if (nni_lmq_getq(&p->rlmq, &msg) == 0) { + //TODO get qos from aio_extra nni_aio_set_msg(&p->aio_send, msg); debug_msg("rlmq msg resending! %ld msgs left\n", - nano_lmq_len(&p->rlmq)); + nni_lmq_len(&p->rlmq)); nni_pipe_send(p->pipe, &p->aio_send); nni_mtx_unlock(&p->lk); return; - } else { - debug_msg("nano_lmq_getq error: %d", rv); } p->busy = false; diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index a9bb626f6..13c9f5900 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -697,22 +697,8 @@ tcptran_pipe_send_start(tcptran_pipe *p) p->qlength = 0; NNI_GET16(body, tlen); - pub_extra *pub_extra_info = - (pub_extra *) nni_aio_get_prov_extra(aio, 0); - - if (pub_extra_info == NULL) { - goto send; - } - - debug_msg("get pub_extra :%p", pub_extra_info); - debug_msg("get pub_extra, qos: %d, packet id: %d", - pub_extra_get_qos(pub_extra_info), - pub_extra_get_packet_id(pub_extra_info)); - - uint8_t qos = pub_extra_get_qos(pub_extra_info); - - pub_extra_free(pub_extra_info); - + // uint8_t qos = nni_aio_get_prov_extra(aio, 0); + uint8_t qos = 0; qos_pac = nni_msg_get_pub_qos(msg); if (qos_pac == 0) { // save time & space for QoS 0 publish @@ -722,6 +708,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) debug_msg("qos_pac %d sub %d\n", qos_pac, qos); memcpy(fixheader, header, nni_msg_header_len(msg)); + // use qos from aio directly. no need such redundant logic here if (qos_pac > qos) { if (qos == 1) { // set qos to 1 From e501ca8b46496f50dc9168488eb1744b7d6461e4 Mon Sep 17 00:00:00 2001 From: eeff Date: Sat, 18 Sep 2021 17:54:19 +0800 Subject: [PATCH 043/180] Add QoS bits packing with message pointer to nano_pipe rlmq --- src/sp/protocol/reqrep0/nano_tcp.c | 117 +++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 8 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index c1ff09710..040ad6ecc 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -22,6 +22,17 @@ #include +// strip off and return the QoS bits +#define NANO_NNI_LMQ_GET_QOS_BITS(msg) ((size_t)(msg) &0x03) + +// strip off and return the msg pointer +#define NANO_NNI_LMQ_GET_MSG_POINTER(msg) \ + ((nng_msg *) ((size_t)(msg) & (~0x03))) + +// packed QoS bits to the least two significant bits of msg pointer +#define NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos) \ + ((nng_msg *) ((size_t)(msg) | ((qos) &0x03))) + // TODO rewrite as nano_mq protocol with RPC support typedef struct nano_pipe nano_pipe; @@ -91,6 +102,93 @@ struct nano_pipe { nni_lmq rlmq; }; +static inline int +nano_nni_lmq_putq(nni_lmq *lmq, nng_msg *msg, uint8_t qos) +{ + msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); + return nni_lmq_putq(lmq, msg); +} + +static inline int +nano_nni_lmq_getq(nni_lmq *lmq, nng_msg **msg, uint8_t *qos) +{ + int rv = nni_lmq_getq(lmq, msg); + if (rv == 0) { + *msg = NANO_NNI_LMQ_GET_MSG_POINTER(*msg); + if (qos) { + *qos = NANO_NNI_LMQ_GET_QOS_BITS(*msg); + } + } + return rv; +} + +void +nano_nni_lmq_flush(nni_lmq *lmq) +{ + while (lmq->lmq_len > 0) { + nng_msg *msg = lmq->lmq_msgs[lmq->lmq_get++]; + lmq->lmq_get &= lmq->lmq_mask; + lmq->lmq_len--; + nni_msg_free(NANO_NNI_LMQ_GET_MSG_POINTER(msg)); + } +} + +int +nano_nni_lmq_resize(nni_lmq *lmq, size_t cap) +{ + nng_msg * msg; + nng_msg **newq; + size_t alloc; + size_t len; + + alloc = 2; + while (alloc < cap) { + alloc *= 2; + } + + newq = nni_alloc(sizeof(nng_msg *) * alloc); + if (newq == NULL) { + return (NNG_ENOMEM); + } + + len = 0; + while ((len < cap) && (nni_lmq_getq(lmq, &msg) == 0)) { + newq[len++] = msg; + } + + // Flush anything left over. + nano_nni_lmq_flush(lmq); + + nni_free(lmq->lmq_msgs, lmq->lmq_alloc * sizeof(nng_msg *)); + lmq->lmq_msgs = newq; + lmq->lmq_cap = cap; + lmq->lmq_alloc = alloc; + lmq->lmq_mask = alloc - 1; + lmq->lmq_len = len; + lmq->lmq_put = len; + lmq->lmq_get = 0; + + return (0); +} + +void +nano_nni_lmq_fini(nni_lmq *lmq) +{ + if (lmq == NULL) { + return; + } + + /* Free any orphaned messages. */ + while (lmq->lmq_len > 0) { + nng_msg *msg = lmq->lmq_msgs[lmq->lmq_get++]; + lmq->lmq_get &= lmq->lmq_mask; + lmq->lmq_len--; + nni_msg_free(NANO_NNI_LMQ_GET_MSG_POINTER(msg)); + } + + nni_free(lmq->lmq_msgs, lmq->lmq_alloc * sizeof(nng_msg *)); +} + static void nano_pipe_timer_cb(void *arg) { @@ -294,16 +392,17 @@ nano_ctx_send(void *arg, nni_aio *aio) if (nni_lmq_full(&p->rlmq)) { // Make space for the new message. TODO add max limit of msgq // len in conf - if ((rv = nni_lmq_resize( + if ((rv = nano_nni_lmq_resize( &p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { debug_syslog("warning msg dropped!"); nni_msg *old; - (void) nni_lmq_getq(&p->rlmq, &old); + (void) nano_nni_lmq_getq(&p->rlmq, &old, NULL); nni_msg_free(old); } } - nni_lmq_putq(&p->rlmq, msg); + size_t qos = (size_t) nni_aio_get_prov_extra(aio, 0); + nano_nni_lmq_putq(&p->rlmq, msg, qos); nni_mtx_unlock(&p->lk); nni_aio_set_msg(aio, NULL); @@ -408,7 +507,7 @@ nano_pipe_fini(void *arg) nni_aio_fini(&p->aio_send); nni_aio_fini(&p->aio_recv); nni_aio_fini(&p->aio_timer); - nni_lmq_fini(&p->rlmq); + nano_nni_lmq_fini(&p->rlmq); } static int @@ -501,7 +600,7 @@ close_pipe(nano_pipe *p) if (nni_list_active(&s->recvpipes, p)) { nni_list_remove(&s->recvpipes, p); } - nni_lmq_flush(&p->rlmq); + nano_nni_lmq_flush(&p->rlmq); // TODO delete while ((ctx = nni_list_first(&p->sendq)) != NULL) { @@ -568,6 +667,7 @@ nano_pipe_send_cb(void *arg) { nano_pipe *p = arg; nni_msg * msg; + uint8_t qos; debug_msg( "################ nano_pipe_send_cb %d ################", p->id); @@ -581,9 +681,10 @@ nano_pipe_send_cb(void *arg) nni_mtx_lock(&p->lk); nni_aio_set_packetid(&p->aio_send, 0); - if (nni_lmq_getq(&p->rlmq, &msg) == 0) { - //TODO get qos from aio_extra - nni_aio_set_msg(&p->aio_send, msg); + if (nni_lmq_getq(&p->rlmq, &msg) == 0) { + qos = nng_aio_get_prov_extra(&p->aio_send, 0); + nni_aio_set_msg( + &p->aio_send, NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos)); debug_msg("rlmq msg resending! %ld msgs left\n", nni_lmq_len(&p->rlmq)); From 435e134d2df3e7941e80f64d75f5846508ed73f9 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 20 Sep 2021 14:51:40 +0800 Subject: [PATCH 044/180] * NEW [nng/mqtt] fix QoS bits methdology --- include/nng/protocol/mqtt/mqtt_parser.h | 11 +++++ src/sp/protocol/reqrep0/nano_tcp.c | 58 +++++++++---------------- src/sp/transport/tcp/tcp.c | 42 ++++++++---------- 3 files changed, 49 insertions(+), 62 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index a2d40f4ca..0b3e99fa3 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -20,6 +20,17 @@ #define CONNECT_TOPIC "$SYS/brokers/connected" +// strip off and return the QoS bits +#define NANO_NNI_LMQ_GET_QOS_BITS(msg) ((size_t)(msg) &0x03) + +// strip off and return the msg pointer +#define NANO_NNI_LMQ_GET_MSG_POINTER(msg) \ + ((nng_msg *) ((size_t)(msg) & (~0x03))) + +// packed QoS bits to the least two significant bits of msg pointer +#define NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos) \ + ((nng_msg *) ((size_t)(msg) | ((qos) &0x03))) + // Variables & Structs typedef struct pub_extra pub_extra; diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 040ad6ecc..1bb14ccba 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -22,17 +22,6 @@ #include -// strip off and return the QoS bits -#define NANO_NNI_LMQ_GET_QOS_BITS(msg) ((size_t)(msg) &0x03) - -// strip off and return the msg pointer -#define NANO_NNI_LMQ_GET_MSG_POINTER(msg) \ - ((nng_msg *) ((size_t)(msg) & (~0x03))) - -// packed QoS bits to the least two significant bits of msg pointer -#define NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos) \ - ((nng_msg *) ((size_t)(msg) | ((qos) &0x03))) - // TODO rewrite as nano_mq protocol with RPC support typedef struct nano_pipe nano_pipe; @@ -102,22 +91,15 @@ struct nano_pipe { nni_lmq rlmq; }; -static inline int -nano_nni_lmq_putq(nni_lmq *lmq, nng_msg *msg, uint8_t qos) -{ - msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); - return nni_lmq_putq(lmq, msg); -} - static inline int nano_nni_lmq_getq(nni_lmq *lmq, nng_msg **msg, uint8_t *qos) { int rv = nni_lmq_getq(lmq, msg); if (rv == 0) { - *msg = NANO_NNI_LMQ_GET_MSG_POINTER(*msg); if (qos) { *qos = NANO_NNI_LMQ_GET_QOS_BITS(*msg); } + *msg = NANO_NNI_LMQ_GET_MSG_POINTER(*msg); } return rv; } @@ -193,18 +175,19 @@ static void nano_pipe_timer_cb(void *arg) { nano_pipe *p = arg; - nni_msg * msg; + int qos_timer = p->rep->conf->qos_timer; + nni_msg * msg, *rmsg; nni_time time; nni_pipe * npipe = p->pipe; uint16_t pid; - int qos_timer = p->rep->conf->qos_timer; + uint8_t qos; if (nng_aio_result(&p->aio_timer) != 0) { return; } nni_mtx_lock(&p->lk); if (p->ka_refresh * (qos_timer) > p->conn_param->keepalive_mqtt) { - printf("Warning: close pipe & kick client due to KeepAlive " + nni_println("Warning: close pipe & kick client due to KeepAlive " "timeout!"); // TODO check keepalived timer interval nni_mtx_unlock(&p->lk); @@ -215,14 +198,15 @@ nano_pipe_timer_cb(void *arg) p->ka_refresh++; if (!p->busy) { msg = nni_id_get_any(npipe->nano_qos_db, &pid); - if (msg != NULL) { + qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); + rmsg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); time = nni_msg_get_timestamp(msg); if ((nni_clock() - time) >= (long unsigned) qos_timer * 1250) { p->busy = true; - nni_msg_clone(msg); - nano_msg_set_dup(msg); + nni_msg_clone(rmsg); + nano_msg_set_dup(rmsg); nni_aio_set_packetid(&p->aio_send, pid); nni_aio_set_msg(&p->aio_send, msg); debug_msg("resending qos msg!\n"); @@ -335,6 +319,7 @@ nano_ctx_send(void *arg, nni_aio *aio) nni_msg * msg; int rv; uint32_t pipe; + size_t qos = 0; msg = nni_aio_get_msg(aio); @@ -373,7 +358,8 @@ nano_ctx_send(void *arg, nni_aio *aio) } nni_mtx_unlock(&s->lk); nni_mtx_lock(&p->lk); - + qos = (size_t) nni_aio_get_prov_extra(aio, 0); + msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); if (!p->busy) { p->busy = true; nni_aio_set_msg(&p->aio_send, msg); @@ -401,8 +387,7 @@ nano_ctx_send(void *arg, nni_aio *aio) } } - size_t qos = (size_t) nni_aio_get_prov_extra(aio, 0); - nano_nni_lmq_putq(&p->rlmq, msg, qos); + nni_lmq_putq(&p->rlmq, msg); nni_mtx_unlock(&p->lk); nni_aio_set_msg(aio, NULL); @@ -551,7 +536,7 @@ nano_pipe_start(void *arg) debug_msg("##########nano_pipe_start################"); /* - // TODO check peer protocol ver + // TODO check peer protocol ver (websocket or tcp or quic??) if (nni_pipe_peer(p->pipe) != NNG_NANO_TCP_PEER) { // Peer protocol mismatch. return (NNG_EPROTO); @@ -669,8 +654,7 @@ nano_pipe_send_cb(void *arg) nni_msg * msg; uint8_t qos; - debug_msg( - "################ nano_pipe_send_cb %d ################", p->id); + debug_msg("******** nano_pipe_send_cb %d ****", p->id); // retry here if (nni_aio_result(&p->aio_send) != 0) { nni_msg_free(nni_aio_get_msg(&p->aio_send)); @@ -682,12 +666,9 @@ nano_pipe_send_cb(void *arg) nni_aio_set_packetid(&p->aio_send, 0); if (nni_lmq_getq(&p->rlmq, &msg) == 0) { - qos = nng_aio_get_prov_extra(&p->aio_send, 0); - nni_aio_set_msg( - &p->aio_send, NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos)); - - debug_msg("rlmq msg resending! %ld msgs left\n", - nni_lmq_len(&p->rlmq)); + // msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); + nni_aio_set_msg(&p->aio_send, msg); + debug_msg("rlmq msg resending! %ld msgs left\n", nni_lmq_len(&p->rlmq)); nni_pipe_send(p->pipe, &p->aio_send); nni_mtx_unlock(&p->lk); return; @@ -853,6 +834,7 @@ nano_pipe_recv_cb(void *arg) NNI_GET16(ptr, ackid); if ((qos_msg = nni_id_get(npipe->nano_qos_db, ackid)) != NULL) { + qos_msg = NANO_NNI_LMQ_GET_MSG_POINTER(qos_msg); nni_msg_free(qos_msg); nni_id_remove(npipe->nano_qos_db, ackid); } else { @@ -1058,4 +1040,4 @@ nng_nano_tcp0_open(nng_socket *sidp) { // TODO Global binary tree init here return (nni_proto_mqtt_open(sidp, &nano_tcp_proto, nano_sock_setdb)); -} +} \ No newline at end of file diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 13c9f5900..cccd38438 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -568,7 +568,6 @@ tcptran_pipe_recv_cb(void *arg) nng_stream_send(p->conn, p->rsaio); } } else if (type == CMD_PUBREC) { - // TODO uint8_t *tmp; nng_aio_wait(p->rpaio); p->txlen[0] = 0X62; @@ -679,7 +678,10 @@ tcptran_pipe_send_start(tcptran_pipe *p) nni_println("ERROR: sending NULL msg!"); return; } - + uint8_t qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); + //qos default to 0 if the msg is not PUBLISH + msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); + nni_aio_set_msg(aio, msg); // never modify msg if (nni_msg_header_len(msg) > 0 && nni_msg_cmd_type(msg) == CMD_PUBLISH) { @@ -697,8 +699,6 @@ tcptran_pipe_send_start(tcptran_pipe *p) p->qlength = 0; NNI_GET16(body, tlen); - // uint8_t qos = nni_aio_get_prov_extra(aio, 0); - uint8_t qos = 0; qos_pac = nni_msg_get_pub_qos(msg); if (qos_pac == 0) { // save time & space for QoS 0 publish @@ -707,8 +707,8 @@ tcptran_pipe_send_start(tcptran_pipe *p) debug_msg("qos_pac %d sub %d\n", qos_pac, qos); memcpy(fixheader, header, nni_msg_header_len(msg)); + qos = qos_pac > qos ? qos : qos_pac; - // use qos from aio directly. no need such redundant logic here if (qos_pac > qos) { if (qos == 1) { // set qos to 1 @@ -718,23 +718,19 @@ tcptran_pipe_send_start(tcptran_pipe *p) } else { // set qos to 0 fixheader[0] = fixheader[0] & 0xF9; - // mdf remaining length TODO get remaining len - // from packet + uint32_t pos = 1; rlen = put_var_integer( - tmp, nni_msg_remaining_len(msg) - 2); + tmp, get_var_integer(header, &pos) - 2); memcpy(fixheader + 1, tmp, rlen); } - } else if (qos_pac < qos) { + } else { if (qos_pac == 1) { // QoS 1 publish to Qos 2 - // TODO rlen = nni_msg_header_len(msg) - 1; } else { // QoS 0 publish to QoS 1/2 nothing to do goto send; } - } else { - rlen = nni_msg_header_len(msg) - 1; } txaio = p->txaio; @@ -745,37 +741,35 @@ tcptran_pipe_send_start(tcptran_pipe *p) p->qlength += tlen + 2; // get topic length // packet id - if (qos > 0 && qos_pac > 0) { + if (qos > 0) { // set pid nni_msg *old; pid = nni_aio_get_packetid(aio); - if (pid == 0) { // first time deal with "pid", it's not - // resending + if (pid == 0) { + //first time send this msg pid = nni_pipe_inc_packetid(pipe); // store msg for qos retrying - debug_msg( - "* processing QoS pubmsg with pipe: %p *", - p); + debug_msg("* processing QoS pubmsg with pipe: %p *", p); nni_msg_clone(msg); if ((old = nni_id_get( pipe->nano_qos_db, pid)) != NULL) { // TODO packetid already exists. - // replace old with new one shouldn't - // get here BUG + // do we need to replace old with new one ? + // print warning to users nni_println( "ERROR: packet id duplicates in " "nano_qos_db"); + old = NANO_NNI_LMQ_GET_MSG_POINTER(old); nni_msg_free(old); // nni_id_remove(&pipe->nano_qos_db, // pid); } - nni_id_set(pipe->nano_qos_db, pid, msg); + old = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); + nni_id_set(pipe->nano_qos_db, pid, old); } NNI_PUT16(varheader, pid); p->qlength += 2; } - // TODO optimize the performance of QoS 1to1 2to2 by reduce the - // length of qlength if (p->qlength > 16 + NNI_NANO_MAX_PACKET_SIZE) { nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); p->qos_buf = nng_alloc(sizeof(uint8_t) * (p->qlength)); @@ -842,6 +836,7 @@ tcptran_pipe_send(void *arg, nni_aio *aio) } nni_list_append(&p->sendq, aio); if (nni_list_first(&p->sendq) == aio) { + //send publish msg or send others tcptran_pipe_send_start(p); } nni_mtx_unlock(&p->mtx); @@ -958,7 +953,6 @@ tcptran_pipe_start(tcptran_pipe *p, nng_stream *conn, tcptran_ep *ep) // p->proto = ep->proto; debug_msg("tcptran_pipe_start!"); - // TODO abide with CONNECT header p->gotrxhead = 0; p->wantrxhead = NANO_CONNECT_PACKET_LEN; // packet type 1 + remaining // length 1 + protocal name 7 From b3051eca357582ee702c37f79f921ee85ffd97d4 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 20 Sep 2021 16:19:10 +0800 Subject: [PATCH 045/180] * FIX [nano_tcp/websocket] Fix #223 & #222 by adapting qos bits method --- src/sp/protocol/reqrep0/nano_tcp.c | 22 +--------------------- src/sp/transport/tcp/tcp.c | 3 ++- src/sp/transport/ws/websocket.c | 9 ++++++++- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 1bb14ccba..d1a9e69cd 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -87,7 +87,6 @@ struct nano_pipe { uint8_t reason_code; uint8_t ka_refresh; nano_conn_param *conn_param; - nano_pipe_db * pipedb_root; nni_lmq rlmq; }; @@ -485,9 +484,6 @@ nano_pipe_fini(void *arg) nni_id_map_fini(nano_qos_db); nng_free(nano_qos_db, sizeof(struct nni_id_map)); - nano_msg_free_pipedb(p->pipedb_root); - p->pipedb_root = NULL; - nni_mtx_fini(&p->lk); nni_aio_fini(&p->aio_send); nni_aio_fini(&p->aio_recv); @@ -772,7 +768,6 @@ nano_pipe_recv_cb(void *arg) nano_ctx * ctx; nni_msg * msg, *qos_msg = NULL; nni_aio * aio; - nano_pipe_db * pipe_db; nni_pipe * npipe = p->pipe; uint8_t * ptr; uint16_t ackid; @@ -796,22 +791,8 @@ nano_pipe_recv_cb(void *arg) // TODO HOOK switch (nng_msg_cmd_type(msg)) { case CMD_UNSUBSCRIBE: - goto unsub; case CMD_SUBSCRIBE: - // TODO only cache topic hash when it is above qos 1/2 - nni_mtx_lock(&p->lk); - cparam = p->conn_param; - pipe_db = nano_msg_get_subtopic(msg, p->pipedb_root, - cparam); // TODO potential memleak when sub failed - p->pipedb_root = pipe_db; - for (; pipe_db != NULL; pipe_db = pipe_db->next) { - nni_id_set( - &npipe->nano_db, DJBHash(pipe_db->topic), pipe_db); - } - nni_mtx_unlock(&p->lk); - - // __attribute__((fallthrough)) - unsub: + cparam = p->conn_param; if (cparam->pro_ver == PROTOCOL_VERSION_v5) { len = get_var_integer(ptr + 2, &len_of_varint); nni_msg_set_payload_ptr( @@ -819,7 +800,6 @@ nano_pipe_recv_cb(void *arg) } else { nni_msg_set_payload_ptr(msg, ptr + 2); } - // TODO remove topic from pipe_db break; case CMD_DISCONNECT: nni_pipe_close(p->pipe); diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index cccd38438..91ab87aee 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -656,6 +656,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) nni_msg *msg; int niov; nni_iov iov[4]; + uint8_t qos; debug_msg("########### tcptran_pipe_send_start ###########"); if (p->closed) { @@ -678,7 +679,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) nni_println("ERROR: sending NULL msg!"); return; } - uint8_t qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); + qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); //qos default to 0 if the msg is not PUBLISH msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); nni_aio_set_msg(aio, msg); diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 21d7000cd..805237394 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -289,6 +289,8 @@ static void wstran_pipe_send(void *arg, nni_aio *aio) { ws_pipe *p = arg; + nni_msg *msg; + uint8_t qos; int rv; if (nni_aio_begin(aio) != 0) { @@ -301,7 +303,12 @@ wstran_pipe_send(void *arg, nni_aio *aio) return; } p->user_txaio = aio; - nni_aio_set_msg(p->txaio, nni_aio_get_msg(aio)); + msg = nni_aio_get_msg(aio); + qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); + //qos default to 0 if the msg is not PUBLISH + msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); + nni_aio_set_msg(aio, msg); + nni_aio_set_msg(p->txaio, msg); nni_aio_set_msg(aio, NULL); nng_stream_send(p->ws, p->txaio); From df7d61d7bb85eddfd7d47d9bc1c8105cb6c22345 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 24 Sep 2021 11:17:59 +0800 Subject: [PATCH 046/180] * FIX [nano_tcp/timer] timer kick connections via aio_finish_error, not pipe_close. --- src/sp/protocol/reqrep0/nano_tcp.c | 2 +- src/sp/transport/tcp/tcp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index d1a9e69cd..b03427881 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -191,7 +191,7 @@ nano_pipe_timer_cb(void *arg) // TODO check keepalived timer interval nni_mtx_unlock(&p->lk); p->reason_code = 0x8D; - nano_pipe_close(p); + nni_aio_finish_error(&p->aio_recv, NNG_ECONNREFUSED); return; } p->ka_refresh++; diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 91ab87aee..4bc74ca99 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -171,7 +171,6 @@ tcptran_pipe_fini(void *arg) } nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); - // nng_free(p->tcp_cparam, sizeof(struct conn_param)); nni_aio_free(p->qsaio); nni_aio_free(p->rpaio); nni_aio_free(p->rsaio); @@ -399,6 +398,7 @@ tcptran_pipe_send_cb(void *arg) cmd = nni_msg_cmd_type(msg); if (cmd == CMD_CONNACK) { header = nni_msg_header(msg); + // parse result code TODO verify bug flag = header[3]; } // nni_pipe_bump_tx(p->npipe, n); From 1777d148fcbcd99eaaa5fba8079611e3c9b0ed7c Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Sun, 26 Sep 2021 19:19:22 +0800 Subject: [PATCH 047/180] * RM [pipe] remove unused nano_db of pipe struct --- src/core/pipe.c | 2 -- src/core/sockimpl.h | 1 - 2 files changed, 3 deletions(-) diff --git a/src/core/pipe.c b/src/core/pipe.c index a1d76665a..bda918fff 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -67,7 +67,6 @@ pipe_destroy(void *arg) while (p->p_ref != 0) { nni_cv_wait(&p->p_cv); } - nni_id_map_fini(&p->nano_db); // nni_id_map_fini(&p->nano_qos_db); nni_mtx_unlock(&pipes_lk); @@ -280,7 +279,6 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) nni_mtx_init(&p->p_mtx); nni_cv_init(&p->p_cv, &pipes_lk); - nni_id_map_init(&p->nano_db, 0, 0, false); p->nano_qos_db = nng_alloc(sizeof(struct nni_id_map)); nni_id_map_init(p->nano_qos_db, 0, 0, false); diff --git a/src/core/sockimpl.h b/src/core/sockimpl.h index 37dc1eaac..87b90925f 100644 --- a/src/core/sockimpl.h +++ b/src/core/sockimpl.h @@ -126,7 +126,6 @@ struct nni_pipe { // NanoMQ void * conn_param; uint16_t packet_id; - nni_id_map nano_db; // storing subscription topics nni_id_map *nano_qos_db; // storing qos backup msgs }; From 32964f86a10bb030b2e591128d66111726f7dd21 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Sun, 26 Sep 2021 19:22:18 +0800 Subject: [PATCH 048/180] * FIX [transport/mqtt] fix QoS message ID increment logic. --- src/sp/transport/tcp/tcp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 4bc74ca99..a06d73468 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -725,13 +725,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) memcpy(fixheader + 1, tmp, rlen); } } else { - if (qos_pac == 1) { - // QoS 1 publish to Qos 2 - rlen = nni_msg_header_len(msg) - 1; - } else { - // QoS 0 publish to QoS 1/2 nothing to do - goto send; - } + rlen = nni_msg_header_len(msg) - 1; } txaio = p->txaio; From 98f610ab015c0a03772490d6cd381064ed44a03f Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 27 Sep 2021 20:03:37 +0800 Subject: [PATCH 049/180] * MDF [mqtt/tcp] remove redundant code. --- src/sp/transport/tcp/tcp.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index a06d73468..2a458cd7e 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -568,24 +568,20 @@ tcptran_pipe_recv_cb(void *arg) nng_stream_send(p->conn, p->rsaio); } } else if (type == CMD_PUBREC) { - uint8_t *tmp; nng_aio_wait(p->rpaio); p->txlen[0] = 0X62; p->txlen[1] = 0x02; - tmp = nni_msg_body(msg); - memcpy(p->txlen + 2, tmp, 2); + memcpy(p->txlen + 2, nni_msg_body(msg), 2); iov.iov_len = 4; iov.iov_buf = &p->txlen; // send it down... nni_aio_set_iov(p->rpaio, 1, &iov); nng_stream_send(p->conn, p->rpaio); } else if (type == CMD_PUBREL) { - uint8_t *tmp; nng_aio_wait(p->qsaio); p->txlen[0] = CMD_PUBCOMP; p->txlen[1] = 0x02; - tmp = nni_msg_body(msg); - memcpy(p->txlen + 2, tmp, 2); + memcpy(p->txlen + 2, nni_msg_body(msg), 2); iov.iov_len = 4; iov.iov_buf = &p->txlen; // send it down... @@ -771,7 +767,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) } memcpy(p->qos_buf, fixheader, rlen + 1); memcpy(p->qos_buf + rlen + 1, body, tlen + 2); - if (qos > 0 && qos_pac > 0) { + if (qos > 0) { memcpy(p->qos_buf + rlen + tlen + 3, varheader, 2); } iov[niov].iov_buf = p->qos_buf; From a29379751139bd1739627196f51bcdd8da72640b Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 27 Sep 2021 20:12:14 +0800 Subject: [PATCH 050/180] * NEW [mqtt/websocket] full support QoS 1/2 msg --- src/sp/transport/ws/websocket.c | 142 +++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 13 deletions(-) diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index 805237394..d92264305 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -14,6 +14,7 @@ #include #include "core/nng_impl.h" +#include "core/sockimpl.h" #include "supplemental/websocket/websocket.h" #include @@ -60,7 +61,6 @@ struct ws_pipe { nni_aio * rxaio; nni_aio * qsaio; nni_pipe * npipe; - uint8_t * qos_buf; conn_param *ws_param; nng_stream *ws; }; @@ -128,8 +128,8 @@ wstran_pipe_recv_cb(void *arg) goto recv; } len = get_var_integer(ptr, &pos); - if (*(ptr + pos - 1) > - 0x7f) { // continue to next byte of remaining length + if (*(ptr + pos - 1) >0x7f) { + // continue to next byte of remaining length if (p->gotrxhead >= NNI_NANO_MAX_HEADER_SIZE) { // length error rv = NNG_EMSGSIZE; @@ -161,8 +161,7 @@ wstran_pipe_recv_cb(void *arg) if (nni_msg_cmd_type(p->tmp_msg) == CMD_CONNECT) { // end of nego if (p->ws_param == NULL) { - p->ws_param = - nng_alloc(sizeof(struct conn_param)); + conn_param_alloc(&p->ws_param); } if (conn_handler( nni_msg_body(p->tmp_msg), p->ws_param) != 0) { @@ -172,6 +171,7 @@ wstran_pipe_recv_cb(void *arg) p->tmp_msg = NULL; nni_aio_set_msg(uaio, smsg); nni_aio_set_output(uaio, 0, p); + // let pipe_start_cb in protocol layer deal with CONNACK nni_aio_finish(uaio, 0, 0); nni_mtx_unlock(&p->mtx); return; @@ -179,17 +179,17 @@ wstran_pipe_recv_cb(void *arg) if (nni_msg_alloc(&smsg, 0) != 0) { goto reset; } + //parse fixed header ws_fixed_header_adaptor(ptr, smsg); nni_msg_free(p->tmp_msg); p->tmp_msg = NULL; nni_msg_set_conn_param(smsg, p->ws_param); } + uint8_t qos_pac; + uint16_t pid; + nni_msg *qos_msg; if (nni_msg_cmd_type(smsg) == CMD_PUBLISH) { - uint8_t qos_pac; - uint16_t pid; - nni_msg * qos_msg; - qos_pac = nni_msg_get_pub_qos(smsg); if (qos_pac > 0) { nng_aio_wait(p->qsaio); @@ -206,6 +206,24 @@ wstran_pipe_recv_cb(void *arg) nni_aio_set_msg(p->qsaio, qos_msg); nng_stream_send(p->ws, p->qsaio); } + } else if (nni_msg_cmd_type(smsg) == CMD_PUBREC) { + nng_aio_wait(p->qsaio); + p->txlen[0] = 0X62; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(smsg), 2); + nni_msg_alloc(&qos_msg, 0); + nni_msg_header_append(qos_msg, p->txlen, 4); + nni_aio_set_msg(p->qsaio, qos_msg); + nng_stream_send(p->ws, p->qsaio); + } else if (nni_msg_cmd_type(smsg) == CMD_PUBREL) { + nng_aio_wait(p->qsaio); + p->txlen[0] = CMD_PUBCOMP; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(smsg), 2); + nni_msg_alloc(&qos_msg, 0); + nni_msg_header_append(qos_msg, p->txlen, 4); + nni_aio_set_msg(p->qsaio, qos_msg); + nng_stream_send(p->ws, p->qsaio); } nni_aio_set_msg(uaio, smsg); @@ -231,6 +249,9 @@ wstran_pipe_recv_cb(void *arg) nni_msg_free(smsg); p->tmp_msg = NULL; } + if (p->ws_param != NULL) { + conn_param_free(p->ws_param); + } nni_mtx_unlock(&p->mtx); return; } @@ -285,11 +306,16 @@ wstran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) nni_mtx_unlock(&p->mtx); } +static inline void +wstran_mqtt_publish(){ + +} + static void wstran_pipe_send(void *arg, nni_aio *aio) { ws_pipe *p = arg; - nni_msg *msg; + nni_msg *msg, *smsg; uint8_t qos; int rv; @@ -306,11 +332,102 @@ wstran_pipe_send(void *arg, nni_aio *aio) msg = nni_aio_get_msg(aio); qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); //qos default to 0 if the msg is not PUBLISH - msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); + msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); + if (nni_msg_cmd_type(msg) == CMD_PUBLISH) { + uint8_t *body, *header, qos_pac; + uint8_t varheader[2], + fixheader[NNI_NANO_MAX_HEADER_SIZE] = { 0 }, + tmp[4] = { 0 }; + nni_pipe *pipe; + uint16_t pid; + size_t tlen, rlen; + + qos_pac = nni_msg_get_pub_qos(msg); + qos = qos_pac > qos ? qos : qos_pac; + if (qos_pac == 0) { + // save time & space for QoS 0 publish + goto send; + } + + pipe = p->npipe; + body = nni_msg_body(msg); + header = nni_msg_header(msg); + NNI_GET16(body, tlen); + memcpy(fixheader, header, nni_msg_header_len(msg)); + if (qos_pac > qos) { + // need to modify the packets + if (qos == 1) { + // set qos to 1 (send qos 2 to 1) + fixheader[0] = fixheader[0] & 0xF9; + fixheader[0] = fixheader[0] | 0x02; + rlen = nni_msg_header_len(msg) - 1; + } else { + // set qos to 0 (send qos 2/1 to 0) + fixheader[0] = fixheader[0] & 0xF9; + uint32_t pos = 1; + rlen = put_var_integer( + tmp, get_var_integer(header, &pos) - 2); + memcpy(fixheader + 1, tmp, rlen); + } + } else { + // send msg as it is (qos_pac) + rlen = nni_msg_header_len(msg) - 1; + } + if (qos > 0) { + nni_msg *old; + pid = nni_aio_get_packetid(aio); + if (pid == 0) { + // first time send this msg + pid = nni_pipe_inc_packetid(pipe); + // store msg for qos retrying + debug_msg( + "* processing QoS pubmsg with pipe: %p *", + p); + nni_msg_clone(msg); + if ((old = nni_id_get( + pipe->nano_qos_db, pid)) != NULL) { + // TODO packetid already exists. + // do we need to replace old with new + // one ? print warning to users + nni_println( + "ERROR: packet id duplicates in " + "nano_qos_db"); + old = + NANO_NNI_LMQ_GET_MSG_POINTER(old); + nni_msg_free(old); + // nni_id_remove(&pipe->nano_qos_db, + // pid); + } + old = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); + nni_id_set(pipe->nano_qos_db, pid, old); + } + NNI_PUT16(varheader, pid); + } + nni_msg_alloc(&smsg, 0); + nni_msg_header_append(smsg, fixheader, rlen + 1); + nni_msg_append(smsg, body, tlen + 2); + if (qos > 0) { + //packetid + nni_msg_append(smsg, varheader, 2); + } + //payload + nni_msg_append(smsg, body + 4 + tlen, nni_msg_len(msg) - 4 - tlen); + //duplicated msg is gonna be freed by http. so we free old one here + nni_msg_free(msg); + msg = smsg; + } +// normal sending if it is not PUBLISH +send: nni_aio_set_msg(aio, msg); nni_aio_set_msg(p->txaio, msg); nni_aio_set_msg(aio, NULL); - + // verify connect + if (nni_msg_cmd_type(msg) == CMD_CONNACK) { + uint8_t *header = nni_msg_header(msg); + if (*(header+3) != 0x00) { + nni_pipe_close(p->npipe); + } + } nng_stream_send(p->ws, p->txaio); nni_mtx_unlock(&p->mtx); } @@ -335,7 +452,6 @@ wstran_pipe_init(void *arg, nni_pipe *pipe) p->npipe = pipe; p->gotrxhead = 0; p->wantrxhead = 0; - // p->qos_buf = nng_alloc(16 + NNI_NANO_MAX_PACKET_SIZE); p->ep_aio = NULL; return (0); } From afca3d0e878088fc9940f5c51f209b61ebd3a111 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Sat, 2 Oct 2021 14:18:06 +0800 Subject: [PATCH 051/180] * FIX [protocol/nano_tcp] use correct msg pointer when resending qos msg. --- src/sp/protocol/reqrep0/nano_tcp.c | 11 ++++------- src/sp/transport/tcp/tcp.c | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index b03427881..60a63e301 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -204,11 +204,12 @@ nano_pipe_timer_cb(void *arg) if ((nni_clock() - time) >= (long unsigned) qos_timer * 1250) { p->busy = true; + //TODO set max retrying times in nanomq.conf nni_msg_clone(rmsg); nano_msg_set_dup(rmsg); nni_aio_set_packetid(&p->aio_send, pid); - nni_aio_set_msg(&p->aio_send, msg); - debug_msg("resending qos msg!\n"); + nni_aio_set_msg(&p->aio_send, rmsg); + debug_msg("resending qos msg packetid: %d", pid); nni_pipe_send(p->pipe, &p->aio_send); nni_id_remove(npipe->nano_qos_db, pid); } @@ -281,8 +282,6 @@ nano_ctx_init(void *carg, void *sarg) NNI_LIST_NODE_INIT(&ctx->sqnode); NNI_LIST_NODE_INIT(&ctx->rqnode); - // TODO send list?? - // ctx->pp_len = 0; ctx->sock = s; ctx->pipe_id = 0; @@ -326,8 +325,7 @@ nano_ctx_send(void *arg, nni_aio *aio) return; } - debug_msg("############### nano_ctx_send with ctx %p msg type %x " - "###############", + debug_msg("#### nano_ctx_send with ctx %p msg type %x ####", ctx, nni_msg_cmd_type(msg)); if ((pipe = nni_msg_get_pipe(msg)) != 0) { @@ -860,7 +858,6 @@ nano_pipe_recv_cb(void *arg) // schedule another receive nni_pipe_recv(p->pipe, &p->aio_recv); - // ctx->pp_len = len; //TODO Rewrite mqtt header length ctx->pipe_id = p->id; debug_msg("currently processing pipe_id: %d", p->id); diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index 2a458cd7e..d6bd5e8f7 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -671,7 +671,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) // This runs to send the message. msg = nni_aio_get_msg(aio); if (msg == NULL) { - // TODO error handle + // TODO error handler nni_println("ERROR: sending NULL msg!"); return; } From 0c889d8ed3fa7b892ca143a67c9486be93a2f639 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 6 Sep 2021 13:08:44 -0700 Subject: [PATCH 052/180] Eliminate the pipe mutex and use atomic for pipe closed. This eliminates several mutex operations done each time a pipe is created or destroyed. For large scale systems this should reduce overall pressure on the memory subsystem, and scale better as many threads are coming and going. This also reduces the overall size of nni_pipe -- on Linux by 36 bytes typically. --- src/core/pipe.c | 29 ++++++++++++++--------------- src/core/socket.c | 13 +++---------- src/core/sockimpl.h | 4 ++-- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/core/pipe.c b/src/core/pipe.c index bda918fff..468caeec1 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -89,7 +89,6 @@ pipe_destroy(void *arg) p->p_tran_ops.p_fini(p->p_tran_data); } nni_cv_fini(&p->p_cv); - nni_mtx_fini(&p->p_mtx); nni_free(p, p->p_size); } @@ -147,14 +146,9 @@ nni_pipe_send(nni_pipe *p, nni_aio *aio) void nni_pipe_close(nni_pipe *p) { - nni_mtx_lock(&p->p_mtx); - if (p->p_closed) { - // We already did a close. - nni_mtx_unlock(&p->p_mtx); - return; + if (nni_atomic_swap_bool(&p->p_closed, true)) { + return; // We already did a close. } - p->p_closed = true; - nni_mtx_unlock(&p->p_mtx); if (p->p_proto_data != NULL) { p->p_proto_ops.pipe_close(p->p_proto_data); @@ -168,6 +162,12 @@ nni_pipe_close(nni_pipe *p) nni_reap(&pipe_reap_list, p); } +bool +nni_pipe_is_closed(nni_pipe *p) +{ + return (nni_atomic_get_bool(&p->p_closed)); +} + uint16_t nni_pipe_peer(nni_pipe *p) { @@ -247,9 +247,9 @@ pipe_stats_init(nni_pipe *p) static int pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) { - nni_pipe * p; + nni_pipe *p; int rv; - void * sdata = nni_sock_proto_data(sock); + void *sdata = nni_sock_proto_data(sock); nni_proto_pipe_ops *pops = nni_sock_proto_pipe_ops(sock); size_t sz; @@ -267,17 +267,16 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) p->p_tran_data = tdata; p->p_proto_ops = *pops; p->p_sock = sock; - p->p_closed = false; p->p_cbs = false; p->p_ref = 0; // NanoMQ p->packet_id = 0; + nni_atomic_init_bool(&p->p_closed); nni_atomic_flag_reset(&p->p_stop); NNI_LIST_NODE_INIT(&p->p_sock_node); NNI_LIST_NODE_INIT(&p->p_ep_node); - nni_mtx_init(&p->p_mtx); nni_cv_init(&p->p_cv, &pipes_lk); p->nano_qos_db = nng_alloc(sizeof(struct nni_id_map)); nni_id_map_init(p->nano_qos_db, 0, 0, false); @@ -306,9 +305,9 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) int nni_pipe_create_dialer(nni_pipe **pp, nni_dialer *d, void *tdata) { - int rv; + int rv; nni_sp_tran *tran = d->d_tran; - nni_pipe *p; + nni_pipe * p; if ((rv = pipe_create(&p, d->d_sock, tran, tdata)) != 0) { return (rv); @@ -332,7 +331,7 @@ nni_pipe_create_listener(nni_pipe **pp, nni_listener *l, void *tdata) { int rv; nni_sp_tran *tran = l->l_tran; - nni_pipe *p; + nni_pipe * p; if ((rv = pipe_create(&p, l->l_sock, tran, tdata)) != 0) { return (rv); diff --git a/src/core/socket.c b/src/core/socket.c index e376b773e..24403ac7f 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1489,9 +1489,7 @@ nni_dialer_add_pipe(nni_dialer *d, void *tpipe) nni_pipe_run_cb(p, NNG_PIPE_EV_ADD_PRE); - nni_mtx_lock(&s->s_mx); - if (p->p_closed) { - nni_mtx_unlock(&s->s_mx); + if (nni_pipe_is_closed(p)) { #ifdef NNG_ENABLE_STATS nni_stat_inc(&d->st_reject, 1); nni_stat_inc(&s->st_rejects, 1); @@ -1499,8 +1497,8 @@ nni_dialer_add_pipe(nni_dialer *d, void *tpipe) nni_pipe_rele(p); return; } + if (p->p_proto_ops.pipe_start(p->p_proto_data) != 0) { - nni_mtx_unlock(&s->s_mx); #ifdef NNG_ENABLE_STATS nni_stat_inc(&d->st_reject, 1); nni_stat_inc(&s->st_rejects, 1); @@ -1509,7 +1507,6 @@ nni_dialer_add_pipe(nni_dialer *d, void *tpipe) nni_pipe_rele(p); return; } - nni_mtx_unlock(&s->s_mx); #ifdef NNG_ENABLE_STATS nni_stat_register(&p->st_root); #endif @@ -1604,9 +1601,7 @@ nni_listener_add_pipe(nni_listener *l, void *tpipe) nni_pipe_run_cb(p, NNG_PIPE_EV_ADD_PRE); - nni_mtx_lock(&s->s_mx); - if (p->p_closed) { - nni_mtx_unlock(&s->s_mx); + if (nni_pipe_is_closed(p)) { #ifdef NNG_ENABLE_STATS nni_stat_inc(&l->st_reject, 1); nni_stat_inc(&s->st_rejects, 1); @@ -1615,7 +1610,6 @@ nni_listener_add_pipe(nni_listener *l, void *tpipe) return; } if (p->p_proto_ops.pipe_start(p->p_proto_data) != 0) { - nni_mtx_unlock(&s->s_mx); #ifdef NNG_ENABLE_STATS nni_stat_inc(&l->st_reject, 1); nni_stat_inc(&s->st_rejects, 1); @@ -1624,7 +1618,6 @@ nni_listener_add_pipe(nni_listener *l, void *tpipe) nni_pipe_rele(p); return; } - nni_mtx_unlock(&s->s_mx); #ifdef NNG_ENABLE_STATS nni_stat_register(&p->st_root); #endif diff --git a/src/core/sockimpl.h b/src/core/sockimpl.h index 87b90925f..35fcf192c 100644 --- a/src/core/sockimpl.h +++ b/src/core/sockimpl.h @@ -104,11 +104,10 @@ struct nni_pipe { nni_sock *p_sock; nni_dialer *p_dialer; nni_listener *p_listener; - bool p_closed; + nni_atomic_bool p_closed; nni_atomic_flag p_stop; bool p_cbs; int p_ref; - nni_mtx p_mtx; nni_cv p_cv; nni_reap_node p_reap; @@ -146,6 +145,7 @@ extern void nni_listener_destroy(nni_listener *); extern void nni_listener_stop(nni_listener *); extern void nni_pipe_remove(nni_pipe *); +extern bool nni_pipe_is_closed(nni_pipe *); extern void nni_pipe_run_cb(nni_pipe *, nng_pipe_ev); extern int nni_pipe_create_dialer(nni_pipe **, nni_dialer *, void *); extern int nni_pipe_create_listener(nni_pipe **, nni_listener *, void *); From 4e2b9bc930a75b0598270db6e6cd671e62fe47d3 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 15 Nov 2020 19:12:28 -0800 Subject: [PATCH 053/180] fixes #1347 windows IPC accept cancellation not wired up --- src/platform/windows/win_ipclisten.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/windows/win_ipclisten.c b/src/platform/windows/win_ipclisten.c index c5f31b22b..eec53aa79 100644 --- a/src/platform/windows/win_ipclisten.c +++ b/src/platform/windows/win_ipclisten.c @@ -282,6 +282,7 @@ ipc_listener_accept(void *arg, nni_aio *aio) nni_aio_finish_error(aio, NNG_ECLOSED); return; } + nni_aio_schedule(aio, ipc_accept_cancel, l); nni_list_append(&l->aios, aio); if (nni_list_first(&l->aios) == aio) { ipc_accept_start(l); From b77034ed01c16f097239214301c396a84e16c38e Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 6 Sep 2021 13:33:10 -0700 Subject: [PATCH 054/180] Remove redundant check. --- src/platform/windows/win_ipclisten.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/platform/windows/win_ipclisten.c b/src/platform/windows/win_ipclisten.c index eec53aa79..07969e974 100644 --- a/src/platform/windows/win_ipclisten.c +++ b/src/platform/windows/win_ipclisten.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2019 Devolutions // @@ -277,11 +277,6 @@ ipc_listener_accept(void *arg, nni_aio *aio) nni_aio_finish_error(aio, NNG_ESTATE); return; } - if (l->closed) { - nni_mtx_unlock(&l->mtx); - nni_aio_finish_error(aio, NNG_ECLOSED); - return; - } nni_aio_schedule(aio, ipc_accept_cancel, l); nni_list_append(&l->aios, aio); if (nni_list_first(&l->aios) == aio) { From a53ec067428655eb56c3ca8efe72e1ea117c9cca Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 6 Sep 2021 16:13:20 -0700 Subject: [PATCH 055/180] Minor cleanups. --- src/core/pipe.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/core/pipe.c b/src/core/pipe.c index 468caeec1..5f4af948f 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -14,7 +14,7 @@ #include -// This file contains functions relating to pipes. +// This file contains functions related to pipe objects. // // Operations on pipes (to the transport) are generally blocking operations, // performed in the context of the protocol. @@ -34,7 +34,7 @@ nni_pipe_sys_init(void) { nni_mtx_init(&pipes_lk); - // Pipe IDs needs to have high order bit clear, and we want + // Pipe IDs need their high bit clear, and we want // them to start at a random value. nni_id_map_init(&pipes, 1, 0x7fffffff, true); } @@ -245,11 +245,11 @@ pipe_stats_init(nni_pipe *p) #endif // NNG_ENABLE_STATS static int -pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) +pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tran_data) { nni_pipe *p; int rv; - void *sdata = nni_sock_proto_data(sock); + void *sock_data = nni_sock_proto_data(sock); nni_proto_pipe_ops *pops = nni_sock_proto_pipe_ops(sock); size_t sz; @@ -257,14 +257,14 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) if ((p = nni_zalloc(sz)) == NULL) { // In this case we just toss the pipe... - tran->tran_pipe->p_fini(tdata); + tran->tran_pipe->p_fini(tran_data); return (NNG_ENOMEM); } p->p_size = sz; p->p_proto_data = p + 1; p->p_tran_ops = *tran->tran_pipe; - p->p_tran_data = tdata; + p->p_tran_data = tran_data; p->p_proto_ops = *pops; p->p_sock = sock; p->p_cbs = false; @@ -291,8 +291,8 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) pipe_stats_init(p); #endif - if ((rv != 0) || ((rv = p->p_tran_ops.p_init(tdata, p)) != 0) || - ((rv = pops->pipe_init(p->p_proto_data, p, sdata)) != 0)) { + if ((rv != 0) || ((rv = p->p_tran_ops.p_init(tran_data, p)) != 0) || + ((rv = pops->pipe_init(p->p_proto_data, p, sock_data)) != 0)) { nni_pipe_close(p); nni_pipe_rele(p); return (rv); @@ -303,13 +303,13 @@ pipe_create(nni_pipe **pp, nni_sock *sock, nni_sp_tran *tran, void *tdata) } int -nni_pipe_create_dialer(nni_pipe **pp, nni_dialer *d, void *tdata) +nni_pipe_create_dialer(nni_pipe **pp, nni_dialer *d, void *tran_data) { int rv; nni_sp_tran *tran = d->d_tran; nni_pipe * p; - if ((rv = pipe_create(&p, d->d_sock, tran, tdata)) != 0) { + if ((rv = pipe_create(&p, d->d_sock, tran, tran_data)) != 0) { return (rv); } p->p_dialer = d; @@ -327,13 +327,13 @@ nni_pipe_create_dialer(nni_pipe **pp, nni_dialer *d, void *tdata) } int -nni_pipe_create_listener(nni_pipe **pp, nni_listener *l, void *tdata) +nni_pipe_create_listener(nni_pipe **pp, nni_listener *l, void *tran_data) { int rv; nni_sp_tran *tran = l->l_tran; nni_pipe * p; - if ((rv = pipe_create(&p, l->l_sock, tran, tdata)) != 0) { + if ((rv = pipe_create(&p, l->l_sock, tran, tran_data)) != 0) { return (rv); } p->p_listener = l; @@ -402,26 +402,26 @@ nni_pipe_add_stat(nni_pipe *p, nni_stat_item *item) } void -nni_pipe_bump_rx(nni_pipe *p, size_t nbytes) +nni_pipe_bump_rx(nni_pipe *p, size_t bytes) { #ifdef NNG_ENABLE_STATS - nni_stat_inc(&p->st_rx_bytes, nbytes); + nni_stat_inc(&p->st_rx_bytes, bytes); nni_stat_inc(&p->st_rx_msgs, 1); #else NNI_ARG_UNUSED(p); - NNI_ARG_UNUSED(nbytes); + NNI_ARG_UNUSED(bytes); #endif } void -nni_pipe_bump_tx(nni_pipe *p, size_t nbytes) +nni_pipe_bump_tx(nni_pipe *p, size_t bytes) { #ifdef NNG_ENABLE_STATS - nni_stat_inc(&p->st_tx_bytes, nbytes); + nni_stat_inc(&p->st_tx_bytes, bytes); nni_stat_inc(&p->st_tx_msgs, 1); #else NNI_ARG_UNUSED(p); - NNI_ARG_UNUSED(nbytes); + NNI_ARG_UNUSED(bytes); #endif } From 209733fbf89dbc7a1d33e7cb9042ea0b63abcd1f Mon Sep 17 00:00:00 2001 From: Jaylin Date: Thu, 7 Oct 2021 20:48:47 +0800 Subject: [PATCH 056/180] * FIX [nano_tcp/timer] keepalive timer should be protected by a mutex --- src/sp/protocol/reqrep0/nano_tcp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 60a63e301..5df46ff6b 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -189,9 +189,9 @@ nano_pipe_timer_cb(void *arg) nni_println("Warning: close pipe & kick client due to KeepAlive " "timeout!"); // TODO check keepalived timer interval - nni_mtx_unlock(&p->lk); p->reason_code = 0x8D; nni_aio_finish_error(&p->aio_recv, NNG_ECONNREFUSED); + nni_mtx_unlock(&p->lk); return; } p->ka_refresh++; @@ -478,6 +478,7 @@ nano_pipe_fini(void *arg) nni_id_map * nano_qos_db = p->pipe->nano_qos_db; + //TODO safely free the msgs in qos_db // nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); nni_id_map_fini(nano_qos_db); nng_free(nano_qos_db, sizeof(struct nni_id_map)); @@ -500,12 +501,9 @@ nano_pipe_init(void *arg, nni_pipe *pipe, void *s) nni_mtx_init(&p->lk); nni_lmq_init(&p->rlmq, sock->conf->msq_len); nni_aio_init(&p->aio_send, nano_pipe_send_cb, p); - // TODO move keepalive monitor to transport layer? nni_aio_init(&p->aio_timer, nano_pipe_timer_cb, p); nni_aio_init(&p->aio_recv, nano_pipe_recv_cb, p); - // NNI_LIST_INIT(&p->sendq, nano_ctx, sqnode); - p->reason_code = 0x00; p->id = nni_pipe_id(pipe); p->pipe = pipe; From 8389aa502675ae15a6af931db813e8229451bc28 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Thu, 14 Oct 2021 17:13:04 +0800 Subject: [PATCH 057/180] Add submodule "mqtt-codec" --- .gitmodules | 3 +++ CMakeLists.txt | 2 ++ extern/mqtt-codec | 1 + 3 files changed, 6 insertions(+) create mode 160000 extern/mqtt-codec diff --git a/.gitmodules b/.gitmodules index 76205940b..9ad4c7573 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "extern/nng-wolfssl"] path = extern/nng-wolfssl url = https://github.com/staysail/nng-wolfssl +[submodule "extern/mqtt-codec"] + path = extern/mqtt-codec + url = https://github.com/nanomq/mqtt-codec.git diff --git a/CMakeLists.txt b/CMakeLists.txt index ef4c2bc87..335634e0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -249,6 +249,8 @@ if (NNG_TESTS) set(all_tests, "") endif () +add_subdirectory(extern/mqtt-codec) + add_subdirectory(src) if (NNG_TESTS) diff --git a/extern/mqtt-codec b/extern/mqtt-codec new file mode 160000 index 000000000..be6a7e7b3 --- /dev/null +++ b/extern/mqtt-codec @@ -0,0 +1 @@ +Subproject commit be6a7e7b32501c31d7e251a1112567bca684cd8e From 6804277c2ee16feafc07586c8b48b20086817edc Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Thu, 14 Oct 2021 17:13:04 +0800 Subject: [PATCH 058/180] Add submodule "mqtt-codec" --- .gitmodules | 3 +++ CMakeLists.txt | 2 ++ extern/mqtt-codec | 1 + 3 files changed, 6 insertions(+) create mode 160000 extern/mqtt-codec diff --git a/.gitmodules b/.gitmodules index 76205940b..9ad4c7573 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "extern/nng-wolfssl"] path = extern/nng-wolfssl url = https://github.com/staysail/nng-wolfssl +[submodule "extern/mqtt-codec"] + path = extern/mqtt-codec + url = https://github.com/nanomq/mqtt-codec.git diff --git a/CMakeLists.txt b/CMakeLists.txt index ef4c2bc87..335634e0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -249,6 +249,8 @@ if (NNG_TESTS) set(all_tests, "") endif () +add_subdirectory(extern/mqtt-codec) + add_subdirectory(src) if (NNG_TESTS) diff --git a/extern/mqtt-codec b/extern/mqtt-codec new file mode 160000 index 000000000..be6a7e7b3 --- /dev/null +++ b/extern/mqtt-codec @@ -0,0 +1 @@ +Subproject commit be6a7e7b32501c31d7e251a1112567bca684cd8e From a725fa9278c8cad608f689d09c748a492da9212a Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Fri, 15 Oct 2021 11:54:08 +0800 Subject: [PATCH 059/180] Update mqtt-codec --- extern/mqtt-codec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/mqtt-codec b/extern/mqtt-codec index be6a7e7b3..34a395b84 160000 --- a/extern/mqtt-codec +++ b/extern/mqtt-codec @@ -1 +1 @@ -Subproject commit be6a7e7b32501c31d7e251a1112567bca684cd8e +Subproject commit 34a395b84a8c32da8a26851234fd4b6065023033 From c6459b6a66f278fe95ad7d104caad1a7fdc4ed8c Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Thu, 17 Jun 2021 18:58:17 -0700 Subject: [PATCH 060/180] MQTT API swag. --- include/nng/mqtt/mqtt_client.h | 217 +++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 include/nng/mqtt/mqtt_client.h diff --git a/include/nng/mqtt/mqtt_client.h b/include/nng/mqtt/mqtt_client.h new file mode 100644 index 000000000..03c09f2e4 --- /dev/null +++ b/include/nng/mqtt/mqtt_client.h @@ -0,0 +1,217 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +// This file is for the MQTT client implementation. +// Note that while there are some similarities, MQTT is sufficiently +// different enough from SP that many of the APIs cannot be easily +// shared. +// +// At this time there is no server provided by NNG itself, although +// the nanomq project provides such a server (and is based on NNG.) +// +// About our semantics: +// +// 1. MQTT client sockets have a single implicit dialer, and cannot +// support creation of additional dialers or listeners. +// 2. MQTT client sockets do support contexts; each context will +// maintain its own subscriptions, and the socket will keep a +// per-socket list of them and manage the full list. +// 3. Send sends PUBLISH messages. +// 4. Receive is used to receive published data from the server. +// 5. Most of the MQTT specific "features" are as options on the socket, +// dialer, or even the message. (For example message topics are set +// as options on the message.) +// 6. Pipe events can be used to detect connect/disconnect events. +// 7. Any QoS details such as retransmit, etc. are handled under the hood. +// This includes packet IDs. +// 8. PING and keep-alive is handled under the hood. +// 9. For publish actions, a separate method is used (not send/receive). + +#ifndef NNG_MQTT_CLIENT_H +#define NNG_MQTT_CLIENT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// NNG_OPT_MQTT_EXPIRES is a 32-bit integer representing the expiration in +// seconds. This can be applied to a message. +// (TODO: What about session expiry?) +#define NNG_OPT_MQTT_EXPIRES "expires" + +// NNG_OPT_MQTT_QOS is a byte (only lower two bits significant) representing +// the quality of service. At this time, only level zero is supported. +// TODO: level 1 and level 2 QoS +#define NNG_OPT_MQTT_QOS "qos" + +// NNG_OPT_MQTT_RETAIN indicates that the message should be retained on +// the server as the single retained message for the associated topic. +// This is a boolean. +#define NNG_OPT_MQTT_RETAIN "retain" + +// NNG_OPT_MQTT_DUP indicates that the message is a duplicate. This can +// only be returned on a message -- this client will add this flag if +// sending a duplicate message (QoS 1 and 2 only). +#define NNG_OPT_MQTT_DUP "dup" + +// NNG_OPT_MQTT_TOPIC is the message topic. It is encoded as an "Encoded +// UTF-8 string" (uint16 length followed by UTF-8 data). At the API, it +// is just a UTF-8 string (C style, with a terminating byte.) Note that +// we do not support embedded NUL bytes in our UTF-8 strings. Every +// MQTT published message must have a topic. +#define NNG_OPT_MQTT_TOPIC "topic" + +// NNG_OPT_MQTT_REASon is a reason that can be conveyed with a message. +// It is a UTF-8 string. +#define NNG_OPT_MQTT_REASON "reason" + +// NNG_OPT_MQTT_USER_PROPS is an array of user properties. These are +// send with the message, and used for application specific purposes. +// The properties are of the type nng_mqtt_user_props_t. +#define NNG_OPT_MQTT_USER_PROPS "user-props" + +// NNG_OPT_MQTT_PAYLOAD_FORMAT is the format of the payload for a message. +// It can be 0, indicating binary data, or 1, indicating UTF-8. +#define NNG_OPT_MQTT_PAYLOAD_FORMAT "mqtt-payload-format" + +// NNG_OPT_MQTT_CONTENT_TYPE is the mime type as UTF-8 for PUBLISH +// or Will messages. +#define NNG_OPT_MQTT_CONTENT_TYPE "content-type" + +// The following options are reserved for MQTT v5.0 request/reply support. +#define NNG_OPT_MQTT_RESPONSE_TOPIC "response-topic" +#define NNG_OPT_MQTT_CORRELATION_DATA "correlation-data" + +// NNG_OPT_MQTT_CLIENT_ID is the UTF-8 string corresponding to the client +// identification. We automatically generate an initial value fo this, +// which is the UUID. +// TODO: Should applications be permitted to change this? +#define NNG_OPT_MQTT_CLIENT_ID "client-id" // UTF-8 string + +#define NNG_OPT_MQTT_WILL_DELAY "will-delay" + +// NNG_OPT_MQTT_RECEIVE_MAX is used with QoS 1 or 2 (not implemented), +// and indicates the level of concurrent receives it is willing to +// process. (TODO: Implementation note: we will need to preallocate a complete +// state machine (aio, plus any state) for each value of this > 0. +// It's not clear whether this should be tunable.) This is read-only +// property on the socket, and records the value given from the server. +// It will be 64K if the server did not indicate a specific value. +#define NNG_OPT_MQTT_RECEIVE_MAX "mqtt-receive-max" + +// NNG_OPT_MQTT_SESSION_EXPIRES is an nng_duration. +// If set to NNG_DURATION_ZERO, then the session will expire automatically +// when the connection is closed. +// If it set to NNG_DURATION_INFINITE, the session never expires. +// Otherwise it will be a whole number of seconds indicating the session +// expiry interval. +#define NNG_OPT_MQTT_SESSION_EXPIRES "session-expires" + +#define NNG_OPT_MQTT_TOPIC_ALIAS_MAX "alias-max" +#define NNG_OPT_MQTT_TOPIC_ALIAS "topic-alias" +#define NNG_OPT_MQTT_MAX_QOS "max-qos" + +// NNG_TLS_xxx options can be set on the client as well. +// E.g. NNG_OPT_TLS_CA_CERT, etc. + +// TBD: Extended authentication. I think we should skip it -- everyone +// should just use TLS if they need security. + +// NNG_OPT_MQTT_KEEP_ALIVE is set on the client, and can be retrieved +// by the client. This is an nng_duration but will always be zero or +// a whole number of seconds less than 65536. If setting the value, +// it must be set before the client connects. When retrieved, the +// server's value will be returned (if it is different from what we +// requested.) If we reconnect, we will try again with the configured +// value rather than the value that we got from the server last time. +#define NNG_OPT_MQTT_KEEP_ALIVE "mqtt-keep-alive" + +// NNG_OPT_MQTT_MAX_PACKET_SIZE is the maximum packet size that can +// be used. It needs to be set before the client dials. +#define NNG_OPT_MQTT_MAX_PACKET_SIZE "mqtt-max-packet-size" +#define NNG_OPT_MQTT_USERNAME "username" +#define NNG_OPT_MQTT_PASSWORD "password" + +// Note that MQTT sockets can be connected to at most a single server. +// Creating the client does not connect it. +NNG_DECL int nng_mqtt_client_open(nng_socket **); + +// Note that there is a single implicit dialer for the client, +// and options may be set on the socket to configure dial options. +// Those options should be set before doing nng_dial(). + +// close done via nng_close(). + +// Question: session resumption. Should we resume sessions under the hood +// as part of reconnection, or do we want to expose this to the API user? +// My inclination is not to expose. + +// nng_dial or nng_dialer_create can be used, but this protocol only +// allows a single dialer to be created on the socket. + +// Subscriptions are normally run synchronously from the view of the +// caller. Because there is a round-trip message involved, we use +// a separate method instead of merely relying upon socket options. +// TODO: shared subscriptions. Subscription options (retain, QoS) +NNG_DECL int nng_mqtt_subscribe(nng_socket, const char *); +NNG_DECL int nng_mqtt_subscribe_aio(nng_socket, const char *, nng_aio *); +NNG_DECL int nng_mqtt_unsubscribe(nng_socket *, const char *); +NNG_DECL int nng_mqtt_unsubscribe_aio(nng_socket *, const char *, nng_aio *); +// as with other ctx based methods, we use the aio form exclusively +NNG_DECL int nng_mqtt_ctx_subscribe(nng_ctx *, const char *, nng_aio *, ...); + +// Message handling. Note that topic aliases are handled by the library +// automatically on behalf of the consumer. + +typedef enum { + nng_mqtt_msg_format_binary = 0, + nng_mqtt_msg_format_utf8 = 1, +} nng_mqtt_msg_format_t; + +// Message options. These are convenience wrappers around the above +// options. + +NNG_DECL int nng_mqtt_set_msg_expiry(nng_msg *, nng_duration); +NNG_DECL int nng_mqtt_get_msg_expiry(nng_msg *, nng_duration *); +NNG_DECL int nng_mqtt_set_msg_format(nng_msg *, nng_mqtt_msg_format_t); +NNG_DECL int nng_mqtt_get_msg_format(nng_msg *, nng_mqtt_msg_format_t *); +NNG_DECL int nng_mqtt_set_msg_topic(nng_msg *, const char *); +NNG_DECL int nng_mqtt_set_msg_qos(nng_msg *, int); +NNG_DECL int nng_mqtt_get_msg_topic(nng_msg *, const char **); +NNG_DECL int nng_mqtt_get_msg_qos(nng_msg *, int *); +NNG_DECL int nng_mqtt_set_content_type(nng_msg *, const char *); +NNG_DECL int nng_mqtt_get_content_type(nng_msg *, const char **); +NNG_DECL int nng_mqtt_get_reason(nng_msg *, const char **); + +// User property support. +typedef struct { + const char *up_name; + const char *up_value; +} nng_mqtt_user_prop_t; + +typedef struct { + int up_count; + nng_mqtt_user_prop_t *up_props; +} nng_mqtt_user_props_t; + +extern int nng_mqtt_user_props_alloc(nng_mqtt_user_props_t **); +extern int nng_mqtt_user_props_add( + nng_mqtt_user_props_t *, const char *, const char *); +extern void nng_mqtt_user_props_free(nng_mqtt_user_props_t *); + + +#ifdef __cplusplus +} +#endif + +#endif // NNG_MQTT_CLIENT_H From 398eab6da218984e4eb2bc555e9711e448d8e104 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Fri, 18 Jun 2021 16:09:48 -0700 Subject: [PATCH 061/180] Add message option manipulation. This is going to be needed for MQTT options, and it has to deal with multiple user options (which may be repeated), etc. --- src/core/message.c | 176 ++++++++++++++++++++++++++++++++++++++++++--- src/core/message.h | 44 ++++++++++++ 2 files changed, 211 insertions(+), 9 deletions(-) diff --git a/src/core/message.c b/src/core/message.c index 2ff2d6da2..18a10ea87 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -24,11 +24,22 @@ typedef struct { // Underlying message structure. struct nng_msg { - uint32_t m_header_buf[(NNI_MAX_MAX_TTL + 1)]; - size_t m_header_len; - nni_chunk m_body; - uint32_t m_pipe; // set on receive - nni_atomic_int m_refcnt; + uint32_t m_header_buf[(NNI_MAX_MAX_TTL + 1)]; + size_t m_header_len; + nni_chunk m_body; + uint32_t m_pipe; // set on receive + nni_atomic_int m_refcnt; + struct nni_msg_opt *m_opts; +}; + +// Message options. For protocol use only. +struct nni_msg_opt { + struct nni_msg_opt *mo_next; + const char * mo_name; + void * mo_value; + size_t mo_size; + void (*mo_free)(void *, size_t); // called by nni_msg_free + int (*mo_dup)(void **, void *, size_t); // called by nni_msg_dup }; #if 0 @@ -112,7 +123,7 @@ nni_chunk_grow(nni_chunk *ch, size_t newsz, size_t headwanted) if ((ch->ch_ptr >= ch->ch_buf) && (ch->ch_ptr != NULL) && (ch->ch_ptr < (ch->ch_buf + ch->ch_cap))) { - size_t headroom = (size_t)(ch->ch_ptr - ch->ch_buf); + size_t headroom = (size_t) (ch->ch_ptr - ch->ch_buf); if (headwanted < headroom) { headwanted = headroom; // Never shrink this. } @@ -268,7 +279,7 @@ nni_chunk_insert(nni_chunk *ch, const void *data, size_t len) if ((ch->ch_ptr >= ch->ch_buf) && (ch->ch_ptr < (ch->ch_buf + ch->ch_cap)) && - (len <= (size_t)(ch->ch_ptr - ch->ch_buf))) { + (len <= (size_t) (ch->ch_ptr - ch->ch_buf))) { // There is already enough room at the beginning. ch->ch_ptr -= len; } else if ((ch->ch_len + len) <= ch->ch_cap) { @@ -408,8 +419,11 @@ nni_msg_alloc(nni_msg **mp, size_t sz) int nni_msg_dup(nni_msg **dup, const nni_msg *src) { - nni_msg *m; - int rv; + nni_msg * m; + struct nni_msg_opt * os; + struct nni_msg_opt * od; + struct nni_msg_opt **opp; + int rv; if ((m = NNI_ALLOC_STRUCT(m)) == NULL) { return (NNG_ENOMEM); @@ -427,6 +441,32 @@ nni_msg_dup(nni_msg **dup, const nni_msg *src) nni_atomic_init(&m->m_refcnt); nni_atomic_set(&m->m_refcnt, 1); + // clone message options -- we use the supplied cloner function + // if one was provided. + opp = &m->m_opts; + for (os = src->m_opts; os != NULL; os = os->mo_next) { + if ((od = NNI_ALLOC_STRUCT(od)) != NULL) { + nni_msg_free(m); + return (NNG_ENOMEM); + } + if ((os->mo_dup) != NULL) { + rv = os->mo_dup( + &od->mo_value, os->mo_value, os->mo_size); + if (rv != 0) { + nni_msg_free(m); + return (rv); + } + od->mo_size = os->mo_size; + od->mo_free = os->mo_free; + od->mo_dup = os->mo_dup; + } else { + od->mo_value = os->mo_value; + od->mo_size = os->mo_size; + } + *opp = od; + opp = &od->mo_next; + } + *dup = m; return (0); } @@ -435,7 +475,16 @@ void nni_msg_free(nni_msg *m) { if ((m != NULL) && (nni_atomic_dec_nv(&m->m_refcnt) == 0)) { + struct nni_msg_opt *mo; nni_chunk_free(&m->m_body); + + while ((mo = m->m_opts) != NULL) { + m->m_opts = mo->mo_next; + if (mo->mo_free != NULL) { + mo->mo_free(mo->mo_value, mo->mo_size); + } + NNI_FREE_STRUCT(mo); + } NNI_FREE_STRUCT(m); } } @@ -634,3 +683,112 @@ nni_msg_get_pipe(const nni_msg *m) { return (m->m_pipe); } + +int +nni_msg_set_opt(nng_msg *m, const char *name, void *val, size_t size, + void (*free_func)(void *, size_t), + int (*dup_func)(void **, void *, size_t)) +{ + struct nni_msg_opt **opp; + struct nni_msg_opt * op; + + for (opp = &m->m_opts; (op = *opp) != NULL; opp = &op->mo_next) { + if (strcmp(op->mo_name, name) == 0) { + break; + } + } + if (op == NULL) { + if ((op = NNI_ALLOC_STRUCT(op)) == NULL) { + return (NNG_ENOMEM); + } + if ((op->mo_name = nni_strdup(name)) == NULL) { + NNI_FREE_STRUCT(op); + return (NNG_ENOMEM); + } + *opp = op; + } + op->mo_value = val; + op->mo_size = size; + op->mo_free = free_func; + op->mo_dup = dup_func; + return (0); +} + +int +nni_msg_add_opt(nng_msg *m, const char *name, void *val, size_t size, + void (*free_func)(void *, size_t), + int (*dup_func)(void **, void *, size_t)) +{ + struct nni_msg_opt **opp; + struct nni_msg_opt * op; + + opp = &m->m_opts; + while ((op = *opp) != NULL) { + opp = &op->mo_next; + } + if ((op = NNI_ALLOC_STRUCT(op)) == NULL) { + return (NNG_ENOMEM); + } + if ((op->mo_name = nni_strdup(name)) == NULL) { + NNI_FREE_STRUCT(op); + return (NNG_ENOMEM); + } + *opp = op; + op->mo_value = val; + op->mo_size = size; + op->mo_free = free_func; + op->mo_dup = dup_func; + return (0); +} + +// nni_msg_rem_opt removes *all* options with the given name. +int +nni_msg_rem_opt(nng_msg *m, const char *name) +{ + struct nni_msg_opt **opp; + struct nni_msg_opt * op; + int rv = NNG_ENOENT; + + opp = &m->m_opts; + while ((op = *opp) != NULL) { + if (strcmp(name, op->mo_name) == 0) { + if (op->mo_free != NULL) { + op->mo_free(op->mo_value, op->mo_size); + } + *opp = op->mo_next; + NNI_FREE_STRUCT(op); + rv = 0; + } else { + *opp = op->mo_next; + } + } + return (rv); +} + +void +nni_msg_walk_opt( + nng_msg *m, void *arg, bool (*fn)(void *, const char *, void *, size_t)) +{ + struct nni_msg_opt *op; + + for (op = m->m_opts; op != NULL; op = op->mo_next) { + if (!fn(arg, op->mo_name, op->mo_value, op->mo_size)) { + break; + } + } +} + +int +nni_msg_get_opt(nng_msg *m, const char *name, void **vp, size_t *szp) +{ + struct nni_msg_opt *op; + + for (op = m->m_opts; op != NULL; op = op->mo_next) { + if (strcmp(op->mo_name, name) == 0) { + *vp = op->mo_value; + *szp = op->mo_size; + return 0; + } + } + return (NNG_ENOENT); +} diff --git a/src/core/message.h b/src/core/message.h index 7e35ba752..71dedb462 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -62,4 +62,48 @@ extern bool nni_msg_shared(nni_msg *); // original message in that case (same semantics as realloc). extern nni_msg *nni_msg_pull_up(nni_msg *); +// Message option handling. Message options are intended for protocol +// specific use. For this reason, their API is not made public -- instead +// protocols should provide protocol specific functions for accessing them. +// Note that manipulation of message options must not be performed while the +// message is shared. If a copy is made with nni_msg_unique(), then the +// options will be cloned appropriately. + +// nni_msg_set_opt sets a given option. This will replace another option +// on the message set using the same name. The supplied functions are +// used when freeing the message, or when duplicating the message. +// If the value was created using nni_alloc, then nni_free and nni_mem_dup +// can be supplied. Note that the message must not be shared when this +// is called. +// +// NB: It is possible to use a non-NULL dup function, but have a NULL +// free function. This is appropriate if the content of the buffer is +// located in the message header, for example. +extern int nni_msg_set_opt(nng_msg *, const char *, void *, size_t, + void (*)(void *, size_t), int (*)(void **, void *, size_t)); + +// nni_msg_add_opt adds a given option, regardless of whether another +// instance of the option with the same name exists. In all other respects +// it behaves like nng_msg_set_opt. +extern int nni_msg_add_opt(nng_msg *, const char *, void *, size_t, + void (*)(void *, size_t), int (*)(void **, void *, size_t)); + +// nni_msg_rem_opt removes any (and all) instances of the named option +// from the message. It returns zero if any instances are removed, or +// NNG_ENOENT if no instance of the option was found on the message. +// The message must not be shared. +extern int nni_msg_rem_opt(nng_msg *, const char *); + +// nni_msg_get_opt is used to get the first instance of a message option. +// If the option cannot be found, then NNG_ENOENT is returned. +extern int nni_msg_get_opt(nng_msg *, const char *, void **, size_t *); + +// nni_msg_walk_opt is used to iterate over all options with a function. +// The called function should return true to keep iterating, or false +// to stop the iteration. The argument is supplied as the first parameter +// to the function. +extern void +nni_msg_walk_opt( + nng_msg *, void *, bool (*)(void *, const char *, void *, size_t)) + #endif // CORE_SOCKET_H From a712530d20f3caa964246a845ee79b77cca50b60 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 19 Jun 2021 07:59:48 -0700 Subject: [PATCH 062/180] Use protocol private data instead of options for messages. This is simpler and faster. --- src/core/message.c | 168 +++++++-------------------------------------- src/core/message.h | 63 +++++++---------- 2 files changed, 48 insertions(+), 183 deletions(-) diff --git a/src/core/message.c b/src/core/message.c index 18a10ea87..d96020884 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -24,22 +24,13 @@ typedef struct { // Underlying message structure. struct nng_msg { - uint32_t m_header_buf[(NNI_MAX_MAX_TTL + 1)]; - size_t m_header_len; - nni_chunk m_body; - uint32_t m_pipe; // set on receive - nni_atomic_int m_refcnt; - struct nni_msg_opt *m_opts; -}; - -// Message options. For protocol use only. -struct nni_msg_opt { - struct nni_msg_opt *mo_next; - const char * mo_name; - void * mo_value; - size_t mo_size; - void (*mo_free)(void *, size_t); // called by nni_msg_free - int (*mo_dup)(void **, void *, size_t); // called by nni_msg_dup + uint32_t m_header_buf[(NNI_MAX_MAX_TTL + 1)]; + size_t m_header_len; + nni_chunk m_body; + nni_proto_msg_ops *m_proto_ops; + void * m_proto_data; + nni_atomic_int m_refcnt; + uint32_t m_pipe; // set on receive }; #if 0 @@ -441,30 +432,15 @@ nni_msg_dup(nni_msg **dup, const nni_msg *src) nni_atomic_init(&m->m_refcnt); nni_atomic_set(&m->m_refcnt, 1); - // clone message options -- we use the supplied cloner function - // if one was provided. - opp = &m->m_opts; - for (os = src->m_opts; os != NULL; os = os->mo_next) { - if ((od = NNI_ALLOC_STRUCT(od)) != NULL) { + // clone protocol data if a method was supplied. + if (src->m_proto_ops != NULL && src->m_proto_ops->msg_free != NULL) { + rv = src->m_proto_ops->msg_dup( + &m->m_proto_data, src->m_proto_data); + if (rv != 0) { nni_msg_free(m); return (NNG_ENOMEM); } - if ((os->mo_dup) != NULL) { - rv = os->mo_dup( - &od->mo_value, os->mo_value, os->mo_size); - if (rv != 0) { - nni_msg_free(m); - return (rv); - } - od->mo_size = os->mo_size; - od->mo_free = os->mo_free; - od->mo_dup = os->mo_dup; - } else { - od->mo_value = os->mo_value; - od->mo_size = os->mo_size; - } - *opp = od; - opp = &od->mo_next; + m->m_proto_ops = src->m_proto_ops; } *dup = m; @@ -478,12 +454,9 @@ nni_msg_free(nni_msg *m) struct nni_msg_opt *mo; nni_chunk_free(&m->m_body); - while ((mo = m->m_opts) != NULL) { - m->m_opts = mo->mo_next; - if (mo->mo_free != NULL) { - mo->mo_free(mo->mo_value, mo->mo_size); - } - NNI_FREE_STRUCT(mo); + if (m->m_proto_ops != NULL && + m->m_proto_ops->msg_free != NULL) { + m->m_proto_ops->msg_free(m->m_proto_data); } NNI_FREE_STRUCT(m); } @@ -684,111 +657,18 @@ nni_msg_get_pipe(const nni_msg *m) return (m->m_pipe); } -int -nni_msg_set_opt(nng_msg *m, const char *name, void *val, size_t size, - void (*free_func)(void *, size_t), - int (*dup_func)(void **, void *, size_t)) -{ - struct nni_msg_opt **opp; - struct nni_msg_opt * op; - - for (opp = &m->m_opts; (op = *opp) != NULL; opp = &op->mo_next) { - if (strcmp(op->mo_name, name) == 0) { - break; - } - } - if (op == NULL) { - if ((op = NNI_ALLOC_STRUCT(op)) == NULL) { - return (NNG_ENOMEM); - } - if ((op->mo_name = nni_strdup(name)) == NULL) { - NNI_FREE_STRUCT(op); - return (NNG_ENOMEM); - } - *opp = op; - } - op->mo_value = val; - op->mo_size = size; - op->mo_free = free_func; - op->mo_dup = dup_func; - return (0); -} - -int -nni_msg_add_opt(nng_msg *m, const char *name, void *val, size_t size, - void (*free_func)(void *, size_t), - int (*dup_func)(void **, void *, size_t)) -{ - struct nni_msg_opt **opp; - struct nni_msg_opt * op; - - opp = &m->m_opts; - while ((op = *opp) != NULL) { - opp = &op->mo_next; - } - if ((op = NNI_ALLOC_STRUCT(op)) == NULL) { - return (NNG_ENOMEM); - } - if ((op->mo_name = nni_strdup(name)) == NULL) { - NNI_FREE_STRUCT(op); - return (NNG_ENOMEM); - } - *opp = op; - op->mo_value = val; - op->mo_size = size; - op->mo_free = free_func; - op->mo_dup = dup_func; - return (0); -} - -// nni_msg_rem_opt removes *all* options with the given name. -int -nni_msg_rem_opt(nng_msg *m, const char *name) -{ - struct nni_msg_opt **opp; - struct nni_msg_opt * op; - int rv = NNG_ENOENT; - - opp = &m->m_opts; - while ((op = *opp) != NULL) { - if (strcmp(name, op->mo_name) == 0) { - if (op->mo_free != NULL) { - op->mo_free(op->mo_value, op->mo_size); - } - *opp = op->mo_next; - NNI_FREE_STRUCT(op); - rv = 0; - } else { - *opp = op->mo_next; - } - } - return (rv); -} - void -nni_msg_walk_opt( - nng_msg *m, void *arg, bool (*fn)(void *, const char *, void *, size_t)) +nni_msg_set_proto_data(nng_msg *m, nni_proto_msg_ops *ops, void *data) { - struct nni_msg_opt *op; - - for (op = m->m_opts; op != NULL; op = op->mo_next) { - if (!fn(arg, op->mo_name, op->mo_value, op->mo_size)) { - break; - } + if (m->m_proto_ops != NULL && m->m_proto_ops->msg_free != NULL) { + m->m_proto_ops->msg_free(m->m_proto_data); } + m->m_proto_ops = ops; + m->m_proto_data = data; } -int -nni_msg_get_opt(nng_msg *m, const char *name, void **vp, size_t *szp) +void * +nni_msg_get_proto_data(nng_msg *m) { - struct nni_msg_opt *op; - - for (op = m->m_opts; op != NULL; op = op->mo_next) { - if (strcmp(op->mo_name, name) == 0) { - *vp = op->mo_value; - *szp = op->mo_size; - return 0; - } - } - return (NNG_ENOENT); + return (m->m_proto_data); } diff --git a/src/core/message.h b/src/core/message.h index 71dedb462..d8999dd5d 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -62,48 +62,33 @@ extern bool nni_msg_shared(nni_msg *); // original message in that case (same semantics as realloc). extern nni_msg *nni_msg_pull_up(nni_msg *); -// Message option handling. Message options are intended for protocol -// specific use. For this reason, their API is not made public -- instead -// protocols should provide protocol specific functions for accessing them. -// Note that manipulation of message options must not be performed while the -// message is shared. If a copy is made with nni_msg_unique(), then the -// options will be cloned appropriately. +// Message protocol private data. This is specific for protocol use, +// and not exposed to library users. -// nni_msg_set_opt sets a given option. This will replace another option -// on the message set using the same name. The supplied functions are -// used when freeing the message, or when duplicating the message. -// If the value was created using nni_alloc, then nni_free and nni_mem_dup -// can be supplied. Note that the message must not be shared when this -// is called. -// -// NB: It is possible to use a non-NULL dup function, but have a NULL -// free function. This is appropriate if the content of the buffer is -// located in the message header, for example. -extern int nni_msg_set_opt(nng_msg *, const char *, void *, size_t, - void (*)(void *, size_t), int (*)(void **, void *, size_t)); - -// nni_msg_add_opt adds a given option, regardless of whether another -// instance of the option with the same name exists. In all other respects -// it behaves like nng_msg_set_opt. -extern int nni_msg_add_opt(nng_msg *, const char *, void *, size_t, - void (*)(void *, size_t), int (*)(void **, void *, size_t)); +// nni_proto_msg_ops is used to handle the protocol private data +// associated with a message. +typedef struct nni_proto_msg_ops { + // This is used to free protocol specific data previously + // attached to the message, and is called when the message + // itself is freed, or when protocol private is replaced. + int (*msg_free)(void *); -// nni_msg_rem_opt removes any (and all) instances of the named option -// from the message. It returns zero if any instances are removed, or -// NNG_ENOENT if no instance of the option was found on the message. -// The message must not be shared. -extern int nni_msg_rem_opt(nng_msg *, const char *); + // Duplicate protocol private data when duplicating a message, + // such as by nni_msg_dup() or calling nni_msg_unique() on a + // shared message. + int (*msg_dup)(void **, const void *); +} nni_proto_msg_ops; -// nni_msg_get_opt is used to get the first instance of a message option. -// If the option cannot be found, then NNG_ENOENT is returned. -extern int nni_msg_get_opt(nng_msg *, const char *, void **, size_t *); +// nni_msg_set_proto_data is used to set protocol private data, and +// callbacks for freeing and duplicating said data, on the message. +// If other protocol private data exists on the message, it will be freed. +// NULL can be used for the ops and the pointer to clear any previously +// set data. The message must not be shared when this is called. +extern void nni_msg_set_proto_data(nng_msg *, nni_proto_msg_ops *, void *); -// nni_msg_walk_opt is used to iterate over all options with a function. -// The called function should return true to keep iterating, or false -// to stop the iteration. The argument is supplied as the first parameter -// to the function. -extern void -nni_msg_walk_opt( - nng_msg *, void *, bool (*)(void *, const char *, void *, size_t)) +// nni_msg_get_proto_data returns the data previously set on the message. +// Note that the protocol is responsible for ensuring that the data on +// the message is set by it alone. +extern void *nni_msg_get_proto_data(nng_msg *); #endif // CORE_SOCKET_H From 680c1290611aa0fd413378fccc4bf2e6c63ab078 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 15 Oct 2021 16:40:21 +0800 Subject: [PATCH 063/180] * FIX [demo] fix camkefile of reqrep demo --- demo/reqrep/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demo/reqrep/CMakeLists.txt b/demo/reqrep/CMakeLists.txt index c7a258b0c..ba4f915ac 100644 --- a/demo/reqrep/CMakeLists.txt +++ b/demo/reqrep/CMakeLists.txt @@ -19,4 +19,5 @@ find_package(Threads) # find_package(zerotiercore) add_executable(reqrep reqrep.c) -target_link_libraries(reqrep nng::nng) +target_link_libraries(reqrep nng) +target_link_libraries(reqrep ${CMAKE_THREAD_LIBS_INIT}) From 287e6cd2139a9e4f54cda0ac38bca93ba6353b7d Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 15 Oct 2021 19:24:38 +0800 Subject: [PATCH 064/180] * NEW [nng/mqtt] add independent transport layer of mqtt --- include/nng/transport/tcp/mqtt_tcp.h | 30 + src/core/stream.c | 3 +- src/sp/protocol/CMakeLists.txt | 1 + src/sp/protocol/mqtt/CMakeLists.txt | 12 + src/sp/transport.c | 9 +- src/sp/transport/CMakeLists.txt | 1 + src/sp/transport/mqtt/CMakeLists.txt | 16 + src/sp/transport/mqtt/mqtt_tcp.c | 1267 ++++++++++++++++++++++++++ src/sp/transport/tcp/CMakeLists.txt | 2 +- 9 files changed, 1337 insertions(+), 4 deletions(-) create mode 100644 include/nng/transport/tcp/mqtt_tcp.h create mode 100644 src/sp/protocol/mqtt/CMakeLists.txt create mode 100644 src/sp/transport/mqtt/CMakeLists.txt create mode 100644 src/sp/transport/mqtt/mqtt_tcp.c diff --git a/include/nng/transport/tcp/mqtt_tcp.h b/include/nng/transport/tcp/mqtt_tcp.h new file mode 100644 index 000000000..31a3c61a0 --- /dev/null +++ b/include/nng/transport/tcp/mqtt_tcp.h @@ -0,0 +1,30 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2017 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef NNG_TRANSPORT_MQTT_TCP_TCP_H +#define NNG_TRANSPORT_MQTT_TCP_TCP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// TCP transport. This is used for communication over TCP/IP. + +#ifndef NNG_ELIDE_DEPRECATED +NNG_DECL int nng_mqtt_tcp_register(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // NNG_TRANSPORT_MQTT_TCP_TCP_H diff --git a/src/core/stream.c b/src/core/stream.c index 418bfb159..b699e526b 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -163,11 +163,10 @@ int nng_stream_dialer_alloc_url(nng_stream_dialer **dp, const nng_url *url) { int rv; - if ((rv = nni_init()) != 0) { return (rv); } - +// check this part for (int i = 0; stream_drivers[i].scheme != NULL; i++) { if (strcmp(stream_drivers[i].scheme, url->u_scheme) == 0) { return (stream_drivers[i].dialer_alloc(dp, url)); diff --git a/src/sp/protocol/CMakeLists.txt b/src/sp/protocol/CMakeLists.txt index fd4805237..4f34c2436 100644 --- a/src/sp/protocol/CMakeLists.txt +++ b/src/sp/protocol/CMakeLists.txt @@ -16,5 +16,6 @@ add_subdirectory(pair1) add_subdirectory(pipeline0) add_subdirectory(pubsub0) add_subdirectory(reqrep0) +add_subdirectory(mqtt) add_subdirectory(survey0) diff --git a/src/sp/protocol/mqtt/CMakeLists.txt b/src/sp/protocol/mqtt/CMakeLists.txt new file mode 100644 index 000000000..7c41c40e6 --- /dev/null +++ b/src/sp/protocol/mqtt/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright 2020 Staysail Systems, Inc. +# Copyright 2018 Capitar IT Group BV +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. +# + +# Req/Rep protocol +nng_directory(mqtt) diff --git a/src/sp/transport.c b/src/sp/transport.c index ed27ebeb1..0ae8261f6 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -36,6 +36,7 @@ nni_sp_tran_find(nni_url *url) nni_rwlock_rdlock(&sp_tran_lk); NNI_LIST_FOREACH (&sp_tran_list, t) { + printf("tran %s %s\n", url->u_scheme, t->tran_scheme); if (strcmp(url->u_scheme, t->tran_scheme) == 0) { nni_rwlock_unlock(&sp_tran_lk); return (t); @@ -57,6 +58,9 @@ extern void nni_sp_ipc_register(void); #ifdef NNG_TRANSPORT_TCP extern void nni_sp_tcp_register(void); #endif +#ifdef NNG_TRANSPORT_TCP +extern void nni_mqtt_tcp_register(); +#endif #ifdef NNG_TRANSPORT_TLS extern void nni_sp_tls_register(void); #endif @@ -85,7 +89,10 @@ nni_sp_tran_sys_init(void) #ifdef NNG_TRANSPORT_TCP nni_sp_tcp_register(); #endif -#ifdef NNG_TRANSPORT_TLS +#ifdef NNG_TRANSPORT_TCP + nni_mqtt_tcp_register(); +#endif +#ifdef NNG_TRANSPORT_MQTT_TCP nni_sp_tls_register(); #endif #ifdef NNG_TRANSPORT_WS diff --git a/src/sp/transport/CMakeLists.txt b/src/sp/transport/CMakeLists.txt index add8a9c95..fdc04e865 100644 --- a/src/sp/transport/CMakeLists.txt +++ b/src/sp/transport/CMakeLists.txt @@ -15,5 +15,6 @@ add_subdirectory(ipc) add_subdirectory(tcp) add_subdirectory(tls) add_subdirectory(ws) +add_subdirectory(mqtt) add_subdirectory(zerotier) diff --git a/src/sp/transport/mqtt/CMakeLists.txt b/src/sp/transport/mqtt/CMakeLists.txt new file mode 100644 index 000000000..4fcf33e83 --- /dev/null +++ b/src/sp/transport/mqtt/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright 2020 Staysail Systems, Inc. +# Copyright 2018 Capitar IT Group BV +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. +# + +# TCP protocol +nng_directory(mqtt) + +nng_sources_if(NNG_TRANSPORT_TCP mqtt_tcp.c) +nng_headers_if(NNG_TRANSPORT_TCP nng/transport/tcp/mqtt_tcp.h) +nng_defines_if(NNG_TRANSPORT_MQTT_TCP NNG_TRANSPORT_MQTT_TCP) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c new file mode 100644 index 000000000..7a940a6c4 --- /dev/null +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -0,0 +1,1267 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// Copyright 2019 Devolutions +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include +#include + +#include "core/nng_impl.h" + +// TCP transport. Platform specific TCP operations must be +// supplied as well. + +typedef struct tcptran_pipe tcptran_pipe; +typedef struct tcptran_ep tcptran_ep; + +// tcp_pipe is one end of a TCP connection. +struct tcptran_pipe { + nng_stream * conn; + nni_pipe * npipe; + uint16_t peer; + uint16_t proto; + size_t rcvmax; + bool closed; + nni_list_node node; + tcptran_ep * ep; + nni_atomic_flag reaped; + nni_reap_node reap; + uint8_t txlen[sizeof(uint64_t)]; + uint8_t rxlen[sizeof(uint64_t)]; + size_t gottxhead; + size_t gotrxhead; + size_t wanttxhead; + size_t wantrxhead; + nni_list recvq; + nni_list sendq; + nni_aio * txaio; + nni_aio * rxaio; + nni_aio * negoaio; + nni_msg * rxmsg; + nni_mtx mtx; +}; + +struct tcptran_ep { + nni_mtx mtx; + uint16_t proto; + size_t rcvmax; + bool fini; + bool started; + bool closed; + nng_url * url; + const char * host; // for dialers + nng_sockaddr src; + int refcnt; // active pipes + nni_aio * useraio; + nni_aio * connaio; + nni_aio * timeaio; + nni_list busypipes; // busy pipes -- ones passed to socket + nni_list waitpipes; // pipes waiting to match to socket + nni_list negopipes; // pipes busy negotiating + nni_reap_node reap; + nng_stream_dialer * dialer; + nng_stream_listener *listener; + +#ifdef NNG_ENABLE_STATS + nni_stat_item st_rcv_max; +#endif +}; + +static void tcptran_pipe_send_start(tcptran_pipe *); +static void tcptran_pipe_recv_start(tcptran_pipe *); +static void tcptran_pipe_send_cb(void *); +static void tcptran_pipe_recv_cb(void *); +static void tcptran_pipe_nego_cb(void *); +static void tcptran_ep_fini(void *); +static void tcptran_pipe_fini(void *); + +static nni_reap_list tcptran_ep_reap_list = { + .rl_offset = offsetof(tcptran_ep, reap), + .rl_func = tcptran_ep_fini, +}; + +static nni_reap_list tcptran_pipe_reap_list = { + .rl_offset = offsetof(tcptran_pipe, reap), + .rl_func = tcptran_pipe_fini, +}; + +static void +tcptran_init(void) +{ +} + +static void +tcptran_fini(void) +{ +} + +static void +tcptran_pipe_close(void *arg) +{ + tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + p->closed = true; + nni_mtx_unlock(&p->mtx); + + nni_aio_close(p->rxaio); + nni_aio_close(p->txaio); + nni_aio_close(p->negoaio); + + nng_stream_close(p->conn); +} + +static void +tcptran_pipe_stop(void *arg) +{ + tcptran_pipe *p = arg; + + nni_aio_stop(p->rxaio); + nni_aio_stop(p->txaio); + nni_aio_stop(p->negoaio); +} + +static int +tcptran_pipe_init(void *arg, nni_pipe *npipe) +{ + tcptran_pipe *p = arg; + p->npipe = npipe; + + return (0); +} + +static void +tcptran_pipe_fini(void *arg) +{ + tcptran_pipe *p = arg; + tcptran_ep * ep; + + tcptran_pipe_stop(p); + if ((ep = p->ep) != NULL) { + nni_mtx_lock(&ep->mtx); + nni_list_node_remove(&p->node); + ep->refcnt--; + if (ep->fini && (ep->refcnt == 0)) { + nni_reap(&tcptran_ep_reap_list, ep); + } + nni_mtx_unlock(&ep->mtx); + } + + nni_aio_free(p->rxaio); + nni_aio_free(p->txaio); + nni_aio_free(p->negoaio); + nng_stream_free(p->conn); + nni_msg_free(p->rxmsg); + nni_mtx_fini(&p->mtx); + NNI_FREE_STRUCT(p); +} + +static void +tcptran_pipe_reap(tcptran_pipe *p) +{ + if (!nni_atomic_flag_test_and_set(&p->reaped)) { + if (p->conn != NULL) { + nng_stream_close(p->conn); + } + nni_reap(&tcptran_pipe_reap_list, p); + } +} + +static int +tcptran_pipe_alloc(tcptran_pipe **pipep) +{ + tcptran_pipe *p; + int rv; + + if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&p->mtx); + if (((rv = nni_aio_alloc(&p->txaio, tcptran_pipe_send_cb, p)) != 0) || + ((rv = nni_aio_alloc(&p->rxaio, tcptran_pipe_recv_cb, p)) != 0) || + ((rv = nni_aio_alloc(&p->negoaio, tcptran_pipe_nego_cb, p)) != + 0)) { + tcptran_pipe_fini(p); + return (rv); + } + nni_aio_list_init(&p->recvq); + nni_aio_list_init(&p->sendq); + nni_atomic_flag_reset(&p->reaped); + + *pipep = p; + + return (0); +} + +static void +tcptran_ep_match(tcptran_ep *ep) +{ + nni_aio * aio; + tcptran_pipe *p; + + if (((aio = ep->useraio) == NULL) || + ((p = nni_list_first(&ep->waitpipes)) == NULL)) { + return; + } + nni_list_remove(&ep->waitpipes, p); + nni_list_append(&ep->busypipes, p); + ep->useraio = NULL; + p->rcvmax = ep->rcvmax; + nni_aio_set_output(aio, 0, p); + nni_aio_finish(aio, 0, 0); +} + +static void +tcptran_pipe_nego_cb(void *arg) +{ + tcptran_pipe *p = arg; + tcptran_ep * ep = p->ep; + nni_aio * aio = p->negoaio; + nni_aio * uaio; + int rv; + + nni_mtx_lock(&ep->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + // We start transmitting before we receive. + if (p->gottxhead < p->wanttxhead) { + p->gottxhead += nni_aio_count(aio); + } else if (p->gotrxhead < p->wantrxhead) { + p->gotrxhead += nni_aio_count(aio); + } + + if (p->gottxhead < p->wanttxhead) { + nni_iov iov; + iov.iov_len = p->wanttxhead - p->gottxhead; + iov.iov_buf = &p->txlen[p->gottxhead]; + // send it down... + nni_aio_set_iov(aio, 1, &iov); + nng_stream_send(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + if (p->gotrxhead < p->wantrxhead) { + nni_iov iov; + iov.iov_len = p->wantrxhead - p->gotrxhead; + iov.iov_buf = &p->rxlen[p->gotrxhead]; + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + // We have both sent and received the headers. Lets check the + // receive side header. + if ((p->rxlen[0] != 0) || (p->rxlen[1] != 'S') || + (p->rxlen[2] != 'P') || (p->rxlen[3] != 0) || (p->rxlen[6] != 0) || + (p->rxlen[7] != 0)) { + rv = NNG_EPROTO; + goto error; + } + + NNI_GET16(&p->rxlen[4], p->peer); + + // We are all ready now. We put this in the wait list, and + // then try to run the matcher. + nni_list_remove(&ep->negopipes, p); + nni_list_append(&ep->waitpipes, p); + + tcptran_ep_match(ep); + nni_mtx_unlock(&ep->mtx); + + return; + +error: + nng_stream_close(p->conn); + + if ((uaio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(uaio, rv); + } + nni_mtx_unlock(&ep->mtx); + tcptran_pipe_reap(p); +} + +static void +tcptran_pipe_send_cb(void *arg) +{ + tcptran_pipe *p = arg; + int rv; + nni_aio * aio; + size_t n; + nni_msg * msg; + nni_aio * txaio = p->txaio; + + nni_mtx_lock(&p->mtx); + aio = nni_list_first(&p->sendq); + + if ((rv = nni_aio_result(txaio)) != 0) { + nni_pipe_bump_error(p->npipe, rv); + // Intentionally we do not queue up another transfer. + // There's an excellent chance that the pipe is no longer + // usable, with a partial transfer. + // The protocol should see this error, and close the + // pipe itself, we hope. + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + + n = nni_aio_count(txaio); + nni_aio_iov_advance(txaio, n); + if (nni_aio_iov_count(txaio) > 0) { + nng_stream_send(p->conn, txaio); + nni_mtx_unlock(&p->mtx); + return; + } + + nni_aio_list_remove(aio); + tcptran_pipe_send_start(p); + + msg = nni_aio_get_msg(aio); + n = nni_msg_len(msg); + nni_pipe_bump_tx(p->npipe, n); + nni_mtx_unlock(&p->mtx); + + nni_aio_set_msg(aio, NULL); + nni_msg_free(msg); + nni_aio_finish_sync(aio, 0, n); +} + +static void +tcptran_pipe_recv_cb(void *arg) +{ + tcptran_pipe *p = arg; + nni_aio * aio; + int rv; + size_t n; + nni_msg * msg; + nni_aio * rxaio = p->rxaio; + + nni_mtx_lock(&p->mtx); + aio = nni_list_first(&p->recvq); + + if ((rv = nni_aio_result(rxaio)) != 0) { + goto recv_error; + } + + n = nni_aio_count(rxaio); + nni_aio_iov_advance(rxaio, n); + if (nni_aio_iov_count(rxaio) > 0) { + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + + // If we don't have a message yet, we were reading the TCP message + // header, which is just the length. This tells us the size of the + // message to allocate and how much more to expect. + if (p->rxmsg == NULL) { + uint64_t len; + // We should have gotten a message header. + NNI_GET64(p->rxlen, len); + + // Make sure the message payload is not too big. If it is + // the caller will shut down the pipe. + if ((len > p->rcvmax) && (p->rcvmax > 0)) { + rv = NNG_EMSGSIZE; + goto recv_error; + } + + if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + goto recv_error; + } + + // Submit the rest of the data for a read -- we want to + // read the entire message now. + if (len != 0) { + nni_iov iov; + iov.iov_buf = nni_msg_body(p->rxmsg); + iov.iov_len = (size_t) len; + + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + } + + // We read a message completely. Let the user know the good news. + nni_aio_list_remove(aio); + msg = p->rxmsg; + p->rxmsg = NULL; + n = nni_msg_len(msg); + + nni_pipe_bump_rx(p->npipe, n); + tcptran_pipe_recv_start(p); + nni_mtx_unlock(&p->mtx); + + nni_aio_set_msg(aio, msg); + nni_aio_finish_sync(aio, 0, n); + return; + +recv_error: + nni_aio_list_remove(aio); + msg = p->rxmsg; + p->rxmsg = NULL; + nni_pipe_bump_error(p->npipe, rv); + // Intentionally, we do not queue up another receive. + // The protocol should notice this error and close the pipe. + nni_mtx_unlock(&p->mtx); + + nni_msg_free(msg); + nni_aio_finish_error(aio, rv); +} + +static void +tcptran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) +{ + tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (!nni_aio_list_active(aio)) { + nni_mtx_unlock(&p->mtx); + return; + } + // If this is being sent, then cancel the pending transfer. + // The callback on the txaio will cause the user aio to + // be canceled too. + if (nni_list_first(&p->sendq) == aio) { + nni_aio_abort(p->txaio, rv); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + + nni_aio_finish_error(aio, rv); +} + +static void +tcptran_pipe_send_start(tcptran_pipe *p) +{ + nni_aio *aio; + nni_aio *txaio; + nni_msg *msg; + int niov; + nni_iov iov[3]; + uint64_t len; + + if (p->closed) { + while ((aio = nni_list_first(&p->sendq)) != NULL) { + nni_list_remove(&p->sendq, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + return; + } + + if ((aio = nni_list_first(&p->sendq)) == NULL) { + return; + } + + // This runs to send the message. + msg = nni_aio_get_msg(aio); + len = nni_msg_len(msg) + nni_msg_header_len(msg); + + NNI_PUT64(p->txlen, len); + + txaio = p->txaio; + niov = 0; + iov[0].iov_buf = p->txlen; + iov[0].iov_len = sizeof(p->txlen); + niov++; + if (nni_msg_header_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_header(msg); + iov[niov].iov_len = nni_msg_header_len(msg); + niov++; + } + if (nni_msg_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_body(msg); + iov[niov].iov_len = nni_msg_len(msg); + niov++; + } + nni_aio_set_iov(txaio, niov, iov); + nng_stream_send(p->conn, txaio); +} + +static void +tcptran_pipe_send(void *arg, nni_aio *aio) +{ + tcptran_pipe *p = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, tcptran_pipe_send_cancel, p)) != 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + nni_list_append(&p->sendq, aio); + if (nni_list_first(&p->sendq) == aio) { + tcptran_pipe_send_start(p); + } + nni_mtx_unlock(&p->mtx); +} + +static void +tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) +{ + tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (!nni_aio_list_active(aio)) { + nni_mtx_unlock(&p->mtx); + return; + } + // If receive in progress, then cancel the pending transfer. + // The callback on the rxaio will cause the user aio to + // be canceled too. + if (nni_list_first(&p->recvq) == aio) { + nni_aio_abort(p->rxaio, rv); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); +} + +static void +tcptran_pipe_recv_start(tcptran_pipe *p) +{ + nni_aio *rxaio; + nni_iov iov; + NNI_ASSERT(p->rxmsg == NULL); + + if (p->closed) { + nni_aio *aio; + while ((aio = nni_list_first(&p->recvq)) != NULL) { + nni_list_remove(&p->recvq, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + return; + } + if (nni_list_empty(&p->recvq)) { + return; + } + + // Schedule a read of the header. + rxaio = p->rxaio; + iov.iov_buf = p->rxlen; + iov.iov_len = sizeof(p->rxlen); + nni_aio_set_iov(rxaio, 1, &iov); + + nng_stream_recv(p->conn, rxaio); +} + +static void +tcptran_pipe_recv(void *arg, nni_aio *aio) +{ + tcptran_pipe *p = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, tcptran_pipe_recv_cancel, p)) != 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + + nni_list_append(&p->recvq, aio); + if (nni_list_first(&p->recvq) == aio) { + tcptran_pipe_recv_start(p); + } + nni_mtx_unlock(&p->mtx); +} + +static uint16_t +tcptran_pipe_peer(void *arg) +{ + tcptran_pipe *p = arg; + + return (p->peer); +} + +static int +tcptran_pipe_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + tcptran_pipe *p = arg; + return (nni_stream_get(p->conn, name, buf, szp, t)); +} + +static void +tcptran_pipe_start(tcptran_pipe *p, nng_stream *conn, tcptran_ep *ep) +{ + nni_iov iov; + + ep->refcnt++; + + p->conn = conn; + p->ep = ep; + p->proto = ep->proto; + + p->txlen[0] = 0; + p->txlen[1] = 'S'; + p->txlen[2] = 'P'; + p->txlen[3] = 0; + NNI_PUT16(&p->txlen[4], p->proto); + NNI_PUT16(&p->txlen[6], 0); + + p->gotrxhead = 0; + p->gottxhead = 0; + p->wantrxhead = 8; + p->wanttxhead = 8; + iov.iov_len = 8; + iov.iov_buf = &p->txlen[0]; + nni_aio_set_iov(p->negoaio, 1, &iov); + nni_list_append(&ep->negopipes, p); + + nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate + nng_stream_send(p->conn, p->negoaio); +} + +static void +tcptran_ep_fini(void *arg) +{ + tcptran_ep *ep = arg; + + nni_mtx_lock(&ep->mtx); + ep->fini = true; + if (ep->refcnt != 0) { + nni_mtx_unlock(&ep->mtx); + return; + } + nni_mtx_unlock(&ep->mtx); + nni_aio_stop(ep->timeaio); + nni_aio_stop(ep->connaio); + nng_stream_dialer_free(ep->dialer); + nng_stream_listener_free(ep->listener); + nni_aio_free(ep->timeaio); + nni_aio_free(ep->connaio); + + nni_mtx_fini(&ep->mtx); + NNI_FREE_STRUCT(ep); +} + +static void +tcptran_ep_close(void *arg) +{ + tcptran_ep * ep = arg; + tcptran_pipe *p; + + nni_mtx_lock(&ep->mtx); + + ep->closed = true; + nni_aio_close(ep->timeaio); + if (ep->dialer != NULL) { + nng_stream_dialer_close(ep->dialer); + } + if (ep->listener != NULL) { + nng_stream_listener_close(ep->listener); + } + NNI_LIST_FOREACH (&ep->negopipes, p) { + tcptran_pipe_close(p); + } + NNI_LIST_FOREACH (&ep->waitpipes, p) { + tcptran_pipe_close(p); + } + NNI_LIST_FOREACH (&ep->busypipes, p) { + tcptran_pipe_close(p); + } + if (ep->useraio != NULL) { + nni_aio_finish_error(ep->useraio, NNG_ECLOSED); + ep->useraio = NULL; + } + + nni_mtx_unlock(&ep->mtx); +} + +// This parses off the optional source address that this transport uses. +// The special handling of this URL format is quite honestly an historical +// mistake, which we would remove if we could. +static int +tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl) +{ + int af; + char * semi; + char * src; + size_t len; + int rv; + nni_aio *aio; + + // We modify the URL. This relies on the fact that the underlying + // transport does not free this, so we can just use references. + + url->u_scheme = surl->u_scheme; + url->u_port = surl->u_port; + url->u_hostname = surl->u_hostname; + + if ((semi = strchr(url->u_hostname, ';')) == NULL) { + memset(sa, 0, sizeof(*sa)); + return (0); + } + + len = (size_t) (semi - url->u_hostname); + url->u_hostname = semi + 1; + + if (strcmp(surl->u_scheme, "tcp") == 0) { + af = NNG_AF_UNSPEC; + } else if (strcmp(surl->u_scheme, "tcp4") == 0) { + af = NNG_AF_INET; + } else if (strcmp(surl->u_scheme, "tcp6") == 0) { + af = NNG_AF_INET6; + } else { + return (NNG_EADDRINVAL); + } + + if ((src = nni_alloc(len + 1)) == NULL) { + return (NNG_ENOMEM); + } + memcpy(src, surl->u_hostname, len); + src[len] = '\0'; + + if ((rv = nni_aio_alloc(&aio, NULL, NULL)) != 0) { + nni_free(src, len + 1); + return (rv); + } + + nni_resolv_ip(src, "0", af, true, sa, aio); + nni_aio_wait(aio); + rv = nni_aio_result(aio); + nni_aio_free(aio); + nni_free(src, len + 1); + return (rv); +} + +static void +tcptran_timer_cb(void *arg) +{ + tcptran_ep *ep = arg; + if (nni_aio_result(ep->timeaio) == 0) { + nng_stream_listener_accept(ep->listener, ep->connaio); + } +} + +static void +tcptran_accept_cb(void *arg) +{ + tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + tcptran_pipe *p; + int rv; + nng_stream * conn; + + nni_mtx_lock(&ep->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + conn = nni_aio_get_output(aio, 0); + if ((rv = tcptran_pipe_alloc(&p)) != 0) { + nng_stream_free(conn); + goto error; + } + + if (ep->closed) { + tcptran_pipe_fini(p); + nng_stream_free(conn); + rv = NNG_ECLOSED; + goto error; + } + tcptran_pipe_start(p, conn, ep); + nng_stream_listener_accept(ep->listener, ep->connaio); + nni_mtx_unlock(&ep->mtx); + return; + +error: + // When an error here occurs, let's send a notice up to the consumer. + // That way it can be reported properly. + if ((aio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + switch (rv) { + + case NNG_ENOMEM: + case NNG_ENOFILES: + nng_sleep_aio(10, ep->timeaio); + break; + + default: + if (!ep->closed) { + nng_stream_listener_accept(ep->listener, ep->connaio); + } + break; + } + nni_mtx_unlock(&ep->mtx); +} + +static void +tcptran_dial_cb(void *arg) +{ + tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + tcptran_pipe *p; + int rv; + nng_stream * conn; + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + conn = nni_aio_get_output(aio, 0); + if ((rv = tcptran_pipe_alloc(&p)) != 0) { + nng_stream_free(conn); + goto error; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + tcptran_pipe_fini(p); + nng_stream_free(conn); + rv = NNG_ECLOSED; + nni_mtx_unlock(&ep->mtx); + goto error; + } else { + tcptran_pipe_start(p, conn, ep); + } + nni_mtx_unlock(&ep->mtx); + return; + +error: + // Error connecting. We need to pass this straight back + // to the user. + nni_mtx_lock(&ep->mtx); + if ((aio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + +static int +tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) +{ + tcptran_ep *ep; + + if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&ep->mtx); + NNI_LIST_INIT(&ep->busypipes, tcptran_pipe, node); + NNI_LIST_INIT(&ep->waitpipes, tcptran_pipe, node); + NNI_LIST_INIT(&ep->negopipes, tcptran_pipe, node); + + ep->proto = nni_sock_proto_id(sock); + ep->url = url; + +#ifdef NNG_ENABLE_STATS + static const nni_stat_info rcv_max_info = { + .si_name = "rcv_max", + .si_desc = "maximum receive size", + .si_type = NNG_STAT_LEVEL, + .si_unit = NNG_UNIT_BYTES, + .si_atomic = true, + }; + nni_stat_init(&ep->st_rcv_max, &rcv_max_info); +#endif + + *epp = ep; + return (0); +} + +static int +tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) +{ + tcptran_ep * ep; + int rv; + nng_sockaddr srcsa; + nni_sock * sock = nni_dialer_sock(ndialer); + nng_url myurl; + + // Check for invalid URL components. only one dialer is allowed + printf("mqtt dialer init\n"); + if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { + return (NNG_EADDRINVAL); + } + if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || + (url->u_query != NULL) || (strlen(url->u_hostname) == 0) || + (strlen(url->u_port) == 0)) { + return (NNG_EADDRINVAL); + } + + if ((rv = tcptran_url_parse_source(&myurl, &srcsa, url)) != 0) { + return (rv); + } + + if ((rv = tcptran_ep_init(&ep, url, sock)) != 0) { + return (rv); + } + + if ((rv != 0) || + ((rv = nni_aio_alloc(&ep->connaio, tcptran_dial_cb, ep)) != 0) || + ((rv = nng_stream_dialer_alloc_url(&ep->dialer, &myurl)) != 0)) { + tcptran_ep_fini(ep); + return (rv); + } + printf("mqtt dialer init2\n"); + if ((srcsa.s_family != NNG_AF_UNSPEC) && + ((rv = nni_stream_dialer_set(ep->dialer, NNG_OPT_LOCADDR, &srcsa, + sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) { + tcptran_ep_fini(ep); + return (rv); + } + printf("mqtt dialer init3\n"); + +#ifdef NNG_ENABLE_STATS + nni_dialer_add_stat(ndialer, &ep->st_rcv_max); +#endif + *dp = ep; + return (0); +} + +static int +tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) +{ + tcptran_ep *ep; + int rv; + nni_sock * sock = nni_listener_sock(nlistener); + + // Check for invalid URL components. + if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { + return (NNG_EADDRINVAL); + } + if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || + (url->u_query != NULL)) { + return (NNG_EADDRINVAL); + } + + if ((rv = tcptran_ep_init(&ep, url, sock)) != 0) { + return (rv); + } + + if (((rv = nni_aio_alloc(&ep->connaio, tcptran_accept_cb, ep)) != 0) || + ((rv = nni_aio_alloc(&ep->timeaio, tcptran_timer_cb, ep)) != 0) || + ((rv = nng_stream_listener_alloc_url(&ep->listener, url)) != 0)) { + tcptran_ep_fini(ep); + return (rv); + } +#ifdef NNG_ENABLE_STATS + nni_listener_add_stat(nlistener, &ep->st_rcv_max); +#endif + + *lp = ep; + return (0); +} + +static void +tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) +{ + tcptran_ep *ep = arg; + nni_mtx_lock(&ep->mtx); + if (ep->useraio == aio) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + +static void +tcptran_ep_connect(void *arg, nni_aio *aio) +{ + tcptran_ep *ep = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + if (ep->useraio != NULL) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + if ((rv = nni_aio_schedule(aio, tcptran_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, rv); + return; + } + ep->useraio = aio; + + nng_stream_dialer_dial(ep->dialer, ep->connaio); + nni_mtx_unlock(&ep->mtx); +} + +static int +tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + tcptran_ep *ep = arg; + char * s; + int rv; + int port = 0; + + if (ep->listener != NULL) { + (void) nng_stream_listener_get_int( + ep->listener, NNG_OPT_TCP_BOUND_PORT, &port); + } + + if ((rv = nni_url_asprintf_port(&s, ep->url, port)) == 0) { + rv = nni_copyout_str(s, v, szp, t); + nni_strfree(s); + } + return (rv); +} + +static int +tcptran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + rv = nni_copyout_size(ep->rcvmax, v, szp, t); + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static int +tcptran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t) +{ + tcptran_ep *ep = arg; + size_t val; + int rv; + if ((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) { + tcptran_pipe *p; + nni_mtx_lock(&ep->mtx); + ep->rcvmax = val; + NNI_LIST_FOREACH (&ep->waitpipes, p) { + p->rcvmax = val; + } + NNI_LIST_FOREACH (&ep->negopipes, p) { + p->rcvmax = val; + } + NNI_LIST_FOREACH (&ep->busypipes, p) { + p->rcvmax = val; + } + nni_mtx_unlock(&ep->mtx); +#ifdef NNG_ENABLE_STATS + nni_stat_set_value(&ep->st_rcv_max, val); +#endif + } + return (rv); +} + +static int +tcptran_ep_bind(void *arg) +{ + tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + rv = nng_stream_listener_listen(ep->listener); + nni_mtx_unlock(&ep->mtx); + + return (rv); +} + +static void +tcptran_ep_accept(void *arg, nni_aio *aio) +{ + tcptran_ep *ep = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + if (ep->useraio != NULL) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + if ((rv = nni_aio_schedule(aio, tcptran_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, rv); + return; + } + ep->useraio = aio; + if (!ep->started) { + ep->started = true; + nng_stream_listener_accept(ep->listener, ep->connaio); + } else { + tcptran_ep_match(ep); + } + nni_mtx_unlock(&ep->mtx); +} + +static nni_sp_pipe_ops tcptran_pipe_ops = { + .p_init = tcptran_pipe_init, + .p_fini = tcptran_pipe_fini, + .p_stop = tcptran_pipe_stop, + .p_send = tcptran_pipe_send, + .p_recv = tcptran_pipe_recv, + .p_close = tcptran_pipe_close, + .p_peer = tcptran_pipe_peer, + .p_getopt = tcptran_pipe_getopt, +}; + +static const nni_option tcptran_ep_opts[] = { + { + .o_name = NNG_OPT_RECVMAXSZ, + .o_get = tcptran_ep_get_recvmaxsz, + .o_set = tcptran_ep_set_recvmaxsz, + }, + { + .o_name = NNG_OPT_URL, + .o_get = tcptran_ep_get_url, + }, + // terminate list + { + .o_name = NULL, + }, +}; + +static int +tcptran_dialer_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_dialer_get(ep->dialer, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t); + } + return (rv); +} + +static int +tcptran_dialer_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_dialer_set(ep->dialer, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t); + } + return (rv); +} + +static int +tcptran_listener_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_listener_get(ep->listener, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t); + } + return (rv); +} + +static int +tcptran_listener_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_listener_set(ep->listener, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t); + } + return (rv); +} + +static nni_sp_dialer_ops tcptran_dialer_ops = { + .d_init = tcptran_dialer_init, + .d_fini = tcptran_ep_fini, + .d_connect = tcptran_ep_connect, + .d_close = tcptran_ep_close, + .d_getopt = tcptran_dialer_getopt, + .d_setopt = tcptran_dialer_setopt, +}; + +static nni_sp_listener_ops tcptran_listener_ops = { + .l_init = tcptran_listener_init, + .l_fini = tcptran_ep_fini, + .l_bind = tcptran_ep_bind, + .l_accept = tcptran_ep_accept, + .l_close = tcptran_ep_close, + .l_getopt = tcptran_listener_getopt, + .l_setopt = tcptran_listener_setopt, +}; + +static nni_sp_tran tcp_tran = { + .tran_scheme = "mqtt-tcp", + .tran_dialer = &tcptran_dialer_ops, + .tran_listener = &tcptran_listener_ops, + .tran_pipe = &tcptran_pipe_ops, + .tran_init = tcptran_init, + .tran_fini = tcptran_fini, +}; + +static nni_sp_tran tcp4_tran = { + .tran_scheme = "mqtt-tcp4", + .tran_dialer = &tcptran_dialer_ops, + .tran_listener = &tcptran_listener_ops, + .tran_pipe = &tcptran_pipe_ops, + .tran_init = tcptran_init, + .tran_fini = tcptran_fini, +}; + +static nni_sp_tran tcp6_tran = { + .tran_scheme = "mqtt-tcp6", + .tran_dialer = &tcptran_dialer_ops, + .tran_listener = &tcptran_listener_ops, + .tran_pipe = &tcptran_pipe_ops, + .tran_init = tcptran_init, + .tran_fini = tcptran_fini, +}; + +#ifndef NNG_ELIDE_DEPRECATED +int +nng_mqtt_tcp_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_mqtt_tcp_register(void) +{ + nni_sp_tran_register(&tcp_tran); + nni_sp_tran_register(&tcp4_tran); + nni_sp_tran_register(&tcp6_tran); +} diff --git a/src/sp/transport/tcp/CMakeLists.txt b/src/sp/transport/tcp/CMakeLists.txt index d60223295..c892c72c3 100644 --- a/src/sp/transport/tcp/CMakeLists.txt +++ b/src/sp/transport/tcp/CMakeLists.txt @@ -14,4 +14,4 @@ nng_directory(tcp) nng_sources_if(NNG_TRANSPORT_TCP tcp.c) nng_headers_if(NNG_TRANSPORT_TCP nng/transport/tcp/tcp.h) nng_defines_if(NNG_TRANSPORT_TCP NNG_TRANSPORT_TCP) -nng_test(tcp_test) \ No newline at end of file +nng_test(tcp_test) From 9749c4a971a9bfba2cd47cc73fb42d4bc57abc4d Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 15 Oct 2021 19:28:49 +0800 Subject: [PATCH 065/180] * NEW [nng/mqtt] add independent stream scheme for mqtt --- src/core/stream.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/core/stream.c b/src/core/stream.c index b699e526b..27560d09b 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -44,6 +44,21 @@ static struct { .listener_alloc = nni_ipc_listener_alloc, }, #endif + { + .scheme = "mqtt-tcp", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, + { + .scheme = "mqtt-tcp4", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, + { + .scheme = "mqtt-tcp6", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, { .scheme = "tcp", .dialer_alloc = nni_tcp_dialer_alloc, From 8a5cbc74987fcb3b935e7bf992fbaf8f842e8698 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 18 Oct 2021 18:32:15 +0800 Subject: [PATCH 066/180] * NEW [nng/cmake] use correct MACRO for mqtt_tcp --- cmake/NNGOptions.cmake | 4 ++++ src/sp/transport.c | 6 +++--- src/sp/transport/mqtt/CMakeLists.txt | 4 ++-- src/sp/transport/mqtt/mqtt_tcp.c | 3 --- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cmake/NNGOptions.cmake b/cmake/NNGOptions.cmake index b8067bca0..fc0179145 100644 --- a/cmake/NNGOptions.cmake +++ b/cmake/NNGOptions.cmake @@ -115,6 +115,10 @@ mark_as_advanced(NNG_TRANSPORT_IPC) option (NNG_TRANSPORT_TCP "Enable TCP transport." ON) mark_as_advanced(NNG_TRANSPORT_TCP) +# TCP transport +option (NNG_TRANSPORT_MQTT_TCP "Enable TCP transport." ON) +mark_as_advanced(NNG_TRANSPORT_MQTT_TCP) + # TLS transport option (NNG_TRANSPORT_TLS "Enable TLS transport." ON) mark_as_advanced(NNG_TRANSPORT_TLS) diff --git a/src/sp/transport.c b/src/sp/transport.c index 0ae8261f6..e6c967b86 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -58,7 +58,7 @@ extern void nni_sp_ipc_register(void); #ifdef NNG_TRANSPORT_TCP extern void nni_sp_tcp_register(void); #endif -#ifdef NNG_TRANSPORT_TCP +#ifdef NNG_TRANSPORT_MQTT_TCP extern void nni_mqtt_tcp_register(); #endif #ifdef NNG_TRANSPORT_TLS @@ -89,10 +89,10 @@ nni_sp_tran_sys_init(void) #ifdef NNG_TRANSPORT_TCP nni_sp_tcp_register(); #endif -#ifdef NNG_TRANSPORT_TCP +#ifdef NNG_TRANSPORT_MQTT_TCP nni_mqtt_tcp_register(); #endif -#ifdef NNG_TRANSPORT_MQTT_TCP +#ifdef NNG_TRANSPORT_TCP nni_sp_tls_register(); #endif #ifdef NNG_TRANSPORT_WS diff --git a/src/sp/transport/mqtt/CMakeLists.txt b/src/sp/transport/mqtt/CMakeLists.txt index 4fcf33e83..ccce1b8d5 100644 --- a/src/sp/transport/mqtt/CMakeLists.txt +++ b/src/sp/transport/mqtt/CMakeLists.txt @@ -11,6 +11,6 @@ # TCP protocol nng_directory(mqtt) -nng_sources_if(NNG_TRANSPORT_TCP mqtt_tcp.c) -nng_headers_if(NNG_TRANSPORT_TCP nng/transport/tcp/mqtt_tcp.h) +nng_sources_if(NNG_TRANSPORT_MQTT_TCP mqtt_tcp.c) +nng_headers_if(NNG_TRANSPORT_MQTT_TCP nng/transport/tcp/mqtt_tcp.h) nng_defines_if(NNG_TRANSPORT_MQTT_TCP NNG_TRANSPORT_MQTT_TCP) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 7a940a6c4..39e4a7721 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -897,7 +897,6 @@ tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) nng_url myurl; // Check for invalid URL components. only one dialer is allowed - printf("mqtt dialer init\n"); if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { return (NNG_EADDRINVAL); } @@ -921,14 +920,12 @@ tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) tcptran_ep_fini(ep); return (rv); } - printf("mqtt dialer init2\n"); if ((srcsa.s_family != NNG_AF_UNSPEC) && ((rv = nni_stream_dialer_set(ep->dialer, NNG_OPT_LOCADDR, &srcsa, sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) { tcptran_ep_fini(ep); return (rv); } - printf("mqtt dialer init3\n"); #ifdef NNG_ENABLE_STATS nni_dialer_add_stat(ndialer, &ep->st_rcv_max); From fdc36dac00f38643873a6c696b9474c5b6660ddb Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 18 Oct 2021 16:11:11 +0800 Subject: [PATCH 067/180] * MDF [nng/mqtt] rename all functions of transport/mqtt/mqtt_tcp.c --- src/sp/transport/mqtt/mqtt_tcp.c | 516 ++++++++++++++++--------------- 1 file changed, 262 insertions(+), 254 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 39e4a7721..82f6a8a4d 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -18,37 +18,37 @@ // TCP transport. Platform specific TCP operations must be // supplied as well. -typedef struct tcptran_pipe tcptran_pipe; -typedef struct tcptran_ep tcptran_ep; +typedef struct mqtt_tcptran_pipe mqtt_tcptran_pipe; +typedef struct mqtt_tcptran_ep mqtt_tcptran_ep; // tcp_pipe is one end of a TCP connection. -struct tcptran_pipe { - nng_stream * conn; - nni_pipe * npipe; - uint16_t peer; - uint16_t proto; - size_t rcvmax; - bool closed; - nni_list_node node; - tcptran_ep * ep; - nni_atomic_flag reaped; - nni_reap_node reap; - uint8_t txlen[sizeof(uint64_t)]; - uint8_t rxlen[sizeof(uint64_t)]; - size_t gottxhead; - size_t gotrxhead; - size_t wanttxhead; - size_t wantrxhead; - nni_list recvq; - nni_list sendq; - nni_aio * txaio; - nni_aio * rxaio; - nni_aio * negoaio; - nni_msg * rxmsg; - nni_mtx mtx; +struct mqtt_tcptran_pipe { + nng_stream * conn; + nni_pipe * npipe; + uint16_t peer; + uint16_t proto; + size_t rcvmax; + bool closed; + nni_list_node node; + mqtt_tcptran_ep *ep; + nni_atomic_flag reaped; + nni_reap_node reap; + uint8_t txlen[sizeof(uint64_t)]; + uint8_t rxlen[sizeof(uint64_t)]; + size_t gottxhead; + size_t gotrxhead; + size_t wanttxhead; + size_t wantrxhead; + nni_list recvq; + nni_list sendq; + nni_aio * txaio; + nni_aio * rxaio; + nni_aio * negoaio; + nni_msg * rxmsg; + nni_mtx mtx; }; -struct tcptran_ep { +struct mqtt_tcptran_ep { nni_mtx mtx; uint16_t proto; size_t rcvmax; @@ -74,38 +74,38 @@ struct tcptran_ep { #endif }; -static void tcptran_pipe_send_start(tcptran_pipe *); -static void tcptran_pipe_recv_start(tcptran_pipe *); -static void tcptran_pipe_send_cb(void *); -static void tcptran_pipe_recv_cb(void *); -static void tcptran_pipe_nego_cb(void *); -static void tcptran_ep_fini(void *); -static void tcptran_pipe_fini(void *); +static void mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *); +static void mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *); +static void mqtt_tcptran_pipe_send_cb(void *); +static void mqtt_tcptran_pipe_recv_cb(void *); +static void mqtt_tcptran_pipe_nego_cb(void *); +static void mqtt_tcptran_ep_fini(void *); +static void mqtt_tcptran_pipe_fini(void *); static nni_reap_list tcptran_ep_reap_list = { - .rl_offset = offsetof(tcptran_ep, reap), - .rl_func = tcptran_ep_fini, + .rl_offset = offsetof(mqtt_tcptran_ep, reap), + .rl_func = mqtt_tcptran_ep_fini, }; static nni_reap_list tcptran_pipe_reap_list = { - .rl_offset = offsetof(tcptran_pipe, reap), - .rl_func = tcptran_pipe_fini, + .rl_offset = offsetof(mqtt_tcptran_pipe, reap), + .rl_func = mqtt_tcptran_pipe_fini, }; static void -tcptran_init(void) +mqtt_tcptran_init(void) { } static void -tcptran_fini(void) +mqtt_tcptran_fini(void) { } static void -tcptran_pipe_close(void *arg) +mqtt_tcptran_pipe_close(void *arg) { - tcptran_pipe *p = arg; + mqtt_tcptran_pipe *p = arg; nni_mtx_lock(&p->mtx); p->closed = true; @@ -119,9 +119,9 @@ tcptran_pipe_close(void *arg) } static void -tcptran_pipe_stop(void *arg) +mqtt_tcptran_pipe_stop(void *arg) { - tcptran_pipe *p = arg; + mqtt_tcptran_pipe *p = arg; nni_aio_stop(p->rxaio); nni_aio_stop(p->txaio); @@ -129,21 +129,21 @@ tcptran_pipe_stop(void *arg) } static int -tcptran_pipe_init(void *arg, nni_pipe *npipe) +mqtt_tcptran_pipe_init(void *arg, nni_pipe *npipe) { - tcptran_pipe *p = arg; - p->npipe = npipe; + mqtt_tcptran_pipe *p = arg; + p->npipe = npipe; return (0); } static void -tcptran_pipe_fini(void *arg) +mqtt_tcptran_pipe_fini(void *arg) { - tcptran_pipe *p = arg; - tcptran_ep * ep; + mqtt_tcptran_pipe *p = arg; + mqtt_tcptran_ep * ep; - tcptran_pipe_stop(p); + mqtt_tcptran_pipe_stop(p); if ((ep = p->ep) != NULL) { nni_mtx_lock(&ep->mtx); nni_list_node_remove(&p->node); @@ -164,7 +164,7 @@ tcptran_pipe_fini(void *arg) } static void -tcptran_pipe_reap(tcptran_pipe *p) +mqtt_tcptran_pipe_reap(mqtt_tcptran_pipe *p) { if (!nni_atomic_flag_test_and_set(&p->reaped)) { if (p->conn != NULL) { @@ -175,20 +175,22 @@ tcptran_pipe_reap(tcptran_pipe *p) } static int -tcptran_pipe_alloc(tcptran_pipe **pipep) +mqtt_tcptran_pipe_alloc(mqtt_tcptran_pipe **pipep) { - tcptran_pipe *p; - int rv; + mqtt_tcptran_pipe *p; + int rv; if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { return (NNG_ENOMEM); } nni_mtx_init(&p->mtx); - if (((rv = nni_aio_alloc(&p->txaio, tcptran_pipe_send_cb, p)) != 0) || - ((rv = nni_aio_alloc(&p->rxaio, tcptran_pipe_recv_cb, p)) != 0) || - ((rv = nni_aio_alloc(&p->negoaio, tcptran_pipe_nego_cb, p)) != + if (((rv = nni_aio_alloc(&p->txaio, mqtt_tcptran_pipe_send_cb, p)) != + 0) || + ((rv = nni_aio_alloc(&p->rxaio, mqtt_tcptran_pipe_recv_cb, p)) != + 0) || + ((rv = nni_aio_alloc(&p->negoaio, mqtt_tcptran_pipe_nego_cb, p)) != 0)) { - tcptran_pipe_fini(p); + mqtt_tcptran_pipe_fini(p); return (rv); } nni_aio_list_init(&p->recvq); @@ -201,10 +203,10 @@ tcptran_pipe_alloc(tcptran_pipe **pipep) } static void -tcptran_ep_match(tcptran_ep *ep) +mqtt_tcptran_ep_match(mqtt_tcptran_ep *ep) { - nni_aio * aio; - tcptran_pipe *p; + nni_aio * aio; + mqtt_tcptran_pipe *p; if (((aio = ep->useraio) == NULL) || ((p = nni_list_first(&ep->waitpipes)) == NULL)) { @@ -219,13 +221,13 @@ tcptran_ep_match(tcptran_ep *ep) } static void -tcptran_pipe_nego_cb(void *arg) +mqtt_tcptran_pipe_nego_cb(void *arg) { - tcptran_pipe *p = arg; - tcptran_ep * ep = p->ep; - nni_aio * aio = p->negoaio; - nni_aio * uaio; - int rv; + mqtt_tcptran_pipe *p = arg; + mqtt_tcptran_ep * ep = p->ep; + nni_aio * aio = p->negoaio; + nni_aio * uaio; + int rv; nni_mtx_lock(&ep->mtx); @@ -275,7 +277,7 @@ tcptran_pipe_nego_cb(void *arg) nni_list_remove(&ep->negopipes, p); nni_list_append(&ep->waitpipes, p); - tcptran_ep_match(ep); + mqtt_tcptran_ep_match(ep); nni_mtx_unlock(&ep->mtx); return; @@ -288,18 +290,18 @@ tcptran_pipe_nego_cb(void *arg) nni_aio_finish_error(uaio, rv); } nni_mtx_unlock(&ep->mtx); - tcptran_pipe_reap(p); + mqtt_tcptran_pipe_reap(p); } static void -tcptran_pipe_send_cb(void *arg) +mqtt_tcptran_pipe_send_cb(void *arg) { - tcptran_pipe *p = arg; - int rv; - nni_aio * aio; - size_t n; - nni_msg * msg; - nni_aio * txaio = p->txaio; + mqtt_tcptran_pipe *p = arg; + int rv; + nni_aio * aio; + size_t n; + nni_msg * msg; + nni_aio * txaio = p->txaio; nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->sendq); @@ -326,7 +328,7 @@ tcptran_pipe_send_cb(void *arg) } nni_aio_list_remove(aio); - tcptran_pipe_send_start(p); + mqtt_tcptran_pipe_send_start(p); msg = nni_aio_get_msg(aio); n = nni_msg_len(msg); @@ -339,14 +341,14 @@ tcptran_pipe_send_cb(void *arg) } static void -tcptran_pipe_recv_cb(void *arg) +mqtt_tcptran_pipe_recv_cb(void *arg) { - tcptran_pipe *p = arg; - nni_aio * aio; - int rv; - size_t n; - nni_msg * msg; - nni_aio * rxaio = p->rxaio; + mqtt_tcptran_pipe *p = arg; + nni_aio * aio; + int rv; + size_t n; + nni_msg * msg; + nni_aio * rxaio = p->rxaio; nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->recvq); @@ -403,7 +405,7 @@ tcptran_pipe_recv_cb(void *arg) n = nni_msg_len(msg); nni_pipe_bump_rx(p->npipe, n); - tcptran_pipe_recv_start(p); + mqtt_tcptran_pipe_recv_start(p); nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, msg); @@ -424,9 +426,9 @@ tcptran_pipe_recv_cb(void *arg) } static void -tcptran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) +mqtt_tcptran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) { - tcptran_pipe *p = arg; + mqtt_tcptran_pipe *p = arg; nni_mtx_lock(&p->mtx); if (!nni_aio_list_active(aio)) { @@ -448,7 +450,7 @@ tcptran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) } static void -tcptran_pipe_send_start(tcptran_pipe *p) +mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *p) { nni_aio *aio; nni_aio *txaio; @@ -495,31 +497,32 @@ tcptran_pipe_send_start(tcptran_pipe *p) } static void -tcptran_pipe_send(void *arg, nni_aio *aio) +mqtt_tcptran_pipe_send(void *arg, nni_aio *aio) { - tcptran_pipe *p = arg; - int rv; + mqtt_tcptran_pipe *p = arg; + int rv; if (nni_aio_begin(aio) != 0) { return; } nni_mtx_lock(&p->mtx); - if ((rv = nni_aio_schedule(aio, tcptran_pipe_send_cancel, p)) != 0) { + if ((rv = nni_aio_schedule(aio, mqtt_tcptran_pipe_send_cancel, p)) != + 0) { nni_mtx_unlock(&p->mtx); nni_aio_finish_error(aio, rv); return; } nni_list_append(&p->sendq, aio); if (nni_list_first(&p->sendq) == aio) { - tcptran_pipe_send_start(p); + mqtt_tcptran_pipe_send_start(p); } nni_mtx_unlock(&p->mtx); } static void -tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) +mqtt_tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) { - tcptran_pipe *p = arg; + mqtt_tcptran_pipe *p = arg; nni_mtx_lock(&p->mtx); if (!nni_aio_list_active(aio)) { @@ -540,7 +543,7 @@ tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) } static void -tcptran_pipe_recv_start(tcptran_pipe *p) +mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *p) { nni_aio *rxaio; nni_iov iov; @@ -568,16 +571,17 @@ tcptran_pipe_recv_start(tcptran_pipe *p) } static void -tcptran_pipe_recv(void *arg, nni_aio *aio) +mqtt_tcptran_pipe_recv(void *arg, nni_aio *aio) { - tcptran_pipe *p = arg; - int rv; + mqtt_tcptran_pipe *p = arg; + int rv; if (nni_aio_begin(aio) != 0) { return; } nni_mtx_lock(&p->mtx); - if ((rv = nni_aio_schedule(aio, tcptran_pipe_recv_cancel, p)) != 0) { + if ((rv = nni_aio_schedule(aio, mqtt_tcptran_pipe_recv_cancel, p)) != + 0) { nni_mtx_unlock(&p->mtx); nni_aio_finish_error(aio, rv); return; @@ -585,29 +589,30 @@ tcptran_pipe_recv(void *arg, nni_aio *aio) nni_list_append(&p->recvq, aio); if (nni_list_first(&p->recvq) == aio) { - tcptran_pipe_recv_start(p); + mqtt_tcptran_pipe_recv_start(p); } nni_mtx_unlock(&p->mtx); } static uint16_t -tcptran_pipe_peer(void *arg) +mqtt_tcptran_pipe_peer(void *arg) { - tcptran_pipe *p = arg; + mqtt_tcptran_pipe *p = arg; return (p->peer); } static int -tcptran_pipe_getopt( +mqtt_tcptran_pipe_getopt( void *arg, const char *name, void *buf, size_t *szp, nni_type t) { - tcptran_pipe *p = arg; + mqtt_tcptran_pipe *p = arg; return (nni_stream_get(p->conn, name, buf, szp, t)); } static void -tcptran_pipe_start(tcptran_pipe *p, nng_stream *conn, tcptran_ep *ep) +mqtt_tcptran_pipe_start( + mqtt_tcptran_pipe *p, nng_stream *conn, mqtt_tcptran_ep *ep) { nni_iov iov; @@ -638,9 +643,9 @@ tcptran_pipe_start(tcptran_pipe *p, nng_stream *conn, tcptran_ep *ep) } static void -tcptran_ep_fini(void *arg) +mqtt_tcptran_ep_fini(void *arg) { - tcptran_ep *ep = arg; + mqtt_tcptran_ep *ep = arg; nni_mtx_lock(&ep->mtx); ep->fini = true; @@ -661,10 +666,10 @@ tcptran_ep_fini(void *arg) } static void -tcptran_ep_close(void *arg) +mqtt_tcptran_ep_close(void *arg) { - tcptran_ep * ep = arg; - tcptran_pipe *p; + mqtt_tcptran_ep * ep = arg; + mqtt_tcptran_pipe *p; nni_mtx_lock(&ep->mtx); @@ -677,13 +682,13 @@ tcptran_ep_close(void *arg) nng_stream_listener_close(ep->listener); } NNI_LIST_FOREACH (&ep->negopipes, p) { - tcptran_pipe_close(p); + mqtt_tcptran_pipe_close(p); } NNI_LIST_FOREACH (&ep->waitpipes, p) { - tcptran_pipe_close(p); + mqtt_tcptran_pipe_close(p); } NNI_LIST_FOREACH (&ep->busypipes, p) { - tcptran_pipe_close(p); + mqtt_tcptran_pipe_close(p); } if (ep->useraio != NULL) { nni_aio_finish_error(ep->useraio, NNG_ECLOSED); @@ -697,7 +702,8 @@ tcptran_ep_close(void *arg) // The special handling of this URL format is quite honestly an historical // mistake, which we would remove if we could. static int -tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl) +mqtt_tcptran_url_parse_source( + nng_url *url, nng_sockaddr *sa, const nng_url *surl) { int af; char * semi; @@ -751,22 +757,22 @@ tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl) } static void -tcptran_timer_cb(void *arg) +mqtt_tcptran_timer_cb(void *arg) { - tcptran_ep *ep = arg; + mqtt_tcptran_ep *ep = arg; if (nni_aio_result(ep->timeaio) == 0) { nng_stream_listener_accept(ep->listener, ep->connaio); } } static void -tcptran_accept_cb(void *arg) +mqtt_tcptran_accept_cb(void *arg) { - tcptran_ep * ep = arg; - nni_aio * aio = ep->connaio; - tcptran_pipe *p; - int rv; - nng_stream * conn; + mqtt_tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + mqtt_tcptran_pipe *p; + int rv; + nng_stream * conn; nni_mtx_lock(&ep->mtx); @@ -775,18 +781,18 @@ tcptran_accept_cb(void *arg) } conn = nni_aio_get_output(aio, 0); - if ((rv = tcptran_pipe_alloc(&p)) != 0) { + if ((rv = mqtt_tcptran_pipe_alloc(&p)) != 0) { nng_stream_free(conn); goto error; } if (ep->closed) { - tcptran_pipe_fini(p); + mqtt_tcptran_pipe_fini(p); nng_stream_free(conn); rv = NNG_ECLOSED; goto error; } - tcptran_pipe_start(p, conn, ep); + mqtt_tcptran_pipe_start(p, conn, ep); nng_stream_listener_accept(ep->listener, ep->connaio); nni_mtx_unlock(&ep->mtx); return; @@ -815,32 +821,32 @@ tcptran_accept_cb(void *arg) } static void -tcptran_dial_cb(void *arg) +mqtt_tcptran_dial_cb(void *arg) { - tcptran_ep * ep = arg; - nni_aio * aio = ep->connaio; - tcptran_pipe *p; - int rv; - nng_stream * conn; + mqtt_tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + mqtt_tcptran_pipe *p; + int rv; + nng_stream * conn; if ((rv = nni_aio_result(aio)) != 0) { goto error; } conn = nni_aio_get_output(aio, 0); - if ((rv = tcptran_pipe_alloc(&p)) != 0) { + if ((rv = mqtt_tcptran_pipe_alloc(&p)) != 0) { nng_stream_free(conn); goto error; } nni_mtx_lock(&ep->mtx); if (ep->closed) { - tcptran_pipe_fini(p); + mqtt_tcptran_pipe_fini(p); nng_stream_free(conn); rv = NNG_ECLOSED; nni_mtx_unlock(&ep->mtx); goto error; } else { - tcptran_pipe_start(p, conn, ep); + mqtt_tcptran_pipe_start(p, conn, ep); } nni_mtx_unlock(&ep->mtx); return; @@ -857,17 +863,17 @@ tcptran_dial_cb(void *arg) } static int -tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) +mqtt_tcptran_ep_init(mqtt_tcptran_ep **epp, nng_url *url, nni_sock *sock) { - tcptran_ep *ep; + mqtt_tcptran_ep *ep; if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); } nni_mtx_init(&ep->mtx); - NNI_LIST_INIT(&ep->busypipes, tcptran_pipe, node); - NNI_LIST_INIT(&ep->waitpipes, tcptran_pipe, node); - NNI_LIST_INIT(&ep->negopipes, tcptran_pipe, node); + NNI_LIST_INIT(&ep->busypipes, mqtt_tcptran_pipe, node); + NNI_LIST_INIT(&ep->waitpipes, mqtt_tcptran_pipe, node); + NNI_LIST_INIT(&ep->negopipes, mqtt_tcptran_pipe, node); ep->proto = nni_sock_proto_id(sock); ep->url = url; @@ -888,13 +894,13 @@ tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) } static int -tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) +mqtt_tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) { - tcptran_ep * ep; - int rv; - nng_sockaddr srcsa; - nni_sock * sock = nni_dialer_sock(ndialer); - nng_url myurl; + mqtt_tcptran_ep *ep; + int rv; + nng_sockaddr srcsa; + nni_sock * sock = nni_dialer_sock(ndialer); + nng_url myurl; // Check for invalid URL components. only one dialer is allowed if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { @@ -906,40 +912,39 @@ tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) return (NNG_EADDRINVAL); } - if ((rv = tcptran_url_parse_source(&myurl, &srcsa, url)) != 0) { + if ((rv = mqtt_tcptran_url_parse_source(&myurl, &srcsa, url)) != 0) { return (rv); } - if ((rv = tcptran_ep_init(&ep, url, sock)) != 0) { + if ((rv = mqtt_tcptran_ep_init(&ep, url, sock)) != 0) { return (rv); } if ((rv != 0) || - ((rv = nni_aio_alloc(&ep->connaio, tcptran_dial_cb, ep)) != 0) || + ((rv = nni_aio_alloc(&ep->connaio, mqtt_tcptran_dial_cb, ep)) != + 0) || ((rv = nng_stream_dialer_alloc_url(&ep->dialer, &myurl)) != 0)) { - tcptran_ep_fini(ep); + mqtt_tcptran_ep_fini(ep); return (rv); } if ((srcsa.s_family != NNG_AF_UNSPEC) && ((rv = nni_stream_dialer_set(ep->dialer, NNG_OPT_LOCADDR, &srcsa, sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) { - tcptran_ep_fini(ep); + mqtt_tcptran_ep_fini(ep); return (rv); } - #ifdef NNG_ENABLE_STATS - nni_dialer_add_stat(ndialer, &ep->st_rcv_max); #endif *dp = ep; return (0); } static int -tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) +mqtt_tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) { - tcptran_ep *ep; - int rv; - nni_sock * sock = nni_listener_sock(nlistener); + mqtt_tcptran_ep *ep; + int rv; + nni_sock * sock = nni_listener_sock(nlistener); // Check for invalid URL components. if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { @@ -950,14 +955,16 @@ tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) return (NNG_EADDRINVAL); } - if ((rv = tcptran_ep_init(&ep, url, sock)) != 0) { + if ((rv = mqtt_tcptran_ep_init(&ep, url, sock)) != 0) { return (rv); } - if (((rv = nni_aio_alloc(&ep->connaio, tcptran_accept_cb, ep)) != 0) || - ((rv = nni_aio_alloc(&ep->timeaio, tcptran_timer_cb, ep)) != 0) || + if (((rv = nni_aio_alloc(&ep->connaio, mqtt_tcptran_accept_cb, ep)) != + 0) || + ((rv = nni_aio_alloc(&ep->timeaio, mqtt_tcptran_timer_cb, ep)) != + 0) || ((rv = nng_stream_listener_alloc_url(&ep->listener, url)) != 0)) { - tcptran_ep_fini(ep); + mqtt_tcptran_ep_fini(ep); return (rv); } #ifdef NNG_ENABLE_STATS @@ -969,9 +976,9 @@ tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) } static void -tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) +mqtt_tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) { - tcptran_ep *ep = arg; + mqtt_tcptran_ep *ep = arg; nni_mtx_lock(&ep->mtx); if (ep->useraio == aio) { ep->useraio = NULL; @@ -981,10 +988,10 @@ tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) } static void -tcptran_ep_connect(void *arg, nni_aio *aio) +mqtt_tcptran_ep_connect(void *arg, nni_aio *aio) { - tcptran_ep *ep = arg; - int rv; + mqtt_tcptran_ep *ep = arg; + int rv; if (nni_aio_begin(aio) != 0) { return; @@ -1000,7 +1007,7 @@ tcptran_ep_connect(void *arg, nni_aio *aio) nni_aio_finish_error(aio, NNG_EBUSY); return; } - if ((rv = nni_aio_schedule(aio, tcptran_ep_cancel, ep)) != 0) { + if ((rv = nni_aio_schedule(aio, mqtt_tcptran_ep_cancel, ep)) != 0) { nni_mtx_unlock(&ep->mtx); nni_aio_finish_error(aio, rv); return; @@ -1012,12 +1019,12 @@ tcptran_ep_connect(void *arg, nni_aio *aio) } static int -tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) +mqtt_tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) { - tcptran_ep *ep = arg; - char * s; - int rv; - int port = 0; + mqtt_tcptran_ep *ep = arg; + char * s; + int rv; + int port = 0; if (ep->listener != NULL) { (void) nng_stream_listener_get_int( @@ -1032,10 +1039,10 @@ tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) } static int -tcptran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t) +mqtt_tcptran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t) { - tcptran_ep *ep = arg; - int rv; + mqtt_tcptran_ep *ep = arg; + int rv; nni_mtx_lock(&ep->mtx); rv = nni_copyout_size(ep->rcvmax, v, szp, t); @@ -1044,13 +1051,14 @@ tcptran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t) } static int -tcptran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t) +mqtt_tcptran_ep_set_recvmaxsz( + void *arg, const void *v, size_t sz, nni_opt_type t) { - tcptran_ep *ep = arg; - size_t val; - int rv; + mqtt_tcptran_ep *ep = arg; + size_t val; + int rv; if ((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) { - tcptran_pipe *p; + mqtt_tcptran_pipe *p; nni_mtx_lock(&ep->mtx); ep->rcvmax = val; NNI_LIST_FOREACH (&ep->waitpipes, p) { @@ -1071,10 +1079,10 @@ tcptran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t) } static int -tcptran_ep_bind(void *arg) +mqtt_tcptran_ep_bind(void *arg) { - tcptran_ep *ep = arg; - int rv; + mqtt_tcptran_ep *ep = arg; + int rv; nni_mtx_lock(&ep->mtx); rv = nng_stream_listener_listen(ep->listener); @@ -1084,10 +1092,10 @@ tcptran_ep_bind(void *arg) } static void -tcptran_ep_accept(void *arg, nni_aio *aio) +mqtt_tcptran_ep_accept(void *arg, nni_aio *aio) { - tcptran_ep *ep = arg; - int rv; + mqtt_tcptran_ep *ep = arg; + int rv; if (nni_aio_begin(aio) != 0) { return; @@ -1103,7 +1111,7 @@ tcptran_ep_accept(void *arg, nni_aio *aio) nni_aio_finish_error(aio, NNG_EBUSY); return; } - if ((rv = nni_aio_schedule(aio, tcptran_ep_cancel, ep)) != 0) { + if ((rv = nni_aio_schedule(aio, mqtt_tcptran_ep_cancel, ep)) != 0) { nni_mtx_unlock(&ep->mtx); nni_aio_finish_error(aio, rv); return; @@ -1113,31 +1121,31 @@ tcptran_ep_accept(void *arg, nni_aio *aio) ep->started = true; nng_stream_listener_accept(ep->listener, ep->connaio); } else { - tcptran_ep_match(ep); + mqtt_tcptran_ep_match(ep); } nni_mtx_unlock(&ep->mtx); } -static nni_sp_pipe_ops tcptran_pipe_ops = { - .p_init = tcptran_pipe_init, - .p_fini = tcptran_pipe_fini, - .p_stop = tcptran_pipe_stop, - .p_send = tcptran_pipe_send, - .p_recv = tcptran_pipe_recv, - .p_close = tcptran_pipe_close, - .p_peer = tcptran_pipe_peer, - .p_getopt = tcptran_pipe_getopt, +static nni_sp_pipe_ops mqtt_tcptran_pipe_ops = { + .p_init = mqtt_tcptran_pipe_init, + .p_fini = mqtt_tcptran_pipe_fini, + .p_stop = mqtt_tcptran_pipe_stop, + .p_send = mqtt_tcptran_pipe_send, + .p_recv = mqtt_tcptran_pipe_recv, + .p_close = mqtt_tcptran_pipe_close, + .p_peer = mqtt_tcptran_pipe_peer, + .p_getopt = mqtt_tcptran_pipe_getopt, }; -static const nni_option tcptran_ep_opts[] = { +static const nni_option mqtt_tcptran_ep_opts[] = { { .o_name = NNG_OPT_RECVMAXSZ, - .o_get = tcptran_ep_get_recvmaxsz, - .o_set = tcptran_ep_set_recvmaxsz, + .o_get = mqtt_tcptran_ep_get_recvmaxsz, + .o_set = mqtt_tcptran_ep_set_recvmaxsz, }, { .o_name = NNG_OPT_URL, - .o_get = tcptran_ep_get_url, + .o_get = mqtt_tcptran_ep_get_url, }, // terminate list { @@ -1146,105 +1154,105 @@ static const nni_option tcptran_ep_opts[] = { }; static int -tcptran_dialer_getopt( +mqtt_tcptran_dialer_getopt( void *arg, const char *name, void *buf, size_t *szp, nni_type t) { - tcptran_ep *ep = arg; - int rv; + mqtt_tcptran_ep *ep = arg; + int rv; rv = nni_stream_dialer_get(ep->dialer, name, buf, szp, t); if (rv == NNG_ENOTSUP) { - rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t); + rv = nni_getopt(mqtt_tcptran_ep_opts, name, ep, buf, szp, t); } return (rv); } static int -tcptran_dialer_setopt( +mqtt_tcptran_dialer_setopt( void *arg, const char *name, const void *buf, size_t sz, nni_type t) { - tcptran_ep *ep = arg; - int rv; + mqtt_tcptran_ep *ep = arg; + int rv; rv = nni_stream_dialer_set(ep->dialer, name, buf, sz, t); if (rv == NNG_ENOTSUP) { - rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t); + rv = nni_setopt(mqtt_tcptran_ep_opts, name, ep, buf, sz, t); } return (rv); } static int -tcptran_listener_getopt( +mqtt_tcptran_listener_getopt( void *arg, const char *name, void *buf, size_t *szp, nni_type t) { - tcptran_ep *ep = arg; - int rv; + mqtt_tcptran_ep *ep = arg; + int rv; rv = nni_stream_listener_get(ep->listener, name, buf, szp, t); if (rv == NNG_ENOTSUP) { - rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t); + rv = nni_getopt(mqtt_tcptran_ep_opts, name, ep, buf, szp, t); } return (rv); } static int -tcptran_listener_setopt( +mqtt_tcptran_listener_setopt( void *arg, const char *name, const void *buf, size_t sz, nni_type t) { - tcptran_ep *ep = arg; - int rv; + mqtt_tcptran_ep *ep = arg; + int rv; rv = nni_stream_listener_set(ep->listener, name, buf, sz, t); if (rv == NNG_ENOTSUP) { - rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t); + rv = nni_setopt(mqtt_tcptran_ep_opts, name, ep, buf, sz, t); } return (rv); } -static nni_sp_dialer_ops tcptran_dialer_ops = { - .d_init = tcptran_dialer_init, - .d_fini = tcptran_ep_fini, - .d_connect = tcptran_ep_connect, - .d_close = tcptran_ep_close, - .d_getopt = tcptran_dialer_getopt, - .d_setopt = tcptran_dialer_setopt, +static nni_sp_dialer_ops mqtt_tcptran_dialer_ops = { + .d_init = mqtt_tcptran_dialer_init, + .d_fini = mqtt_tcptran_ep_fini, + .d_connect = mqtt_tcptran_ep_connect, + .d_close = mqtt_tcptran_ep_close, + .d_getopt = mqtt_tcptran_dialer_getopt, + .d_setopt = mqtt_tcptran_dialer_setopt, }; -static nni_sp_listener_ops tcptran_listener_ops = { - .l_init = tcptran_listener_init, - .l_fini = tcptran_ep_fini, - .l_bind = tcptran_ep_bind, - .l_accept = tcptran_ep_accept, - .l_close = tcptran_ep_close, - .l_getopt = tcptran_listener_getopt, - .l_setopt = tcptran_listener_setopt, +static nni_sp_listener_ops mqtt_tcptran_listener_ops = { + .l_init = mqtt_tcptran_listener_init, + .l_fini = mqtt_tcptran_ep_fini, + .l_bind = mqtt_tcptran_ep_bind, + .l_accept = mqtt_tcptran_ep_accept, + .l_close = mqtt_tcptran_ep_close, + .l_getopt = mqtt_tcptran_listener_getopt, + .l_setopt = mqtt_tcptran_listener_setopt, }; -static nni_sp_tran tcp_tran = { +static nni_sp_tran mqtt_tcp_tran = { .tran_scheme = "mqtt-tcp", - .tran_dialer = &tcptran_dialer_ops, - .tran_listener = &tcptran_listener_ops, - .tran_pipe = &tcptran_pipe_ops, - .tran_init = tcptran_init, - .tran_fini = tcptran_fini, + .tran_dialer = &mqtt_tcptran_dialer_ops, + .tran_listener = &mqtt_tcptran_listener_ops, + .tran_pipe = &mqtt_tcptran_pipe_ops, + .tran_init = mqtt_tcptran_init, + .tran_fini = mqtt_tcptran_fini, }; -static nni_sp_tran tcp4_tran = { +static nni_sp_tran mqtt_tcp4_tran = { .tran_scheme = "mqtt-tcp4", - .tran_dialer = &tcptran_dialer_ops, - .tran_listener = &tcptran_listener_ops, - .tran_pipe = &tcptran_pipe_ops, - .tran_init = tcptran_init, - .tran_fini = tcptran_fini, + .tran_dialer = &mqtt_tcptran_dialer_ops, + .tran_listener = &mqtt_tcptran_listener_ops, + .tran_pipe = &mqtt_tcptran_pipe_ops, + .tran_init = mqtt_tcptran_init, + .tran_fini = mqtt_tcptran_fini, }; -static nni_sp_tran tcp6_tran = { +static nni_sp_tran mqtt_tcp6_tran = { .tran_scheme = "mqtt-tcp6", - .tran_dialer = &tcptran_dialer_ops, - .tran_listener = &tcptran_listener_ops, - .tran_pipe = &tcptran_pipe_ops, - .tran_init = tcptran_init, - .tran_fini = tcptran_fini, + .tran_dialer = &mqtt_tcptran_dialer_ops, + .tran_listener = &mqtt_tcptran_listener_ops, + .tran_pipe = &mqtt_tcptran_pipe_ops, + .tran_init = mqtt_tcptran_init, + .tran_fini = mqtt_tcptran_fini, }; #ifndef NNG_ELIDE_DEPRECATED @@ -1258,7 +1266,7 @@ nng_mqtt_tcp_register(void) void nni_mqtt_tcp_register(void) { - nni_sp_tran_register(&tcp_tran); - nni_sp_tran_register(&tcp4_tran); - nni_sp_tran_register(&tcp6_tran); + nni_sp_tran_register(&mqtt_tcp_tran); + nni_sp_tran_register(&mqtt_tcp4_tran); + nni_sp_tran_register(&mqtt_tcp6_tran); } From 08e6812e5334b1d29a05a7461e2fe5584f6fc19c Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Thu, 21 Oct 2021 16:19:01 +0800 Subject: [PATCH 068/180] * FIX [nng/mqtt] definition NNG_TRANSPORT_MQTT_TCP usage --- cmake/NNGOptions.cmake | 2 +- include/nng/transport/{tcp => mqtt}/mqtt_tcp.h | 0 src/sp/transport.c | 4 ++-- src/sp/transport/mqtt/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename include/nng/transport/{tcp => mqtt}/mqtt_tcp.h (100%) diff --git a/cmake/NNGOptions.cmake b/cmake/NNGOptions.cmake index fc0179145..b99bfc936 100644 --- a/cmake/NNGOptions.cmake +++ b/cmake/NNGOptions.cmake @@ -116,7 +116,7 @@ option (NNG_TRANSPORT_TCP "Enable TCP transport." ON) mark_as_advanced(NNG_TRANSPORT_TCP) # TCP transport -option (NNG_TRANSPORT_MQTT_TCP "Enable TCP transport." ON) +option (NNG_TRANSPORT_MQTT_TCP "Enable MQTT TCP transport." ON) mark_as_advanced(NNG_TRANSPORT_MQTT_TCP) # TLS transport diff --git a/include/nng/transport/tcp/mqtt_tcp.h b/include/nng/transport/mqtt/mqtt_tcp.h similarity index 100% rename from include/nng/transport/tcp/mqtt_tcp.h rename to include/nng/transport/mqtt/mqtt_tcp.h diff --git a/src/sp/transport.c b/src/sp/transport.c index e6c967b86..14577716c 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -36,7 +36,7 @@ nni_sp_tran_find(nni_url *url) nni_rwlock_rdlock(&sp_tran_lk); NNI_LIST_FOREACH (&sp_tran_list, t) { - printf("tran %s %s\n", url->u_scheme, t->tran_scheme); + printf("tran %s %s\n", url->u_scheme, t->tran_scheme); if (strcmp(url->u_scheme, t->tran_scheme) == 0) { nni_rwlock_unlock(&sp_tran_lk); return (t); @@ -92,7 +92,7 @@ nni_sp_tran_sys_init(void) #ifdef NNG_TRANSPORT_MQTT_TCP nni_mqtt_tcp_register(); #endif -#ifdef NNG_TRANSPORT_TCP +#ifdef NNG_TRANSPORT_TLS nni_sp_tls_register(); #endif #ifdef NNG_TRANSPORT_WS diff --git a/src/sp/transport/mqtt/CMakeLists.txt b/src/sp/transport/mqtt/CMakeLists.txt index ccce1b8d5..798d3dff6 100644 --- a/src/sp/transport/mqtt/CMakeLists.txt +++ b/src/sp/transport/mqtt/CMakeLists.txt @@ -12,5 +12,5 @@ nng_directory(mqtt) nng_sources_if(NNG_TRANSPORT_MQTT_TCP mqtt_tcp.c) -nng_headers_if(NNG_TRANSPORT_MQTT_TCP nng/transport/tcp/mqtt_tcp.h) +nng_headers_if(NNG_TRANSPORT_MQTT_TCP nng/transport/mqtt/mqtt_tcp.h) nng_defines_if(NNG_TRANSPORT_MQTT_TCP NNG_TRANSPORT_MQTT_TCP) From 58d9bd215b5a81f5d9d02c9849cf9524387eb3a1 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Thu, 21 Oct 2021 16:20:31 +0800 Subject: [PATCH 069/180] * NEW [nng/mqtt] nni_mqtt_msg releated APIs --- .gitmodules | 4 +- CMakeLists.txt | 2 - extern/mqtt-codec | 1 - src/CMakeLists.txt | 1 + src/core/message.c | 3 +- src/core/nng_impl.h | 2 +- src/mqtt/CMakeLists.txt | 25 +++ src/mqtt/mqtt-codec | 1 + src/mqtt/mqtt.c | 464 ++++++++++++++++++++++++++++++++++++++++ src/mqtt/mqtt.h | 103 +++++++++ 10 files changed, 599 insertions(+), 7 deletions(-) delete mode 160000 extern/mqtt-codec create mode 100644 src/mqtt/CMakeLists.txt create mode 160000 src/mqtt/mqtt-codec create mode 100644 src/mqtt/mqtt.c create mode 100644 src/mqtt/mqtt.h diff --git a/.gitmodules b/.gitmodules index 9ad4c7573..6d2640002 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "extern/nng-wolfssl"] path = extern/nng-wolfssl url = https://github.com/staysail/nng-wolfssl -[submodule "extern/mqtt-codec"] - path = extern/mqtt-codec +[submodule "src/mqtt/mqtt-codec"] + path = src/mqtt/mqtt-codec url = https://github.com/nanomq/mqtt-codec.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 335634e0c..ef4c2bc87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -249,8 +249,6 @@ if (NNG_TESTS) set(all_tests, "") endif () -add_subdirectory(extern/mqtt-codec) - add_subdirectory(src) if (NNG_TESTS) diff --git a/extern/mqtt-codec b/extern/mqtt-codec deleted file mode 160000 index 34a395b84..000000000 --- a/extern/mqtt-codec +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 34a395b84a8c32da8a26851234fd4b6065023033 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 20a7bef0c..d010d6ca3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,7 @@ target_include_directories(nng_testing PRIVATE ${PROJECT_SOURCE_DIR}/src) add_subdirectory(core) add_subdirectory(platform) add_subdirectory(compat) +add_subdirectory(mqtt) add_subdirectory(sp) add_subdirectory(supplemental) add_subdirectory(tools) diff --git a/src/core/message.c b/src/core/message.c index d96020884..be12cf838 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -487,7 +487,8 @@ nni_msg_reserve(nni_msg *m, size_t capacity) size_t nni_msg_capacity(nni_msg *m) { - return ((size_t) ((m->m_body.ch_buf + m->m_body.ch_cap) - m->m_body.ch_ptr)); + return ((size_t) ((m->m_body.ch_buf + m->m_body.ch_cap) - + m->m_body.ch_ptr)); } void * diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h index 15db8d160..bcb29e114 100644 --- a/src/core/nng_impl.h +++ b/src/core/nng_impl.h @@ -49,8 +49,8 @@ #include "core/url.h" // transport needs to come after url +#include "mqtt/mqtt.h" #include "sp/transport.h" - // These have to come after the others - particularly transport.h #include "core/dialer.h" diff --git a/src/mqtt/CMakeLists.txt b/src/mqtt/CMakeLists.txt new file mode 100644 index 000000000..7d56a9b4a --- /dev/null +++ b/src/mqtt/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright 2021 Staysail Systems, Inc. +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. +# + +# Core. +nng_directory(mqtt) + +add_subdirectory(mqtt-codec) +include_directories(mqtt-codec/include) + +nng_check_sym(strlcpy string.h NNG_HAVE_STRLCPY) +nng_check_sym(strnlen string.h NNG_HAVE_STRNLEN) +nng_check_sym(strcasecmp string.h NNG_HAVE_STRCASECMP) +nng_check_sym(strncasecmp string.h NNG_HAVE_STRNCASECMP) + +nng_sources( + mqtt.c + mqtt.h +) + diff --git a/src/mqtt/mqtt-codec b/src/mqtt/mqtt-codec new file mode 160000 index 000000000..61dcdacd7 --- /dev/null +++ b/src/mqtt/mqtt-codec @@ -0,0 +1 @@ +Subproject commit 61dcdacd750c65618b1c3c9744c31344e08ad400 diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c new file mode 100644 index 000000000..b218ec27e --- /dev/null +++ b/src/mqtt/mqtt.c @@ -0,0 +1,464 @@ +#include "mqtt.h" +#include + +static int nni_mqtt_msg_free(void *); +static int nni_mqtt_msg_dup(void **, const void *); + +static nni_proto_msg_ops proto_msg_ops = { + + .msg_free = nni_mqtt_msg_free, + + .msg_dup = nni_mqtt_msg_dup +}; + +static int +nni_mqtt_msg_free(void *self) +{ + return mqtt_msg_destroy((mqtt_msg *) self); +} + +static int +nni_mqtt_msg_dup(void **dest, const void *src) +{ + return mqtt_msg_dup((mqtt_msg **) dest, (const mqtt_msg *) src); +} + +int +nni_mqtt_msg_proto_data_alloc(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data; + + if ((proto_data = NNI_ALLOC_STRUCT(proto_data)) == NULL) { + return NNG_ENOMEM; + } + + nni_msg_set_proto_data(msg, &proto_msg_ops, proto_data); + + return 0; +} + +void +nni_mqtt_msg_proto_data_free(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + NNI_FREE_STRUCT(proto_data); +} + +int +nni_mqtt_msg_encode(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + + mqtt_msg_encode(proto_data); + + nni_msg_clear(msg); + + return nni_msg_append(msg, proto_data->entire_raw_msg.buf, + proto_data->entire_raw_msg.length); +} + +int +nni_mqtt_msg_decode(nni_msg *msg) +{ + uint8_t *packet = nni_msg_body(msg); + size_t len = nni_msg_len(msg); + + uint32_t result; + + nni_mqtt_proto_data *proto_data = + mqtt_msg_decode_raw_packet(packet, len, &result, 0); + + if (result != MQTT_SUCCESS) { + return result; + } + + nni_msg_set_proto_data(msg, &proto_msg_ops, proto_data); + + return (0); +} + +int +nni_mqtt_msg_set_packet_type(nni_msg *msg, nni_mqtt_packet_type packet_type) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + + proto_data->fixed_header.common.packet_type = packet_type; + + return 0; +} + +nni_mqtt_packet_type +nni_mqtt_msg_get_packet_type(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + + return proto_data->fixed_header.common.packet_type; +} + +void +nni_mqtt_msg_set_publish_qos(nni_msg *msg, uint8_t qos) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + + proto_data->fixed_header.publish.qos = qos; +} + +uint8_t +nni_mqtt_msg_get_publish_qos(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + + return proto_data->fixed_header.publish.qos; +} + +void +nni_mqtt_msg_set_publish_retain(nni_msg *msg, bool retain) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->fixed_header.publish.retain = (uint8_t) retain; +} + +bool +nni_mqtt_msg_get_publish_retain(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->fixed_header.publish.retain; +} + +void +nni_mqtt_msg_set_publish_dup(nni_msg *msg, bool dup) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->fixed_header.publish.dup = (uint8_t) dup; +} + +bool +nni_mqtt_msg_get_publish_dup(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->fixed_header.publish.dup; +} + +void +nni_mqtt_msg_set_publish_payload(nni_msg *msg, uint8_t *payload, uint32_t len) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.publish.payload.buf = payload; + proto_data->payload.publish.payload.length = len; +} + +uint8_t * +nni_mqtt_msg_get_publish_payload(nni_msg *msg, uint32_t *outlen) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + *outlen = proto_data->payload.publish.payload.length; + return proto_data->payload.publish.payload.buf; +} + +void +nni_mqtt_msg_set_publish_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.publish.packet_id = packet_id; +} + +uint16_t +nni_mqtt_msg_get_publish_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.publish.packet_id; +} + +void +nni_mqtt_msg_set_puback_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.puback.packet_id = packet_id; +} + +uint16_t +nni_mqtt_msg_get_puback_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.puback.packet_id; +} + +uint16_t +nni_mqtt_msg_get_pubrec_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.pubrec.packet_id; +} + +void +nni_mqtt_msg_set_pubrec_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.pubrec.packet_id = packet_id; +} + +uint16_t +nni_mqtt_msg_get_pubrel_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.pubrel.packet_id; +} + +void +nni_mqtt_msg_set_pubrel_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.pubrel.packet_id = packet_id; +} + +uint16_t +nni_mqtt_msg_get_pubcomp_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.pubcomp.packet_id; +} + +void +nni_mqtt_msg_set_pubcomp_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.pubcomp.packet_id = packet_id; +} + +uint16_t +nni_mqtt_msg_get_subscribe_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.subscribe.packet_id; +} + +void +nni_mqtt_msg_set_subscribe_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.subscribe.packet_id = packet_id; +} + +void +nni_mqtt_msg_set_subscribe_topics( + nni_msg *msg, nni_mqtt_topic *topic, uint32_t topic_count) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.subscribe.topic_arr = topic; + proto_data->payload.subscribe.topic_count = topic_count; +} + +nni_mqtt_topic * +nni_mqtt_msg_get_subscribe_topics(nni_msg *msg, uint32_t *topic_count) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + *topic_count = proto_data->payload.subscribe.topic_count; + return proto_data->payload.subscribe.topic_arr; +} + +uint16_t +nni_mqtt_msg_get_suback_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.suback.packet_id; +} + +void +nni_mqtt_msg_set_suback_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.suback.packet_id = packet_id; +} + +void +nni_mqtt_msg_set_suback_return_codes( + nni_msg *msg, uint8_t *ret_codes, uint32_t ret_codes_count) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.suback.ret_code_arr = ret_codes; + proto_data->payload.suback.ret_code_count = ret_codes_count; +} + +uint8_t * +nni_mqtt_msg_get_suback_return_codes(nni_msg *msg, uint32_t *ret_codes_count) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + *ret_codes_count = proto_data->payload.suback.ret_code_count; + return proto_data->payload.suback.ret_code_arr; +} + +uint16_t +nni_mqtt_msg_get_unsubscribe_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.unsubscribe.packet_id; +} + +void +nni_mqtt_msg_set_unsubscribe_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.unsubscribe.packet_id = packet_id; +} + +void +nni_mqtt_msg_set_unsubscribe_topics( + nni_msg *msg, nni_mqtt_buffer *topic, uint32_t topic_count) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.unsubscribe.topic_arr = (nni_mqtt_buffer *) topic; + proto_data->payload.unsubscribe.topic_count = topic_count; +} + +nni_mqtt_buffer * +nni_mqtt_msg_get_unsubscribe_topics(nni_msg *msg, uint32_t *topic_count) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + *topic_count = proto_data->payload.unsubscribe.topic_count; + return (nni_mqtt_buffer *) proto_data->payload.unsubscribe.topic_arr; +} + +void +nni_mqtt_msg_set_unsuback_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.unsuback.packet_id = packet_id; +} + +uint16_t +nni_mqtt_msg_get_unsuback_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.unsuback.packet_id; +} + +void +nni_mqtt_msg_set_connect_proto_version(nni_msg *msg, uint8_t version) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.connect.protocol_version = version; +} + +void +nni_mqtt_msg_set_connect_keep_alive(nni_msg *msg, uint16_t keep_alive) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.connect.keep_alive = keep_alive; +} + +uint8_t +nni_mqtt_msg_get_connect_proto_version(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.connect.protocol_version; +} + +uint16_t +nni_mqtt_msg_get_connect_keep_alive(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.connect.keep_alive; +} + +void +nni_mqtt_msg_set_connect_client_id(nni_msg *msg, const char *client_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.connect.client_id.buf = (uint8_t *) client_id; + proto_data->payload.connect.client_id.length = strlen(client_id); +} + +void +nni_mqtt_msg_set_connect_will_topic(nni_msg *msg, const char *will_topic) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.connect.will_topic.buf = (uint8_t *) will_topic; + proto_data->payload.connect.will_topic.length = strlen(will_topic); +} + +void +nni_mqtt_msg_set_connect_will_msg(nni_msg *msg, const char *will_msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.connect.will_msg.buf = (uint8_t *) will_msg; + proto_data->payload.connect.will_msg.length = strlen(will_msg); +} + +void +nni_mqtt_msg_set_connect_user_name(nni_msg *msg, const char *user_name) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.connect.user_name.buf = (uint8_t *) user_name; + proto_data->payload.connect.user_name.length = strlen(user_name); +} + +void +nni_mqtt_msg_set_connect_password(nni_msg *msg, const char *password) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->payload.connect.password.buf = (uint8_t *) password; + proto_data->payload.connect.password.length = strlen(password); +} + +const char * +nni_mqtt_msg_get_connect_client_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return (const char *) proto_data->payload.connect.client_id.buf; +} + +const char * +nni_mqtt_msg_get_connect_will_topic(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return (const char *) proto_data->payload.connect.will_topic.buf; +} + +const char * +nni_mqtt_msg_get_connect_will_msg(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return (const char *) proto_data->payload.connect.will_msg.buf; +} + +const char * +nni_mqtt_msg_get_connect_user_name(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return (const char *) proto_data->payload.connect.user_name.buf; +} + +const char * +nni_mqtt_msg_get_connect_password(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return (const char *) proto_data->payload.connect.password.buf; +} + +void +nni_mqtt_msg_set_conack_return_code(nni_msg *msg, uint8_t code) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.connack.conn_return_code = code; +} + +void +nni_mqtt_msg_set_conack_flags(nni_msg *msg, uint8_t flags) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.connack.connack_flags = flags; +} + +uint8_t +nni_mqtt_msg_get_conack_return_code(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.connack.conn_return_code; +} + +uint8_t +nni_mqtt_msg_get_conack_flags(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.connack.connack_flags; +} diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h new file mode 100644 index 000000000..ac79ac9f1 --- /dev/null +++ b/src/mqtt/mqtt.h @@ -0,0 +1,103 @@ +#ifndef MQTT_MQTT_H +#define MQTT_MQTT_H + +#include "core/nng_impl.h" +#include "mqtt-codec/include/mqtt_codec.h" + +typedef mqtt_msg nni_mqtt_proto_data; +typedef mqtt_packet_type nni_mqtt_packet_type; +typedef union mqtt_payload nni_mqtt_payload; +typedef mqtt_topic nni_mqtt_topic; +typedef mqtt_buf_t nni_mqtt_buffer; + +// nni_msg proto_data alloc/free +extern int nni_mqtt_msg_proto_data_alloc(nni_msg *); +extern void nni_mqtt_msg_proto_data_free(nni_msg *); + +// mqtt message encode/decode +extern int nni_mqtt_msg_encode(nni_msg *); +extern int nni_mqtt_msg_decode(nni_msg *); + +// mqtt packet_type +extern int nni_mqtt_msg_set_packet_type( + nni_msg *, nni_mqtt_packet_type packet_type); +extern nni_mqtt_packet_type nni_mqtt_msg_get_packet_type(nni_msg *); + +// mqtt connect +extern void nni_mqtt_msg_set_connect_proto_version(nni_msg *, uint8_t); +extern void nni_mqtt_msg_set_connect_keep_alive(nni_msg *, uint16_t); +extern void nni_mqtt_msg_set_connect_client_id(nni_msg *, const char *); +extern void nni_mqtt_msg_set_connect_will_topic(nni_msg *, const char *); +extern void nni_mqtt_msg_set_connect_will_msg(nni_msg *, const char *); +extern void nni_mqtt_msg_set_connect_user_name(nni_msg *, const char *); +extern void nni_mqtt_msg_set_connect_password(nni_msg *, const char *); +extern uint8_t nni_mqtt_msg_get_connect_proto_version(nni_msg *); +extern uint16_t nni_mqtt_msg_get_connect_keep_alive(nni_msg *); +extern const char *nni_mqtt_msg_get_connect_client_id(nni_msg *); +extern const char *nni_mqtt_msg_get_connect_will_topic(nni_msg *); +extern const char *nni_mqtt_msg_get_connect_will_msg(nni_msg *); +extern const char *nni_mqtt_msg_get_connect_user_name(nni_msg *); +extern const char *nni_mqtt_msg_get_connect_password(nni_msg *); + +// mqtt conack +extern void nni_mqtt_msg_set_conack_return_code(nni_msg *, uint8_t); +extern void nni_mqtt_msg_set_conack_flags(nni_msg *, uint8_t); +extern uint8_t nni_mqtt_msg_get_conack_return_code(nni_msg *); +extern uint8_t nni_mqtt_msg_get_conack_flags(nni_msg *); + +// mqtt publish +extern void nni_mqtt_msg_set_publish_qos(nni_msg *, uint8_t); +extern uint8_t nni_mqtt_msg_get_publish_qos(nni_msg *); +extern void nni_mqtt_msg_set_publish_retain(nni_msg *, bool); +extern bool nni_mqtt_msg_get_publish_retain(nni_msg *); +extern void nni_mqtt_msg_set_publish_dup(nni_msg *, bool); +extern bool nni_mqtt_msg_get_publish_dup(nni_msg *); +extern void nni_mqtt_msg_set_publish_packet_id(nni_msg *, uint16_t); +extern uint16_t nni_mqtt_msg_get_publish_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_publish_payload(nni_msg *, uint8_t *, uint32_t); +extern uint8_t *nni_mqtt_msg_get_publish_payload(nni_msg *, uint32_t *); + +// mqtt puback +extern uint16_t nni_mqtt_msg_get_puback_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_puback_packet_id(nni_msg *, uint16_t); + +// mqtt pubrec +extern uint16_t nni_mqtt_msg_get_pubrec_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_pubrec_packet_id(nni_msg *, uint16_t); + +// mqtt pubrel +extern uint16_t nni_mqtt_msg_get_pubrel_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_pubrel_packet_id(nni_msg *, uint16_t); + +// mqtt pubcomp +extern uint16_t nni_mqtt_msg_get_pubcomp_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_pubcomp_packet_id(nni_msg *, uint16_t); + +// mqtt subscribe +extern uint16_t nni_mqtt_msg_get_subscribe_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_subscribe_packet_id(nni_msg *, uint16_t); +extern void nni_mqtt_msg_set_subscribe_topics( + nni_msg *, nni_mqtt_topic *, uint32_t); +extern nni_mqtt_topic *nni_mqtt_msg_get_subscribe_topics( + nni_msg *, uint32_t *); + +// mqtt suback +extern uint16_t nni_mqtt_msg_get_suback_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_suback_packet_id(nni_msg *, uint16_t); +extern void nni_mqtt_msg_set_suback_return_codes( + nni_msg *, uint8_t *, uint32_t); +extern uint8_t *nni_mqtt_msg_get_suback_return_codes(nni_msg *, uint32_t *); + +// mqtt unsubscribe +extern uint16_t nni_mqtt_msg_get_unsubscribe_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_unsubscribe_packet_id(nni_msg *, uint16_t); +extern void nni_mqtt_msg_set_unsubscribe_topics( + nni_msg *, nni_mqtt_buffer *, uint32_t); +extern nni_mqtt_buffer *nni_mqtt_msg_get_unsubscribe_topics( + nni_msg *, uint32_t *); + +// mqtt unsuback +extern void nni_mqtt_msg_set_unsuback_packet_id(nni_msg *, uint16_t); +extern uint16_t nni_mqtt_msg_get_unsuback_packet_id(nni_msg *); + +#endif \ No newline at end of file From 595c0406aa2c41d1c9d23c89c5ca3b2cb0898f04 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Sun, 3 Oct 2021 11:01:46 +0800 Subject: [PATCH 070/180] * NEW [nano_tcp] msg cache/restore in clean session is supported. --- src/core/sockimpl.h | 1 + src/sp/protocol/reqrep0/nano_tcp.c | 37 ++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/core/sockimpl.h b/src/core/sockimpl.h index 35fcf192c..9fcb656aa 100644 --- a/src/core/sockimpl.h +++ b/src/core/sockimpl.h @@ -125,6 +125,7 @@ struct nni_pipe { // NanoMQ void * conn_param; uint16_t packet_id; + // TODO turn map to msgqueue nni_id_map *nano_qos_db; // storing qos backup msgs }; diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 5df46ff6b..42beebacd 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -525,6 +525,11 @@ nano_pipe_start(void *arg) nni_msg * msg; uint8_t rv, *reason; // reason code of CONNACK uint8_t buf[4] = { 0x20, 0x02, 0x00, 0x00 }; + nni_pipe * npipe = p->pipe; + char * clientid = NULL; + uint32_t clientid_key = 0; + nni_msg ** msgq = NULL; + uint16_t pid = 0; debug_msg("##########nano_pipe_start################"); /* @@ -549,6 +554,17 @@ nano_pipe_start(void *arg) } nni_mtx_unlock(&s->lk); + // restore cached qos msg + clientid = (char *) conn_param_get_clientid(p->conn_param); + clientid_key = DJBHashn(clientid, strlen(clientid)); + if (cached_check_id(clientid_key)) { + msgq = (nni_msg **)dbtree_restore_session_msg(p->tree, clientid_key); + for(int i=0; i< (int) cvector_size(msgq); i++) { + pid = nni_pipe_inc_packetid(npipe); + nni_id_set(npipe->nano_qos_db, pid, msgq[i]); + } + } + // TODO MQTT V5 check return code if (*(reason + 1) == 0) { nni_sleep_aio(s->conf->qos_timer * 1500, &p->aio_timer); @@ -600,14 +616,27 @@ nano_pipe_close(void *arg) nano_pipe *p = arg; nano_sock *s = p->rep; nano_ctx * ctx; - // conn_param *cparam; - nni_aio *aio = NULL; - nni_msg *msg; + nni_aio * aio = NULL; + nni_msg * msg; + nni_pipe * npipe = p->pipe; + uint16_t packetid = 0; + char * clientid = NULL; + uint32_t clientid_key = 0; debug_msg("################# nano_pipe_close ##############"); nni_mtx_lock(&s->lk); close_pipe(p); + // cache qos msg TODO optimization in processing + if (p->conn_param->clean_start == 0) { + clientid = (char *)conn_param_get_clientid(p->conn_param); + clientid_key = DJBHashn(clientid, strlen(clientid)); + while((msg = nni_id_get_any(npipe->nano_qos_db, &packetid)) != NULL) { + dbtree_cache_session_msg(p->tree, msg, clientid_key); + nni_id_remove(npipe->nano_qos_db, packetid); + } + } + // create disconnect event msg msg = nano_msg_notify_disconnect(p->conn_param, p->reason_code); if (msg == NULL) { @@ -1015,4 +1044,4 @@ nng_nano_tcp0_open(nng_socket *sidp) { // TODO Global binary tree init here return (nni_proto_mqtt_open(sidp, &nano_tcp_proto, nano_sock_setdb)); -} \ No newline at end of file +} From 07f0d20f77a0ddeed3493b81feff5002bd6aded1 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Thu, 14 Oct 2021 15:37:32 +0800 Subject: [PATCH 071/180] * FIX [nano_tcp] rename variable qos_timer as qos_duration. --- src/sp/protocol/reqrep0/nano_tcp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 42beebacd..2bdcf159e 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -174,7 +174,7 @@ static void nano_pipe_timer_cb(void *arg) { nano_pipe *p = arg; - int qos_timer = p->rep->conf->qos_timer; + int qos_duration = p->rep->conf->qos_duration; nni_msg * msg, *rmsg; nni_time time; nni_pipe * npipe = p->pipe; @@ -185,7 +185,7 @@ nano_pipe_timer_cb(void *arg) return; } nni_mtx_lock(&p->lk); - if (p->ka_refresh * (qos_timer) > p->conn_param->keepalive_mqtt) { + if (p->ka_refresh * (qos_duration) > p->conn_param->keepalive_mqtt) { nni_println("Warning: close pipe & kick client due to KeepAlive " "timeout!"); // TODO check keepalived timer interval @@ -202,7 +202,7 @@ nano_pipe_timer_cb(void *arg) rmsg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); time = nni_msg_get_timestamp(msg); if ((nni_clock() - time) >= - (long unsigned) qos_timer * 1250) { + (long unsigned) qos_duration * 1250) { p->busy = true; //TODO set max retrying times in nanomq.conf nni_msg_clone(rmsg); @@ -217,7 +217,7 @@ nano_pipe_timer_cb(void *arg) } nni_mtx_unlock(&p->lk); - nni_sleep_aio(qos_timer * 1000, &p->aio_timer); + nni_sleep_aio(qos_duration * 1000, &p->aio_timer); return; } @@ -567,7 +567,7 @@ nano_pipe_start(void *arg) // TODO MQTT V5 check return code if (*(reason + 1) == 0) { - nni_sleep_aio(s->conf->qos_timer * 1500, &p->aio_timer); + nni_sleep_aio(s->conf->qos_duration * 1500, &p->aio_timer); } nni_msg_set_cmd_type(msg, CMD_CONNACK); nni_msg_set_conn_param(msg, p->conn_param); From ebf8889ff9db817e6219eec78d0bd590b0b9e78a Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Thu, 21 Oct 2021 18:07:56 +0800 Subject: [PATCH 072/180] * FIX [nano_tcp] fix the memleak about cached msg --- src/sp/protocol/reqrep0/nano_tcp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 2bdcf159e..4863c237d 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -563,6 +563,7 @@ nano_pipe_start(void *arg) pid = nni_pipe_inc_packetid(npipe); nni_id_set(npipe->nano_qos_db, pid, msgq[i]); } + cvector_free(msgq); } // TODO MQTT V5 check return code From f4f6b5a0baf2fb4f5bc74382a139b3ab53a036fe Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Fri, 22 Oct 2021 16:14:56 +0800 Subject: [PATCH 073/180] * FIX [nano_tcp] make cached msg unique, it ensures no leaks exists. --- src/sp/protocol/reqrep0/nano_tcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 4863c237d..37a8a4e06 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -633,6 +633,8 @@ nano_pipe_close(void *arg) clientid = (char *)conn_param_get_clientid(p->conn_param); clientid_key = DJBHashn(clientid, strlen(clientid)); while((msg = nni_id_get_any(npipe->nano_qos_db, &packetid)) != NULL) { + while(nni_msg_shared(msg)) + nni_msg_free(msg); dbtree_cache_session_msg(p->tree, msg, clientid_key); nni_id_remove(npipe->nano_qos_db, packetid); } From 8f0cccd562a8073902faedeb945c5b9a2338e905 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Tue, 26 Oct 2021 14:51:36 +0800 Subject: [PATCH 074/180] New [nng/mqtt] mqtt msg related APIs 1. Add nng_mqtt_msg related APIs 2. Fix mqtt-codec cmake build --- .gitmodules | 10 +- CMakeLists.txt | 6 + demo/async/CMakeLists.txt | 3 +- include/nng/nng.h | 82 +++++++- src/core/message_test.c | 90 +++++++- src/core/nng_impl.h | 2 + src/mqtt/.gitignore | 1 + src/mqtt/CMakeLists.txt | 5 +- src/mqtt/mqtt.c | 142 ++++++++++++- src/mqtt/mqtt.h | 61 ++++-- src/nng.c | 428 ++++++++++++++++++++++++++++++++++++++ 11 files changed, 786 insertions(+), 44 deletions(-) create mode 100644 src/mqtt/.gitignore diff --git a/.gitmodules b/.gitmodules index 6d2640002..083f49f33 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "extern/nng-wolfssl"] - path = extern/nng-wolfssl - url = https://github.com/staysail/nng-wolfssl -[submodule "src/mqtt/mqtt-codec"] - path = src/mqtt/mqtt-codec - url = https://github.com/nanomq/mqtt-codec.git +path = extern/nng-wolfssl +url = https://github.com/staysail/nng-wolfssl +[submodule "extern/mqtt-codec"] +path = extern/mqtt-codec +url = https://github.com/nanomq/mqtt-codec.git diff --git a/CMakeLists.txt b/CMakeLists.txt index ef4c2bc87..f25a1605b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,12 @@ if (NOT (BUILD_SHARED_LIBS)) message(STATUS "Building static libs.") endif () +configure_file(${CMAKE_SOURCE_DIR}/extern/mqtt-codec/src/mqtt_codec.c + ${CMAKE_SOURCE_DIR}/src/mqtt/mqtt_codec.c COPYONLY) + +configure_file(${CMAKE_SOURCE_DIR}/extern/mqtt-codec/src/mqtt_codec.h + ${CMAKE_SOURCE_DIR}/src/mqtt/mqtt_codec.h COPYONLY) + # These are library targets. The "nng" library is the main public library. # The "nng_testing" is a full build of the library for test cases # only, which is done statically and includes even portions of the code diff --git a/demo/async/CMakeLists.txt b/demo/async/CMakeLists.txt index 614bcfc3b..736829e73 100644 --- a/demo/async/CMakeLists.txt +++ b/demo/async/CMakeLists.txt @@ -15,10 +15,11 @@ set(PARALLEL 128 CACHE STRING "Parallelism (min 4, max 1000)") # Call this from your own project's makefile. find_package(nng CONFIG REQUIRED) +find_package(Threads) add_executable(server server.c) target_link_libraries(server nng::nng) target_compile_definitions(server PRIVATE -DPARALLEL=${PARALLEL}) add_executable(client client.c) -target_link_libraries(client nng::nng) +target_link_libraries(client nng::nng) \ No newline at end of file diff --git a/include/nng/nng.h b/include/nng/nng.h index cd75495a6..195fc249a 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -659,7 +659,7 @@ NNG_DECL nng_dialer nng_pipe_dialer(nng_pipe); NNG_DECL nng_listener nng_pipe_listener(nng_pipe); // Flags. -#define NNG_FLAG_ALLOC 1u // Recv to allocate receive buffer +#define NNG_FLAG_ALLOC 1u // Recv to allocate receive buffer #define NNG_FLAG_NONBLOCK 2u // Non-blocking operations // Options. @@ -1179,7 +1179,6 @@ NNG_DECL int nng_stream_listener_set_ptr( NNG_DECL int nng_stream_listener_set_addr( nng_stream_listener *, const char *, const nng_sockaddr *); - #ifndef NNG_ELIDE_DEPRECATED // These are legacy APIs that have been deprecated. // Their use is strongly discouraged. @@ -1277,6 +1276,85 @@ NNG_DECL int nng_pipe_getopt_string(nng_pipe, const char *, char **); // a library; it will affect all sockets. NNG_DECL void nng_closeall(void); +typedef enum { + NNG_MQTT_CONNECT = 0x01, + NNG_MQTT_CONNACK = 0x02, + NNG_MQTT_PUBLISH = 0x03, + NNG_MQTT_PUBACK = 0x04, + NNG_MQTT_PUBREC = 0x05, + NNG_MQTT_PUBREL = 0x06, + NNG_MQTT_PUBCOMP = 0x07, + NNG_MQTT_SUBSCRIBE = 0x08, + NNG_MQTT_SUBACK = 0x09, + NNG_MQTT_UNSUBSCRIBE = 0x0A, + NNG_MQTT_UNSUBACK = 0x0B, + NNG_MQTT_PINGREQ = 0x0C, + NNG_MQTT_PINGRESP = 0x0D, + NNG_MQTT_DISCONNECT = 0x0E, + NNG_MQTT_AUTH = 0x0F +} nng_mqtt_packet_type; + +typedef struct mqtt_buf_t nng_mqtt_buffer; +typedef struct mqtt_buf_t nng_mqtt_topic; +typedef struct mqtt_topic_qos_t nng_mqtt_topic_qos; + +NNG_DECL int nng_mqtt_msg_alloc(nng_msg **msg, size_t sz); +NNG_DECL int nng_mqtt_msg_encode(nng_msg *); +NNG_DECL int nng_mqtt_msg_decode(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_packet_type(nng_msg *, nng_mqtt_packet_type); +NNG_DECL nng_mqtt_packet_type nng_mqtt_msg_get_packet_type(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_connect_proto_version(nng_msg *, uint8_t); +NNG_DECL void nng_mqtt_msg_set_connect_keep_alive(nng_msg *, uint16_t); +NNG_DECL void nng_mqtt_msg_set_connect_client_id(nng_msg *, const char *); +NNG_DECL void nng_mqtt_msg_set_connect_will_topic(nng_msg *, const char *); +NNG_DECL void nng_mqtt_msg_set_connect_will_msg(nng_msg *, const char *); +NNG_DECL void nng_mqtt_msg_set_connect_user_name(nng_msg *, const char *); +NNG_DECL void nng_mqtt_msg_set_connect_password(nng_msg *, const char *); +NNG_DECL void nng_mqtt_msg_set_connect_clean_session(nng_msg *, bool); +NNG_DECL void nng_mqtt_msg_set_connect_will_retain(nng_msg *, bool); +NNG_DECL bool nng_mqtt_msg_get_connect_clean_session(nng_msg *); +NNG_DECL bool nng_mqtt_msg_get_connect_will_retain(nng_msg *); +NNG_DECL uint8_t nng_mqtt_msg_get_connect_proto_version(nng_msg *); +NNG_DECL uint16_t nng_mqtt_msg_get_connect_keep_alive(nng_msg *); +NNG_DECL const char *nng_mqtt_msg_get_connect_client_id(nng_msg *); +NNG_DECL const char *nng_mqtt_msg_get_connect_will_topic(nng_msg *); +NNG_DECL const char *nng_mqtt_msg_get_connect_will_msg(nng_msg *); +NNG_DECL const char *nng_mqtt_msg_get_connect_user_name(nng_msg *); +NNG_DECL const char *nng_mqtt_msg_get_connect_password(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_conack_return_code(nng_msg *, uint8_t); +NNG_DECL void nng_mqtt_msg_set_conack_flags(nng_msg *, uint8_t); +NNG_DECL uint8_t nng_mqtt_msg_get_conack_return_code(nng_msg *); +NNG_DECL uint8_t nng_mqtt_msg_get_conack_flags(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_publish_qos(nng_msg *, uint8_t); +NNG_DECL uint8_t nng_mqtt_msg_get_publish_qos(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_publish_retain(nng_msg *, bool); +NNG_DECL bool nng_mqtt_msg_get_publish_retain(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_publish_dup(nng_msg *, bool); +NNG_DECL bool nng_mqtt_msg_get_publish_dup(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_publish_topic(nng_msg *, const char *); +NNG_DECL const char *nng_mqtt_msg_get_publish_topic(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_publish_payload(nng_msg *, uint8_t *, uint32_t); +NNG_DECL uint8_t *nng_mqtt_msg_get_publish_payload(nng_msg *, uint32_t *); +NNG_DECL nng_mqtt_topic_qos *nng_mqtt_msg_get_subscribe_topics( + nng_msg *, uint32_t *); +NNG_DECL void nng_mqtt_msg_set_subscribe_topics( + nng_msg *, nng_mqtt_topic_qos *, uint32_t); +NNG_DECL void nng_mqtt_msg_set_suback_return_codes( + nng_msg *, uint8_t *, uint32_t); +NNG_DECL uint8_t *nng_mqtt_msg_get_suback_return_codes(nng_msg *, uint32_t *); +NNG_DECL void nng_mqtt_msg_set_unsubscribe_topics( + nng_msg *, nng_mqtt_topic *, uint32_t); +NNG_DECL nng_mqtt_topic *nng_mqtt_msg_get_unsubscribe_topics( + nng_msg *, uint32_t *); +NNG_DECL nng_mqtt_topic *nng_mqtt_topic_array_create(size_t); +NNG_DECL void nng_mqtt_topic_array_set(nng_mqtt_topic *, size_t, const char *); +NNG_DECL void nng_mqtt_topic_free(nng_mqtt_topic *); +NNG_DECL nng_mqtt_topic_qos *nng_mqtt_topic_qos_array_create(size_t); +NNG_DECL void nng_mqtt_topic_qos_array_set( + nng_mqtt_topic_qos *, size_t, const char *, uint8_t); +NNG_DECL void nng_mqtt_topic_qos_array_free(nng_mqtt_topic_qos *, size_t); +NNG_DECL void nng_mqtt_msg_dump(nng_msg *, uint8_t *, uint32_t, bool); + #endif #ifdef __cplusplus diff --git a/src/core/message_test.c b/src/core/message_test.c index 0f9204996..7ab0615d9 100644 --- a/src/core/message_test.c +++ b/src/core/message_test.c @@ -522,6 +522,87 @@ test_msg_reserve(void) nng_msg_free(msg); } +void +test_msg_mqtt_alloc(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_msg_free(msg); +} + +void +test_msg_mqtt_encode_connect(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); + + nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); + NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), + "nanomq-mqtt") == 0); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + +void +test_msg_mqtt_encode_subscribe(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); + + size_t sz = 2; + nng_mqtt_topic_qos *topic_qos = nng_mqtt_topic_qos_array_create(sz); + nng_mqtt_topic_qos_array_set(topic_qos, 0, "/nanomq/mqtt/msg/0", 1); + nng_mqtt_topic_qos_array_set(topic_qos, 1, "/nanomq/mqtt/msg/1", 1); + + nng_mqtt_msg_set_subscribe_topics(msg, topic_qos, sz); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + +void +test_msg_mqtt_encode_unsubscribe(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); + + size_t sz = 2; + nng_mqtt_topic *topic_qos = nng_mqtt_topic_array_create(sz); + nng_mqtt_topic_array_set(topic_qos, 0, "/nanomq/mqtt/1"); + nng_mqtt_topic_array_set(topic_qos, 1, "/nanomq/mqtt/2"); + + nng_mqtt_msg_set_unsubscribe_topics(msg, topic_qos, sz); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + TEST_LIST = { { "msg option", test_msg_option }, { "msg empty", test_msg_empty }, @@ -541,13 +622,16 @@ TEST_LIST = { { "msg dup", test_msg_dup }, { "msg dup pipe", test_msg_dup_pipe }, { "msg body u16", test_msg_body_uint16 }, - { "msg header u16", test_msg_body_uint16 }, { "msg header u32", test_msg_header_uint16 }, { "msg body u32", test_msg_body_uint32 }, { "msg header u32", test_msg_header_uint32 }, - { "msg body u32", test_msg_body_uint64 }, - { "msg header u32", test_msg_header_uint64 }, + { "msg body u64", test_msg_body_uint64 }, + { "msg header u64", test_msg_header_uint64 }, { "msg capacity", test_msg_capacity }, { "msg reserve", test_msg_reserve }, + { "msg mqtt msg alloc", test_msg_mqtt_alloc }, + { "msg mqtt encode connect", test_msg_mqtt_encode_connect }, + { "msg mqtt encode subscribe", test_msg_mqtt_encode_subscribe }, + { "msg mqtt encode unsubscribe", test_msg_mqtt_encode_unsubscribe }, { NULL, NULL }, }; diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h index bcb29e114..78d6a7e6e 100644 --- a/src/core/nng_impl.h +++ b/src/core/nng_impl.h @@ -49,6 +49,8 @@ #include "core/url.h" // transport needs to come after url +#include "mqtt/mqtt_codec.h" + #include "mqtt/mqtt.h" #include "sp/transport.h" // These have to come after the others - particularly transport.h diff --git a/src/mqtt/.gitignore b/src/mqtt/.gitignore new file mode 100644 index 000000000..9252d1609 --- /dev/null +++ b/src/mqtt/.gitignore @@ -0,0 +1 @@ +mqtt_codec.* diff --git a/src/mqtt/CMakeLists.txt b/src/mqtt/CMakeLists.txt index 7d56a9b4a..943adb200 100644 --- a/src/mqtt/CMakeLists.txt +++ b/src/mqtt/CMakeLists.txt @@ -10,9 +10,6 @@ # Core. nng_directory(mqtt) -add_subdirectory(mqtt-codec) -include_directories(mqtt-codec/include) - nng_check_sym(strlcpy string.h NNG_HAVE_STRLCPY) nng_check_sym(strnlen string.h NNG_HAVE_STRNLEN) nng_check_sym(strcasecmp string.h NNG_HAVE_STRCASECMP) @@ -21,5 +18,7 @@ nng_check_sym(strncasecmp string.h NNG_HAVE_STRNCASECMP) nng_sources( mqtt.c mqtt.h + mqtt_codec.c + mqtt_codec.h ) diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index b218ec27e..5543d9a3d 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -44,6 +44,22 @@ nni_mqtt_msg_proto_data_free(nni_msg *msg) NNI_FREE_STRUCT(proto_data); } +int +nni_mqtt_msg_alloc(nni_msg **msg, size_t sz) +{ + int rv; + + if ((rv = nni_msg_alloc(msg, sz)) != 0) { + return rv; + } + + if ((rv = nni_mqtt_msg_proto_data_alloc(*msg)) != 0) { + return rv; + } + + return (0); +} + int nni_mqtt_msg_encode(nni_msg *msg) { @@ -62,7 +78,6 @@ nni_mqtt_msg_decode(nni_msg *msg) { uint8_t *packet = nni_msg_body(msg); size_t len = nni_msg_len(msg); - uint32_t result; nni_mqtt_proto_data *proto_data = @@ -77,14 +92,12 @@ nni_mqtt_msg_decode(nni_msg *msg) return (0); } -int +void nni_mqtt_msg_set_packet_type(nni_msg *msg, nni_mqtt_packet_type packet_type) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); proto_data->fixed_header.common.packet_type = packet_type; - - return 0; } nni_mqtt_packet_type @@ -139,6 +152,21 @@ nni_mqtt_msg_get_publish_dup(nni_msg *msg) return proto_data->fixed_header.publish.dup; } +void +nni_mqtt_msg_set_publish_topic(nni_msg *msg, const char *topic) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.publish.topic_name.buf = (uint8_t *) topic; + proto_data->var_header.publish.topic_name.length = strlen(topic); +} + +const char * +nni_mqtt_msg_get_publish_topic(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return (const char *) proto_data->var_header.publish.topic_name.buf; +} + void nni_mqtt_msg_set_publish_payload(nni_msg *msg, uint8_t *payload, uint32_t len) { @@ -241,14 +269,14 @@ nni_mqtt_msg_set_subscribe_packet_id(nni_msg *msg, uint16_t packet_id) void nni_mqtt_msg_set_subscribe_topics( - nni_msg *msg, nni_mqtt_topic *topic, uint32_t topic_count) + nni_msg *msg, nni_mqtt_topic_qos *topic, uint32_t topic_count) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); proto_data->payload.subscribe.topic_arr = topic; proto_data->payload.subscribe.topic_count = topic_count; } -nni_mqtt_topic * +nni_mqtt_topic_qos * nni_mqtt_msg_get_subscribe_topics(nni_msg *msg, uint32_t *topic_count) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); @@ -303,19 +331,19 @@ nni_mqtt_msg_set_unsubscribe_packet_id(nni_msg *msg, uint16_t packet_id) void nni_mqtt_msg_set_unsubscribe_topics( - nni_msg *msg, nni_mqtt_buffer *topic, uint32_t topic_count) + nni_msg *msg, nni_mqtt_topic *topic, uint32_t topic_count) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.unsubscribe.topic_arr = (nni_mqtt_buffer *) topic; + proto_data->payload.unsubscribe.topic_arr = (nni_mqtt_topic *) topic; proto_data->payload.unsubscribe.topic_count = topic_count; } -nni_mqtt_buffer * +nni_mqtt_topic * nni_mqtt_msg_get_unsubscribe_topics(nni_msg *msg, uint32_t *topic_count) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); *topic_count = proto_data->payload.unsubscribe.topic_count; - return (nni_mqtt_buffer *) proto_data->payload.unsubscribe.topic_arr; + return (nni_mqtt_topic *) proto_data->payload.unsubscribe.topic_arr; } void @@ -332,6 +360,21 @@ nni_mqtt_msg_get_unsuback_packet_id(nni_msg *msg) return proto_data->var_header.unsuback.packet_id; } +void +nni_mqtt_msg_set_connect_clean_session(nni_msg *msg, bool clean_session) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.connect.conn_flags.clean_session = + clean_session; +} + +void +nni_mqtt_msg_set_connect_will_retain(nni_msg *msg, bool will_retain) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + proto_data->var_header.connect.conn_flags.will_retain = will_retain; +} + void nni_mqtt_msg_set_connect_proto_version(nni_msg *msg, uint8_t version) { @@ -346,6 +389,20 @@ nni_mqtt_msg_set_connect_keep_alive(nni_msg *msg, uint16_t keep_alive) proto_data->var_header.connect.keep_alive = keep_alive; } +bool +nni_mqtt_msg_get_connect_clean_session(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.connect.conn_flags.clean_session; +} + +bool +nni_mqtt_msg_get_connect_will_retain(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + return proto_data->var_header.connect.conn_flags.will_retain; +} + uint8_t nni_mqtt_msg_get_connect_proto_version(nni_msg *msg) { @@ -462,3 +519,68 @@ nni_mqtt_msg_get_conack_flags(nni_msg *msg) nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); return proto_data->var_header.connack.connack_flags; } + +void +nni_mqtt_msg_dump( + nni_msg *msg, uint8_t *buffer, uint32_t len, bool print_bytes) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + + mqtt_buf mqbuf; + mqbuf.buf = buffer; + mqbuf.length = len; + + mqtt_msg_dump(proto_data, &mqbuf, print_bytes); +} + +nni_mqtt_topic * +nni_mqtt_topic_array_create(size_t n) +{ + nni_mqtt_topic *topic; + topic = (nni_mqtt_topic *) NNI_ALLOC_STRUCTS(topic, n); + return topic; +} + +void +nni_mqtt_topic_array_set( + nni_mqtt_topic *topic, size_t index, const char *topic_name) +{ + topic[index].buf = (uint8_t *) nni_strdup(topic_name); + topic[index].length = strlen(topic_name); +} + +void +nni_mqtt_topic_array_free(nni_mqtt_topic *topic, size_t n) +{ + for (size_t i = 0; i < n; i++) { + nni_strfree((char *) topic[i].buf); + topic[i].length = 0; + } + NNI_FREE_STRUCTS(topic, n); +} + +nni_mqtt_topic_qos * +nni_mqtt_topic_qos_array_create(size_t n) +{ + nni_mqtt_topic_qos *tq; + tq = NNI_ALLOC_STRUCTS(tq, n); + return tq; +} + +void +nni_mqtt_topic_qos_array_set(nni_mqtt_topic_qos *topic_qos, size_t index, + const char *topic_name, uint8_t qos) +{ + topic_qos[index].topic.buf = (uint8_t *) nni_strdup(topic_name); + topic_qos[index].topic.length = strlen(topic_name); + topic_qos[index].qos = qos; +} + +void +nni_mqtt_topic_qos_array_free(nni_mqtt_topic_qos *topic_qos, size_t n) +{ + for (size_t i = 0; i < n; i++) { + nni_strfree((char *) topic_qos[i].topic.buf); + } + NNI_FREE_STRUCTS(topic_qos, n); +} diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index ac79ac9f1..b1691fdbb 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -2,28 +2,32 @@ #define MQTT_MQTT_H #include "core/nng_impl.h" -#include "mqtt-codec/include/mqtt_codec.h" +#include "nng/nng.h" -typedef mqtt_msg nni_mqtt_proto_data; -typedef mqtt_packet_type nni_mqtt_packet_type; -typedef union mqtt_payload nni_mqtt_payload; -typedef mqtt_topic nni_mqtt_topic; -typedef mqtt_buf_t nni_mqtt_buffer; +typedef mqtt_msg nni_mqtt_proto_data; +typedef mqtt_packet_type nni_mqtt_packet_type; +typedef union mqtt_payload nni_mqtt_payload; +typedef struct mqtt_topic_qos_t nni_mqtt_topic_qos; +typedef struct mqtt_buf_t nni_mqtt_buffer; +typedef struct mqtt_buf_t nni_mqtt_topic; // nni_msg proto_data alloc/free extern int nni_mqtt_msg_proto_data_alloc(nni_msg *); extern void nni_mqtt_msg_proto_data_free(nni_msg *); -// mqtt message encode/decode +// mqtt message alloc/encode/decode +extern int nni_mqtt_msg_alloc(nni_msg **, size_t); extern int nni_mqtt_msg_encode(nni_msg *); extern int nni_mqtt_msg_decode(nni_msg *); // mqtt packet_type -extern int nni_mqtt_msg_set_packet_type( +extern void nni_mqtt_msg_set_packet_type( nni_msg *, nni_mqtt_packet_type packet_type); extern nni_mqtt_packet_type nni_mqtt_msg_get_packet_type(nni_msg *); // mqtt connect +extern void nni_mqtt_msg_set_connect_clean_session(nni_msg *, bool); +extern void nni_mqtt_msg_set_connect_will_retain(nni_msg *, bool); extern void nni_mqtt_msg_set_connect_proto_version(nni_msg *, uint8_t); extern void nni_mqtt_msg_set_connect_keep_alive(nni_msg *, uint16_t); extern void nni_mqtt_msg_set_connect_client_id(nni_msg *, const char *); @@ -31,6 +35,8 @@ extern void nni_mqtt_msg_set_connect_will_topic(nni_msg *, const char *); extern void nni_mqtt_msg_set_connect_will_msg(nni_msg *, const char *); extern void nni_mqtt_msg_set_connect_user_name(nni_msg *, const char *); extern void nni_mqtt_msg_set_connect_password(nni_msg *, const char *); +extern bool nni_mqtt_msg_get_connect_clean_session(nni_msg *); +extern bool nni_mqtt_msg_get_connect_will_retain(nni_msg *); extern uint8_t nni_mqtt_msg_get_connect_proto_version(nni_msg *); extern uint16_t nni_mqtt_msg_get_connect_keep_alive(nni_msg *); extern const char *nni_mqtt_msg_get_connect_client_id(nni_msg *); @@ -46,14 +52,16 @@ extern uint8_t nni_mqtt_msg_get_conack_return_code(nni_msg *); extern uint8_t nni_mqtt_msg_get_conack_flags(nni_msg *); // mqtt publish -extern void nni_mqtt_msg_set_publish_qos(nni_msg *, uint8_t); -extern uint8_t nni_mqtt_msg_get_publish_qos(nni_msg *); -extern void nni_mqtt_msg_set_publish_retain(nni_msg *, bool); -extern bool nni_mqtt_msg_get_publish_retain(nni_msg *); -extern void nni_mqtt_msg_set_publish_dup(nni_msg *, bool); -extern bool nni_mqtt_msg_get_publish_dup(nni_msg *); -extern void nni_mqtt_msg_set_publish_packet_id(nni_msg *, uint16_t); -extern uint16_t nni_mqtt_msg_get_publish_packet_id(nni_msg *); +extern void nni_mqtt_msg_set_publish_qos(nni_msg *, uint8_t); +extern uint8_t nni_mqtt_msg_get_publish_qos(nni_msg *); +extern void nni_mqtt_msg_set_publish_retain(nni_msg *, bool); +extern bool nni_mqtt_msg_get_publish_retain(nni_msg *); +extern void nni_mqtt_msg_set_publish_dup(nni_msg *, bool); +extern bool nni_mqtt_msg_get_publish_dup(nni_msg *); +extern void nni_mqtt_msg_set_publish_topic(nni_msg *, const char *); +extern const char *nni_mqtt_msg_get_publish_topic(nni_msg *); +extern void nni_mqtt_msg_set_publish_packet_id(nni_msg *, uint16_t); +extern uint16_t nni_mqtt_msg_get_publish_packet_id(nni_msg *); extern void nni_mqtt_msg_set_publish_payload(nni_msg *, uint8_t *, uint32_t); extern uint8_t *nni_mqtt_msg_get_publish_payload(nni_msg *, uint32_t *); @@ -77,8 +85,8 @@ extern void nni_mqtt_msg_set_pubcomp_packet_id(nni_msg *, uint16_t); extern uint16_t nni_mqtt_msg_get_subscribe_packet_id(nni_msg *); extern void nni_mqtt_msg_set_subscribe_packet_id(nni_msg *, uint16_t); extern void nni_mqtt_msg_set_subscribe_topics( - nni_msg *, nni_mqtt_topic *, uint32_t); -extern nni_mqtt_topic *nni_mqtt_msg_get_subscribe_topics( + nni_msg *, nni_mqtt_topic_qos *, uint32_t); +extern nni_mqtt_topic_qos *nni_mqtt_msg_get_subscribe_topics( nni_msg *, uint32_t *); // mqtt suback @@ -92,12 +100,25 @@ extern uint8_t *nni_mqtt_msg_get_suback_return_codes(nni_msg *, uint32_t *); extern uint16_t nni_mqtt_msg_get_unsubscribe_packet_id(nni_msg *); extern void nni_mqtt_msg_set_unsubscribe_packet_id(nni_msg *, uint16_t); extern void nni_mqtt_msg_set_unsubscribe_topics( - nni_msg *, nni_mqtt_buffer *, uint32_t); -extern nni_mqtt_buffer *nni_mqtt_msg_get_unsubscribe_topics( + nni_msg *, nni_mqtt_topic *, uint32_t); +extern nni_mqtt_topic *nni_mqtt_msg_get_unsubscribe_topics( nni_msg *, uint32_t *); // mqtt unsuback extern void nni_mqtt_msg_set_unsuback_packet_id(nni_msg *, uint16_t); extern uint16_t nni_mqtt_msg_get_unsuback_packet_id(nni_msg *); +extern void nni_mqtt_msg_dump( + nni_msg *msg, uint8_t *buffer, uint32_t len, bool print_bytes); +// mqtt topic create/free +extern nni_mqtt_topic *nni_mqtt_topic_array_create(size_t n); +extern void nni_mqtt_topic_array_set(nni_mqtt_topic *, size_t, const char *); +extern void nni_mqtt_topic_array_free(nni_mqtt_topic *, size_t); + +// mqtt topic_qos create/free/set +extern nni_mqtt_topic_qos *nni_mqtt_topic_qos_array_create(size_t); +extern void nni_mqtt_topic_qos_array_set( + nni_mqtt_topic_qos *, size_t, const char *, uint8_t); +extern void nni_mqtt_topic_qos_array_free(nni_mqtt_topic_qos *, size_t); + #endif \ No newline at end of file diff --git a/src/nng.c b/src/nng.c index b1ebbd11e..6841e3716 100644 --- a/src/nng.c +++ b/src/nng.c @@ -1894,3 +1894,431 @@ nng_version(void) return (xstr(NNG_MAJOR_VERSION) "." xstr(NNG_MINOR_VERSION) "." xstr( NNG_PATCH_VERSION) NNG_RELEASE_SUFFIX); } + +int +nng_mqtt_msg_proto_data_alloc(nng_msg *msg) +{ + return nni_mqtt_msg_proto_data_alloc(msg); +} + +void +nng_mqtt_msg_proto_data_free(nng_msg *msg) +{ + nni_mqtt_msg_proto_data_free(msg); +} + +int +nng_mqtt_msg_alloc(nng_msg **msg, size_t sz) +{ + return nni_mqtt_msg_alloc(msg, sz); +} + +int +nng_mqtt_msg_encode(nng_msg *msg) +{ + return nni_mqtt_msg_encode(msg); +} + +int +nng_mqtt_msg_decode(nng_msg *msg) +{ + return nni_mqtt_msg_decode(msg); +} + +void +nng_mqtt_msg_set_packet_type(nng_msg *msg, nng_mqtt_packet_type packet_type) +{ + nni_mqtt_msg_set_packet_type(msg, (nni_mqtt_packet_type) packet_type); +} + +nng_mqtt_packet_type +nng_mqtt_msg_get_packet_type(nng_msg *msg) +{ + return (nng_mqtt_packet_type) nni_mqtt_msg_get_packet_type(msg); +} + +void +nng_mqtt_msg_set_connect_clean_session(nng_msg *msg, bool clean_session) +{ + nni_mqtt_msg_set_connect_clean_session(msg, clean_session); +} + +void +nng_mqtt_msg_set_connect_will_retain(nng_msg *msg, bool will_retain) +{ + nni_mqtt_msg_set_connect_will_retain(msg, will_retain); +} + +bool +nng_mqtt_msg_get_connect_clean_session(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_clean_session(msg); +} + +bool +nng_mqtt_msg_get_connect_will_retain(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_will_retain(msg); +} + +void +nng_mqtt_msg_set_connect_proto_version(nng_msg *msg, uint8_t proto_version) +{ + nni_mqtt_msg_set_connect_proto_version(msg, proto_version); +} + +void +nng_mqtt_msg_set_connect_keep_alive(nng_msg *msg, uint16_t keep_alive) +{ + nni_mqtt_msg_set_connect_keep_alive(msg, keep_alive); +} + +void +nng_mqtt_msg_set_connect_client_id(nng_msg *msg, const char *client_id) +{ + nni_mqtt_msg_set_connect_client_id(msg, client_id); +} + +void +nng_mqtt_msg_set_connect_will_topic(nng_msg *msg, const char *will_topic) +{ + nni_mqtt_msg_set_connect_will_topic(msg, will_topic); +} + +void +nng_mqtt_msg_set_connect_will_msg(nng_msg *msg, const char *will_msg) +{ + nni_mqtt_msg_set_connect_will_msg(msg, will_msg); +} + +void +nng_mqtt_msg_set_connect_user_name(nng_msg *msg, const char *user_name) +{ + nni_mqtt_msg_set_connect_user_name(msg, user_name); +} +void +nng_mqtt_msg_set_connect_password(nng_msg *msg, const char *password) +{ + nni_mqtt_msg_set_connect_password(msg, password); +} + +uint8_t +nng_mqtt_msg_get_connect_proto_version(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_proto_version(msg); +} + +uint16_t +nng_mqtt_msg_get_connect_keep_alive(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_keep_alive(msg); +} + +const char * +nng_mqtt_msg_get_connect_client_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_client_id(msg); +} + +const char * +nng_mqtt_msg_get_connect_will_topic(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_will_topic(msg); +} + +const char * +nng_mqtt_msg_get_connect_will_msg(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_will_msg(msg); +} + +const char * +nng_mqtt_msg_get_connect_user_name(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_user_name(msg); +} + +const char * +nng_mqtt_msg_get_connect_password(nng_msg *msg) +{ + return nni_mqtt_msg_get_connect_password(msg); +} + +void +nng_mqtt_msg_set_conack_return_code(nng_msg *msg, uint8_t return_code) +{ + nni_mqtt_msg_set_conack_return_code(msg, return_code); +} + +void +nng_mqtt_msg_set_conack_flags(nng_msg *msg, uint8_t flags) +{ + nni_mqtt_msg_set_conack_flags(msg, flags); +} + +uint8_t +nng_mqtt_msg_get_conack_return_code(nng_msg *msg) +{ + return nni_mqtt_msg_get_conack_return_code(msg); +} + +uint8_t +nng_mqtt_msg_get_conack_flags(nng_msg *msg) +{ + return nni_mqtt_msg_get_conack_flags(msg); +} + +void +nng_mqtt_msg_set_publish_qos(nng_msg *msg, uint8_t qos) +{ + nni_mqtt_msg_set_publish_qos(msg, qos); +} + +uint8_t +nng_mqtt_msg_get_publish_qos(nng_msg *msg) +{ + return nni_mqtt_msg_get_publish_qos(msg); +} + +void +nng_mqtt_msg_set_publish_retain(nng_msg *msg, bool retain) +{ + nni_mqtt_msg_set_publish_retain(msg, retain); +} + +bool +nng_mqtt_msg_get_publish_retain(nng_msg *msg) +{ + return nni_mqtt_msg_get_publish_retain(msg); +} + +void +nng_mqtt_msg_set_publish_dup(nng_msg *msg, bool dup) +{ + nni_mqtt_msg_set_publish_dup(msg, dup); +} + +bool +nng_mqtt_msg_get_publish_dup(nng_msg *msg) +{ + return nni_mqtt_msg_get_publish_dup(msg); +} + +void +nng_mqtt_msg_set_publish_topic(nng_msg *msg, const char *topic) +{ + nni_mqtt_msg_set_publish_topic(msg, topic); +} + +const char * +nng_mqtt_msg_get_publish_topic(nng_msg *msg) +{ + return nni_mqtt_msg_get_publish_topic(msg); +} + +void +nng_mqtt_msg_set_publish_packet_id(nng_msg *msg, uint16_t packet_id) +{ + nni_mqtt_msg_set_publish_packet_id(msg, packet_id); +} + +uint16_t +nng_mqtt_msg_get_publish_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_publish_packet_id(msg); +} + +void +nng_mqtt_msg_set_publish_payload(nng_msg *msg, uint8_t *payload, uint32_t len) +{ + nni_mqtt_msg_set_publish_payload(msg, payload, len); +} + +uint8_t * +nng_mqtt_msg_get_publish_payload(nng_msg *msg, uint32_t *len) +{ + return nni_mqtt_msg_get_publish_payload(msg, len); +} + +uint16_t +nng_mqtt_msg_get_puback_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_puback_packet_id(msg); +} + +void +nng_mqtt_msg_set_puback_packet_id(nng_msg *msg, uint16_t packet_id) +{ + nni_mqtt_msg_set_puback_packet_id(msg, packet_id); +} + +uint16_t +nng_mqtt_msg_get_pubrec_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_pubrec_packet_id(msg); +} + +void +nng_mqtt_msg_set_pubrec_packet_id(nng_msg *msg, uint16_t packet_id) +{ + nni_mqtt_msg_set_pubrec_packet_id(msg, packet_id); +} + +uint16_t +nng_mqtt_msg_get_pubrel_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_pubrel_packet_id(msg); +} + +void +nng_mqtt_msg_set_pubrel_packet_id(nng_msg *msg, uint16_t packet_id) +{ + nni_mqtt_msg_set_pubrel_packet_id(msg, packet_id); +} + +uint16_t +nng_mqtt_msg_get_pubcomp_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_pubcomp_packet_id(msg); +} + +void +nng_mqtt_msg_set_pubcomp_packet_id(nng_msg *msg, uint16_t packet_id) +{ + nni_mqtt_msg_set_pubcomp_packet_id(msg, packet_id); +} + +uint16_t +nng_mqtt_msg_get_subscribe_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_subscribe_packet_id(msg); +} + +void +nng_mqtt_msg_set_subscribe_packet_id(nng_msg *msg, uint16_t packet_id) +{ + nni_mqtt_msg_set_subscribe_packet_id(msg, packet_id); +} + +void +nng_mqtt_msg_set_subscribe_topics( + nng_msg *msg, nng_mqtt_topic_qos *topics, uint32_t topics_count) +{ + nni_mqtt_msg_set_subscribe_topics( + msg, (nni_mqtt_topic_qos *) topics, topics_count); +} + +nng_mqtt_topic_qos * +nng_mqtt_msg_get_subscribe_topics(nng_msg *msg, uint32_t *topics_count) +{ + return nni_mqtt_msg_get_subscribe_topics(msg, topics_count); +} + +uint16_t +nng_mqtt_msg_get_suback_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_suback_packet_id(msg); +} + +void +nng_mqtt_msg_set_suback_packet_id(nng_msg *msg, uint16_t packet_id) +{ + nni_mqtt_msg_set_suback_packet_id(msg, packet_id); +} +void +nng_mqtt_msg_set_suback_return_codes( + nng_msg *msg, uint8_t *return_codes, uint32_t return_codes_count) +{ + nni_mqtt_msg_set_suback_return_codes( + msg, return_codes, return_codes_count); +} +uint8_t * +nng_mqtt_msg_get_suback_return_codes( + nng_msg *msg, uint32_t *return_codes_counts) +{ + return nni_mqtt_msg_get_suback_return_codes(msg, return_codes_counts); +} + +uint16_t +nng_mqtt_msg_get_unsubscribe_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_unsubscribe_packet_id(msg); +} + +void +nng_mqtt_msg_set_unsubscribe_packet_id(nng_msg *msg, uint16_t packet_id) +{ + + nni_mqtt_msg_set_unsubscribe_packet_id(msg, packet_id); +} + +void +nng_mqtt_msg_set_unsubscribe_topics( + nng_msg *msg, nng_mqtt_topic *topics, uint32_t topics_count) +{ + nni_mqtt_msg_set_unsubscribe_topics( + msg, (nni_mqtt_topic *) topics, topics_count); +} + +nng_mqtt_topic * +nng_mqtt_msg_get_unsubscribe_topics(nng_msg *msg, uint32_t *topics_count) +{ + return nni_mqtt_msg_get_unsubscribe_topics(msg, topics_count); +} + +void +nng_mqtt_msg_set_unsuback_packet_id(nng_msg *msg, uint16_t packet_id) +{ + nni_mqtt_msg_set_unsuback_packet_id(msg, packet_id); +} + +uint16_t +nng_mqtt_msg_get_unsuback_packet_id(nng_msg *msg) +{ + return nni_mqtt_msg_get_unsuback_packet_id(msg); +} + +nng_mqtt_topic * +nng_mqtt_topic_array_create(size_t n) +{ + return nni_mqtt_topic_array_create(n); +} + +void +nng_mqtt_topic_array_set( + nng_mqtt_topic *topic, size_t n, const char *topic_name) +{ + nni_mqtt_topic_array_set(topic, n, topic_name); +} + +void +nng_mqtt_topic_array_free(nng_mqtt_topic *topic, size_t n) +{ + return nni_mqtt_topic_array_free(topic, n); +} + +nng_mqtt_topic_qos * +nng_mqtt_topic_qos_array_create(size_t n) +{ + return nni_mqtt_topic_qos_array_create(n); +} + +void +nng_mqtt_topic_qos_array_set(nng_mqtt_topic_qos *topic_qos, size_t index, + const char *topic_name, uint8_t qos) +{ + return nni_mqtt_topic_qos_array_set(topic_qos, index, topic_name, qos); +} + +void +nng_mqtt_topic_qos_array_free(nng_mqtt_topic_qos *topic_qos, size_t n) +{ + return nni_mqtt_topic_qos_array_free(topic_qos, n); +} + +void +nng_mqtt_msg_dump( + nng_msg *msg, uint8_t *buffer, uint32_t len, bool print_bytes) +{ + nni_mqtt_msg_dump(msg, buffer, len, print_bytes); +} \ No newline at end of file From e49af14d0c2ffc1cf50bbfdd5042e3d00db99e8c Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Wed, 27 Oct 2021 16:54:44 +0800 Subject: [PATCH 075/180] * NEW [nng/mqtt] mqtt msg encode APIs for nni_mqtt_msg_encode --- .gitmodules | 2 +- extern/mqtt-codec | 1 + include/nng/nng.h | 2 +- src/core/message_test.c | 138 +++++++++++ src/mqtt/mqtt-codec | 1 - src/mqtt/mqtt.c | 506 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 640 insertions(+), 10 deletions(-) create mode 160000 extern/mqtt-codec delete mode 160000 src/mqtt/mqtt-codec diff --git a/.gitmodules b/.gitmodules index 083f49f33..5f29877dd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ path = extern/nng-wolfssl url = https://github.com/staysail/nng-wolfssl [submodule "extern/mqtt-codec"] path = extern/mqtt-codec -url = https://github.com/nanomq/mqtt-codec.git +url = https://github.com/nanomq/mqtt-codec.git/ diff --git a/extern/mqtt-codec b/extern/mqtt-codec new file mode 160000 index 000000000..14d3ded60 --- /dev/null +++ b/extern/mqtt-codec @@ -0,0 +1 @@ +Subproject commit 14d3ded606c05d44839f1e90ab64fe8de8572fcc diff --git a/include/nng/nng.h b/include/nng/nng.h index 195fc249a..78136347b 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1348,7 +1348,7 @@ NNG_DECL nng_mqtt_topic *nng_mqtt_msg_get_unsubscribe_topics( nng_msg *, uint32_t *); NNG_DECL nng_mqtt_topic *nng_mqtt_topic_array_create(size_t); NNG_DECL void nng_mqtt_topic_array_set(nng_mqtt_topic *, size_t, const char *); -NNG_DECL void nng_mqtt_topic_free(nng_mqtt_topic *); +NNG_DECL void nng_mqtt_topic_array_free(nng_mqtt_topic *, size_t); NNG_DECL nng_mqtt_topic_qos *nng_mqtt_topic_qos_array_create(size_t); NNG_DECL void nng_mqtt_topic_qos_array_set( nng_mqtt_topic_qos *, size_t, const char *, uint8_t); diff --git a/src/core/message_test.c b/src/core/message_test.c index 7ab0615d9..45b3f7ca0 100644 --- a/src/core/message_test.c +++ b/src/core/message_test.c @@ -532,6 +532,41 @@ test_msg_mqtt_alloc(void) nng_msg_free(msg); } +void +test_msg_mqtt_dup(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); + + size_t sz = 2; + nng_mqtt_topic_qos *topic_qos = nng_mqtt_topic_qos_array_create(sz); + nng_mqtt_topic_qos_array_set(topic_qos, 0, "/nanomq/mqtt/msg/0", 1); + nng_mqtt_topic_qos_array_set(topic_qos, 1, "/nanomq/mqtt/msg/1", 1); + + nng_mqtt_msg_set_subscribe_topics(msg, topic_qos, sz); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + nng_msg *msg2; + NUTS_PASS(nng_msg_dup(&msg2, msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("msg: \n%s\n", print_buf); + + nng_mqtt_msg_dump(msg2, print_buf, 1024, true); + printf("msg2: \n%s\n", print_buf); + + nng_mqtt_topic_qos_array_free(topic_qos, sz); + + nng_msg_free(msg); + nng_msg_free(msg2); +} + void test_msg_mqtt_encode_connect(void) { @@ -575,6 +610,8 @@ test_msg_mqtt_encode_subscribe(void) uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); + nng_mqtt_topic_qos_array_free(topic_qos, sz); + // printf("%s\n", print_buf); nng_msg_free(msg); } @@ -595,8 +632,104 @@ test_msg_mqtt_encode_unsubscribe(void) nng_mqtt_topic_array_set(topic_qos, 1, "/nanomq/mqtt/2"); nng_mqtt_msg_set_unsubscribe_topics(msg, topic_qos, sz); + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + nng_mqtt_topic_array_free(topic_qos, sz); + + // printf("%s\n", print_buf); + nng_msg_free(msg); +} +void +test_msg_mqtt_encode_disconnect(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + + nng_msg_free(msg); +} + +void +test_msg_mqtt_decode_connect(void) +{ + nng_msg *msg; + uint8_t connect[] = { + + 0x10, 0x3f, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54, 0x04, 0xc6, + 0x00, 0x3c, 0x00, 0x0c, 0x54, 0x65, 0x73, 0x74, 0x2d, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x31, 0x00, 0x0a, 0x77, 0x69, + 0x6c, 0x6c, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x00, 0x07, + 0x62, 0x79, 0x65, 0x2d, 0x62, 0x79, 0x65, 0x00, 0x05, 0x61, + 0x6c, 0x76, 0x69, 0x6e, 0x00, 0x09, 0x48, 0x48, 0x48, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36 + }; + + size_t sz = sizeof(connect) / sizeof(uint8_t); + nng_msg_alloc(&msg, sz); + + memcpy(nng_msg_body(msg), connect, sz); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + +void +test_msg_mqtt_decode_publish(void) +{ + nng_msg *msg; + + uint8_t publish[] = { + + 0x34, 0x3f, 0x00, 0x10, 0x2f, 0x6e, 0x61, 0x6e, 0x6f, 0x6d, + 0x71, 0x2f, 0x6d, 0x71, 0x74, 0x74, 0x2f, 0x6d, 0x73, 0x67, + 0x03, 0x6c, 0x7b, 0x22, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, + 0x22, 0x20, 0x3a, 0x20, 0x22, 0x2f, 0x6e, 0x61, 0x6e, 0x6f, + 0x6d, 0x71, 0x22, 0x2c, 0x22, 0x73, 0x64, 0x6b, 0x22, 0x20, + 0x3a, 0x20, 0x22, 0x6d, 0x71, 0x74, 0x74, 0x2d, 0x63, 0x6f, + 0x64, 0x65, 0x63, 0x22, 0x7d + }; + + size_t sz = sizeof(publish) / sizeof(uint8_t); + nng_msg_alloc(&msg, sz); + memcpy(nng_msg_body(msg), publish, sz); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + + nng_msg_free(msg); +} + +void +test_msg_mqtt_decode_disconnect(void) +{ + nng_msg *msg; + uint8_t disconnect[] = { 0xe0, 0x00 }; + + size_t sz = sizeof(disconnect) / sizeof(uint8_t); + nng_msg_alloc(&msg, sz); + + memcpy(nng_msg_body(msg), disconnect, sz); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); // printf("%s\n", print_buf); @@ -630,8 +763,13 @@ TEST_LIST = { { "msg capacity", test_msg_capacity }, { "msg reserve", test_msg_reserve }, { "msg mqtt msg alloc", test_msg_mqtt_alloc }, + { "msg mqtt msg dup", test_msg_mqtt_dup }, { "msg mqtt encode connect", test_msg_mqtt_encode_connect }, + { "msg mqtt encode disconnect", test_msg_mqtt_encode_disconnect }, { "msg mqtt encode subscribe", test_msg_mqtt_encode_subscribe }, { "msg mqtt encode unsubscribe", test_msg_mqtt_encode_unsubscribe }, + { "msg mqtt decode connect", test_msg_mqtt_decode_connect }, + { "msg mqtt decode disconnect", test_msg_mqtt_decode_disconnect }, + { "msg mqtt decode publish", test_msg_mqtt_decode_publish }, { NULL, NULL }, }; diff --git a/src/mqtt/mqtt-codec b/src/mqtt/mqtt-codec deleted file mode 160000 index 61dcdacd7..000000000 --- a/src/mqtt/mqtt-codec +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 61dcdacd750c65618b1c3c9744c31344e08ad400 diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index 5543d9a3d..65b5ee1d6 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -1,9 +1,49 @@ #include "mqtt.h" +#include #include +static void nni_mqtt_msg_append_u8(nni_msg *, uint8_t); +static void nni_mqtt_msg_append_u16(nni_msg *, uint16_t); +static void nni_mqtt_msg_append_byte_str(nni_msg *, nni_mqtt_buffer *); +static void nni_mqtt_msg_encode_fixed_header(nni_msg *, nni_mqtt_proto_data *); +static int nni_mqtt_msg_encode_connect(nni_msg *); +static int nni_mqtt_msg_encode_connack(nni_msg *); +static int nni_mqtt_msg_encode_subscribe(nni_msg *); +static int nni_mqtt_msg_encode_suback(nni_msg *); +static int nni_mqtt_msg_encode_publish(nni_msg *); +static int nni_mqtt_msg_encode_puback(nni_msg *); +static int nni_mqtt_msg_encode_pubrec(nni_msg *); +static int nni_mqtt_msg_encode_pubrel(nni_msg *); +static int nni_mqtt_msg_encode_pubcomp(nni_msg *); +static int nni_mqtt_msg_encode_unsubscribe(nni_msg *); +static int nni_mqtt_msg_encode_unsuback(nni_msg *); +static int nni_mqtt_msg_encode_base(nni_msg *); + static int nni_mqtt_msg_free(void *); static int nni_mqtt_msg_dup(void **, const void *); +typedef struct { + nni_mqtt_packet_type packet_type; + int (*encode)(nni_msg *); +} mqtt_msg_encode_handler; + +static mqtt_msg_encode_handler encode_funcs[] = { + { NNG_MQTT_CONNECT, nni_mqtt_msg_encode_connect }, + { NNG_MQTT_CONNACK, nni_mqtt_msg_encode_connack }, + { NNG_MQTT_PUBLISH, nni_mqtt_msg_encode_publish }, + { NNG_MQTT_PUBACK, nni_mqtt_msg_encode_puback }, + { NNG_MQTT_PUBREC, nni_mqtt_msg_encode_pubrec }, + { NNG_MQTT_PUBREL, nni_mqtt_msg_encode_pubrel }, + { NNG_MQTT_PUBCOMP, nni_mqtt_msg_encode_pubcomp }, + { NNG_MQTT_SUBSCRIBE, nni_mqtt_msg_encode_subscribe }, + { NNG_MQTT_SUBACK, nni_mqtt_msg_encode_suback }, + { NNG_MQTT_UNSUBSCRIBE, nni_mqtt_msg_encode_unsubscribe }, + { NNG_MQTT_UNSUBACK, nni_mqtt_msg_encode_unsuback }, + { NNG_MQTT_PINGREQ, nni_mqtt_msg_encode_base }, + { NNG_MQTT_PINGRESP, nni_mqtt_msg_encode_base }, + { NNG_MQTT_DISCONNECT, nni_mqtt_msg_encode_base } +}; + static nni_proto_msg_ops proto_msg_ops = { .msg_free = nni_mqtt_msg_free, @@ -14,13 +54,23 @@ static nni_proto_msg_ops proto_msg_ops = { static int nni_mqtt_msg_free(void *self) { - return mqtt_msg_destroy((mqtt_msg *) self); + if (self) { + free(self); + return (0); + } + return (1); } static int nni_mqtt_msg_dup(void **dest, const void *src) { - return mqtt_msg_dup((mqtt_msg **) dest, (const mqtt_msg *) src); + nni_mqtt_proto_data *mqtt; + + mqtt = NNI_ALLOC_STRUCT(mqtt); + memcpy(mqtt, (nni_mqtt_proto_data *) src, sizeof(nni_mqtt_proto_data)); + *dest = mqtt; + + return (0); } int @@ -63,14 +113,20 @@ nni_mqtt_msg_alloc(nni_msg **msg, size_t sz) int nni_mqtt_msg_encode(nni_msg *msg) { - nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + nni_msg_header_clear(msg); - mqtt_msg_encode(proto_data); + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); + for (size_t i = 0; + i < sizeof(encode_funcs) / sizeof(mqtt_msg_encode_handler); i++) { + if (encode_funcs[i].packet_type == + mqtt->fixed_header.common.packet_type) { + return encode_funcs[i].encode(msg); + } + } - return nni_msg_append(msg, proto_data->entire_raw_msg.buf, - proto_data->entire_raw_msg.length); + return MQTT_ERR_PROTOCOL; } int @@ -584,3 +640,439 @@ nni_mqtt_topic_qos_array_free(nni_mqtt_topic_qos *topic_qos, size_t n) } NNI_FREE_STRUCTS(topic_qos, n); } + +static void +nni_mqtt_msg_append_u8(nni_msg *msg, uint8_t val) +{ + nni_msg_append(msg, &val, 1); +} + +static void +nni_mqtt_msg_append_u16(nni_msg *msg, uint16_t val) +{ + uint8_t buf[2] = { 0 }; + NNI_PUT16(buf, val); + nni_msg_append(msg, buf, 2); +} + +static void +nni_mqtt_msg_append_byte_str(nni_msg *msg, nni_mqtt_buffer *str) +{ + nni_mqtt_msg_append_u16(msg, (uint16_t) str->length); + nni_msg_append(msg, str->buf, str->length); +} + +static void +nni_mqtt_msg_encode_fixed_header(nni_msg *msg, nni_mqtt_proto_data *data) +{ + uint8_t rlen[4] = { 0 }; + struct pos_buf buf = { .curpos = &rlen[0], + .endpos = &rlen[sizeof(rlen) / sizeof(rlen[0]) - 1] }; + + nni_msg_header_clear(msg); + uint8_t header = *(uint8_t *) &data->fixed_header.common; + + nni_msg_header_append_u32(msg, (uint32_t) header); + + int len = write_variable_length_value( + data->fixed_header.remaining_length, &buf); + + for (int i = 0; i < len; i++) { + nni_msg_header_append_u32(msg, rlen[i]); + } +} + +static int +nni_mqtt_msg_encode_connect(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + nni_msg_clear(msg); + + int poslength = 6; + + mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; + + /* length of protocol-name (consider "MQTT" by default */ + poslength += (var_header->protocol_name.length == 0) + ? 4 + : var_header->protocol_name.length; + + /* add the length of payload part */ + mqtt_connect_payload *payload = &mqtt->payload.connect; + + /* Will Topic */ + if (payload->will_topic.length > 0) { + poslength += 2 + payload->will_topic.length; + var_header->conn_flags.will_flag = 1; + } + /* Will Message */ + if (payload->will_msg.length > 0) { + poslength += 2 + payload->will_msg.length; + var_header->conn_flags.will_flag = 1; + } + /* User Name */ + if (payload->user_name.length > 0) { + poslength += 2 + payload->user_name.length; + var_header->conn_flags.username_flag = 1; + } + /* Password */ + if (payload->password.length > 0) { + poslength += 2 + payload->password.length; + var_header->conn_flags.password_flag = 1; + } + + mqtt->fixed_header.remaining_length = poslength; + if (mqtt->fixed_header.remaining_length > MQTT_MAX_MSG_LEN) { + return MQTT_ERR_PAYLOAD_SIZE; + } + + nni_mqtt_msg_append_byte_str(msg, &var_header->protocol_name); + + nni_mqtt_msg_append_u8(msg, var_header->protocol_version); + + /* Connect Flags */ + nni_mqtt_msg_append_u8(msg, *(uint8_t *) &var_header->conn_flags); + + /* Keep Alive */ + nni_mqtt_msg_append_u16(msg, var_header->keep_alive); + + /* Now we are in payload part */ + + /* Client Identifier */ + /* Client Identifier is mandatory */ + nni_mqtt_msg_append_byte_str(msg, &payload->client_id); + + /* Will Topic */ + if (payload->will_topic.length) { + if (!(var_header->conn_flags.will_flag)) { + return MQTT_ERR_PROTOCOL; + } + nni_mqtt_msg_append_byte_str(msg, &payload->will_topic); + } else { + if (var_header->conn_flags.will_flag) { + return MQTT_ERR_PROTOCOL; + } + } + + /* Will Message */ + if (payload->will_msg.length) { + if (!(var_header->conn_flags.will_flag)) { + return MQTT_ERR_PROTOCOL; + } + nni_mqtt_msg_append_byte_str(msg, &payload->will_msg); + } else { + if (var_header->conn_flags.will_flag) { + return MQTT_ERR_PROTOCOL; + } + } + + /* User-Name */ + if (payload->user_name.length) { + if (!(var_header->conn_flags.username_flag)) { + return MQTT_ERR_PROTOCOL; + } + nni_mqtt_msg_append_byte_str(msg, &payload->user_name); + } else { + if (var_header->conn_flags.username_flag) { + return MQTT_ERR_PROTOCOL; + } + } + + /* Password */ + if (payload->password.length) { + if (!(var_header->conn_flags.password_flag)) { + return MQTT_ERR_PROTOCOL; + } + nni_mqtt_msg_append_byte_str(msg, &payload->password); + } else { + if (var_header->conn_flags.password_flag) { + return MQTT_ERR_PROTOCOL; + } + } + + // Append mqtt fixed header to nng_msg header + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_connack(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* ConnAck Flags(1) + Connect Return Code(1) */ + + mqtt_connack_vhdr *var_header = &mqtt->var_header.connack; + + mqtt->fixed_header.remaining_length = poslength; + + /* Connect Acknowledge Flags */ + nni_mqtt_msg_append_u8(msg, *(uint8_t *) &var_header->connack_flags); + + /* Connect Return Code */ + nni_mqtt_msg_append_u8( + msg, *(uint8_t *) &var_header->conn_return_code); + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_subscribe(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 0; + + poslength += 2; /* for Packet Identifier */ + + mqtt_subscribe_payload *spld = &mqtt->payload.subscribe; + + /* Go through topic filters to calculate length information */ + for (size_t i = 0; i < spld->topic_count; i++) { + mqtt_topic_qos *topic = &spld->topic_arr[i]; + poslength += topic->topic.length; + poslength += 1; // for 'options' byte + poslength += 2; // for 'length' field of Topic Filter, which is + // encoded as UTF-8 encoded strings */ + } + + mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.common.bit_1 = 1; + + mqtt_subscribe_vhdr *var_header = &mqtt->var_header.subscribe; + /* Packet Id */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + /* Subscribe topic_arr */ + for (size_t i = 0; i < spld->topic_count; i++) { + mqtt_topic_qos *topic = &spld->topic_arr[i]; + nni_mqtt_msg_append_byte_str(msg, &topic->topic); + nni_mqtt_msg_append_u8(msg, topic->qos); + } + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_suback(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_suback_vhdr * var_header = &mqtt->var_header.suback; + mqtt_suback_payload *spld = &mqtt->payload.suback; + + poslength += spld->ret_code_count; + + mqtt->fixed_header.remaining_length = poslength; + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + /* Return Codes */ + nni_msg_append(msg, spld->ret_code_arr, spld->ret_code_count); + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_publish(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 0; + + poslength += 2; /* for Topic Name length field */ + poslength += mqtt->var_header.publish.topic_name.length; + /* Packet Identifier is requested if QoS>0 */ + if (mqtt->fixed_header.publish.qos > 0) { + poslength += 2; /* for Packet Identifier */ + } + poslength += mqtt->payload.publish.payload.length; + + mqtt->fixed_header.remaining_length = poslength; + + mqtt_publish_vhdr *var_header = &mqtt->var_header.publish; + + /* Topic Name */ + nni_mqtt_msg_append_byte_str(msg, &var_header->topic_name); + + if (mqtt->fixed_header.publish.qos > 0) { + /* Packet Id */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + } + + /* Payload */ + if (mqtt->payload.publish.payload.length > 0) { + nni_msg_append(msg, mqtt->payload.publish.payload.buf, + mqtt->payload.publish.payload.length); + } + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_puback(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_puback_vhdr *var_header = &mqtt->var_header.puback; + + mqtt->fixed_header.remaining_length = poslength; + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_pubrec(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_pubrec_vhdr *var_header = &mqtt->var_header.pubrec; + + mqtt->fixed_header.remaining_length = poslength; + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_pubrel(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_pubrec_vhdr *var_header = &mqtt->var_header.pubrec; + + mqtt->fixed_header.common.bit_1 = 1; + mqtt->fixed_header.remaining_length = poslength; + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_pubcomp(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_pubcomp_vhdr *var_header = &mqtt->var_header.pubcomp; + + mqtt->fixed_header.remaining_length = poslength; + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_unsubscribe(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 0; + + poslength += 2; /* for Packet Identifier */ + + mqtt_unsubscribe_payload *uspld = &mqtt->payload.unsubscribe; + + /* Go through topic filters to calculate length information */ + for (size_t i = 0; i < uspld->topic_count; i++) { + mqtt_buf *topic = &uspld->topic_arr[i]; + poslength += topic->length; + poslength += 2; // for 'length' field of Topic Filter, which is + // encoded as UTF-8 encoded strings */ + } + + mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.common.bit_1 = 1; + + mqtt_subscribe_vhdr *var_header = &mqtt->var_header.subscribe; + /* Packet Id */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + /* Subscribe topic_arr */ + for (size_t i = 0; i < uspld->topic_count; i++) { + mqtt_buf *topic = &uspld->topic_arr[i]; + nni_mqtt_msg_append_byte_str(msg, topic); + } + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_unsuback(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_unsuback_vhdr *var_header = &mqtt->var_header.unsuback; + + mqtt->fixed_header.remaining_length = poslength; + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_base(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + mqtt->fixed_header.remaining_length = 0; + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} From 7dfcff6ef2a7bda0143e95d251436bc5a4172cfe Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Fri, 29 Oct 2021 15:14:27 +0800 Subject: [PATCH 076/180] * MDF [nng/mqtt] nng_mqtt_msg decode APIs, remove mqtt_codec submodule dependency --- .gitmodules | 3 - CMakeLists.txt | 6 - extern/mqtt-codec | 1 - include/nng/nng.h | 4 +- src/core/message_test.c | 223 ------ src/core/nng_impl.h | 2 - src/mqtt/.gitignore | 1 - src/mqtt/CMakeLists.txt | 9 +- src/mqtt/mqtt.c | 530 +------------- src/mqtt/mqtt.h | 287 +++++++- src/mqtt/mqtt_codec.c | 1486 +++++++++++++++++++++++++++++++++++++++ src/mqtt/mqtt_test.c | 268 +++++++ src/nng.c | 6 +- 13 files changed, 2060 insertions(+), 766 deletions(-) delete mode 160000 extern/mqtt-codec delete mode 100644 src/mqtt/.gitignore create mode 100644 src/mqtt/mqtt_codec.c create mode 100644 src/mqtt/mqtt_test.c diff --git a/.gitmodules b/.gitmodules index 5f29877dd..ca4f07182 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "extern/nng-wolfssl"] path = extern/nng-wolfssl url = https://github.com/staysail/nng-wolfssl -[submodule "extern/mqtt-codec"] -path = extern/mqtt-codec -url = https://github.com/nanomq/mqtt-codec.git/ diff --git a/CMakeLists.txt b/CMakeLists.txt index f25a1605b..ef4c2bc87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,12 +78,6 @@ if (NOT (BUILD_SHARED_LIBS)) message(STATUS "Building static libs.") endif () -configure_file(${CMAKE_SOURCE_DIR}/extern/mqtt-codec/src/mqtt_codec.c - ${CMAKE_SOURCE_DIR}/src/mqtt/mqtt_codec.c COPYONLY) - -configure_file(${CMAKE_SOURCE_DIR}/extern/mqtt-codec/src/mqtt_codec.h - ${CMAKE_SOURCE_DIR}/src/mqtt/mqtt_codec.h COPYONLY) - # These are library targets. The "nng" library is the main public library. # The "nng_testing" is a full build of the library for test cases # only, which is done statically and includes even portions of the code diff --git a/extern/mqtt-codec b/extern/mqtt-codec deleted file mode 160000 index 14d3ded60..000000000 --- a/extern/mqtt-codec +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 14d3ded606c05d44839f1e90ab64fe8de8572fcc diff --git a/include/nng/nng.h b/include/nng/nng.h index 78136347b..ca4f065a9 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1298,7 +1298,8 @@ typedef struct mqtt_buf_t nng_mqtt_buffer; typedef struct mqtt_buf_t nng_mqtt_topic; typedef struct mqtt_topic_qos_t nng_mqtt_topic_qos; -NNG_DECL int nng_mqtt_msg_alloc(nng_msg **msg, size_t sz); +#ifdef NNG_TRANSPORT_MQTT_TCP +NNG_DECL int nng_mqtt_msg_alloc(nng_msg **, size_t); NNG_DECL int nng_mqtt_msg_encode(nng_msg *); NNG_DECL int nng_mqtt_msg_decode(nng_msg *); NNG_DECL void nng_mqtt_msg_set_packet_type(nng_msg *, nng_mqtt_packet_type); @@ -1354,6 +1355,7 @@ NNG_DECL void nng_mqtt_topic_qos_array_set( nng_mqtt_topic_qos *, size_t, const char *, uint8_t); NNG_DECL void nng_mqtt_topic_qos_array_free(nng_mqtt_topic_qos *, size_t); NNG_DECL void nng_mqtt_msg_dump(nng_msg *, uint8_t *, uint32_t, bool); +#endif // NNG_TRANSPORT_MQTT_TCP #endif diff --git a/src/core/message_test.c b/src/core/message_test.c index 45b3f7ca0..1b5b7f48e 100644 --- a/src/core/message_test.c +++ b/src/core/message_test.c @@ -522,220 +522,6 @@ test_msg_reserve(void) nng_msg_free(msg); } -void -test_msg_mqtt_alloc(void) -{ - nng_msg *msg; - - NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); - - nng_msg_free(msg); -} - -void -test_msg_mqtt_dup(void) -{ - nng_msg *msg; - - NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); - - nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); - - size_t sz = 2; - nng_mqtt_topic_qos *topic_qos = nng_mqtt_topic_qos_array_create(sz); - nng_mqtt_topic_qos_array_set(topic_qos, 0, "/nanomq/mqtt/msg/0", 1); - nng_mqtt_topic_qos_array_set(topic_qos, 1, "/nanomq/mqtt/msg/1", 1); - - nng_mqtt_msg_set_subscribe_topics(msg, topic_qos, sz); - - NUTS_PASS(nng_mqtt_msg_encode(msg)); - - nng_msg *msg2; - NUTS_PASS(nng_msg_dup(&msg2, msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("msg: \n%s\n", print_buf); - - nng_mqtt_msg_dump(msg2, print_buf, 1024, true); - printf("msg2: \n%s\n", print_buf); - - nng_mqtt_topic_qos_array_free(topic_qos, sz); - - nng_msg_free(msg); - nng_msg_free(msg2); -} - -void -test_msg_mqtt_encode_connect(void) -{ - nng_msg *msg; - - NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); - - nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); - - nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); - NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), - "nanomq-mqtt") == 0); - - NUTS_PASS(nng_mqtt_msg_encode(msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); - nng_msg_free(msg); -} - -void -test_msg_mqtt_encode_subscribe(void) -{ - nng_msg *msg; - - NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); - - nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); - - size_t sz = 2; - nng_mqtt_topic_qos *topic_qos = nng_mqtt_topic_qos_array_create(sz); - nng_mqtt_topic_qos_array_set(topic_qos, 0, "/nanomq/mqtt/msg/0", 1); - nng_mqtt_topic_qos_array_set(topic_qos, 1, "/nanomq/mqtt/msg/1", 1); - - nng_mqtt_msg_set_subscribe_topics(msg, topic_qos, sz); - - NUTS_PASS(nng_mqtt_msg_encode(msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - nng_mqtt_topic_qos_array_free(topic_qos, sz); - - // printf("%s\n", print_buf); - nng_msg_free(msg); -} - -void -test_msg_mqtt_encode_unsubscribe(void) -{ - nng_msg *msg; - - NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); - - nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); - - size_t sz = 2; - nng_mqtt_topic *topic_qos = nng_mqtt_topic_array_create(sz); - nng_mqtt_topic_array_set(topic_qos, 0, "/nanomq/mqtt/1"); - nng_mqtt_topic_array_set(topic_qos, 1, "/nanomq/mqtt/2"); - - nng_mqtt_msg_set_unsubscribe_topics(msg, topic_qos, sz); - NUTS_PASS(nng_mqtt_msg_encode(msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - nng_mqtt_topic_array_free(topic_qos, sz); - - // printf("%s\n", print_buf); - nng_msg_free(msg); -} - -void -test_msg_mqtt_encode_disconnect(void) -{ - nng_msg *msg; - - NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); - - nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); - NUTS_PASS(nng_mqtt_msg_encode(msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); - - nng_msg_free(msg); -} - -void -test_msg_mqtt_decode_connect(void) -{ - nng_msg *msg; - uint8_t connect[] = { - - 0x10, 0x3f, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54, 0x04, 0xc6, - 0x00, 0x3c, 0x00, 0x0c, 0x54, 0x65, 0x73, 0x74, 0x2d, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x31, 0x00, 0x0a, 0x77, 0x69, - 0x6c, 0x6c, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x00, 0x07, - 0x62, 0x79, 0x65, 0x2d, 0x62, 0x79, 0x65, 0x00, 0x05, 0x61, - 0x6c, 0x76, 0x69, 0x6e, 0x00, 0x09, 0x48, 0x48, 0x48, 0x31, - 0x32, 0x33, 0x34, 0x35, 0x36 - }; - - size_t sz = sizeof(connect) / sizeof(uint8_t); - nng_msg_alloc(&msg, sz); - - memcpy(nng_msg_body(msg), connect, sz); - - NUTS_PASS(nng_mqtt_msg_decode(msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); - nng_msg_free(msg); -} - -void -test_msg_mqtt_decode_publish(void) -{ - nng_msg *msg; - - uint8_t publish[] = { - - 0x34, 0x3f, 0x00, 0x10, 0x2f, 0x6e, 0x61, 0x6e, 0x6f, 0x6d, - 0x71, 0x2f, 0x6d, 0x71, 0x74, 0x74, 0x2f, 0x6d, 0x73, 0x67, - 0x03, 0x6c, 0x7b, 0x22, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, - 0x22, 0x20, 0x3a, 0x20, 0x22, 0x2f, 0x6e, 0x61, 0x6e, 0x6f, - 0x6d, 0x71, 0x22, 0x2c, 0x22, 0x73, 0x64, 0x6b, 0x22, 0x20, - 0x3a, 0x20, 0x22, 0x6d, 0x71, 0x74, 0x74, 0x2d, 0x63, 0x6f, - 0x64, 0x65, 0x63, 0x22, 0x7d - }; - - size_t sz = sizeof(publish) / sizeof(uint8_t); - nng_msg_alloc(&msg, sz); - memcpy(nng_msg_body(msg), publish, sz); - - NUTS_PASS(nng_mqtt_msg_decode(msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); - - nng_msg_free(msg); -} - -void -test_msg_mqtt_decode_disconnect(void) -{ - nng_msg *msg; - uint8_t disconnect[] = { 0xe0, 0x00 }; - - size_t sz = sizeof(disconnect) / sizeof(uint8_t); - nng_msg_alloc(&msg, sz); - - memcpy(nng_msg_body(msg), disconnect, sz); - - NUTS_PASS(nng_mqtt_msg_decode(msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); - nng_msg_free(msg); -} - TEST_LIST = { { "msg option", test_msg_option }, { "msg empty", test_msg_empty }, @@ -762,14 +548,5 @@ TEST_LIST = { { "msg header u64", test_msg_header_uint64 }, { "msg capacity", test_msg_capacity }, { "msg reserve", test_msg_reserve }, - { "msg mqtt msg alloc", test_msg_mqtt_alloc }, - { "msg mqtt msg dup", test_msg_mqtt_dup }, - { "msg mqtt encode connect", test_msg_mqtt_encode_connect }, - { "msg mqtt encode disconnect", test_msg_mqtt_encode_disconnect }, - { "msg mqtt encode subscribe", test_msg_mqtt_encode_subscribe }, - { "msg mqtt encode unsubscribe", test_msg_mqtt_encode_unsubscribe }, - { "msg mqtt decode connect", test_msg_mqtt_decode_connect }, - { "msg mqtt decode disconnect", test_msg_mqtt_decode_disconnect }, - { "msg mqtt decode publish", test_msg_mqtt_decode_publish }, { NULL, NULL }, }; diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h index 78d6a7e6e..bcb29e114 100644 --- a/src/core/nng_impl.h +++ b/src/core/nng_impl.h @@ -49,8 +49,6 @@ #include "core/url.h" // transport needs to come after url -#include "mqtt/mqtt_codec.h" - #include "mqtt/mqtt.h" #include "sp/transport.h" // These have to come after the others - particularly transport.h diff --git a/src/mqtt/.gitignore b/src/mqtt/.gitignore deleted file mode 100644 index 9252d1609..000000000 --- a/src/mqtt/.gitignore +++ /dev/null @@ -1 +0,0 @@ -mqtt_codec.* diff --git a/src/mqtt/CMakeLists.txt b/src/mqtt/CMakeLists.txt index 943adb200..5e024d724 100644 --- a/src/mqtt/CMakeLists.txt +++ b/src/mqtt/CMakeLists.txt @@ -15,10 +15,13 @@ nng_check_sym(strnlen string.h NNG_HAVE_STRNLEN) nng_check_sym(strcasecmp string.h NNG_HAVE_STRCASECMP) nng_check_sym(strncasecmp string.h NNG_HAVE_STRNCASECMP) -nng_sources( +nng_sources_if( + NNG_TRANSPORT_MQTT_TCP + + mqtt_codec.c mqtt.c mqtt.h - mqtt_codec.c - mqtt_codec.h ) +nng_test_if(NNG_TRANSPORT_MQTT_TCP mqtt_test) + diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index 65b5ee1d6..7f3caec82 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -2,48 +2,9 @@ #include #include -static void nni_mqtt_msg_append_u8(nni_msg *, uint8_t); -static void nni_mqtt_msg_append_u16(nni_msg *, uint16_t); -static void nni_mqtt_msg_append_byte_str(nni_msg *, nni_mqtt_buffer *); -static void nni_mqtt_msg_encode_fixed_header(nni_msg *, nni_mqtt_proto_data *); -static int nni_mqtt_msg_encode_connect(nni_msg *); -static int nni_mqtt_msg_encode_connack(nni_msg *); -static int nni_mqtt_msg_encode_subscribe(nni_msg *); -static int nni_mqtt_msg_encode_suback(nni_msg *); -static int nni_mqtt_msg_encode_publish(nni_msg *); -static int nni_mqtt_msg_encode_puback(nni_msg *); -static int nni_mqtt_msg_encode_pubrec(nni_msg *); -static int nni_mqtt_msg_encode_pubrel(nni_msg *); -static int nni_mqtt_msg_encode_pubcomp(nni_msg *); -static int nni_mqtt_msg_encode_unsubscribe(nni_msg *); -static int nni_mqtt_msg_encode_unsuback(nni_msg *); -static int nni_mqtt_msg_encode_base(nni_msg *); - static int nni_mqtt_msg_free(void *); static int nni_mqtt_msg_dup(void **, const void *); -typedef struct { - nni_mqtt_packet_type packet_type; - int (*encode)(nni_msg *); -} mqtt_msg_encode_handler; - -static mqtt_msg_encode_handler encode_funcs[] = { - { NNG_MQTT_CONNECT, nni_mqtt_msg_encode_connect }, - { NNG_MQTT_CONNACK, nni_mqtt_msg_encode_connack }, - { NNG_MQTT_PUBLISH, nni_mqtt_msg_encode_publish }, - { NNG_MQTT_PUBACK, nni_mqtt_msg_encode_puback }, - { NNG_MQTT_PUBREC, nni_mqtt_msg_encode_pubrec }, - { NNG_MQTT_PUBREL, nni_mqtt_msg_encode_pubrel }, - { NNG_MQTT_PUBCOMP, nni_mqtt_msg_encode_pubcomp }, - { NNG_MQTT_SUBSCRIBE, nni_mqtt_msg_encode_subscribe }, - { NNG_MQTT_SUBACK, nni_mqtt_msg_encode_suback }, - { NNG_MQTT_UNSUBSCRIBE, nni_mqtt_msg_encode_unsubscribe }, - { NNG_MQTT_UNSUBACK, nni_mqtt_msg_encode_unsuback }, - { NNG_MQTT_PINGREQ, nni_mqtt_msg_encode_base }, - { NNG_MQTT_PINGRESP, nni_mqtt_msg_encode_base }, - { NNG_MQTT_DISCONNECT, nni_mqtt_msg_encode_base } -}; - static nni_proto_msg_ops proto_msg_ops = { .msg_free = nni_mqtt_msg_free, @@ -110,44 +71,6 @@ nni_mqtt_msg_alloc(nni_msg **msg, size_t sz) return (0); } -int -nni_mqtt_msg_encode(nni_msg *msg) -{ - nni_msg_clear(msg); - nni_msg_header_clear(msg); - - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - - for (size_t i = 0; - i < sizeof(encode_funcs) / sizeof(mqtt_msg_encode_handler); i++) { - if (encode_funcs[i].packet_type == - mqtt->fixed_header.common.packet_type) { - return encode_funcs[i].encode(msg); - } - } - - return MQTT_ERR_PROTOCOL; -} - -int -nni_mqtt_msg_decode(nni_msg *msg) -{ - uint8_t *packet = nni_msg_body(msg); - size_t len = nni_msg_len(msg); - uint32_t result; - - nni_mqtt_proto_data *proto_data = - mqtt_msg_decode_raw_packet(packet, len, &result, 0); - - if (result != MQTT_SUCCESS) { - return result; - } - - nni_msg_set_proto_data(msg, &proto_msg_ops, proto_data); - - return (0); -} - void nni_mqtt_msg_set_packet_type(nni_msg *msg, nni_mqtt_packet_type packet_type) { @@ -582,11 +505,20 @@ nni_mqtt_msg_dump( { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - mqtt_buf mqbuf; - mqbuf.buf = buffer; - mqbuf.length = len; + mqtt_buf mqbuf = { .buf = buffer, .length = len }; + + nni_msg *mqtt_data; + + nni_msg_dup(&mqtt_data, msg); + nni_msg_insert( + mqtt_data, nni_msg_header(msg), nni_msg_header_len(msg)); + + mqtt_buf body = { .buf = nni_msg_body(mqtt_data), + .length = nni_msg_len(mqtt_data) }; - mqtt_msg_dump(proto_data, &mqbuf, print_bytes); + mqtt_msg_dump(proto_data, &mqbuf, &body, print_bytes); + + nni_msg_free(mqtt_data); } nni_mqtt_topic * @@ -640,439 +572,3 @@ nni_mqtt_topic_qos_array_free(nni_mqtt_topic_qos *topic_qos, size_t n) } NNI_FREE_STRUCTS(topic_qos, n); } - -static void -nni_mqtt_msg_append_u8(nni_msg *msg, uint8_t val) -{ - nni_msg_append(msg, &val, 1); -} - -static void -nni_mqtt_msg_append_u16(nni_msg *msg, uint16_t val) -{ - uint8_t buf[2] = { 0 }; - NNI_PUT16(buf, val); - nni_msg_append(msg, buf, 2); -} - -static void -nni_mqtt_msg_append_byte_str(nni_msg *msg, nni_mqtt_buffer *str) -{ - nni_mqtt_msg_append_u16(msg, (uint16_t) str->length); - nni_msg_append(msg, str->buf, str->length); -} - -static void -nni_mqtt_msg_encode_fixed_header(nni_msg *msg, nni_mqtt_proto_data *data) -{ - uint8_t rlen[4] = { 0 }; - struct pos_buf buf = { .curpos = &rlen[0], - .endpos = &rlen[sizeof(rlen) / sizeof(rlen[0]) - 1] }; - - nni_msg_header_clear(msg); - uint8_t header = *(uint8_t *) &data->fixed_header.common; - - nni_msg_header_append_u32(msg, (uint32_t) header); - - int len = write_variable_length_value( - data->fixed_header.remaining_length, &buf); - - for (int i = 0; i < len; i++) { - nni_msg_header_append_u32(msg, rlen[i]); - } -} - -static int -nni_mqtt_msg_encode_connect(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - - nni_msg_clear(msg); - - int poslength = 6; - - mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; - - /* length of protocol-name (consider "MQTT" by default */ - poslength += (var_header->protocol_name.length == 0) - ? 4 - : var_header->protocol_name.length; - - /* add the length of payload part */ - mqtt_connect_payload *payload = &mqtt->payload.connect; - - /* Will Topic */ - if (payload->will_topic.length > 0) { - poslength += 2 + payload->will_topic.length; - var_header->conn_flags.will_flag = 1; - } - /* Will Message */ - if (payload->will_msg.length > 0) { - poslength += 2 + payload->will_msg.length; - var_header->conn_flags.will_flag = 1; - } - /* User Name */ - if (payload->user_name.length > 0) { - poslength += 2 + payload->user_name.length; - var_header->conn_flags.username_flag = 1; - } - /* Password */ - if (payload->password.length > 0) { - poslength += 2 + payload->password.length; - var_header->conn_flags.password_flag = 1; - } - - mqtt->fixed_header.remaining_length = poslength; - if (mqtt->fixed_header.remaining_length > MQTT_MAX_MSG_LEN) { - return MQTT_ERR_PAYLOAD_SIZE; - } - - nni_mqtt_msg_append_byte_str(msg, &var_header->protocol_name); - - nni_mqtt_msg_append_u8(msg, var_header->protocol_version); - - /* Connect Flags */ - nni_mqtt_msg_append_u8(msg, *(uint8_t *) &var_header->conn_flags); - - /* Keep Alive */ - nni_mqtt_msg_append_u16(msg, var_header->keep_alive); - - /* Now we are in payload part */ - - /* Client Identifier */ - /* Client Identifier is mandatory */ - nni_mqtt_msg_append_byte_str(msg, &payload->client_id); - - /* Will Topic */ - if (payload->will_topic.length) { - if (!(var_header->conn_flags.will_flag)) { - return MQTT_ERR_PROTOCOL; - } - nni_mqtt_msg_append_byte_str(msg, &payload->will_topic); - } else { - if (var_header->conn_flags.will_flag) { - return MQTT_ERR_PROTOCOL; - } - } - - /* Will Message */ - if (payload->will_msg.length) { - if (!(var_header->conn_flags.will_flag)) { - return MQTT_ERR_PROTOCOL; - } - nni_mqtt_msg_append_byte_str(msg, &payload->will_msg); - } else { - if (var_header->conn_flags.will_flag) { - return MQTT_ERR_PROTOCOL; - } - } - - /* User-Name */ - if (payload->user_name.length) { - if (!(var_header->conn_flags.username_flag)) { - return MQTT_ERR_PROTOCOL; - } - nni_mqtt_msg_append_byte_str(msg, &payload->user_name); - } else { - if (var_header->conn_flags.username_flag) { - return MQTT_ERR_PROTOCOL; - } - } - - /* Password */ - if (payload->password.length) { - if (!(var_header->conn_flags.password_flag)) { - return MQTT_ERR_PROTOCOL; - } - nni_mqtt_msg_append_byte_str(msg, &payload->password); - } else { - if (var_header->conn_flags.password_flag) { - return MQTT_ERR_PROTOCOL; - } - } - - // Append mqtt fixed header to nng_msg header - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_connack(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 2; /* ConnAck Flags(1) + Connect Return Code(1) */ - - mqtt_connack_vhdr *var_header = &mqtt->var_header.connack; - - mqtt->fixed_header.remaining_length = poslength; - - /* Connect Acknowledge Flags */ - nni_mqtt_msg_append_u8(msg, *(uint8_t *) &var_header->connack_flags); - - /* Connect Return Code */ - nni_mqtt_msg_append_u8( - msg, *(uint8_t *) &var_header->conn_return_code); - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_subscribe(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 0; - - poslength += 2; /* for Packet Identifier */ - - mqtt_subscribe_payload *spld = &mqtt->payload.subscribe; - - /* Go through topic filters to calculate length information */ - for (size_t i = 0; i < spld->topic_count; i++) { - mqtt_topic_qos *topic = &spld->topic_arr[i]; - poslength += topic->topic.length; - poslength += 1; // for 'options' byte - poslength += 2; // for 'length' field of Topic Filter, which is - // encoded as UTF-8 encoded strings */ - } - - mqtt->fixed_header.remaining_length = poslength; - mqtt->fixed_header.common.bit_1 = 1; - - mqtt_subscribe_vhdr *var_header = &mqtt->var_header.subscribe; - /* Packet Id */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - - /* Subscribe topic_arr */ - for (size_t i = 0; i < spld->topic_count; i++) { - mqtt_topic_qos *topic = &spld->topic_arr[i]; - nni_mqtt_msg_append_byte_str(msg, &topic->topic); - nni_mqtt_msg_append_u8(msg, topic->qos); - } - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_suback(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 2; /* for Packet Identifier */ - - mqtt_suback_vhdr * var_header = &mqtt->var_header.suback; - mqtt_suback_payload *spld = &mqtt->payload.suback; - - poslength += spld->ret_code_count; - - mqtt->fixed_header.remaining_length = poslength; - - /* Packet Identifier */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - - /* Return Codes */ - nni_msg_append(msg, spld->ret_code_arr, spld->ret_code_count); - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_publish(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 0; - - poslength += 2; /* for Topic Name length field */ - poslength += mqtt->var_header.publish.topic_name.length; - /* Packet Identifier is requested if QoS>0 */ - if (mqtt->fixed_header.publish.qos > 0) { - poslength += 2; /* for Packet Identifier */ - } - poslength += mqtt->payload.publish.payload.length; - - mqtt->fixed_header.remaining_length = poslength; - - mqtt_publish_vhdr *var_header = &mqtt->var_header.publish; - - /* Topic Name */ - nni_mqtt_msg_append_byte_str(msg, &var_header->topic_name); - - if (mqtt->fixed_header.publish.qos > 0) { - /* Packet Id */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - } - - /* Payload */ - if (mqtt->payload.publish.payload.length > 0) { - nni_msg_append(msg, mqtt->payload.publish.payload.buf, - mqtt->payload.publish.payload.length); - } - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_puback(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 2; /* for Packet Identifier */ - - mqtt_puback_vhdr *var_header = &mqtt->var_header.puback; - - mqtt->fixed_header.remaining_length = poslength; - - /* Packet Identifier */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_pubrec(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 2; /* for Packet Identifier */ - - mqtt_pubrec_vhdr *var_header = &mqtt->var_header.pubrec; - - mqtt->fixed_header.remaining_length = poslength; - - /* Packet Identifier */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_pubrel(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 2; /* for Packet Identifier */ - - mqtt_pubrec_vhdr *var_header = &mqtt->var_header.pubrec; - - mqtt->fixed_header.common.bit_1 = 1; - mqtt->fixed_header.remaining_length = poslength; - - /* Packet Identifier */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_pubcomp(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 2; /* for Packet Identifier */ - - mqtt_pubcomp_vhdr *var_header = &mqtt->var_header.pubcomp; - - mqtt->fixed_header.remaining_length = poslength; - - /* Packet Identifier */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_unsubscribe(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 0; - - poslength += 2; /* for Packet Identifier */ - - mqtt_unsubscribe_payload *uspld = &mqtt->payload.unsubscribe; - - /* Go through topic filters to calculate length information */ - for (size_t i = 0; i < uspld->topic_count; i++) { - mqtt_buf *topic = &uspld->topic_arr[i]; - poslength += topic->length; - poslength += 2; // for 'length' field of Topic Filter, which is - // encoded as UTF-8 encoded strings */ - } - - mqtt->fixed_header.remaining_length = poslength; - mqtt->fixed_header.common.bit_1 = 1; - - mqtt_subscribe_vhdr *var_header = &mqtt->var_header.subscribe; - /* Packet Id */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - - /* Subscribe topic_arr */ - for (size_t i = 0; i < uspld->topic_count; i++) { - mqtt_buf *topic = &uspld->topic_arr[i]; - nni_mqtt_msg_append_byte_str(msg, topic); - } - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_unsuback(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - int poslength = 2; /* for Packet Identifier */ - - mqtt_unsuback_vhdr *var_header = &mqtt->var_header.unsuback; - - mqtt->fixed_header.remaining_length = poslength; - - /* Packet Identifier */ - nni_mqtt_msg_append_u16(msg, var_header->packet_id); - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - return MQTT_SUCCESS; -} - -static int -nni_mqtt_msg_encode_base(nni_msg *msg) -{ - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - nni_msg_clear(msg); - - mqtt->fixed_header.remaining_length = 0; - - nni_mqtt_msg_encode_fixed_header(msg, mqtt); - - return MQTT_SUCCESS; -} diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index b1691fdbb..1a401910c 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -1,28 +1,296 @@ #ifndef MQTT_MQTT_H #define MQTT_MQTT_H +// #include "mqtt_codec.h" +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#include +#else +#include +#endif + #include "core/nng_impl.h" + #include "nng/nng.h" -typedef mqtt_msg nni_mqtt_proto_data; -typedef mqtt_packet_type nni_mqtt_packet_type; +#define MQTT_VERSION_3_1 3 +#define MQTT_VERSION_3_1_1 4 +#define MQTT_VERSION_5_0 5 + +#define MQTT_PROTOCOL_NAME "MQTT" + +#define MQTT_MAX_MSG_LEN 268435455 + +#define MQTT_MAX_LENGTH_BYTES 4 +#define MQTT_LENGTH_VALUE_MASK 0x7F +#define MQTT_LENGTH_CONTINUATION_BIT 0x80 +#define MQTT_LENGTH_SHIFT 7 + +typedef struct mqtt_msg_t nni_mqtt_proto_data; +typedef enum mqtt_packet_type_t nni_mqtt_packet_type; typedef union mqtt_payload nni_mqtt_payload; typedef struct mqtt_topic_qos_t nni_mqtt_topic_qos; typedef struct mqtt_buf_t nni_mqtt_buffer; typedef struct mqtt_buf_t nni_mqtt_topic; +/* Packet types */ +typedef enum mqtt_packet_type_t { + MQTT_CONNECT = 0x01, + MQTT_CONNACK = 0x02, + MQTT_PUBLISH = 0x03, + MQTT_PUBACK = 0x04, + MQTT_PUBREC = 0x05, + MQTT_PUBREL = 0x06, + MQTT_PUBCOMP = 0x07, + MQTT_SUBSCRIBE = 0x08, + MQTT_SUBACK = 0x09, + MQTT_UNSUBSCRIBE = 0x0A, + MQTT_UNSUBACK = 0x0B, + MQTT_PINGREQ = 0x0C, + MQTT_PINGRESP = 0x0D, + MQTT_DISCONNECT = 0x0E, + MQTT_AUTH = 0x0F +} mqtt_packet_type; + +/* Quality of Service types. */ +#define MQTT_QOS_0_AT_MOST_ONCE 0 +#define MQTT_QOS_1_AT_LEAST_ONCE 1 +#define MQTT_QOS_2_EXACTLY_ONCE 2 + +/* CONNACK codes */ +#define MQTT_CONNACK_ACCEPTED 0 +#define MQTT_CONNACK_REFUSED_PROTOCOL_VERSION 1 +#define MQTT_CONNACK_REFUSED_IDENTIFIER_REJECTED 2 +#define MQTT_CONNACK_REFUSED_SERVER_UNAVAILABLE 3 +#define MQTT_CONNACK_REFUSED_BAD_USERNAME_PASSWORD 4 +#define MQTT_CONNACK_REFUSED_NOT_AUTHORIZED 5 + +/* Function return codes */ +#define MQTT_SUCCESS 0 +#define MQTT_ERR_NOMEM 1 +#define MQTT_ERR_PROTOCOL 2 +#define MQTT_ERR_INVAL 3 +#define MQTT_ERR_PAYLOAD_SIZE 4 +#define MQTT_ERR_NOT_SUPPORTED 5 +#define MQTT_ERR_NOT_FOUND 6 +#define MQTT_ERR_MALFORMED 7 + +struct pos_buf { + uint8_t *curpos; + uint8_t *endpos; +}; + +/* Compact string type */ +typedef struct mqtt_buf_t { + uint32_t length; + uint8_t *buf; +} mqtt_buf; + +/* CONNECT flags */ +typedef struct conn_flags_t { + uint8_t reserved : 1; + uint8_t clean_session : 1; + uint8_t will_flag : 1; + uint8_t will_qos : 2; + uint8_t will_retain : 1; + uint8_t password_flag : 1; + uint8_t username_flag : 1; +} conn_flags; + +/***************************************************************************** + * Variable header parts + ****************************************************************************/ +typedef struct mqtt_connect_vhdr_t { + mqtt_buf protocol_name; + uint8_t protocol_version; + conn_flags conn_flags; + uint16_t keep_alive; +} mqtt_connect_vhdr; + +typedef struct mqtt_connack_vhdr_t { + uint8_t connack_flags; + uint8_t conn_return_code; +} mqtt_connack_vhdr; + +typedef struct mqtt_publish_vhdr_t { + mqtt_buf topic_name; + uint16_t packet_id; +} mqtt_publish_vhdr; + +typedef struct mqtt_puback_vhdr_t { + uint16_t packet_id; +} mqtt_puback_vhdr; + +typedef struct mqtt_pubrec_vhdr_t { + uint16_t packet_id; +} mqtt_pubrec_vhdr; + +typedef struct mqtt_pubrel_vhdr_t { + uint16_t packet_id; +} mqtt_pubrel_vhdr; + +typedef struct mqtt_pubcomp_vhdr_t { + uint16_t packet_id; +} mqtt_pubcomp_vhdr; + +typedef struct mqtt_subscribe_vhdr_t { + uint16_t packet_id; +} mqtt_subscribe_vhdr; + +typedef struct mqtt_suback_vhdr_t { + uint16_t packet_id; +} mqtt_suback_vhdr; + +typedef struct mqtt_unsubscribe_vhdr_t { + uint16_t packet_id; +} mqtt_unsubscribe_vhdr; + +typedef struct mqtt_unsuback_vhdr_t { + uint16_t packet_id; +} mqtt_unsuback_vhdr; + +/***************************************************************************** + * Union to cover all Variable Header types + ****************************************************************************/ +union mqtt_variable_header { + mqtt_connect_vhdr connect; + mqtt_connack_vhdr connack; + mqtt_publish_vhdr publish; + mqtt_puback_vhdr puback; + mqtt_pubrec_vhdr pubrec; + mqtt_pubrel_vhdr pubrel; + mqtt_pubcomp_vhdr pubcomp; + mqtt_subscribe_vhdr subscribe; + mqtt_suback_vhdr suback; + mqtt_unsubscribe_vhdr unsubscribe; + mqtt_unsuback_vhdr unsuback; +}; + +typedef struct mqtt_topic_qos_t { + mqtt_buf topic; + uint8_t qos; +} mqtt_topic_qos; + +/***************************************************************************** + * Payloads + ****************************************************************************/ +typedef struct { + mqtt_buf client_id; + mqtt_buf will_topic; + mqtt_buf will_msg; + mqtt_buf user_name; + mqtt_buf password; +} mqtt_connect_payload; + +typedef struct { + mqtt_buf payload; +} mqtt_publish_payload; + +typedef struct { + mqtt_topic_qos *topic_arr; /* array of mqtt_topic_qos instances + continuous in memory */ + uint32_t topic_count; /* not included in the message itself */ +} mqtt_subscribe_payload; + +typedef struct { + uint8_t *ret_code_arr; /* array of return codes continuous in memory */ + uint32_t ret_code_count; /* not included in the message itself */ +} mqtt_suback_payload; + +typedef struct { + mqtt_buf *topic_arr; /* array of topic_arr continuous in memory */ + uint32_t topic_count; /* not included in the message itself */ +} mqtt_unsubscribe_payload; + +/***************************************************************************** + * Union to cover all Payload types + ****************************************************************************/ +union mqtt_payload { + mqtt_connect_payload connect; + mqtt_publish_payload publish; + mqtt_subscribe_payload subscribe; + mqtt_suback_payload suback; + mqtt_unsubscribe_payload unsubscribe; +}; + +typedef struct { + uint8_t bit_0 : 1; + uint8_t bit_1 : 1; + uint8_t bit_2 : 1; + uint8_t bit_3 : 1; + mqtt_packet_type packet_type : 4; +} mqtt_common_hdr; + +typedef struct { + uint8_t retain : 1; + uint8_t qos : 2; + uint8_t dup : 1; + mqtt_packet_type packet_type : 4; +} mqtt_pub_hdr; + +typedef struct mqtt_fixed_hdr_t { + union { + mqtt_common_hdr common; + mqtt_pub_hdr publish; + }; + + uint32_t remaining_length; /* up to 268,435,455 (256 MB) */ +} mqtt_fixed_hdr; + +typedef struct mqtt_msg_t { + /* Fixed header part */ + mqtt_fixed_hdr fixed_header; + union mqtt_variable_header var_header; + union mqtt_payload payload; + + uint8_t used_bytes : 4; /* byte count for used remainingLength + representation This information (combined with + packetType and packetFlags) may be used to + jump the point where the actual data starts */ + + bool is_decoded : 1; /* message is obtained from decoded or encoded */ + bool attached_raw : 1; /* indicates if entire_raw_msg is to be owned */ + uint8_t _unused : 2; + +} mqtt_msg; + +extern int byte_number_for_variable_length(uint32_t variable); +extern int write_variable_length_value(uint32_t value, struct pos_buf *buf); +extern int write_byte(uint8_t val, struct pos_buf *buf); +extern int write_uint16(uint16_t value, struct pos_buf *buf); +extern int write_byte_string(mqtt_buf *str, struct pos_buf *buf); + +extern int read_byte(struct pos_buf *buf, uint8_t *val); +extern int read_uint16(struct pos_buf *buf, uint16_t *val); +extern int read_utf8_str(struct pos_buf *buf, mqtt_buf *val); +extern int read_str_data(struct pos_buf *buf, mqtt_buf *val); +extern int read_packet_length(struct pos_buf *buf, uint32_t *length); + +extern mqtt_buf mqtt_buf_dup(const mqtt_buf *src); +extern void mqtt_buf_free(mqtt_buf *buf); + +extern mqtt_msg *mqtt_msg_create(mqtt_packet_type packet_type); + +extern int mqtt_msg_dump( + mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes); + +extern int nni_mqtt_msg_encode(nni_msg *msg); +extern int nni_mqtt_msg_decode(nni_msg *msg); + // nni_msg proto_data alloc/free extern int nni_mqtt_msg_proto_data_alloc(nni_msg *); extern void nni_mqtt_msg_proto_data_free(nni_msg *); // mqtt message alloc/encode/decode extern int nni_mqtt_msg_alloc(nni_msg **, size_t); -extern int nni_mqtt_msg_encode(nni_msg *); -extern int nni_mqtt_msg_decode(nni_msg *); +// extern int nni_mqtt_msg_encode(nni_msg *); +// extern int nni_mqtt_msg_decode(nni_msg *); // mqtt packet_type -extern void nni_mqtt_msg_set_packet_type( - nni_msg *, nni_mqtt_packet_type packet_type); +extern void nni_mqtt_msg_set_packet_type(nni_msg *, nni_mqtt_packet_type); extern nni_mqtt_packet_type nni_mqtt_msg_get_packet_type(nni_msg *); // mqtt connect @@ -108,8 +376,7 @@ extern nni_mqtt_topic *nni_mqtt_msg_get_unsubscribe_topics( extern void nni_mqtt_msg_set_unsuback_packet_id(nni_msg *, uint16_t); extern uint16_t nni_mqtt_msg_get_unsuback_packet_id(nni_msg *); -extern void nni_mqtt_msg_dump( - nni_msg *msg, uint8_t *buffer, uint32_t len, bool print_bytes); +extern void nni_mqtt_msg_dump(nni_msg *, uint8_t *, uint32_t, bool); // mqtt topic create/free extern nni_mqtt_topic *nni_mqtt_topic_array_create(size_t n); extern void nni_mqtt_topic_array_set(nni_mqtt_topic *, size_t, const char *); @@ -121,4 +388,8 @@ extern void nni_mqtt_topic_qos_array_set( nni_mqtt_topic_qos *, size_t, const char *, uint8_t); extern void nni_mqtt_topic_qos_array_free(nni_mqtt_topic_qos *, size_t); +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c new file mode 100644 index 000000000..cfecc269b --- /dev/null +++ b/src/mqtt/mqtt_codec.c @@ -0,0 +1,1486 @@ + +#include "mqtt.h" + +#include +#include +#include + +static void nni_mqtt_msg_append_u8(nni_msg *, uint8_t); +static void nni_mqtt_msg_append_u16(nni_msg *, uint16_t); +static void nni_mqtt_msg_append_byte_str(nni_msg *, nni_mqtt_buffer *); + +static void nni_mqtt_msg_encode_fixed_header(nni_msg *, nni_mqtt_proto_data *); +static int nni_mqtt_msg_encode_connect(nni_msg *); +static int nni_mqtt_msg_encode_connack(nni_msg *); +static int nni_mqtt_msg_encode_subscribe(nni_msg *); +static int nni_mqtt_msg_encode_suback(nni_msg *); +static int nni_mqtt_msg_encode_publish(nni_msg *); +static int nni_mqtt_msg_encode_puback(nni_msg *); +static int nni_mqtt_msg_encode_pubrec(nni_msg *); +static int nni_mqtt_msg_encode_pubrel(nni_msg *); +static int nni_mqtt_msg_encode_pubcomp(nni_msg *); +static int nni_mqtt_msg_encode_unsubscribe(nni_msg *); +static int nni_mqtt_msg_encode_unsuback(nni_msg *); +static int nni_mqtt_msg_encode_base(nni_msg *); + +static int nni_mqtt_msg_decode_fixed_header(nni_msg *); +static int nni_mqtt_msg_decode_connect(nni_msg *); +static int nni_mqtt_msg_decode_connack(nni_msg *); +static int nni_mqtt_msg_decode_subscribe(nni_msg *); +static int nni_mqtt_msg_decode_suback(nni_msg *); +static int nni_mqtt_msg_decode_publish(nni_msg *); +static int nni_mqtt_msg_decode_puback(nni_msg *); +static int nni_mqtt_msg_decode_pubrec(nni_msg *); +static int nni_mqtt_msg_decode_pubrel(nni_msg *); +static int nni_mqtt_msg_decode_pubcomp(nni_msg *); +static int nni_mqtt_msg_decode_unsubscribe(nni_msg *); +static int nni_mqtt_msg_decode_unsuback(nni_msg *); +static int nni_mqtt_msg_decode_base(nni_msg *); + +typedef struct { + nni_mqtt_packet_type packet_type; + int (*encode)(nni_msg *); + int (*decode)(nni_msg *); +} mqtt_msg_codec_handler; + +static mqtt_msg_codec_handler codec_handler[] = { + { NNG_MQTT_CONNECT, nni_mqtt_msg_encode_connect, + nni_mqtt_msg_decode_connect }, + { NNG_MQTT_CONNACK, nni_mqtt_msg_encode_connack, + nni_mqtt_msg_decode_connack }, + { NNG_MQTT_PUBLISH, nni_mqtt_msg_encode_publish, + nni_mqtt_msg_decode_publish }, + { NNG_MQTT_PUBACK, nni_mqtt_msg_encode_puback, + nni_mqtt_msg_decode_puback }, + { NNG_MQTT_PUBREC, nni_mqtt_msg_encode_pubrec, + nni_mqtt_msg_decode_pubrec }, + { NNG_MQTT_PUBREL, nni_mqtt_msg_encode_pubrel, + nni_mqtt_msg_decode_pubrel }, + { NNG_MQTT_PUBCOMP, nni_mqtt_msg_encode_pubcomp, + nni_mqtt_msg_decode_pubcomp }, + { NNG_MQTT_SUBSCRIBE, nni_mqtt_msg_encode_subscribe, + nni_mqtt_msg_decode_subscribe }, + { NNG_MQTT_SUBACK, nni_mqtt_msg_encode_suback, + nni_mqtt_msg_decode_suback }, + { NNG_MQTT_UNSUBSCRIBE, nni_mqtt_msg_encode_unsubscribe, + nni_mqtt_msg_decode_unsubscribe }, + { NNG_MQTT_UNSUBACK, nni_mqtt_msg_encode_unsuback, + nni_mqtt_msg_decode_unsuback }, + { NNG_MQTT_PINGREQ, nni_mqtt_msg_encode_base, + nni_mqtt_msg_decode_base }, + { NNG_MQTT_PINGRESP, nni_mqtt_msg_encode_base, + nni_mqtt_msg_decode_base }, + { NNG_MQTT_DISCONNECT, nni_mqtt_msg_encode_base, + nni_mqtt_msg_decode_base } +}; + +int +nni_mqtt_msg_encode(nni_msg *msg) +{ + nni_msg_clear(msg); + nni_msg_header_clear(msg); + + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + for (size_t i = 0; + i < sizeof(codec_handler) / sizeof(mqtt_msg_codec_handler); i++) { + if (codec_handler[i].packet_type == + mqtt->fixed_header.common.packet_type) { + return codec_handler[i].encode(msg); + } + } + + return MQTT_ERR_PROTOCOL; +} + +int +nni_mqtt_msg_decode(nni_msg *msg) +{ + int ret; + if ((ret = nni_mqtt_msg_decode_fixed_header(msg)) != MQTT_SUCCESS) { + nni_plat_printf("decode_fixed_header failed %d\n", ret); + return ret; + } + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + for (size_t i = 0; + i < sizeof(codec_handler) / sizeof(mqtt_msg_codec_handler); i++) { + if (codec_handler[i].packet_type == + mqtt->fixed_header.common.packet_type) { + mqtt->is_decoded = true; + return codec_handler[i].decode(msg); + } + } + + return MQTT_ERR_PROTOCOL; +} + +static void +nni_mqtt_msg_append_u8(nni_msg *msg, uint8_t val) +{ + nni_msg_append(msg, &val, 1); +} + +static void +nni_mqtt_msg_append_u16(nni_msg *msg, uint16_t val) +{ + uint8_t buf[2] = { 0 }; + NNI_PUT16(buf, val); + nni_msg_append(msg, buf, 2); +} + +static void +nni_mqtt_msg_append_byte_str(nni_msg *msg, nni_mqtt_buffer *str) +{ + nni_mqtt_msg_append_u16(msg, (uint16_t) str->length); + nni_msg_append(msg, str->buf, str->length); +} + +static void +nni_mqtt_msg_encode_fixed_header(nni_msg *msg, nni_mqtt_proto_data *data) +{ + uint8_t rlen[4] = { 0 }; + struct pos_buf buf = { .curpos = &rlen[0], + .endpos = &rlen[sizeof(rlen) / sizeof(rlen[0]) - 1] }; + + nni_msg_header_clear(msg); + uint8_t header = *(uint8_t *) &data->fixed_header.common; + + nni_msg_header_append(msg, &header, 1); + + int len = write_variable_length_value( + data->fixed_header.remaining_length, &buf); + + nni_msg_header_append(msg, rlen, len); +} + +static int +nni_mqtt_msg_encode_connect(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + nni_msg_clear(msg); + + int poslength = 6; + + mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; + + /* length of protocol-name (consider "MQTT" by default */ + poslength += (var_header->protocol_name.length == 0) + ? 4 + : var_header->protocol_name.length; + + /* add the length of payload part */ + mqtt_connect_payload *payload = &mqtt->payload.connect; + + /* Will Topic */ + if (payload->will_topic.length > 0) { + poslength += 2 + payload->will_topic.length; + var_header->conn_flags.will_flag = 1; + } + /* Will Message */ + if (payload->will_msg.length > 0) { + poslength += 2 + payload->will_msg.length; + var_header->conn_flags.will_flag = 1; + } + /* User Name */ + if (payload->user_name.length > 0) { + poslength += 2 + payload->user_name.length; + var_header->conn_flags.username_flag = 1; + } + /* Password */ + if (payload->password.length > 0) { + poslength += 2 + payload->password.length; + var_header->conn_flags.password_flag = 1; + } + + mqtt->fixed_header.remaining_length = poslength; + if (mqtt->fixed_header.remaining_length > MQTT_MAX_MSG_LEN) { + return MQTT_ERR_PAYLOAD_SIZE; + } + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + nni_mqtt_msg_append_byte_str(msg, &var_header->protocol_name); + + nni_mqtt_msg_append_u8(msg, var_header->protocol_version); + + /* Connect Flags */ + nni_mqtt_msg_append_u8(msg, *(uint8_t *) &var_header->conn_flags); + + /* Keep Alive */ + nni_mqtt_msg_append_u16(msg, var_header->keep_alive); + + /* Now we are in payload part */ + + /* Client Identifier */ + /* Client Identifier is mandatory */ + nni_mqtt_msg_append_byte_str(msg, &payload->client_id); + + /* Will Topic */ + if (payload->will_topic.length) { + if (!(var_header->conn_flags.will_flag)) { + return MQTT_ERR_PROTOCOL; + } + nni_mqtt_msg_append_byte_str(msg, &payload->will_topic); + } else { + if (var_header->conn_flags.will_flag) { + return MQTT_ERR_PROTOCOL; + } + } + + /* Will Message */ + if (payload->will_msg.length) { + if (!(var_header->conn_flags.will_flag)) { + return MQTT_ERR_PROTOCOL; + } + nni_mqtt_msg_append_byte_str(msg, &payload->will_msg); + } else { + if (var_header->conn_flags.will_flag) { + return MQTT_ERR_PROTOCOL; + } + } + + /* User-Name */ + if (payload->user_name.length) { + if (!(var_header->conn_flags.username_flag)) { + return MQTT_ERR_PROTOCOL; + } + nni_mqtt_msg_append_byte_str(msg, &payload->user_name); + } else { + if (var_header->conn_flags.username_flag) { + return MQTT_ERR_PROTOCOL; + } + } + + /* Password */ + if (payload->password.length) { + if (!(var_header->conn_flags.password_flag)) { + return MQTT_ERR_PROTOCOL; + } + nni_mqtt_msg_append_byte_str(msg, &payload->password); + } else { + if (var_header->conn_flags.password_flag) { + return MQTT_ERR_PROTOCOL; + } + } + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_connack(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* ConnAck Flags(1) + Connect Return Code(1) */ + + mqtt_connack_vhdr *var_header = &mqtt->var_header.connack; + + mqtt->fixed_header.remaining_length = poslength; + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + /* Connect Acknowledge Flags */ + nni_mqtt_msg_append_u8(msg, *(uint8_t *) &var_header->connack_flags); + + /* Connect Return Code */ + nni_mqtt_msg_append_u8( + msg, *(uint8_t *) &var_header->conn_return_code); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_subscribe(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 0; + + poslength += 2; /* for Packet Identifier */ + + mqtt_subscribe_payload *spld = &mqtt->payload.subscribe; + + /* Go through topic filters to calculate length information */ + for (size_t i = 0; i < spld->topic_count; i++) { + mqtt_topic_qos *topic = &spld->topic_arr[i]; + poslength += topic->topic.length; + poslength += 1; // for 'options' byte + poslength += 2; // for 'length' field of Topic Filter, which is + // encoded as UTF-8 encoded strings */ + } + + mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.common.bit_1 = 1; + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + mqtt_subscribe_vhdr *var_header = &mqtt->var_header.subscribe; + /* Packet Id */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + /* Subscribe topic_arr */ + for (size_t i = 0; i < spld->topic_count; i++) { + mqtt_topic_qos *topic = &spld->topic_arr[i]; + nni_mqtt_msg_append_byte_str(msg, &topic->topic); + nni_mqtt_msg_append_u8(msg, topic->qos); + } + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_suback(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_suback_vhdr * var_header = &mqtt->var_header.suback; + mqtt_suback_payload *spld = &mqtt->payload.suback; + + poslength += spld->ret_code_count; + + mqtt->fixed_header.remaining_length = poslength; + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + /* Return Codes */ + nni_msg_append(msg, spld->ret_code_arr, spld->ret_code_count); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_publish(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 0; + + poslength += 2; /* for Topic Name length field */ + poslength += mqtt->var_header.publish.topic_name.length; + /* Packet Identifier is requested if QoS>0 */ + if (mqtt->fixed_header.publish.qos > 0) { + poslength += 2; /* for Packet Identifier */ + } + poslength += mqtt->payload.publish.payload.length; + mqtt->fixed_header.remaining_length = poslength; + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + mqtt_publish_vhdr *var_header = &mqtt->var_header.publish; + + /* Topic Name */ + nni_mqtt_msg_append_byte_str(msg, &var_header->topic_name); + + if (mqtt->fixed_header.publish.qos > 0) { + /* Packet Id */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + } + + /* Payload */ + if (mqtt->payload.publish.payload.length > 0) { + nni_msg_append(msg, mqtt->payload.publish.payload.buf, + mqtt->payload.publish.payload.length); + } + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_puback(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_puback_vhdr *var_header = &mqtt->var_header.puback; + + mqtt->fixed_header.remaining_length = poslength; + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_pubrec(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + mqtt->fixed_header.remaining_length = poslength; + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + mqtt_pubrec_vhdr *var_header = &mqtt->var_header.pubrec; + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_pubrel(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_pubrec_vhdr *var_header = &mqtt->var_header.pubrec; + + mqtt->fixed_header.common.bit_1 = 1; + mqtt->fixed_header.remaining_length = poslength; + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_pubcomp(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_pubcomp_vhdr *var_header = &mqtt->var_header.pubcomp; + + mqtt->fixed_header.remaining_length = poslength; + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_unsubscribe(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 0; + + poslength += 2; /* for Packet Identifier */ + + mqtt_unsubscribe_payload *uspld = &mqtt->payload.unsubscribe; + + /* Go through topic filters to calculate length information */ + for (size_t i = 0; i < uspld->topic_count; i++) { + mqtt_buf *topic = &uspld->topic_arr[i]; + poslength += topic->length; + poslength += 2; // for 'length' field of Topic Filter, which is + // encoded as UTF-8 encoded strings */ + } + + mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.common.bit_1 = 1; + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + mqtt_subscribe_vhdr *var_header = &mqtt->var_header.subscribe; + /* Packet Id */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + /* Subscribe topic_arr */ + for (size_t i = 0; i < uspld->topic_count; i++) { + mqtt_buf *topic = &uspld->topic_arr[i]; + nni_mqtt_msg_append_byte_str(msg, topic); + } + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_unsuback(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + int poslength = 2; /* for Packet Identifier */ + + mqtt_unsuback_vhdr *var_header = &mqtt->var_header.unsuback; + + mqtt->fixed_header.remaining_length = poslength; + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + /* Packet Identifier */ + nni_mqtt_msg_append_u16(msg, var_header->packet_id); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_encode_base(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_msg_clear(msg); + + mqtt->fixed_header.remaining_length = 0; + + nni_mqtt_msg_encode_fixed_header(msg, mqtt); + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_decode_fixed_header(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + size_t len = nni_msg_header_len(msg); + uint8_t *header = nni_msg_header(msg); + + if (len < 2) { + return MQTT_ERR_PROTOCOL; + } + + uint8_t first = (uint8_t)(*header); + + memcpy(&mqtt->fixed_header.common, &first, 1); + + int multiplier = 1; + int32_t lword = 0; + uint8_t lbytes = 0; + uint8_t *ptr = header + 1; + uint8_t *start = ptr; + + uint32_t remain_len = 0; + uint8_t count = 0; + + for (size_t i = 0; i < 4; i++) { + if ((size_t)(ptr - start + 1) > len) { + return MQTT_ERR_PAYLOAD_SIZE; + } + lbytes++; + uint8_t byte = ptr[0]; + lword += (byte & 127) * multiplier; + multiplier *= 128; + ptr++; + if ((byte & 128) == 0) { + if (lbytes > 1 && byte == 0) { + return MQTT_ERR_INVAL; + } else { + remain_len = lword; + count = lbytes; + break; + } + } + } + + mqtt->fixed_header.remaining_length = remain_len; + mqtt->used_bytes = count; + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_decode_connect(nni_msg *msg) +{ + int ret; + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + uint8_t *body = nni_msg_body(msg); + size_t length = nni_msg_len(msg); + + struct pos_buf buf; + buf.curpos = &body[0]; + buf.endpos = &body[length]; + + /* Protocol Name */ + ret = read_str_data(&buf, &mqtt->var_header.connect.protocol_name); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + /* Protocol Level */ + ret = read_byte(&buf, &mqtt->var_header.connect.protocol_version); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + /* Protocol Level */ + ret = + read_byte(&buf, (uint8_t *) &mqtt->var_header.connect.conn_flags); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + + /* Keep Alive */ + ret = read_uint16(&buf, &mqtt->var_header.connect.keep_alive); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + /* Client Identifier */ + ret = read_utf8_str(&buf, &mqtt->payload.connect.client_id); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + if (mqtt->var_header.connect.conn_flags.will_flag) { + /* Will Topic */ + ret = read_utf8_str(&buf, &mqtt->payload.connect.will_topic); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + /* Will Message */ + ret = read_str_data(&buf, &mqtt->payload.connect.will_msg); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + } + if (mqtt->var_header.connect.conn_flags.username_flag) { + /* Will Topic */ + ret = read_utf8_str(&buf, &mqtt->payload.connect.user_name); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + } + if (mqtt->var_header.connect.conn_flags.password_flag) { + /* Will Topic */ + ret = read_str_data(&buf, &mqtt->payload.connect.password); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + } + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_decode_connack(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + uint8_t *body = nni_msg_body(msg); + size_t length = nni_msg_len(msg); + + struct pos_buf buf; + buf.curpos = &body[0]; + buf.endpos = &body[length]; + + int result = read_byte(&buf, &mqtt->var_header.connack.connack_flags); + if (result != 0) { + return MQTT_ERR_PROTOCOL; + } + + /* Connect Return Code */ + result = read_byte(&buf, &mqtt->var_header.connack.connack_flags); + if (result != 0) { + return MQTT_ERR_PROTOCOL; + } + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_decode_subscribe(nni_msg *msg) +{ + int ret; + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + uint8_t *body = nni_msg_body(msg); + size_t length = nni_msg_len(msg); + + struct pos_buf buf; + buf.curpos = &body[0]; + buf.endpos = &body[length]; + + mqtt_subscribe_payload *spld = &mqtt->payload.subscribe; + + /* Packet Identifier */ + ret = read_uint16(&buf, &mqtt->var_header.subscribe.packet_id); + if (ret != 0) { + return MQTT_ERR_PROTOCOL; + } + + uint8_t *saved_current_pos = NULL; + uint16_t temp_length = 0; + uint32_t topic_count = 0; + + /* The loop to determine the number of topic_arr. + * TODO: Some other way may be used such as std::vector to collect + * topic_arr but there is a question that which is faster + */ + /* Save the current position to back */ + saved_current_pos = buf.curpos; + while (buf.curpos < buf.endpos) { + ret = read_uint16(&buf, &temp_length); + /* jump to the end of topic-name */ + buf.curpos += temp_length; + /* skip QoS field */ + buf.curpos++; + topic_count++; + } + /* Allocate topic_qos array */ + spld->topic_arr = + (mqtt_topic_qos *) nni_alloc(sizeof(mqtt_topic_qos) * topic_count); + + /* Set back current position */ + buf.curpos = saved_current_pos; + while (buf.curpos < buf.endpos) { + /* Topic Name */ + ret = read_utf8_str( + &buf, &spld->topic_arr[spld->topic_count].topic); + if (ret != MQTT_SUCCESS) { + + ret = MQTT_ERR_PROTOCOL; + goto ERROR; + } + /* QoS */ + ret = read_byte(&buf, &spld->topic_arr[spld->topic_count].qos); + if (ret != MQTT_SUCCESS) { + ret = MQTT_ERR_PROTOCOL; + goto ERROR; + } + spld->topic_count++; + } + return ret; + +ERROR: + nni_free(spld->topic_arr, topic_count); + return ret; +} + +static int +nni_mqtt_msg_decode_suback(nni_msg *msg) +{ + int ret; + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + uint8_t *body = nni_msg_body(msg); + size_t length = nni_msg_len(msg); + + struct pos_buf buf; + buf.curpos = &body[0]; + buf.endpos = &body[length]; + + ret = read_uint16(&buf, &mqtt->var_header.suback.packet_id); + if (ret != MQTT_SUCCESS) { + return MQTT_ERR_PROTOCOL; + } + + /* Suback Return Codes */ + mqtt->payload.suback.ret_code_count = buf.endpos - buf.curpos; + + mqtt->payload.suback.ret_code_arr = (uint8_t *) nni_alloc( + mqtt->payload.suback.ret_code_count * sizeof(uint8_t)); + uint8_t *ptr = mqtt->payload.suback.ret_code_arr; + + for (uint32_t i = 0; i < mqtt->payload.suback.ret_code_count; i++) { + ret = read_byte(&buf, ptr); + if (ret != MQTT_SUCCESS) { + ret = MQTT_ERR_PROTOCOL; + goto ERROR; + } + ptr++; + } + return MQTT_SUCCESS; + +ERROR: + nni_free(mqtt->payload.suback.ret_code_arr, + mqtt->payload.suback.ret_code_count * sizeof(uint8_t)); + return ret; +} + +static int +nni_mqtt_msg_decode_publish(nni_msg *msg) +{ + int ret; + int packid_length = 0; + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + uint8_t *body = nni_msg_body(msg); + size_t length = nni_msg_len(msg); + + struct pos_buf buf; + buf.curpos = &body[0]; + buf.endpos = &body[length]; + + /* Topic Name */ + ret = read_utf8_str(&buf, &mqtt->var_header.publish.topic_name); + if (ret != MQTT_SUCCESS) { + return MQTT_ERR_PROTOCOL; + } + + if (mqtt->fixed_header.publish.qos > MQTT_QOS_0_AT_MOST_ONCE) { + /* Packet Identifier */ + ret = read_uint16(&buf, &mqtt->var_header.publish.packet_id); + if (ret != MQTT_SUCCESS) { + return MQTT_ERR_PROTOCOL; + } + packid_length = 2; + } + + /* Payload */ + /* No length information for payload. The length of the payload can be + calculated by subtracting the length of the variable header from the + Remaining Length field that is in the Fixed Header. It is valid for + a PUBLISH Packet to contain a zero length payload.*/ + mqtt->payload.publish.payload.length = + mqtt->fixed_header.remaining_length - + (2 /* Length bytes of Topic Name */ + + mqtt->var_header.publish.topic_name.length + packid_length); + mqtt->payload.publish.payload.buf = + (mqtt->payload.publish.payload.length > 0) ? buf.curpos : NULL; + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_decode_base_with_packet_id(nni_msg *msg, uint16_t *packet_id) +{ + uint8_t *body = nni_msg_body(msg); + size_t length = nni_msg_len(msg); + + struct pos_buf buf; + buf.curpos = &body[0]; + buf.endpos = &body[length]; + + int result = read_uint16(&buf, packet_id); + if (result != MQTT_SUCCESS) { + return MQTT_ERR_PROTOCOL; + } + + return MQTT_SUCCESS; +} + +static int +nni_mqtt_msg_decode_puback(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + return nni_mqtt_msg_decode_base_with_packet_id( + msg, &mqtt->var_header.puback.packet_id); +} + +static int +nni_mqtt_msg_decode_pubrec(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + return nni_mqtt_msg_decode_base_with_packet_id( + msg, &mqtt->var_header.pubrec.packet_id); +} + +static int +nni_mqtt_msg_decode_pubrel(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + return nni_mqtt_msg_decode_base_with_packet_id( + msg, &mqtt->var_header.pubrel.packet_id); +} + +static int +nni_mqtt_msg_decode_pubcomp(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + return nni_mqtt_msg_decode_base_with_packet_id( + msg, &mqtt->var_header.pubcomp.packet_id); +} + +static int +nni_mqtt_msg_decode_unsubscribe(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + uint8_t * body = nni_msg_body(msg); + size_t length = nni_msg_len(msg); + + struct pos_buf buf; + buf.curpos = &body[0]; + buf.endpos = &body[length]; + mqtt_unsubscribe_payload *uspld = &mqtt->payload.unsubscribe; + + int ret = read_uint16(&buf, &mqtt->var_header.unsubscribe.packet_id); + if (ret != MQTT_SUCCESS) { + return MQTT_ERR_PROTOCOL; + } + + uint8_t *saved_current_pos = NULL; + uint16_t temp_length = 0; + uint32_t topic_count = 0; + + saved_current_pos = buf.curpos; + while (buf.curpos < buf.endpos) { + ret = read_uint16(&buf, &temp_length); + /* jump to the end of topic-name */ + buf.curpos += temp_length; + /* skip QoS field */ + topic_count++; + } + + /* Allocate topic array */ + uspld->topic_arr = + (mqtt_buf *) nni_alloc(topic_count * sizeof(mqtt_buf)); + // uspld->topic_arr = (mqtt_buf *) malloc(topic_count * + // sizeof(mqtt_buf)); + + /* Set back current position */ + buf.curpos = saved_current_pos; + while (buf.curpos < buf.endpos) { + /* Topic Name */ + ret = + read_utf8_str(&buf, &uspld->topic_arr[uspld->topic_count]); + if (ret != 0) { + ret = MQTT_ERR_PROTOCOL; + goto ERROR; + } + uspld->topic_count++; + } + +ERROR: + nni_free(uspld->topic_arr, topic_count); + + return ret; +} + +static int +nni_mqtt_msg_decode_unsuback(nni_msg *msg) +{ + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + return nni_mqtt_msg_decode_base_with_packet_id( + msg, &mqtt->var_header.unsuback.packet_id); +} + +static int +nni_mqtt_msg_decode_base(nni_msg *msg) +{ + NNI_ARG_UNUSED(msg); + return MQTT_SUCCESS; +} + +int +byte_number_for_variable_length(uint32_t variable) +{ + if (variable < 128) { + return 1; + } else if (variable < 16384) { + return 2; + } else if (variable < 2097152) { + return 3; + } else if (variable < 268435456) { + return 4; + } + return 5; +} + +int +write_variable_length_value(uint32_t value, struct pos_buf *buf) +{ + uint8_t byte; + int count = 0; + + do { + byte = value % 128; + value = value / 128; + /* If there are more digits to encode, set the top bit of this + * digit */ + if (value > 0) { + byte = byte | 0x80; + } + *(buf->curpos++) = byte; + count++; + } while (value > 0 && count < 5); + + if (count == 5) { + return -1; + } + return count; +} + +int +write_byte(uint8_t val, struct pos_buf *buf) +{ + if ((buf->endpos - buf->curpos) < 1) { + return MQTT_ERR_NOMEM; + } + + *(buf->curpos++) = val; + + return 0; +} + +int +write_uint16(uint16_t value, struct pos_buf *buf) +{ + if ((buf->endpos - buf->curpos) < 2) { + return MQTT_ERR_NOMEM; + } + + *(buf->curpos++) = (value >> 8) & 0xFF; + *(buf->curpos++) = value & 0xFF; + + return 0; +} + +int +write_byte_string(mqtt_buf *str, struct pos_buf *buf) +{ + if ((buf->endpos - buf->curpos) < (str->length + 2)) { + return MQTT_ERR_NOMEM; + } + write_uint16(str->length, buf); + + memcpy(buf->curpos, str->buf, str->length); + str->buf = buf->curpos; /* reset data position to indicate data in raw + data block */ + buf->curpos += str->length; + + return 0; +} + +int +read_byte(struct pos_buf *buf, uint8_t *val) +{ + if ((buf->endpos - buf->curpos) < 1) { + return MQTT_ERR_NOMEM; + } + + *val = *(buf->curpos++); + + return 0; +} + +int +read_uint16(struct pos_buf *buf, uint16_t *val) +{ + if ((size_t)(buf->endpos - buf->curpos) < sizeof(uint16_t)) { + return MQTT_ERR_INVAL; + } + + *val = *(buf->curpos++) << 8; /* MSB */ + *val |= *(buf->curpos++); /* LSB */ + + return 0; +} + +int +read_utf8_str(struct pos_buf *buf, mqtt_buf *val) +{ + uint16_t length = 0; + int ret = read_uint16(buf, &length); + if (ret != 0) { + return ret; + } + if ((buf->endpos - buf->curpos) < length) { + return MQTT_ERR_INVAL; + } + + val->length = length; + /* Zero length UTF8 strings are permitted. */ + if (length > 0) { + val->buf = buf->curpos; + buf->curpos += length; + } else { + val->buf = NULL; + } + return 0; +} + +int +read_str_data(struct pos_buf *buf, mqtt_buf *val) +{ + uint16_t length = 0; + int ret = read_uint16(buf, &length); + if (ret != 0) { + return ret; + } + if ((buf->endpos - buf->curpos) < length) { + return MQTT_ERR_INVAL; + } + + val->length = length; + if (length > 0) { + val->buf = buf->curpos; + buf->curpos += length; + } else { + val->buf = NULL; + } + return 0; +} + +int +read_packet_length(struct pos_buf *buf, uint32_t *length) +{ + uint8_t shift = 0; + uint32_t bytes = 0; + + *length = 0; + do { + if (bytes >= MQTT_MAX_MSG_LEN) { + return MQTT_ERR_INVAL; + } + + if (buf->curpos >= buf->endpos) { + return MQTT_ERR_MALFORMED; + } + + *length += + ((uint32_t) * (buf->curpos) & MQTT_LENGTH_VALUE_MASK) + << shift; + shift += MQTT_LENGTH_SHIFT; + bytes++; + } while ((*(buf->curpos++) & MQTT_LENGTH_CONTINUATION_BIT) != 0U); + + if (*length > MQTT_MAX_MSG_LEN) { + return MQTT_ERR_INVAL; + } + + return 0; +} + +mqtt_buf +mqtt_buf_dup(const mqtt_buf *src) +{ + mqtt_buf dest; + + dest.length = src->length; + dest.buf = malloc(dest.length); + memcpy(dest.buf, src->buf, dest.length); + return dest; +} + +void +mqtt_buf_free(mqtt_buf *buf) +{ + free(buf->buf); +} + +static mqtt_msg * +mqtt_msg_create_empty(void) +{ + mqtt_msg *msg = (mqtt_msg *) malloc(sizeof(mqtt_msg)); + memset((char *) msg, 0, sizeof(mqtt_msg)); + + return msg; +} + +mqtt_msg * +mqtt_msg_create(mqtt_packet_type packet_type) +{ + mqtt_msg *msg = mqtt_msg_create_empty(); + msg->fixed_header.common.packet_type = packet_type; + + return msg; +} + +int +mqtt_msg_destroy(mqtt_msg *self) +{ + free(self); + + return 0; +} + +const char * +get_packet_type_str(mqtt_packet_type packtype) +{ + static const char *packTypeNames[16] = { "Forbidden-0", "CONNECT", + "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", + "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", + "PINGRESP", "DISCONNECT", "Forbidden-15" }; + if (packtype > 15) { + packtype = 0; + } + return packTypeNames[packtype]; +} + +int +mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) +{ + uint32_t pos = 0; + int ret = 0; + + size_t i = 0; + + ret = sprintf((char *) &buf->buf[pos], + "\n----- mqtt message dump -----\n" + "packet type : %d (%s)\n" + "packet flags : |%d|%d|%d|%d|\n" + "remaining length : %d (%d bytes)\n", + msg->fixed_header.common.packet_type, + get_packet_type_str(msg->fixed_header.common.packet_type), + msg->fixed_header.common.bit_3, msg->fixed_header.common.bit_2, + msg->fixed_header.common.bit_1, msg->fixed_header.common.bit_0, + (int) msg->fixed_header.remaining_length, msg->used_bytes); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + + /* Print variable header part */ + switch (msg->fixed_header.common.packet_type) { + case MQTT_CONNECT: { + ret = sprintf((char *) &buf->buf[pos], + "protocol name : %.*s\n" + "protocol version : %d\n" + "keep alive : %d\n", + msg->var_header.connect.protocol_name.length, + msg->var_header.connect.protocol_name.buf, + (int) msg->var_header.connect.protocol_version, + (int) msg->var_header.connect.keep_alive); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + conn_flags flags_set = msg->var_header.connect.conn_flags; + + ret = sprintf((char *) &buf->buf[pos], + "connect flags:\n" + " clean session flag : %s,\n" + " will flag : %s,\n" + " will retain flag : %s,\n" + " will qos flag : %d,\n" + " user name flag : %s,\n" + " password flag : %s\n", + ((flags_set.clean_session) ? "true" : "false"), + ((flags_set.will_flag) ? "true" : "false"), + ((flags_set.will_retain) ? "true" : "false"), + flags_set.will_qos, + ((flags_set.username_flag) ? "true" : "false"), + ((flags_set.password_flag) ? "true" : "false")); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + ret = sprintf((char *) &buf->buf[pos], + "client identifier : %.*s\n", + msg->payload.connect.client_id.length, + msg->payload.connect.client_id.buf); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + ret = sprintf((char *) &buf->buf[pos], + "will topic : %.*s\n", + msg->payload.connect.will_topic.length, + msg->payload.connect.will_topic.buf); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + ret = sprintf((char *) &buf->buf[pos], + "will message : %.*s\n", + msg->payload.connect.will_msg.length, + msg->payload.connect.will_msg.buf); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + ret = sprintf((char *) &buf->buf[pos], + "user name : %.*s\n", + msg->payload.connect.user_name.length, + msg->payload.connect.user_name.buf); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + ret = sprintf((char *) &buf->buf[pos], + "password : %.*s\n", + msg->payload.connect.password.length, + msg->payload.connect.password.buf); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + } break; + + case MQTT_CONNACK: + ret = sprintf((char *) &buf->buf[pos], + "connack flags : %d\n" + "connack return-code: %d\n", + (int) msg->var_header.connack.connack_flags, + (int) msg->var_header.connack.conn_return_code); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + break; + + case MQTT_PUBLISH: { + + ret = sprintf((char *) &buf->buf[pos], + "publis flags:\n" + " retain : %s\n" + " qos : %d\n" + " dup : %s\n", + ((msg->fixed_header.publish.retain) ? "true" : "false"), + msg->fixed_header.publish.qos, + ((msg->fixed_header.publish.dup) ? "true" : "false")); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + ret = sprintf((char *) &buf->buf[pos], + "topic : %.*s\n" + "packet id : %d\n" + "payload : %.*s\n", + msg->var_header.publish.topic_name.length, + msg->var_header.publish.topic_name.buf, + (int) msg->var_header.publish.packet_id, + msg->payload.publish.payload.length, + msg->payload.publish.payload.buf); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + } break; + + case MQTT_PUBACK: + ret = sprintf((char *) &buf->buf[pos], "packet-id: %d\n", + msg->var_header.puback.packet_id); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + break; + + case MQTT_PUBREC: + ret = sprintf((char *) &buf->buf[pos], "packet-id: %d\n", + msg->var_header.pubrec.packet_id); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + break; + + case MQTT_PUBREL: + ret = sprintf((char *) &buf->buf[pos], "packet-id: %d\n", + msg->var_header.pubrel.packet_id); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + break; + + case MQTT_PUBCOMP: + ret = sprintf((char *) &buf->buf[pos], "packet-id: %d\n", + msg->var_header.pubcomp.packet_id); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + break; + + case MQTT_SUBSCRIBE: { + ret = sprintf((char *) &buf->buf[pos], + "packet-id : %d\n", + msg->var_header.subscribe.packet_id); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + for (uint32_t i = 0; i < msg->payload.subscribe.topic_count; + i++) { + ret = sprintf((char *) &buf->buf[pos], + "topic [%u] : %.*s\n" + "requested qos[%u] : %d\n", + i, + msg->payload.subscribe.topic_arr[i].topic.length, + msg->payload.subscribe.topic_arr[i].topic.buf, i, + (int) msg->payload.subscribe.topic_arr[i].qos); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + } + } break; + + case MQTT_SUBACK: { + ret = sprintf((char *) &buf->buf[pos], + "packet-id : %d\n", + msg->var_header.suback.packet_id); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + for (uint32_t i = 0; i < msg->payload.suback.ret_code_count; + i++) { + ret = sprintf((char *) &buf->buf[pos], + "return code[%u]: %d\n", i, + (int) msg->payload.suback.ret_code_arr[i]); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + } + } break; + + case MQTT_UNSUBSCRIBE: { + ret = sprintf((char *) &buf->buf[pos], + "packet-id : %d\n", + msg->var_header.unsubscribe.packet_id); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + for (i = 0; i < msg->payload.unsubscribe.topic_count; i++) { + ret = sprintf((char *) &buf->buf[pos], + "topic [%lu] : %.*s\n", i, + msg->payload.unsubscribe.topic_arr[i].length, + (char *) msg->payload.unsubscribe.topic_arr[i] + .buf); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + } + } break; + + case MQTT_UNSUBACK: + ret = sprintf((char *) &buf->buf[pos], + "packet-id : %d\n", + msg->var_header.unsuback.packet_id); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + break; + + case MQTT_PINGREQ: + case MQTT_PINGRESP: + break; + + case MQTT_DISCONNECT: + break; + + case MQTT_AUTH: + break; + } + + if (print_bytes) { + ret = sprintf((char *) &buf->buf[pos], "raw message: "); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + for (i = 0; i < packet->length; i++) { + ret = sprintf((char *) &buf->buf[pos], "%02x ", + ((uint8_t)(packet->buf[i] & 0xff))); + if ((ret < 0) || ((pos + ret) > buf->length)) { + return 1; + } + pos += ret; + } + buf->buf[pos++] = '\n'; + if (pos > packet->length) { + return 1; + } + sprintf((char *) &buf->buf[pos], "------------------------\n"); + } + return 0; +} diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c new file mode 100644 index 000000000..d0be76b99 --- /dev/null +++ b/src/mqtt/mqtt_test.c @@ -0,0 +1,268 @@ +#include + +#include "nng/nng.h" + +#include "nuts.h" + +void +test_alloc(void) +{ + nng_msg *msg; + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + nng_msg_free(msg); +} + +void +test_dup(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); + + size_t sz = 2; + nng_mqtt_topic_qos *topic_qos = nng_mqtt_topic_qos_array_create(sz); + nng_mqtt_topic_qos_array_set(topic_qos, 0, "/nanomq/mqtt/msg/0", 1); + nng_mqtt_topic_qos_array_set(topic_qos, 1, "/nanomq/mqtt/msg/1", 1); + + nng_mqtt_msg_set_subscribe_topics(msg, topic_qos, sz); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + nng_msg *msg2; + NUTS_PASS(nng_msg_dup(&msg2, msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("msg: \n%s\n", print_buf); + + nng_mqtt_msg_dump(msg2, print_buf, 1024, true); + printf("msg2: \n%s\n", print_buf); + + nng_mqtt_topic_qos_array_free(topic_qos, sz); + + nng_msg_free(msg); + nng_msg_free(msg2); +} + +void +test_encode_connect(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); + + nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); + NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), + "nanomq-mqtt") == 0); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + +void +test_encode_subscribe(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); + + size_t sz = 2; + nng_mqtt_topic_qos *topic_qos = nng_mqtt_topic_qos_array_create(sz); + nng_mqtt_topic_qos_array_set(topic_qos, 0, "/nanomq/mqtt/msg/0", 1); + nng_mqtt_topic_qos_array_set(topic_qos, 1, "/nanomq/mqtt/msg/1", 1); + + nng_mqtt_msg_set_subscribe_topics(msg, topic_qos, sz); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + nng_mqtt_topic_qos_array_free(topic_qos, sz); + + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + +void +test_encode_unsubscribe(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); + + size_t sz = 2; + nng_mqtt_topic *topic_qos = nng_mqtt_topic_array_create(sz); + nng_mqtt_topic_array_set(topic_qos, 0, "/nanomq/mqtt/1"); + nng_mqtt_topic_array_set(topic_qos, 1, "/nanomq/mqtt/2"); + + nng_mqtt_msg_set_unsubscribe_topics(msg, topic_qos, sz); + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + nng_mqtt_topic_array_free(topic_qos, sz); + + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + +void +test_encode_disconnect(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + + nng_msg_free(msg); +} + +void +test_decode_connect(void) +{ + nng_msg *msg; + uint8_t connect[] = { + + 0x10, 0x3f, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54, 0x04, 0xc6, + 0x00, 0x3c, 0x00, 0x0c, 0x54, 0x65, 0x73, 0x74, 0x2d, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x31, 0x00, 0x0a, 0x77, 0x69, + 0x6c, 0x6c, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x00, 0x07, + 0x62, 0x79, 0x65, 0x2d, 0x62, 0x79, 0x65, 0x00, 0x05, 0x61, + 0x6c, 0x76, 0x69, 0x6e, 0x00, 0x09, 0x48, 0x48, 0x48, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36 + }; + + size_t sz = sizeof(connect) / sizeof(uint8_t); + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, sz - 2)); + + nng_msg_header_append(msg, connect, 2); + + memcpy(nng_msg_body(msg), connect + 2, sz - 2); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + +void +test_decode_publish(void) +{ + nng_msg *msg; + + uint8_t publish[] = { 0x34, 0xba, 0x03, 0x00, 0x10, 0x2f, 0x6e, 0x61, + 0x6e, 0x6f, 0x6d, 0x71, 0x2f, 0x6d, 0x71, 0x74, 0x74, 0x2f, + 0x6d, 0x73, 0x67, 0x03, 0x6c, 0x7b, 0x22, 0x62, 0x72, 0x6f, + 0x6b, 0x65, 0x72, 0x22, 0x20, 0x3a, 0x20, 0x22, 0x2f, 0x6e, + 0x61, 0x6e, 0x6f, 0x6d, 0x71, 0x22, 0x2c, 0x22, 0x73, 0x64, + 0x6b, 0x22, 0x20, 0x3a, 0x20, 0x22, 0x6d, 0x71, 0x74, 0x74, + 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x22, 0x2c, 0x22, 0x64, + 0x61, 0x74, 0x61, 0x22, 0x20, 0x3a, 0x20, 0x22, 0x31, 0x39, + 0x33, 0x37, 0x38, 0x38, 0x39, 0x37, 0x36, 0x38, 0x39, 0x31, + 0x39, 0x33, 0x37, 0x39, 0x38, 0x37, 0x35, 0x38, 0x39, 0x37, + 0x33, 0x39, 0x31, 0x38, 0x37, 0x38, 0x39, 0x33, 0x37, 0x39, + 0x38, 0x35, 0x36, 0x37, 0x39, 0x38, 0x37, 0x31, 0x38, 0x39, + 0x37, 0x39, 0x34, 0x38, 0x37, 0x36, 0x39, 0x37, 0x39, 0x38, + 0x34, 0x37, 0x39, 0x38, 0x32, 0x37, 0x38, 0x39, 0x34, 0x37, + 0x38, 0x39, 0x36, 0x37, 0x34, 0x38, 0x33, 0x37, 0x32, 0x39, + 0x37, 0x39, 0x37, 0x34, 0x39, 0x37, 0x39, 0x32, 0x36, 0x37, + 0x39, 0x38, 0x33, 0x34, 0x32, 0x37, 0x39, 0x38, 0x34, 0x37, + 0x39, 0x38, 0x36, 0x37, 0x39, 0x38, 0x32, 0x37, 0x34, 0x39, + 0x38, 0x37, 0x36, 0x38, 0x39, 0x32, 0x37, 0x33, 0x34, 0x38, + 0x39, 0x37, 0x36, 0x32, 0x37, 0x39, 0x34, 0x37, 0x36, 0x37, + 0x32, 0x39, 0x38, 0x37, 0x41, 0x45, 0x46, 0x45, 0x46, 0x41, + 0x45, 0x46, 0x44, 0x43, 0x42, 0x46, 0x45, 0x41, 0x4b, 0x4a, + 0x53, 0x48, 0x46, 0x4b, 0x4a, 0x48, 0x53, 0x4a, 0x4b, 0x46, + 0x48, 0x4b, 0x4a, 0x53, 0x48, 0x4c, 0x4b, 0x4a, 0x4b, 0x55, + 0x49, 0x59, 0x49, 0x55, 0x45, 0x54, 0x49, 0x55, 0x51, 0x57, + 0x4f, 0x49, 0x51, 0x4f, 0x3c, 0x4d, 0x5a, 0x4e, 0x3c, 0x4d, + 0x42, 0x4a, 0x48, 0x47, 0x48, 0x4a, 0x46, 0x48, 0x47, 0x4c, + 0x4b, 0x4a, 0x48, 0x47, 0x46, 0x44, 0x53, 0x41, 0x51, 0x57, + 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4f, 0x50, 0x5a, 0x58, + 0x43, 0x56, 0x42, 0x4e, 0x4d, 0x39, 0x38, 0x38, 0x32, 0x34, + 0x37, 0x35, 0x39, 0x32, 0x38, 0x37, 0x38, 0x39, 0x37, 0x35, + 0x34, 0x39, 0x38, 0x32, 0x37, 0x39, 0x38, 0x35, 0x37, 0x61, + 0x64, 0x41, 0x53, 0x44, 0x46, 0x47, 0x48, 0x4a, 0x46, 0x47, + 0x48, 0x4a, 0x46, 0x47, 0x48, 0x4a, 0x47, 0x48, 0x4a, 0x47, + 0x48, 0x4a, 0x46, 0x47, 0x48, 0x47, 0x48, 0x4a, 0x47, 0x48, + 0x47, 0x48, 0x4a, 0x44, 0x46, 0x31, 0x39, 0x33, 0x37, 0x38, + 0x38, 0x39, 0x37, 0x36, 0x38, 0x39, 0x31, 0x39, 0x33, 0x37, + 0x39, 0x38, 0x37, 0x35, 0x38, 0x39, 0x37, 0x33, 0x39, 0x31, + 0x38, 0x37, 0x38, 0x39, 0x33, 0x37, 0x39, 0x38, 0x35, 0x36, + 0x37, 0x39, 0x38, 0x37, 0x31, 0x38, 0x39, 0x37, 0x39, 0x34, + 0x38, 0x37, 0x36, 0x39, 0x37, 0x39, 0x38, 0x34, 0x37, 0x39, + 0x38, 0x32, 0x37, 0x38, 0x39, 0x64, 0x6a, 0x61, 0x6b, 0x68, + 0x6b, 0x6a, 0x68, 0x65, 0x71, 0x69, 0x75, 0x79, 0x69, 0x65, + 0x75, 0x79, 0x69, 0x75, 0x74, 0x79, 0x69, 0x75, 0x71, 0x79, + 0x69, 0x75, 0x79, 0x69, 0x75, 0x22, 0x7d }; + + size_t sz = sizeof(publish) / sizeof(uint8_t); + nng_mqtt_msg_alloc(&msg, sz - 3); + + nng_msg_header_append(msg, publish, 3); + memcpy(nng_msg_body(msg), publish + 3, sz - 3); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + uint8_t print_buf[2048] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 2048, true); + // printf("%s\n", print_buf); + + nng_msg_free(msg); +} + +void +test_decode_disconnect(void) +{ + nng_msg *msg; + uint8_t disconnect[] = { 0xe0, 0x00 }; + + size_t sz = sizeof(disconnect) / sizeof(uint8_t); + nng_mqtt_msg_alloc(&msg, 0); + + nng_msg_header_append(msg, disconnect, sz); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); + nng_msg_free(msg); +} + +TEST_LIST = { + { "encode connect", test_encode_connect }, + { "encode disconnect", test_encode_disconnect }, + { "encode subscribe", test_encode_subscribe }, + { "encode unsubscribe", test_encode_unsubscribe }, + { "decode connect", test_decode_connect }, + { "decode disconnect", test_decode_disconnect }, + { "decode publish", test_decode_publish }, + { NULL, NULL }, +}; diff --git a/src/nng.c b/src/nng.c index 6841e3716..a5b1287bf 100644 --- a/src/nng.c +++ b/src/nng.c @@ -1895,6 +1895,8 @@ nng_version(void) NNG_PATCH_VERSION) NNG_RELEASE_SUFFIX); } +#ifdef NNG_TRANSPORT_MQTT_TCP + int nng_mqtt_msg_proto_data_alloc(nng_msg *msg) { @@ -2321,4 +2323,6 @@ nng_mqtt_msg_dump( nng_msg *msg, uint8_t *buffer, uint32_t len, bool print_bytes) { nni_mqtt_msg_dump(msg, buffer, len, print_bytes); -} \ No newline at end of file +} + +#endif // NNG_TRANSPORT_MQTT_TCP From d88f80d14b5aa9b85b185d4e014d15b907b0a03b Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Fri, 29 Oct 2021 16:29:36 +0800 Subject: [PATCH 077/180] Add Remaining_length function --- src/mqtt/mqtt.h | 38 +++++++++++------------ src/mqtt/mqtt_codec.c | 70 +++++++++++++++++++++++-------------------- src/mqtt/mqtt_test.c | 7 +++-- 3 files changed, 59 insertions(+), 56 deletions(-) diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index 1a401910c..ffbe18f58 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -250,35 +250,31 @@ typedef struct mqtt_msg_t { representation This information (combined with packetType and packetFlags) may be used to jump the point where the actual data starts */ - bool is_decoded : 1; /* message is obtained from decoded or encoded */ bool attached_raw : 1; /* indicates if entire_raw_msg is to be owned */ uint8_t _unused : 2; } mqtt_msg; -extern int byte_number_for_variable_length(uint32_t variable); -extern int write_variable_length_value(uint32_t value, struct pos_buf *buf); -extern int write_byte(uint8_t val, struct pos_buf *buf); -extern int write_uint16(uint16_t value, struct pos_buf *buf); -extern int write_byte_string(mqtt_buf *str, struct pos_buf *buf); - -extern int read_byte(struct pos_buf *buf, uint8_t *val); -extern int read_uint16(struct pos_buf *buf, uint16_t *val); -extern int read_utf8_str(struct pos_buf *buf, mqtt_buf *val); -extern int read_str_data(struct pos_buf *buf, mqtt_buf *val); -extern int read_packet_length(struct pos_buf *buf, uint32_t *length); +extern uint32_t mqtt_get_remaining_length(uint8_t *, uint32_t, uint8_t *); +extern int byte_number_for_variable_length(uint32_t); +extern int write_variable_length_value(uint32_t, struct pos_buf *); +extern int write_byte(uint8_t, struct pos_buf *); +extern int write_uint16(uint16_t, struct pos_buf *); +extern int write_byte_string(mqtt_buf *, struct pos_buf *); -extern mqtt_buf mqtt_buf_dup(const mqtt_buf *src); -extern void mqtt_buf_free(mqtt_buf *buf); +extern int read_byte(struct pos_buf *, uint8_t *); +extern int read_uint16(struct pos_buf *, uint16_t *); +extern int read_utf8_str(struct pos_buf *, mqtt_buf *); +extern int read_str_data(struct pos_buf *, mqtt_buf *); +extern int read_packet_length(struct pos_buf *, uint32_t *); -extern mqtt_msg *mqtt_msg_create(mqtt_packet_type packet_type); +extern mqtt_buf mqtt_buf_dup(const mqtt_buf *); +extern void mqtt_buf_free(mqtt_buf *); -extern int mqtt_msg_dump( - mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes); +extern mqtt_msg *mqtt_msg_create(mqtt_packet_type); -extern int nni_mqtt_msg_encode(nni_msg *msg); -extern int nni_mqtt_msg_decode(nni_msg *msg); +extern int mqtt_msg_dump(mqtt_msg *, mqtt_buf *, mqtt_buf *, bool); // nni_msg proto_data alloc/free extern int nni_mqtt_msg_proto_data_alloc(nni_msg *); @@ -286,8 +282,8 @@ extern void nni_mqtt_msg_proto_data_free(nni_msg *); // mqtt message alloc/encode/decode extern int nni_mqtt_msg_alloc(nni_msg **, size_t); -// extern int nni_mqtt_msg_encode(nni_msg *); -// extern int nni_mqtt_msg_decode(nni_msg *); +extern int nni_mqtt_msg_encode(nni_msg *); +extern int nni_mqtt_msg_decode(nni_msg *); // mqtt packet_type extern void nni_mqtt_msg_set_packet_type(nni_msg *, nni_mqtt_packet_type); diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index cfecc269b..f65649f28 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -554,37 +554,11 @@ nni_mqtt_msg_decode_fixed_header(nni_msg *msg) memcpy(&mqtt->fixed_header.common, &first, 1); - int multiplier = 1; - int32_t lword = 0; - uint8_t lbytes = 0; - uint8_t *ptr = header + 1; - uint8_t *start = ptr; - - uint32_t remain_len = 0; - uint8_t count = 0; - - for (size_t i = 0; i < 4; i++) { - if ((size_t)(ptr - start + 1) > len) { - return MQTT_ERR_PAYLOAD_SIZE; - } - lbytes++; - uint8_t byte = ptr[0]; - lword += (byte & 127) * multiplier; - multiplier *= 128; - ptr++; - if ((byte & 128) == 0) { - if (lbytes > 1 && byte == 0) { - return MQTT_ERR_INVAL; - } else { - remain_len = lword; - count = lbytes; - break; - } - } - } + uint8_t used_bytes; + mqtt->fixed_header.remaining_length = + mqtt_get_remaining_length(header, len, &used_bytes); - mqtt->fixed_header.remaining_length = remain_len; - mqtt->used_bytes = count; + mqtt->used_bytes = used_bytes; return MQTT_SUCCESS; } @@ -925,8 +899,6 @@ nni_mqtt_msg_decode_unsubscribe(nni_msg *msg) /* Allocate topic array */ uspld->topic_arr = (mqtt_buf *) nni_alloc(topic_count * sizeof(mqtt_buf)); - // uspld->topic_arr = (mqtt_buf *) malloc(topic_count * - // sizeof(mqtt_buf)); /* Set back current position */ buf.curpos = saved_current_pos; @@ -1143,6 +1115,40 @@ read_packet_length(struct pos_buf *buf, uint32_t *length) return 0; } +uint32_t +mqtt_get_remaining_length(uint8_t *packet, uint32_t len, uint8_t *used_bytes) +{ + int multiplier = 1; + int32_t lword = 0; + uint8_t lbytes = 0; + uint8_t *ptr = packet + 1; + uint8_t *start = ptr; + + uint32_t remain_len = 0; + + for (size_t i = 0; i < 4; i++) { + if ((size_t)(ptr - start + 1) > len) { + return MQTT_ERR_PAYLOAD_SIZE; + } + lbytes++; + uint8_t byte = ptr[0]; + lword += (byte & 127) * multiplier; + multiplier *= 128; + ptr++; + if ((byte & 128) == 0) { + if (lbytes > 1 && byte == 0) { + return MQTT_ERR_INVAL; + } else { + remain_len = lword; + *used_bytes = lbytes; + break; + } + } + } + + return remain_len; +} + mqtt_buf mqtt_buf_dup(const mqtt_buf *src) { diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index d0be76b99..4b298318e 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -2,6 +2,7 @@ #include "nng/nng.h" +#include "mqtt.h" #include "nuts.h" void @@ -167,7 +168,7 @@ test_decode_connect(void) uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); + printf("%s\n", print_buf); nng_msg_free(msg); } @@ -232,7 +233,7 @@ test_decode_publish(void) uint8_t print_buf[2048] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 2048, true); - // printf("%s\n", print_buf); + printf("%s\n", print_buf); nng_msg_free(msg); } @@ -252,7 +253,7 @@ test_decode_disconnect(void) uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); + printf("%s\n", print_buf); nng_msg_free(msg); } From 9e432412ec807cccab702276fdee1c6b37ba81a9 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Fri, 29 Oct 2021 16:57:58 +0800 Subject: [PATCH 078/180] Fix mqtt_get_remaining_length() --- src/mqtt/mqtt.h | 13 +++++++------ src/mqtt/mqtt_codec.c | 31 +++++++++++++++++++------------ src/mqtt/mqtt_test.c | 28 ++++++++++++++-------------- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index ffbe18f58..1ecec626e 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -256,12 +256,13 @@ typedef struct mqtt_msg_t { } mqtt_msg; -extern uint32_t mqtt_get_remaining_length(uint8_t *, uint32_t, uint8_t *); -extern int byte_number_for_variable_length(uint32_t); -extern int write_variable_length_value(uint32_t, struct pos_buf *); -extern int write_byte(uint8_t, struct pos_buf *); -extern int write_uint16(uint16_t, struct pos_buf *); -extern int write_byte_string(mqtt_buf *, struct pos_buf *); +extern int mqtt_get_remaining_length(uint8_t *packet, uint32_t len, + uint32_t *remainning_length, uint8_t *used_bytes); +extern int byte_number_for_variable_length(uint32_t); +extern int write_variable_length_value(uint32_t, struct pos_buf *); +extern int write_byte(uint8_t, struct pos_buf *); +extern int write_uint16(uint16_t, struct pos_buf *); +extern int write_byte_string(mqtt_buf *, struct pos_buf *); extern int read_byte(struct pos_buf *, uint8_t *); extern int read_uint16(struct pos_buf *, uint16_t *); diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index f65649f28..9b445dc58 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -554,11 +554,17 @@ nni_mqtt_msg_decode_fixed_header(nni_msg *msg) memcpy(&mqtt->fixed_header.common, &first, 1); - uint8_t used_bytes; - mqtt->fixed_header.remaining_length = - mqtt_get_remaining_length(header, len, &used_bytes); + uint8_t used_bytes; + uint32_t remain_len = 0; + + int ret; + if ((ret = mqtt_get_remaining_length( + header, len, &remain_len, &used_bytes)) != MQTT_SUCCESS) { + return ret; + } - mqtt->used_bytes = used_bytes; + mqtt->fixed_header.remaining_length = remain_len; + mqtt->used_bytes = used_bytes; return MQTT_SUCCESS; } @@ -1115,8 +1121,9 @@ read_packet_length(struct pos_buf *buf, uint32_t *length) return 0; } -uint32_t -mqtt_get_remaining_length(uint8_t *packet, uint32_t len, uint8_t *used_bytes) +int +mqtt_get_remaining_length(uint8_t *packet, uint32_t len, + uint32_t *remainning_length, uint8_t *used_bytes) { int multiplier = 1; int32_t lword = 0; @@ -1124,8 +1131,6 @@ mqtt_get_remaining_length(uint8_t *packet, uint32_t len, uint8_t *used_bytes) uint8_t *ptr = packet + 1; uint8_t *start = ptr; - uint32_t remain_len = 0; - for (size_t i = 0; i < 4; i++) { if ((size_t)(ptr - start + 1) > len) { return MQTT_ERR_PAYLOAD_SIZE; @@ -1139,14 +1144,16 @@ mqtt_get_remaining_length(uint8_t *packet, uint32_t len, uint8_t *used_bytes) if (lbytes > 1 && byte == 0) { return MQTT_ERR_INVAL; } else { - remain_len = lword; - *used_bytes = lbytes; - break; + *remainning_length = lword; + if (used_bytes) { + *used_bytes = lbytes; + } + return MQTT_SUCCESS; } } } - return remain_len; + return MQTT_ERR_INVAL; } mqtt_buf diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 4b298318e..60a3c7277 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -35,12 +35,12 @@ test_dup(void) nng_msg *msg2; NUTS_PASS(nng_msg_dup(&msg2, msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("msg: \n%s\n", print_buf); + // uint8_t print_buf[1024] = { 0 }; + // nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("msg: \n%s\n", print_buf); - nng_mqtt_msg_dump(msg2, print_buf, 1024, true); - printf("msg2: \n%s\n", print_buf); + // nng_mqtt_msg_dump(msg2, print_buf, 1024, true); + // printf("msg2: \n%s\n", print_buf); nng_mqtt_topic_qos_array_free(topic_qos, sz); @@ -166,9 +166,9 @@ test_decode_connect(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + // uint8_t print_buf[1024] = { 0 }; + // nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); nng_msg_free(msg); } @@ -231,9 +231,9 @@ test_decode_publish(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[2048] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 2048, true); - printf("%s\n", print_buf); + // uint8_t print_buf[2048] = { 0 }; + // nng_mqtt_msg_dump(msg, print_buf, 2048, true); + // printf("%s\n", print_buf); nng_msg_free(msg); } @@ -251,9 +251,9 @@ test_decode_disconnect(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + // uint8_t print_buf[1024] = { 0 }; + // nng_mqtt_msg_dump(msg, print_buf, 1024, true); + // printf("%s\n", print_buf); nng_msg_free(msg); } From 911f4217e14493ebadcceffca29c3d029e9efb02 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 22 Oct 2021 10:15:12 +0800 Subject: [PATCH 079/180] * MDF [nng/transport] modify mqtt-tcp/transport recv_cb for mqtt usage --- src/sp/transport/mqtt/mqtt_tcp.c | 165 ++++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 26 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 82f6a8a4d..25dc3b59a 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -14,6 +14,8 @@ #include #include "core/nng_impl.h" +#include "mqtt/mqtt-codec/include/mqtt.h" +// #include "mqtt.h" // TCP transport. Platform specific TCP operations must be // supplied as well. @@ -21,6 +23,8 @@ typedef struct mqtt_tcptran_pipe mqtt_tcptran_pipe; typedef struct mqtt_tcptran_ep mqtt_tcptran_ep; +#define NNI_NANO_MAX_HEADER_SIZE 5 + // tcp_pipe is one end of a TCP connection. struct mqtt_tcptran_pipe { nng_stream * conn; @@ -45,6 +49,7 @@ struct mqtt_tcptran_pipe { nni_aio * rxaio; nni_aio * negoaio; nni_msg * rxmsg; + nni_msg * smsg; nni_mtx mtx; }; @@ -82,6 +87,7 @@ static void mqtt_tcptran_pipe_nego_cb(void *); static void mqtt_tcptran_ep_fini(void *); static void mqtt_tcptran_pipe_fini(void *); + static nni_reap_list tcptran_ep_reap_list = { .rl_offset = offsetof(mqtt_tcptran_ep, reap), .rl_func = mqtt_tcptran_ep_fini, @@ -231,10 +237,11 @@ mqtt_tcptran_pipe_nego_cb(void *arg) nni_mtx_lock(&ep->mtx); +// connack if ((rv = nni_aio_result(aio)) != 0) { goto error; } - + printf("mqtt_tcptran_pipe_nego_cb \n"); // We start transmitting before we receive. if (p->gottxhead < p->wanttxhead) { p->gottxhead += nni_aio_count(aio); @@ -343,14 +350,18 @@ mqtt_tcptran_pipe_send_cb(void *arg) static void mqtt_tcptran_pipe_recv_cb(void *arg) { - mqtt_tcptran_pipe *p = arg; - nni_aio * aio; - int rv; - size_t n; - nni_msg * msg; - nni_aio * rxaio = p->rxaio; - + nni_aio * aio; + nni_iov iov; + uint8_t type; + uint32_t len = 0, rv, pos = 1; + size_t n; + nni_msg * msg; + mqtt_tcptran_pipe *p = arg; + nni_aio * rxaio = p->rxaio; + + printf("tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); + aio = nni_list_first(&p->recvq); if ((rv = nni_aio_result(rxaio)) != 0) { @@ -358,58 +369,138 @@ mqtt_tcptran_pipe_recv_cb(void *arg) } n = nni_aio_count(rxaio); + p->gotrxhead += n; + nni_aio_iov_advance(rxaio, n); + // not receive enough bytes, deal with remaining length + read_packet_length(p->rxlen, &len); + printf("new %ld recevied %ld header %x %d len : %d", n, + p->gotrxhead, p->rxlen[0], p->rxlen[1], len); + printf("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); + if (nni_aio_iov_count(rxaio) > 0) { + printf("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], + strlen((char *) p->rxlen)); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } else if (p->gotrxhead <= NNI_NANO_MAX_HEADER_SIZE && + p->rxlen[p->gotrxhead - 1] > 0x7f) { + // length error + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { + rv = NNG_EMSGSIZE; + goto recv_error; + } + // same packet, continue receving next byte of remaining length + iov.iov_buf = &p->rxlen[p->gotrxhead]; + iov.iov_len = 1; + nni_aio_set_iov(rxaio, 1, &iov); nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; } - // If we don't have a message yet, we were reading the TCP message - // header, which is just the length. This tells us the size of the - // message to allocate and how much more to expect. - if (p->rxmsg == NULL) { - uint64_t len; - // We should have gotten a message header. - NNI_GET64(p->rxlen, len); + // finish fixed header + p->wantrxhead = len + p->gotrxhead; + if (p->rxmsg == NULL) { + // We should have gotten a message header. len -> remaining + // length to define how many bytes left + printf("pipe %p header got: %x %x %x %x %x, %ld!!\n", p, + p->rxlen[0], p->rxlen[1], p->rxlen[2], p->rxlen[3], + p->rxlen[4], p->wantrxhead); // Make sure the message payload is not too big. If it is // the caller will shut down the pipe. if ((len > p->rcvmax) && (p->rcvmax > 0)) { + printf("size error\n"); rv = NNG_EMSGSIZE; goto recv_error; } if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + printf("mem error %ld\n", (size_t) len); goto recv_error; } - // Submit the rest of the data for a read -- we want to - // read the entire message now. + // Submit the rest of the data for a read -- seperate Fixed + // header with variable header and so on + // we want to read the entire message now. if (len != 0) { - nni_iov iov; iov.iov_buf = nni_msg_body(p->rxmsg); iov.iov_len = (size_t) len; nni_aio_set_iov(rxaio, 1, &iov); + // second recv action nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; } } - // We read a message completely. Let the user know the good news. + // We read a message completely. Let the user know the good news. use + // as application message callback of users nni_aio_list_remove(aio); msg = p->rxmsg; p->rxmsg = NULL; n = nni_msg_len(msg); - - nni_pipe_bump_rx(p->npipe, n); + type = p->rxlen[0] & 0xf0; + + // fixed_header_adaptor(p->rxlen, msg); + read_packet_length(p->rxlen, &len); + nni_msg_header_append(msg, p->rxlen, len); + + // set the payload pointer of msg according to packet_type + // if (type == CMD_PUBLISH) { + // uint8_t qos_pac; + // uint16_t pid; + + // qos_pac = nni_msg_get_pub_qos(msg); + // if (qos_pac > 0) { + // nng_aio_wait(p->rsaio); + // if (qos_pac == 1) { + // p->txlen[0] = CMD_PUBACK; + // } else if (qos_pac == 2) { + // p->txlen[0] = CMD_PUBREC; + // } + // p->txlen[1] = 0x02; + // pid = nni_msg_get_pub_pid(msg); + // NNI_PUT16(p->txlen + 2, pid); + // iov.iov_len = 4; + // iov.iov_buf = &p->txlen; + // // send it down... + // nni_aio_set_iov(p->rsaio, 1, &iov); + // nng_stream_send(p->conn, p->rsaio); + // } + // } else if (type == CMD_PUBREC) { + // nng_aio_wait(p->rpaio); + // p->txlen[0] = 0X62; + // p->txlen[1] = 0x02; + // memcpy(p->txlen + 2, nni_msg_body(msg), 2); + // iov.iov_len = 4; + // iov.iov_buf = &p->txlen; + // // send it down... + // nni_aio_set_iov(p->rpaio, 1, &iov); + // nng_stream_send(p->conn, p->rpaio); + // } else if (type == CMD_PUBREL) { + // nng_aio_wait(p->qsaio); + // p->txlen[0] = CMD_PUBCOMP; + // p->txlen[1] = 0x02; + // memcpy(p->txlen + 2, nni_msg_body(msg), 2); + // iov.iov_len = 4; + // iov.iov_buf = &p->txlen; + // // send it down... + // nni_aio_set_iov(p->qsaio, 1, &iov); + // nng_stream_send(p->conn, p->qsaio); + // } + + // keep connection & Schedule next receive + // nni_pipe_bump_rx(p->npipe, n); mqtt_tcptran_pipe_recv_start(p); nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, n); + printf("end of tcptran_pipe_recv_cb: synch! %p\n", p); return; recv_error: @@ -417,12 +508,20 @@ mqtt_tcptran_pipe_recv_cb(void *arg) msg = p->rxmsg; p->rxmsg = NULL; nni_pipe_bump_error(p->npipe, rv); - // Intentionally, we do not queue up another receive. - // The protocol should notice this error and close the pipe. nni_mtx_unlock(&p->mtx); nni_msg_free(msg); nni_aio_finish_error(aio, rv); + printf("tcptran_pipe_recv_cb: recv error rv: %d\n", rv); + return; +notify: + // nni_pipe_bump_rx(p->npipe, n); + nni_aio_list_remove(aio); + tcptran_pipe_recv_start(p); + nni_mtx_unlock(&p->mtx); + nni_aio_set_msg(aio, NULL); + nni_aio_finish(aio, 0, 0); + return; } static void @@ -614,7 +713,8 @@ static void mqtt_tcptran_pipe_start( mqtt_tcptran_pipe *p, nng_stream *conn, mqtt_tcptran_ep *ep) { - nni_iov iov; + nni_iov iov; + nni_msg * cmsg; ep->refcnt++; @@ -622,6 +722,13 @@ mqtt_tcptran_pipe_start( p->ep = ep; p->proto = ep->proto; + // CONNECT packet + nni_msg_alloc(&cmsg, 0); + nni_mqtt_msg_set_packet_type(cmsg, MQTT_CONNECT); + nni_mqtt_msg_set_connect_proto_version(cmsg, MQTT_VERSION_3_1_1); + nni_mqtt_msg_encode(cmsg); + + p->txlen[0] = 0; p->txlen[1] = 'S'; p->txlen[2] = 'P'; @@ -638,8 +745,13 @@ mqtt_tcptran_pipe_start( nni_aio_set_iov(p->negoaio, 1, &iov); nni_list_append(&ep->negopipes, p); - nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate - nng_stream_send(p->conn, p->negoaio); + nni_list_remove(&ep->negopipes, p); + nni_list_append(&ep->waitpipes, p); + + mqtt_tcptran_ep_match(ep); + // nni_mtx_unlock(&ep->mtx); + // nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate + // nng_stream_send(p->conn, p->negoaio); } static void @@ -1174,6 +1286,7 @@ mqtt_tcptran_dialer_setopt( mqtt_tcptran_ep *ep = arg; int rv; + //TODO get mqtt dialer's option rv = nni_stream_dialer_set(ep->dialer, name, buf, sz, t); if (rv == NNG_ENOTSUP) { rv = nni_setopt(mqtt_tcptran_ep_opts, name, ep, buf, sz, t); From 7e4d4fa03c78131be47b137a2358c92df9f5be8f Mon Sep 17 00:00:00 2001 From: eeff Date: Fri, 22 Oct 2021 18:42:39 +0800 Subject: [PATCH 080/180] Fix nng_mqtt_client_open function signature --- include/nng/mqtt/mqtt_client.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/nng/mqtt/mqtt_client.h b/include/nng/mqtt/mqtt_client.h index 03c09f2e4..79d15b52f 100644 --- a/include/nng/mqtt/mqtt_client.h +++ b/include/nng/mqtt/mqtt_client.h @@ -144,7 +144,7 @@ extern "C" { // Note that MQTT sockets can be connected to at most a single server. // Creating the client does not connect it. -NNG_DECL int nng_mqtt_client_open(nng_socket **); +NNG_DECL int nng_mqtt_client_open(nng_socket *); // Note that there is a single implicit dialer for the client, // and options may be set on the socket to configure dial options. @@ -209,7 +209,6 @@ extern int nng_mqtt_user_props_add( nng_mqtt_user_props_t *, const char *, const char *); extern void nng_mqtt_user_props_free(nng_mqtt_user_props_t *); - #ifdef __cplusplus } #endif From d8f42ddba6fe28b8e586c7fe1861f2532421dc68 Mon Sep 17 00:00:00 2001 From: eeff Date: Fri, 22 Oct 2021 18:51:00 +0800 Subject: [PATCH 081/180] Fix mqtt tcp transport receicve --- src/sp/transport/mqtt/mqtt_tcp.c | 200 +++++++++++++++++++------------ 1 file changed, 123 insertions(+), 77 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 25dc3b59a..63bbb6e45 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -14,8 +14,6 @@ #include #include "core/nng_impl.h" -#include "mqtt/mqtt-codec/include/mqtt.h" -// #include "mqtt.h" // TCP transport. Platform specific TCP operations must be // supplied as well. @@ -368,74 +366,123 @@ mqtt_tcptran_pipe_recv_cb(void *arg) goto recv_error; } - n = nni_aio_count(rxaio); - p->gotrxhead += n; + if (NULL == p->rxmsg) { + // receiving the header first to determine the packet size + n = nni_aio_count(rxaio); + p->gotrxhead += n; - nni_aio_iov_advance(rxaio, n); - // not receive enough bytes, deal with remaining length - read_packet_length(p->rxlen, &len); - printf("new %ld recevied %ld header %x %d len : %d", n, - p->gotrxhead, p->rxlen[0], p->rxlen[1], len); - printf("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); - - if (nni_aio_iov_count(rxaio) > 0) { - printf("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], - strlen((char *) p->rxlen)); - nng_stream_recv(p->conn, rxaio); - nni_mtx_unlock(&p->mtx); - return; - } else if (p->gotrxhead <= NNI_NANO_MAX_HEADER_SIZE && - p->rxlen[p->gotrxhead - 1] > 0x7f) { - // length error - if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { - rv = NNG_EMSGSIZE; - goto recv_error; - } - // same packet, continue receving next byte of remaining length - iov.iov_buf = &p->rxlen[p->gotrxhead]; - iov.iov_len = 1; - nni_aio_set_iov(rxaio, 1, &iov); - nng_stream_recv(p->conn, rxaio); - nni_mtx_unlock(&p->mtx); - return; - } - - // finish fixed header - p->wantrxhead = len + p->gotrxhead; - - if (p->rxmsg == NULL) { - // We should have gotten a message header. len -> remaining - // length to define how many bytes left - printf("pipe %p header got: %x %x %x %x %x, %ld!!\n", p, - p->rxlen[0], p->rxlen[1], p->rxlen[2], p->rxlen[3], - p->rxlen[4], p->wantrxhead); - // Make sure the message payload is not too big. If it is - // the caller will shut down the pipe. - if ((len > p->rcvmax) && (p->rcvmax > 0)) { - printf("size error\n"); - rv = NNG_EMSGSIZE; - goto recv_error; - } - - if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { - printf("mem error %ld\n", (size_t) len); - goto recv_error; + struct pos_buf buf = { .curpos = p->rxlen + 1, + .endpos = p->rxlen + p->gotrxhead }; + if (read_packet_length(&buf, &len) != 0) { + // not enough header, schedule another receive + nni_aio_bump_count(rxaio, n); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; } - // Submit the rest of the data for a read -- seperate Fixed - // header with variable header and so on - // we want to read the entire message now. - if (len != 0) { - iov.iov_buf = nni_msg_body(p->rxmsg); - iov.iov_len = (size_t) len; - + // we have decode the remaining length from the header + // the total packet length is one byte for the packet type, + // plus the number of bytes to encode the remaining length + // field, plus the remaining length. + size_t tot = 1 + byte_number_for_variable_length(len) + len; + nni_msg_alloc(&p->rxmsg, tot); + memcpy(nni_msg_body(p->rxmsg), p->rxlen, p->gotrxhead); + if (tot > p->gotrxhead) { + // schedule to receive the bulk of the packet + iov.iov_buf = nni_msg_body(p->rxmsg) + p->gotrxhead; + iov.iov_len = tot - p->gotrxhead; + p->gotrxhead = 0; nni_aio_set_iov(rxaio, 1, &iov); - // second recv action nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; + } else { + // good news, this is very small packet + // we have done receiving + p->gotrxhead = 0; } - } + } else { + // we are receiving the bulk of the packet + n = nni_aio_count(rxaio); + nni_aio_bump_count(rxaio, n); + if (nni_aio_iov_advance(rxaio, n) > 0) { + // still data remaining, schedule to receive + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + // good news, the whole packet is received + } + + //// not receive enough bytes, deal with remaining length + // read_packet_length(p->rxlen, &len); + // printf("new %ld recevied %ld header %x %d len : %d", n, + // p->gotrxhead, + // p->rxlen[0], p->rxlen[1], len); + // printf("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); + + // //if (nni_aio_iov_count(rxaio) > 0) { + // printf("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], + // strlen((char *) p->rxlen)); + // nng_stream_recv(p->conn, rxaio); + // nni_mtx_unlock(&p->mtx); + // return; + //} else if (p->gotrxhead <= NNI_NANO_MAX_HEADER_SIZE && + // p->rxlen[p->gotrxhead - 1] > 0x7f) { + // // length error + // if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { + // rv = NNG_EMSGSIZE; + // goto recv_error; + // } + // // same packet, continue receving next byte of remaining length + // iov.iov_buf = &p->rxlen[p->gotrxhead]; + // iov.iov_len = 1; + // nni_aio_set_iov(rxaio, 1, &iov); + // nng_stream_recv(p->conn, rxaio); + // nni_mtx_unlock(&p->mtx); + // return; + //} + + // finish fixed header + // p->wantrxhead = len + p->gotrxhead; + // + // if (p->rxmsg == NULL) { + // // We should have gotten a message header. len -> + // remaining + // // length to define how many bytes left + // printf("pipe %p header got: %x %x %x %x %x, %ld!!\n", + // p, p->rxlen[0], p->rxlen[1], p->rxlen[2], p->rxlen[3], + // p->rxlen[4], p->wantrxhead); + // // Make sure the message payload is not too big. If it + // is + // // the caller will shut down the pipe. + // if ((len > p->rcvmax) && (p->rcvmax > 0)) { + // printf("size error\n"); + // rv = NNG_EMSGSIZE; + // goto recv_error; + // } + // + // if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) + //{ printf("mem error %ld\n", (size_t) len); + // goto recv_error; + // } + // + // // Submit the rest of the data for a read -- seperate + // Fixed + // // header with variable header and so on + // // we want to read the entire message now. + // if (len != 0) { + // iov.iov_buf = nni_msg_body(p->rxmsg); + // iov.iov_len = (size_t) len; + // + // nni_aio_set_iov(rxaio, 1, &iov); + // // second recv action + // nng_stream_recv(p->conn, rxaio); + // nni_mtx_unlock(&p->mtx); + // return; + // } + // } // We read a message completely. Let the user know the good news. use // as application message callback of users @@ -443,11 +490,11 @@ mqtt_tcptran_pipe_recv_cb(void *arg) msg = p->rxmsg; p->rxmsg = NULL; n = nni_msg_len(msg); - type = p->rxlen[0] & 0xf0; + // type = p->rxlen[0] & 0xf0; // fixed_header_adaptor(p->rxlen, msg); - read_packet_length(p->rxlen, &len); - nni_msg_header_append(msg, p->rxlen, len); + // read_packet_length(p->rxlen, &len); + // nni_msg_header_append(msg, p->rxlen, len); // set the payload pointer of msg according to packet_type // if (type == CMD_PUBLISH) { @@ -574,13 +621,13 @@ mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *p) msg = nni_aio_get_msg(aio); len = nni_msg_len(msg) + nni_msg_header_len(msg); - NNI_PUT64(p->txlen, len); + // NNI_PUT64(p->txlen, len); - txaio = p->txaio; - niov = 0; - iov[0].iov_buf = p->txlen; - iov[0].iov_len = sizeof(p->txlen); - niov++; + txaio = p->txaio; + niov = 0; + // iov[0].iov_buf = p->txlen; + // iov[0].iov_len = sizeof(p->txlen); + // niov++; if (nni_msg_header_len(msg) > 0) { iov[niov].iov_buf = nni_msg_header(msg); iov[niov].iov_len = nni_msg_header_len(msg); @@ -722,12 +769,11 @@ mqtt_tcptran_pipe_start( p->ep = ep; p->proto = ep->proto; - // CONNECT packet - nni_msg_alloc(&cmsg, 0); - nni_mqtt_msg_set_packet_type(cmsg, MQTT_CONNECT); - nni_mqtt_msg_set_connect_proto_version(cmsg, MQTT_VERSION_3_1_1); - nni_mqtt_msg_encode(cmsg); - + // CONNECT packet + // nni_msg_alloc(&cmsg, 0); + // nni_mqtt_msg_set_packet_type(cmsg, MQTT_CONNECT); + // nni_mqtt_msg_set_connect_proto_version(cmsg, MQTT_VERSION_3_1_1); + // nni_mqtt_msg_encode(cmsg); p->txlen[0] = 0; p->txlen[1] = 'S'; From 7bd296f6be2fb5df675c5f7117569ee39194f38c Mon Sep 17 00:00:00 2001 From: eeff Date: Sat, 23 Oct 2021 16:30:29 +0800 Subject: [PATCH 082/180] Add mqtt_client protocol --- cmake/NNGOptions.cmake | 3 + src/sp/protocol/mqtt/CMakeLists.txt | 9 +- src/sp/protocol/mqtt/mqtt_client.c | 752 ++++++++++++++++++++++++++++ 3 files changed, 760 insertions(+), 4 deletions(-) create mode 100644 src/sp/protocol/mqtt/mqtt_client.c diff --git a/cmake/NNGOptions.cmake b/cmake/NNGOptions.cmake index b99bfc936..16680798e 100644 --- a/cmake/NNGOptions.cmake +++ b/cmake/NNGOptions.cmake @@ -76,6 +76,9 @@ mark_as_advanced(NNG_PROTO_RESPONDENT0) option (NNG_PROTO_SURVEYOR0 "Enable SURVEYORv0 protocol." ON) mark_as_advanced(NNG_PROTO_SURVEYOR0) +option (NNG_PROTO_MQTT_CLIENT "Enable MQTT Client protocol." ON) +mark_as_advanced(NNG_PROTO_MQTT_CLIENT) + # TLS support. # Enabling TLS is required to enable support for the TLS transport diff --git a/src/sp/protocol/mqtt/CMakeLists.txt b/src/sp/protocol/mqtt/CMakeLists.txt index 7c41c40e6..7348d4465 100644 --- a/src/sp/protocol/mqtt/CMakeLists.txt +++ b/src/sp/protocol/mqtt/CMakeLists.txt @@ -1,12 +1,13 @@ # -# Copyright 2020 Staysail Systems, Inc. -# Copyright 2018 Capitar IT Group BV -# # This software is supplied under the terms of the MIT License, a # copy of which should be located in the distribution where this # file was obtained (LICENSE.txt). A copy of the license may also be # found online at https://opensource.org/licenses/MIT. # -# Req/Rep protocol +# MQTT protocol nng_directory(mqtt) + +nng_sources_if(NNG_PROTO_MQTT_CLIENT mqtt_client.c) +nng_headers_if(NNG_PROTO_MQTT_CLIENT nng/mqtt/mqtt_client.h) +nng_defines_if(NNG_PROTO_MQTT_CLIENT NNG_HAVE_MQTT_CLIENT) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c new file mode 100644 index 000000000..55cafdc13 --- /dev/null +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -0,0 +1,752 @@ +// Author: eeff +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// +#include + +#include "core/nng_impl.h" + +// MQTT client implementation. +// +// 1. MQTT client sockets have a single implicit dialer, and cannot +// support creation of additional dialers or listeners. +// 2. Send sends PUBLISH messages. +// 3. Receive is used to receive published data from the server. + +// FIXME: assign valid id, or do we need these ? +#define NNG_MQTT_SELF 0 +#define NNG_MQTT_SELF_NAME "mqtt-client" +#define NNG_MQTT_PEER 0 +#define NNG_MQTT_PEER_NAME "mqtt-server" + +#define MQTT_WORK_NUM 16 + +typedef struct mqtt_sock_s mqtt_sock_t; +typedef struct mqtt_pipe_s mqtt_pipe_t; +typedef struct mqtt_ctx_s mqtt_ctx_t; + +static int mqtt_sock_init(void *arg, nni_sock *sock); +static void mqtt_sock_fini(void *arg); +static void mqtt_sock_open(void *arg); +static void mqtt_sock_send(void *arg, nni_aio *aio); +static void mqtt_sock_recv(void *arg, nni_aio *aio); +static void mqtt_send_cb(void *arg); +static void mqtt_recv_cb(void *arg); +static void mqtt_send_start(mqtt_sock_t *s, nni_aio *aio); +static void mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio); +static void mqtt_run_send_queue(mqtt_sock_t *s); +static void mqtt_run_recv_queue(mqtt_sock_t *s); + +static int mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s); +static void mqtt_pipe_fini(void *arg); +static int mqtt_pipe_start(void *arg); +static void mqtt_pipe_stop(void *arg); +static void mqtt_pipe_close(void *arg); + +static int mqtt_ctx_init(void *arg, void *sock); +static void mqtt_ctx_fini(void *arg); +static void mqtt_ctx_send(void *arg, nni_aio *aio); +static void mqtt_ctx_recv(void *arg, nni_aio *aio); + +// Work state indicating what MQTT packet we *expect* to send/recv. +typedef enum { + WORK_START, // start state + WORK_CONNECT, + WORK_CONNACK, + WORK_DISCONNECT, // send DISCONNECT + WORK_PUBACK, // send/recv PUBACK + WORK_PUBCOMP, // send/recv PUBCOMP + WORK_PUBLISH, // send/recv PUBLISH + WORK_PUBRECV, // send/recv PUBRECV + WORK_PUBREL, // send/recv PUBREL + WORK_SUBSCRIBE, // send SUBSCRIBE + WORK_SUBACK, // recv SUBACK + WORK_ERROR, // error state + WORK_END, // terminal state +} work_state_t; + +// A work_t represents an asynchronous send/recv of MQTT packet. +typedef struct { + work_state_t state; + uint8_t qos; // QoS of the MQTT PUBLISH packet + mqtt_sock_t * mqtt_sock; + nni_aio * user_aio; + nni_aio send_aio; // send aio to the underlying transport + nni_aio recv_aio; // recv aio to the underlying transport + nni_list_node node; // in one of send_queue, free_list +} work_t; + +// A mqtt_ctx_s is our per-ctx protocol private state. +struct mqtt_ctx_s { + mqtt_sock_t *mqtt_sock; +}; + +// A mqtt_pipe_s is our per-pipe protocol private structure. +struct mqtt_pipe_s { + nni_atomic_bool closed; + nni_pipe * pipe; + mqtt_sock_t * mqtt_sock; +}; + +// A mqtt_sock_s is our per-socket protocol private structure. +struct mqtt_sock_s { + nni_atomic_bool closed; + nni_atomic_int ttl; + nni_duration retry; + nni_mtx mtx; // TODO: more fine grained mutual exclusion + mqtt_ctx_t master; // to which we delegate send/recv calls + mqtt_pipe_t * mqtt_pipe; + nni_list send_queue; // work pending to send + nni_list recv_queue; // work pending to receive + nni_list free_list; // free list of work + work_t works[MQTT_WORK_NUM]; // pre allocated work +}; + +/****************************************************************************** + * Work Implementation * + ******************************************************************************/ + +static inline void +work_init(work_t *work, mqtt_sock_t *s) +{ + work->state = WORK_START; + work->qos = 0; + work->user_aio = NULL; + work->mqtt_sock = s; + nni_aio_init(&work->send_aio, mqtt_send_cb, work); + nni_aio_init(&work->recv_aio, mqtt_recv_cb, work); + NNI_LIST_NODE_INIT(&work->node); +} + +static inline void +work_fini(work_t *work) +{ + nni_aio_fini(&work->send_aio); + nni_aio_fini(&work->recv_aio); +} + +static inline void +work_reset(work_t *work) +{ + work->state = WORK_START; + work->qos = 0; + work->user_aio = NULL; + nni_list_node_remove(&work->node); +} + +// cancels any outstanding operation, +// and waits for the work to complete, if still running. +static inline void +work_stop(work_t *work) +{ + nni_aio_stop(&work->send_aio); + nni_list_node_remove(&work->node); +} + +// closes the aio for further activity. +// It aborts any in-progress transaction (if it can). +static inline void +work_close(work_t *work) +{ + nni_aio_close(&work->send_aio); + if (NULL != work->user_aio) { + nni_aio_finish_error(work->user_aio, NNG_ECONNRESET); + work->user_aio = NULL; + } + nni_list_node_remove(&work->node); +} + +static inline void +work_stop_queue(nni_list *queue) +{ + work_t *work; + NNI_LIST_FOREACH (queue, work) { + work_stop(work); + } +} + +static inline void +work_close_queue(nni_list *queue) +{ + work_t *work; + NNI_LIST_FOREACH (queue, work) { + work_close(work); + } +} + +/****************************************************************************** + * Sock Implementation * + ******************************************************************************/ + +static int +mqtt_sock_init(void *arg, nni_sock *sock) +{ + NNI_ARG_UNUSED(sock); + mqtt_sock_t *s = arg; + + nni_atomic_init_bool(&s->closed); + nni_atomic_set_bool(&s->closed, false); + + nni_atomic_init(&s->ttl); + nni_atomic_set(&s->ttl, 8); + + // this is "semi random" start for request IDs. + s->retry = NNI_SECOND * 60; + + nni_mtx_init(&s->mtx); + + mqtt_ctx_init(&s->master, s); + + s->mqtt_pipe = NULL; + + NNI_LIST_INIT(&s->send_queue, work_t, node); + NNI_LIST_INIT(&s->recv_queue, work_t, node); + NNI_LIST_INIT(&s->free_list, work_t, node); + for (int i = 0; i < MQTT_WORK_NUM; ++i) { + work_init(&s->works[i], s); + nni_list_append(&s->free_list, &s->works[i]); + } + + return (0); +} + +static void +mqtt_sock_fini(void *arg) +{ + mqtt_sock_t *s = arg; + + nni_mtx_lock(&s->mtx); + NNI_ASSERT(nni_list_empty(&s->send_queue)); + NNI_ASSERT(nni_list_empty(&s->recv_queue)); + nni_mtx_unlock(&s->mtx); + + for (int i = 0; i < MQTT_WORK_NUM; ++i) { + work_fini(&s->works[i]); + } + + mqtt_ctx_fini(&s->master); + nni_mtx_fini(&s->mtx); +} + +static void +mqtt_sock_open(void *arg) +{ + NNI_ARG_UNUSED(arg); +} + +static void +mqtt_sock_close(void *arg) +{ + mqtt_sock_t *s = arg; + + nni_atomic_set_bool(&s->closed, true); +} + +static void +mqtt_sock_send(void *arg, nni_aio *aio) +{ + mqtt_sock_t *s = arg; + mqtt_ctx_send(&s->master, aio); +} + +static void +mqtt_sock_recv(void *arg, nni_aio *aio) +{ + mqtt_sock_t *s = arg; + mqtt_ctx_recv(&s->master, aio); +} + +/****************************************************************************** + * Pipe Implementation * + ******************************************************************************/ + +static int +mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) +{ + mqtt_pipe_t *p = arg; + mqtt_sock_t *sock = s; + + nni_mtx_lock(&sock->mtx); + sock->mqtt_pipe = p; + nni_mtx_unlock(&sock->mtx); + + nni_atomic_init_bool(&p->closed); + nni_atomic_set_bool(&p->closed, false); + p->pipe = pipe; + p->mqtt_sock = s; + return (0); +} + +static void +mqtt_pipe_fini(void *arg) +{ + NNI_ARG_UNUSED(arg); +} + +static int +mqtt_pipe_start(void *arg) +{ + mqtt_pipe_t *p = arg; + mqtt_sock_t *s = p->mqtt_sock; + + // TODO: do we need this ? + // if (nni_pipe_peer(p->pipe) != NNG_MQTT_SELF) { + // return (NNG_EPROTO); + // } + + nni_mtx_lock(&s->mtx); + mqtt_run_send_queue(s); + mqtt_run_recv_queue(s); + nni_mtx_unlock(&s->mtx); + + return (0); +} + +static void +mqtt_pipe_stop(void *arg) +{ + mqtt_pipe_t *p = arg; + mqtt_sock_t *s = p->mqtt_sock; + + nni_mtx_lock(&s->mtx); + work_stop_queue(&s->send_queue); + work_stop_queue(&s->recv_queue); + nni_mtx_unlock(&s->mtx); +} + +static void +mqtt_pipe_close(void *arg) +{ + mqtt_pipe_t *p = arg; + mqtt_sock_t *s = p->mqtt_sock; + + nni_mtx_lock(&s->mtx); + s->mqtt_pipe = NULL; + work_close_queue(&s->send_queue); + work_close_queue(&s->recv_queue); + nni_mtx_unlock(&s->mtx); + + nni_atomic_set_bool(&p->closed, true); +} + +static void +mqtt_send_cb(void *arg) +{ + work_t * work = arg; + mqtt_sock_t *s = work->mqtt_sock; + + nni_mtx_lock(&s->mtx); + mqtt_pipe_t *p = s->mqtt_pipe; + nni_mtx_unlock(&s->mtx); + + if (nni_aio_result(&work->send_aio) != 0) { + // We failed to send... clean up and deal with it. + nni_msg_free(nni_aio_get_msg(&work->send_aio)); + nni_aio_set_msg(&work->send_aio, NULL); + nni_pipe_close(p->pipe); + return; + } + + if (nni_atomic_get_bool(&p->closed) || + nni_atomic_get_bool(&s->closed)) { + // This occurs if the mqtt_pipe_close has been called. + // In that case we don't want any more processing. + return; + } + + // state transitions + switch (work->state) { + case WORK_CONNECT: + work->state = WORK_CONNACK; + nni_pipe_recv(p->pipe, &work->recv_aio); + break; + case WORK_DISCONNECT: + // fall through + case WORK_PUBACK: + // fall through + case WORK_PUBCOMP: + work->state = WORK_END; + break; + case WORK_PUBLISH: + // TODO: handle retry + if (0 == work->qos) { + work->state = WORK_END; + } else if (1 == work->qos) { + work->state = WORK_PUBACK; + nni_pipe_recv(p->pipe, &work->recv_aio); + } else if (2 == work->qos) { + work->state = WORK_PUBRECV; + nni_pipe_recv(p->pipe, &work->recv_aio); + } + break; + case WORK_PUBRECV: + work->state = WORK_PUBREL; + nni_pipe_recv(p->pipe, &work->recv_aio); + break; + case WORK_PUBREL: + work->state = WORK_PUBCOMP; + nni_pipe_recv(p->pipe, &work->recv_aio); + break; + case WORK_SUBSCRIBE: + printf("mqtt_send_cb send SUBSCRIBE done\n"); + work->state = WORK_SUBACK; + nni_pipe_recv(p->pipe, &work->recv_aio); + break; + default: + work->state = WORK_ERROR; + break; + } + + if (WORK_ERROR == work->state) { + nni_aio_finish_error(work->user_aio, NNG_EPROTO); + nni_pipe_close(p->pipe); + } else if (WORK_END == work->state) { + nni_aio_finish_sync(work->user_aio, 0, 0); + work_reset(work); + nni_mtx_lock(&s->mtx); + nni_list_append(&s->free_list, work); + nni_mtx_unlock(&s->mtx); + } +} + +static void +mqtt_recv_cb(void *arg) +{ + work_t * work = arg; + mqtt_sock_t *s = work->mqtt_sock; + nni_msg * msg = nni_aio_get_msg(&work->recv_aio); + + nni_mtx_lock(&s->mtx); + mqtt_pipe_t *p = s->mqtt_pipe; + nni_mtx_unlock(&s->mtx); + + if (nni_aio_result(&work->recv_aio) != 0) { + nni_msg_free(msg); + nni_pipe_close(p->pipe); + return; + } + + if (nni_atomic_get_bool(&p->closed) || + nni_atomic_get_bool(&s->closed)) { + return; + } + + nni_aio_set_msg(&work->recv_aio, NULL); + nni_msg_set_pipe(msg, nni_pipe_id(p->pipe)); + nni_mqtt_msg_proto_data_alloc(msg); + nni_mqtt_msg_decode(msg); + nni_mqtt_packet_type packet_type = nni_mqtt_msg_get_packet_type(msg); + + // state transitions + switch (work->state) { + case WORK_CONNACK: + work->state = + (MQTT_CONNACK == packet_type) ? WORK_END : WORK_ERROR; + break; + case WORK_PUBACK: + work->state = + (MQTT_PUBACK == packet_type) ? WORK_END : WORK_ERROR; + break; + case WORK_PUBCOMP: + work->state = + (MQTT_PUBCOMP == packet_type) ? WORK_END : WORK_ERROR; + break; + case WORK_SUBACK: + printf("mqtt_recv_cb recv SUBACK done\n"); + work->state = + (MQTT_SUBACK == packet_type) ? WORK_END : WORK_ERROR; + break; + case WORK_PUBREL: + if (MQTT_PUBREL != packet_type) { + work->state = WORK_ERROR; + break; + } + work->state = WORK_PUBCOMP; + nni_pipe_send(p->pipe, &work->send_aio); + break; + case WORK_PUBRECV: + if (MQTT_PUBREC != packet_type) { + work->state = WORK_ERROR; + break; + } + work->state = WORK_PUBREL; + nni_pipe_send(p->pipe, &work->send_aio); + break; + case WORK_PUBLISH: + if (MQTT_PUBLISH != packet_type) { + work->state = WORK_ERROR; + break; + } + // TODO: handle retry + uint8_t qos = nni_mqtt_msg_get_publish_qos(msg); + if (0 == qos) { + work->state = WORK_END; + } else if (1 == qos) { + work->state = WORK_PUBACK; + nni_pipe_send(p->pipe, &work->send_aio); + } else if (2 == qos) { + work->state = WORK_PUBRECV; + nni_pipe_send(p->pipe, &work->send_aio); + } + nni_aio_finish_msg(work->user_aio, msg); + break; + default: + work->state = WORK_ERROR; + break; + } + + if (WORK_ERROR == work->state) { + nni_aio_finish_error(work->user_aio, NNG_EPROTO); + nni_pipe_close(p->pipe); + } else if (WORK_END == work->state) { + nni_aio_finish_sync(work->user_aio, 0, 0); + work->state = WORK_START; + nni_mtx_lock(&s->mtx); + nni_list_append(&s->free_list, work); + nni_mtx_unlock(&s->mtx); + } + + return; +} + +static void +mqtt_send_start(mqtt_sock_t *s, nni_aio *aio) +{ + work_t * work; + nni_mqtt_packet_type packet_type; + + nni_mtx_lock(&s->mtx); + + work = nni_list_first(&s->free_list); + if (NULL == work) { + nni_mtx_unlock(&s->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + + // only allow to send PUBLISH and SUBSCRIBE packet + nni_msg *msg = nni_aio_get_msg(aio); + packet_type = nni_mqtt_msg_get_packet_type(msg); + + switch (packet_type) { + case MQTT_CONNECT: + work->state = WORK_CONNECT; + break; + case MQTT_PUBLISH: + work->state = WORK_PUBLISH; + break; + case MQTT_SUBSCRIBE: + work->state = WORK_SUBSCRIBE; + break; + default: + work->state = WORK_ERROR; + nni_mtx_unlock(&s->mtx); + nni_aio_finish_error(aio, NNG_EPROTO); + return; + } + + work->user_aio = aio; + nni_list_remove(&s->free_list, work); + nni_list_append(&s->send_queue, work); // enqueue to send + mqtt_run_send_queue(s); + + nni_mtx_unlock(&s->mtx); +} + +static void +mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) +{ + work_t *work; + + nni_mtx_lock(&s->mtx); + + work = nni_list_first(&s->free_list); + + if (NULL == work) { + nni_mtx_unlock(&s->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + + work->user_aio = aio; + nni_list_remove(&s->free_list, work); + nni_list_append(&s->recv_queue, work); // enqueue to recv + mqtt_run_recv_queue(s); + + nni_mtx_unlock(&s->mtx); +} + +// Note: This routine should be called with the sock lock held. +static void +mqtt_run_recv_queue(mqtt_sock_t *s) +{ + work_t * work = nni_list_first(&s->recv_queue); + mqtt_pipe_t *p = s->mqtt_pipe; + + while (NULL != work) { + nni_list_remove(&s->recv_queue, work); + nni_pipe_recv(p->pipe, &work->recv_aio); + work = nni_list_first(&s->recv_queue); + } + + return; +} + +// Note: This routine should be called with the pipe lock held. +static void +mqtt_run_send_queue(mqtt_sock_t *s) +{ + work_t * work; + mqtt_pipe_t *p = s->mqtt_pipe; + + // no open pipe + if (NULL == p) { + return; + } + + // TODO: handle retry + while (NULL != (work = nni_list_first(&s->send_queue))) { + nni_list_remove(&s->send_queue, work); + nni_msg *msg = nni_aio_get_msg(work->user_aio); + nni_aio_set_msg(work->user_aio, NULL); + nni_aio_bump_count(work->user_aio, nni_msg_len(msg)); + nni_aio_set_msg(&work->send_aio, msg); + nni_pipe_send(p->pipe, &work->send_aio); + } + + return; +} + +/****************************************************************************** + * Context Implementation * + ******************************************************************************/ + +static int +mqtt_ctx_init(void *arg, void *sock) +{ + mqtt_ctx_t * ctx = arg; + mqtt_sock_t *s = sock; + + ctx->mqtt_sock = s; + + return (0); +} + +static void +mqtt_ctx_fini(void *arg) +{ + NNI_ARG_UNUSED(arg); +} + +static void +mqtt_ctx_send(void *arg, nni_aio *aio) +{ + mqtt_ctx_t * ctx = arg; + mqtt_sock_t *s = ctx->mqtt_sock; + mqtt_pipe_t *p; + + if (nni_aio_begin(aio) != 0) { + return; + } + + if (nni_atomic_get_bool(&s->closed)) { + nni_mtx_unlock(&s->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + + nni_mtx_lock(&s->mtx); + p = s->mqtt_pipe; + nni_mtx_unlock(&s->mtx); + + mqtt_send_start(s, aio); +} + +static void +mqtt_ctx_recv(void *arg, nni_aio *aio) +{ + mqtt_ctx_t * ctx = arg; + mqtt_sock_t *s = ctx->mqtt_sock; + mqtt_pipe_t *p; + + if (nni_aio_begin(aio) != 0) { + return; + } + + if (nni_atomic_get_bool(&s->closed)) { + nni_mtx_unlock(&s->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + + nni_mtx_lock(&s->mtx); + p = s->mqtt_pipe; + nni_mtx_unlock(&s->mtx); + + mqtt_recv_start(s, aio); +} + +/****************************************************************************** + * Proto * + ******************************************************************************/ + +static nni_proto_pipe_ops mqtt_pipe_ops = { + .pipe_size = sizeof(mqtt_pipe_t), + .pipe_init = mqtt_pipe_init, + .pipe_fini = mqtt_pipe_fini, + .pipe_start = mqtt_pipe_start, + .pipe_close = mqtt_pipe_close, + .pipe_stop = mqtt_pipe_stop, +}; + +static nni_option mqtt_ctx_options[] = { + { + .o_name = NULL, + }, +}; + +static nni_proto_ctx_ops mqtt_ctx_ops = { + .ctx_size = sizeof(mqtt_ctx_t), + .ctx_init = mqtt_ctx_init, + .ctx_fini = mqtt_ctx_fini, + .ctx_recv = mqtt_ctx_recv, + .ctx_send = mqtt_ctx_send, + .ctx_options = mqtt_ctx_options, +}; + +static nni_option mqtt_sock_options[] = { + // terminate list + { + .o_name = NULL, + }, +}; + +static nni_proto_sock_ops mqtt_sock_ops = { + .sock_size = sizeof(mqtt_sock_t), + .sock_init = mqtt_sock_init, + .sock_fini = mqtt_sock_fini, + .sock_open = mqtt_sock_open, + .sock_close = mqtt_sock_close, + .sock_options = mqtt_sock_options, + .sock_send = mqtt_sock_send, + .sock_recv = mqtt_sock_recv, +}; + +static nni_proto mqtt_proto = { + .proto_version = NNI_PROTOCOL_VERSION, + .proto_self = { NNG_MQTT_SELF, NNG_MQTT_SELF_NAME }, + .proto_peer = { NNG_MQTT_PEER, NNG_MQTT_PEER_NAME }, + .proto_flags = NNI_PROTO_FLAG_SNDRCV, + .proto_sock_ops = &mqtt_sock_ops, + .proto_pipe_ops = &mqtt_pipe_ops, + .proto_ctx_ops = &mqtt_ctx_ops, +}; + +int +nng_mqtt_client_open(nng_socket *sock) +{ + return (nni_proto_open(sock, &mqtt_proto)); +} From 894945288b50910509781bdc1dfadbaa3cbd90c4 Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 25 Oct 2021 00:27:10 +0800 Subject: [PATCH 083/180] Add mqtt_client demo --- demo/mqtt/CMakeLists.txt | 17 +++ demo/mqtt/mqtt_client.c | 278 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 demo/mqtt/CMakeLists.txt create mode 100644 demo/mqtt/mqtt_client.c diff --git a/demo/mqtt/CMakeLists.txt b/demo/mqtt/CMakeLists.txt new file mode 100644 index 000000000..6e96fc745 --- /dev/null +++ b/demo/mqtt/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. + +cmake_minimum_required (VERSION 2.8.7) + +project(mqtt_client) + +find_package(nng CONFIG REQUIRED) + +find_package(Threads) + +add_executable(mqtt_client mqtt_client.c) +target_link_libraries(mqtt_client nng) +target_link_libraries(mqtt_client ${CMAKE_THREAD_LIBS_INIT}) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c new file mode 100644 index 000000000..e2a4ca06c --- /dev/null +++ b/demo/mqtt/mqtt_client.c @@ -0,0 +1,278 @@ +// Author: eeff +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +// +// This is just a simple MQTT client demonstration application. +// +// The application has two sub-commands: `pub` and `sub`. The `pub` +// sub-command publishes a given message to the server and then exits. +// The `sub` sub-command subscribes to the given topic filter and blocks +// waiting for incoming messages. +// +// # Example: +// +// Publish 'hello' to `topic` with QoS `0`: +// ``` +// $ ./mqtt_client pub mqtt-tcp://127.0.0.1:1883 0 topic hello +// ``` +// +// Subscribe to `topic` with QoS `0` and waiting for messages: +// ``` +// $ ./mqtt_client sub mqtt-tcp://127.0.0.1:1883 0 topic +// ``` +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Subcommands +#define PUBLISH "pub" +#define SUBSCRIBE "sub" + +void +fatal(const char *msg, int rv) +{ + fprintf(stderr, "%s: %s\n", msg, nng_strerror(rv)); + exit(1); +} + +// Print the given string limited to 80 columns. +// +// The `prefix` should be a null terminated string much smaller than 80, +// `str` and `len` designates the string to be printed, `quote` specifies +// whether to print in single quotes. +void +print80(const char *prefix, const char *str, size_t len, bool quote) +{ + size_t max_len = 80 - strlen(prefix) - (quote ? 2 : 0); + char * q = quote ? "'" : ""; + if (len <= max_len) { + // case the output fit in a line + printf("%s%s%.*s%s\n", prefix, q, len, str, q); + } else { + // case we truncate the payload with ellipses + printf("%s%s%.*s%s...\n", prefix, q, max_len - 3, str, q); + } +} + +// Connect to the given address. +int +client_connect(nng_socket *sock, const char *url, bool verbose) +{ + nng_dialer dialer; + int rv; + + if ((rv = nng_mqtt_client_open(sock)) != 0) { + fatal("nng_socket", rv); + } + + if ((rv = nng_dialer_create(&dialer, *sock, url)) != 0) { + fatal("nng_dialer_create", rv); + } + + nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); + + // create a CONNECT message + nng_msg *connmsg; + nng_mqtt_msg_alloc(&connmsg, 0); + nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); + nng_mqtt_msg_set_connect_proto_version(connmsg, 4); + nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); + nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); + nng_mqtt_msg_set_connect_password(connmsg, "secrets"); + nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); + nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); + nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); + nng_mqtt_msg_set_connect_clean_session(connmsg, true); + + rv = nng_mqtt_msg_encode(connmsg); + + if (rv != 0) { + printf("Problem on building CONNECT message: %d\n", rv); + } + + uint8_t buff[1024] = { 0 }; + + if (verbose) { + nng_mqtt_msg_dump(connmsg, buff, sizeof(buff), true); + printf("%s\n", buff); + } + + printf("Connecting to server ..."); + if ((rv = nng_sendmsg(*sock, connmsg, 0)) != 0) { + fatal("nng_sendmsg", rv); + } + printf("connected\n"); + + nng_msg_free(connmsg); + + return (0); +} + +// Subscribe to the given subscriptions, and start receiving messages forever. +int +client_subscribe(nng_socket sock, nng_mqtt_topic_qos *subscriptions, int count, + bool verbose) +{ + int rv; + + // create a SUBSCRIBE message + nng_msg *submsg; + nng_mqtt_msg_alloc(&submsg, 0); + nng_mqtt_msg_set_packet_type(submsg, NNG_MQTT_SUBSCRIBE); + nng_mqtt_msg_set_subscribe_topics(submsg, subscriptions, count); + + rv = nng_mqtt_msg_encode(submsg); + + if (rv != 0) { + fatal("Problem on building SUBSCRIBE message: %d\n", rv); + } + + uint8_t buff[1024] = { 0 }; + + if (verbose) { + nng_mqtt_msg_dump(submsg, buff, sizeof(buff), true); + printf("%s\n", buff); + } + + printf("Subscribing ..."); + if ((rv = nng_sendmsg(sock, submsg, 0)) != 0) { + fatal("nng_sendmsg", rv); + } + printf("done.\n"); + + nng_msg_free(submsg); + + printf("Start receiving loop:\n"); + while (true) { + nng_msg *msg; + uint8_t *payload; + uint32_t payload_len; + + if ((rv = nng_recvmsg(sock, &msg, 0)) != 0) { + fatal("nng_recvmsg", rv); + } + + // we should only receive publish messages + assert(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBLISH); + + payload = nng_mqtt_msg_get_publish_payload(msg, &payload_len); + + print80("Received: ", (char *) payload, payload_len, true); + + if (verbose) { + nng_mqtt_msg_decode(msg); + memset(buff, 0, sizeof(buff)); + nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); + printf("%s\n", buff); + } + + nng_msg_free(msg); + } + + return rv; +} + +// Publish a message to the given topic and with the given QoS. +int +client_publish(nng_socket sock, const char *topic, const char *payload, + uint8_t qos, bool verbose) +{ + int rv; + + // create a PUBLISH message + nng_msg *pubmsg; + nng_mqtt_msg_alloc(&pubmsg, 0); + nng_mqtt_msg_set_packet_type(pubmsg, NNG_MQTT_PUBLISH); + nng_mqtt_msg_set_publish_dup(pubmsg, 0); + nng_mqtt_msg_set_publish_qos(pubmsg, qos); + nng_mqtt_msg_set_publish_retain(pubmsg, 0); + nng_mqtt_msg_set_publish_payload( + pubmsg, (uint8_t *) payload, sizeof(payload)); + nng_mqtt_msg_set_publish_topic(pubmsg, topic); + + rv = nng_mqtt_msg_encode(pubmsg); + + if (rv != 0) { + fatal("Problem on building PUBLISH message: %d\n", rv); + } + + uint8_t print[1024] = { 0 }; + + if (verbose) { + nng_mqtt_msg_dump(pubmsg, print, 1024, true); + printf("%s\n", print); + } + + printf("Publishing to '%s' ...", topic); + if ((rv = nng_sendmsg(sock, pubmsg, 0)) != 0) { + fatal("nng_sendmsg", rv); + } + printf(" done\n"); + + nng_msg_free(pubmsg); + return rv; +} + +int +main(const int argc, const char **argv) +{ + nng_socket sock; + + const char *exe = argv[0]; + + const char *cmd; + + if (5 == argc && 0 == strcmp(argv[1], SUBSCRIBE)) { + cmd = SUBSCRIBE; + } else if (6 == argc && 0 == strcmp(argv[1], PUBLISH)) { + cmd = PUBLISH; + } else { + goto error; + } + + const char *url = argv[2]; + uint8_t qos = atoi(argv[3]); + const char *topic = argv[4]; + int rv = 0; + char * verbose_env = getenv("VERBOSE"); + bool verbose = verbose_env && strlen(verbose_env) > 0; + + client_connect(&sock, url, verbose); + + if (PUBLISH == cmd) { + const char *data = argv[5]; + rv = client_publish(sock, topic, data, qos, verbose); + } else if (SUBSCRIBE == cmd) { + nng_mqtt_topic_qos *subscriptions = + nng_mqtt_topic_qos_array_create(1); + nng_mqtt_topic_qos_array_set(subscriptions, 0, topic, qos); + rv = client_subscribe(sock, subscriptions, 1, verbose); + nng_mqtt_topic_qos_array_free(subscriptions, 1); + } + + nng_msleep(1000); + nng_close(sock); + + return 0; + +error: + fprintf(stderr, + "Usage: %s %s \n" + " %s %s \n", + exe, PUBLISH, exe, SUBSCRIBE); + return 1; +} From df0c6e818cb0d6c4fa1f0154126f8694c31f3cfc Mon Sep 17 00:00:00 2001 From: eeff Date: Thu, 28 Oct 2021 16:40:01 +0800 Subject: [PATCH 084/180] Update mqtt_client protocol 1. Support PUBLISH QoS 0 2. Support PUBLISH QoS 1 --- src/sp/protocol/mqtt/mqtt_client.c | 434 ++++++++++++++++++++--------- 1 file changed, 303 insertions(+), 131 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 55cafdc13..0409710c7 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -22,7 +22,7 @@ #define NNG_MQTT_PEER 0 #define NNG_MQTT_PEER_NAME "mqtt-server" -#define MQTT_WORK_NUM 16 +#define MQTT_WORK_NUM 64 typedef struct mqtt_sock_s mqtt_sock_t; typedef struct mqtt_pipe_s mqtt_pipe_t; @@ -56,26 +56,29 @@ typedef enum { WORK_START, // start state WORK_CONNECT, WORK_CONNACK, - WORK_DISCONNECT, // send DISCONNECT - WORK_PUBACK, // send/recv PUBACK - WORK_PUBCOMP, // send/recv PUBCOMP - WORK_PUBLISH, // send/recv PUBLISH - WORK_PUBRECV, // send/recv PUBRECV - WORK_PUBREL, // send/recv PUBREL - WORK_SUBSCRIBE, // send SUBSCRIBE - WORK_SUBACK, // recv SUBACK - WORK_ERROR, // error state - WORK_END, // terminal state + WORK_DISCONNECT, // send DISCONNECT + WORK_PUBACK, // send/recv PUBACK + WORK_PUBCOMP, // send/recv PUBCOMP + WORK_PUBLISH, // send/recv PUBLISH + WORK_PUBRECV, // send/recv PUBRECV + WORK_PUBREL, // send/recv PUBREL + WORK_SUBSCRIBE, // send SUBSCRIBE + WORK_SUBACK, // recv SUBACK + WORK_UNSUBSCRIBE, // send UNSUBSCRIBE + WORK_UNSUBACK, // recv UNSUBACK + WORK_ERROR, // error state + WORK_END, // terminal state } work_state_t; // A work_t represents an asynchronous send/recv of MQTT packet. typedef struct { work_state_t state; - uint8_t qos; // QoS of the MQTT PUBLISH packet + uint8_t qos; // QoS of the MQTT PUBLISH packet + uint16_t packet_id; // packet id of the message that have it mqtt_sock_t * mqtt_sock; + nni_msg * msg; nni_aio * user_aio; nni_aio send_aio; // send aio to the underlying transport - nni_aio recv_aio; // recv aio to the underlying transport nni_list_node node; // in one of send_queue, free_list } work_t; @@ -87,8 +90,13 @@ struct mqtt_ctx_s { // A mqtt_pipe_s is our per-pipe protocol private structure. struct mqtt_pipe_s { nni_atomic_bool closed; + nni_atomic_int next_packet_id; // next packet id to use nni_pipe * pipe; mqtt_sock_t * mqtt_sock; + nni_id_map send_unack; // send messages unacknowledged + nni_id_map recv_unack; // recv messages unacknowledged + nni_aio recv_aio; // recv aio to the underlying transport + nni_lmq recv_messages; // recv messages queue }; // A mqtt_sock_s is our per-socket protocol private structure. @@ -114,10 +122,11 @@ work_init(work_t *work, mqtt_sock_t *s) { work->state = WORK_START; work->qos = 0; + work->packet_id = 0; + work->msg = NULL; work->user_aio = NULL; - work->mqtt_sock = s; nni_aio_init(&work->send_aio, mqtt_send_cb, work); - nni_aio_init(&work->recv_aio, mqtt_recv_cb, work); + work->mqtt_sock = s; NNI_LIST_NODE_INIT(&work->node); } @@ -125,14 +134,16 @@ static inline void work_fini(work_t *work) { nni_aio_fini(&work->send_aio); - nni_aio_fini(&work->recv_aio); } static inline void work_reset(work_t *work) { - work->state = WORK_START; - work->qos = 0; + work->state = WORK_START; + work->qos = 0; + work->packet_id = 0; + nni_msg_free(work->msg); + work->msg = NULL; work->user_aio = NULL; nni_list_node_remove(&work->node); } @@ -154,6 +165,7 @@ work_close(work_t *work) nni_aio_close(&work->send_aio); if (NULL != work->user_aio) { nni_aio_finish_error(work->user_aio, NNG_ECONNRESET); + work->msg = NULL; work->user_aio = NULL; } nni_list_node_remove(&work->node); @@ -275,15 +287,27 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) nni_atomic_init_bool(&p->closed); nni_atomic_set_bool(&p->closed, false); + nni_atomic_set(&p->next_packet_id, 0); p->pipe = pipe; p->mqtt_sock = s; + nni_aio_init(&p->recv_aio, mqtt_recv_cb, p); + // Packet IDs are 16 bits + // We start at a random point, to minimize likelihood of + // accidental collision across restarts. + nni_id_map_init(&p->send_unack, 0x0000u, 0xffffu, true); + nni_id_map_init(&p->recv_unack, 0x0000u, 0xffffu, true); + nni_lmq_init(&p->recv_messages, 1024); // FIXME: remove hard code value return (0); } static void mqtt_pipe_fini(void *arg) { - NNI_ARG_UNUSED(arg); + mqtt_pipe_t *p = arg; + nni_aio_fini(&p->recv_aio); + nni_id_map_fini(&p->send_unack); + nni_id_map_fini(&p->recv_unack); + nni_lmq_fini(&p->recv_messages); } static int @@ -299,9 +323,10 @@ mqtt_pipe_start(void *arg) nni_mtx_lock(&s->mtx); mqtt_run_send_queue(s); - mqtt_run_recv_queue(s); nni_mtx_unlock(&s->mtx); + nni_pipe_recv(p->pipe, &p->recv_aio); + return (0); } @@ -312,6 +337,7 @@ mqtt_pipe_stop(void *arg) mqtt_sock_t *s = p->mqtt_sock; nni_mtx_lock(&s->mtx); + nni_aio_stop(&p->recv_aio); work_stop_queue(&s->send_queue); work_stop_queue(&s->recv_queue); nni_mtx_unlock(&s->mtx); @@ -324,7 +350,9 @@ mqtt_pipe_close(void *arg) mqtt_sock_t *s = p->mqtt_sock; nni_mtx_lock(&s->mtx); + mqtt_sock_close(s); s->mqtt_pipe = NULL; + nni_aio_close(&p->recv_aio); work_close_queue(&s->send_queue); work_close_queue(&s->recv_queue); nni_mtx_unlock(&s->mtx); @@ -332,191 +360,324 @@ mqtt_pipe_close(void *arg) nni_atomic_set_bool(&p->closed, true); } +static uint16_t +mqtt_pipe_get_next_packet_id(mqtt_pipe_t *p) +{ + int packet_id; + do { + packet_id = nni_atomic_get(&p->next_packet_id); + } while ( + !nni_atomic_cas(&p->next_packet_id, packet_id, packet_id + 1)); + return packet_id & 0xFFFF; +} + static void mqtt_send_cb(void *arg) { work_t * work = arg; mqtt_sock_t *s = work->mqtt_sock; + mqtt_pipe_t *p; nni_mtx_lock(&s->mtx); - mqtt_pipe_t *p = s->mqtt_pipe; - nni_mtx_unlock(&s->mtx); + p = s->mqtt_pipe; if (nni_aio_result(&work->send_aio) != 0) { // We failed to send... clean up and deal with it. nni_msg_free(nni_aio_get_msg(&work->send_aio)); nni_aio_set_msg(&work->send_aio, NULL); + nni_mtx_unlock(&s->mtx); nni_pipe_close(p->pipe); return; } - if (nni_atomic_get_bool(&p->closed) || - nni_atomic_get_bool(&s->closed)) { + if (nni_atomic_get_bool(&s->closed) || + nni_atomic_get_bool(&p->closed)) { // This occurs if the mqtt_pipe_close has been called. // In that case we don't want any more processing. + nni_mtx_unlock(&s->mtx); return; } // state transitions switch (work->state) { case WORK_CONNECT: + // we have sent a CONNECT, expect receiving a CONNACK work->state = WORK_CONNACK; - nni_pipe_recv(p->pipe, &work->recv_aio); + // FIXME + work->state = WORK_END; break; + case WORK_DISCONNECT: - // fall through + // we have sent a DISCONNECT, just close the socket. + work->state = WORK_END; + // FIXME: close the socket + break; + case WORK_PUBACK: + // we have sent a PUBACK, + // indicating a successful receipt of a QoS 1 message + // fall through + case WORK_PUBCOMP: + // FIXME: check packet id + // we have sent a PUBCOMP, + // indicating a successful receipt of a QoS 2 message work->state = WORK_END; - break; + nni_id_remove(&p->recv_unack, work->packet_id); + nni_lmq_putq(&p->recv_messages, work->msg); + mqtt_run_recv_queue(s); + work->msg = NULL; + work_reset(work); + nni_list_append(&s->free_list, work); + nni_mtx_unlock(&s->mtx); + return; + case WORK_PUBLISH: // TODO: handle retry + // we have sent a PUBLISH if (0 == work->qos) { + // QoS 0, no further actions work->state = WORK_END; - } else if (1 == work->qos) { - work->state = WORK_PUBACK; - nni_pipe_recv(p->pipe, &work->recv_aio); - } else if (2 == work->qos) { - work->state = WORK_PUBRECV; - nni_pipe_recv(p->pipe, &work->recv_aio); + } else { + // for QoS 1, expect receiving a PUBACK + // for QoS 2, expect receiving a PUBRECV + work->state = + (1 == work->qos) ? WORK_PUBACK : WORK_PUBRECV; + if (0 != + nni_id_set( + &p->send_unack, work->packet_id, work)) { + // FIXME + } } break; + case WORK_PUBRECV: + // we have sent a PUBRECV, expect receiving a PUBREL work->state = WORK_PUBREL; - nni_pipe_recv(p->pipe, &work->recv_aio); break; + case WORK_PUBREL: + // we have sent a PUBREL, expect receiving a PUBCOMP work->state = WORK_PUBCOMP; - nni_pipe_recv(p->pipe, &work->recv_aio); break; + case WORK_SUBSCRIBE: - printf("mqtt_send_cb send SUBSCRIBE done\n"); + // we have sent a SUBSCRIBE, expect receiving a SUBACK work->state = WORK_SUBACK; - nni_pipe_recv(p->pipe, &work->recv_aio); + nni_id_set(&p->send_unack, work->packet_id, work); + break; + + case WORK_UNSUBSCRIBE: + // we have sent a UNSUBSCRIBE, expect receiving a UNSUBACK + work->state = WORK_UNSUBACK; + nni_id_set(&p->send_unack, work->packet_id, work); break; + default: work->state = WORK_ERROR; break; } if (WORK_ERROR == work->state) { + // MQTT protocol error, terminate the connection nni_aio_finish_error(work->user_aio, NNG_EPROTO); + nni_mtx_unlock(&s->mtx); nni_pipe_close(p->pipe); + return; } else if (WORK_END == work->state) { - nni_aio_finish_sync(work->user_aio, 0, 0); + // good news, protocol state machine run to the end + if (NULL != work->user_aio) { + nni_aio_finish_sync(work->user_aio, 0, 0); + } work_reset(work); - nni_mtx_lock(&s->mtx); nni_list_append(&s->free_list, work); - nni_mtx_unlock(&s->mtx); } + + nni_mtx_unlock(&s->mtx); } static void mqtt_recv_cb(void *arg) { - work_t * work = arg; - mqtt_sock_t *s = work->mqtt_sock; - nni_msg * msg = nni_aio_get_msg(&work->recv_aio); + mqtt_pipe_t *p = arg; + mqtt_sock_t *s = p->mqtt_sock; + work_t * work; nni_mtx_lock(&s->mtx); - mqtt_pipe_t *p = s->mqtt_pipe; - nni_mtx_unlock(&s->mtx); - if (nni_aio_result(&work->recv_aio) != 0) { + nni_msg *msg = nni_aio_get_msg(&p->recv_aio); + + if (nni_aio_result(&p->recv_aio) != 0) { nni_msg_free(msg); + nni_mtx_unlock(&s->mtx); nni_pipe_close(p->pipe); return; } - if (nni_atomic_get_bool(&p->closed) || - nni_atomic_get_bool(&s->closed)) { + if (nni_atomic_get_bool(&s->closed) || + nni_atomic_get_bool(&p->closed)) { + nni_mtx_unlock(&s->mtx); return; } - nni_aio_set_msg(&work->recv_aio, NULL); + nni_aio_set_msg(&p->recv_aio, NULL); nni_msg_set_pipe(msg, nni_pipe_id(p->pipe)); nni_mqtt_msg_proto_data_alloc(msg); nni_mqtt_msg_decode(msg); + nni_mqtt_packet_type packet_type = nni_mqtt_msg_get_packet_type(msg); + int32_t packet_id; + uint8_t qos; + + // schedule another receive + nni_pipe_recv(p->pipe, &p->recv_aio); // state transitions - switch (work->state) { - case WORK_CONNACK: - work->state = - (MQTT_CONNACK == packet_type) ? WORK_END : WORK_ERROR; - break; - case WORK_PUBACK: - work->state = - (MQTT_PUBACK == packet_type) ? WORK_END : WORK_ERROR; - break; - case WORK_PUBCOMP: - work->state = - (MQTT_PUBCOMP == packet_type) ? WORK_END : WORK_ERROR; - break; - case WORK_SUBACK: - printf("mqtt_recv_cb recv SUBACK done\n"); - work->state = - (MQTT_SUBACK == packet_type) ? WORK_END : WORK_ERROR; - break; - case WORK_PUBREL: - if (MQTT_PUBREL != packet_type) { - work->state = WORK_ERROR; - break; + switch (packet_type) { + case MQTT_CONNACK: + // FIXME + // we have received the CONNACK + nni_mtx_unlock(&s->mtx); + return; + + case MQTT_PUBACK: + // we have received a PUBACK, successful delivery of a QoS 1 + + // fall through + + case MQTT_PUBCOMP: + // we have received a PUBCOMP, successful delivery of a QoS 2 + + // fall through + + case MQTT_SUBACK: + // we have received a SUBACK, successful subcription + + // fall through + + case MQTT_UNSUBACK: + // we have received a UNSUBACK, successful unsubcription + // FIXME: check packet type match + packet_id = nni_mqtt_msg_get_unsuback_packet_id(msg); + work = nni_id_get(&p->send_unack, packet_id); + if (NULL == work) { + nni_msg_free(msg); + nni_mtx_unlock(&s->mtx); + nni_pipe_close(p->pipe); + return; } - work->state = WORK_PUBCOMP; - nni_pipe_send(p->pipe, &work->send_aio); + nni_msg_free(msg); + nni_id_remove(&p->send_unack, packet_id); + work->state = WORK_END; break; - case WORK_PUBRECV: - if (MQTT_PUBREC != packet_type) { - work->state = WORK_ERROR; - break; + + case MQTT_PUBREC: + // we have received a PUBRECV in the QoS 2 delivery, + // then send a PUBREL + packet_id = nni_mqtt_msg_get_pubrec_packet_id(msg); + work = nni_id_get(&p->send_unack, packet_id); + if (NULL == work) { + nni_msg_free(msg); + nni_mtx_unlock(&s->mtx); + nni_pipe_close(p->pipe); + return; } work->state = WORK_PUBREL; + // reuse msg + nni_mqtt_msg_set_packet_type(msg, MQTT_PUBREL); + nni_mqtt_msg_set_pubrel_packet_id(msg, packet_id); + nni_mqtt_msg_encode(msg); + nni_aio_set_msg(&work->send_aio, msg); nni_pipe_send(p->pipe, &work->send_aio); break; - case WORK_PUBLISH: - if (MQTT_PUBLISH != packet_type) { - work->state = WORK_ERROR; - break; + + case MQTT_PUBREL: + // we have received a PUBREL, then send a PUBCOMP + packet_id = nni_mqtt_msg_get_pubrel_packet_id(msg); + work = nni_id_get(&p->recv_unack, packet_id); + if (NULL == work) { + nni_msg_free(msg); + nni_mtx_unlock(&s->mtx); + nni_pipe_close(p->pipe); + return; } - // TODO: handle retry - uint8_t qos = nni_mqtt_msg_get_publish_qos(msg); + work->state = WORK_PUBCOMP; + // reuse msg + nni_mqtt_msg_set_packet_type(msg, MQTT_PUBCOMP); + nni_mqtt_msg_set_pubcomp_packet_id(msg, packet_id); + nni_mqtt_msg_encode(msg); + nni_aio_set_msg(&work->send_aio, msg); + nni_pipe_send(p->pipe, &work->send_aio); + break; + + case MQTT_PUBLISH: + // we have received a PUBLISH + qos = nni_mqtt_msg_get_publish_qos(msg); if (0 == qos) { - work->state = WORK_END; - } else if (1 == qos) { - work->state = WORK_PUBACK; - nni_pipe_send(p->pipe, &work->send_aio); - } else if (2 == qos) { - work->state = WORK_PUBRECV; + // QoS 0, successful receipt + nni_lmq_putq(&p->recv_messages, msg); + mqtt_run_recv_queue(s); + nni_mtx_unlock(&s->mtx); + return; + } else { + work = nni_list_first(&s->free_list); + nni_list_remove(&s->free_list, work); + // keep the message, and alloc a new ack message + work->qos = qos; + work->msg = msg; + work->packet_id = + nni_mqtt_msg_get_publish_packet_id(msg); + nni_mqtt_msg_alloc(&msg, 0); + + if (1 == qos) { + // QoS 1, then send a PUBACK + work->state = WORK_PUBACK; + nni_mqtt_msg_set_packet_type(msg, MQTT_PUBACK); + nni_mqtt_msg_set_puback_packet_id( + msg, work->packet_id); + } else { + // QoS 2, then send a PUBRECV + work->state = WORK_PUBRECV; + nni_mqtt_msg_set_packet_type(msg, MQTT_PUBREC); + nni_mqtt_msg_set_pubrec_packet_id( + msg, work->packet_id); + } + + nni_mqtt_msg_encode(msg); + nni_aio_set_msg(&work->send_aio, msg); + nni_id_set(&p->recv_unack, work->packet_id, work); nni_pipe_send(p->pipe, &work->send_aio); } - nni_aio_finish_msg(work->user_aio, msg); break; + default: - work->state = WORK_ERROR; + // something bad happen break; } if (WORK_ERROR == work->state) { + // protocol error, just close the connection nni_aio_finish_error(work->user_aio, NNG_EPROTO); + nni_mtx_unlock(&s->mtx); nni_pipe_close(p->pipe); + return; } else if (WORK_END == work->state) { + // good news, protocol state machine run to the end nni_aio_finish_sync(work->user_aio, 0, 0); - work->state = WORK_START; - nni_mtx_lock(&s->mtx); + work_reset(work); nni_list_append(&s->free_list, work); - nni_mtx_unlock(&s->mtx); } + nni_mtx_unlock(&s->mtx); + return; } static void mqtt_send_start(mqtt_sock_t *s, nni_aio *aio) { - work_t * work; - nni_mqtt_packet_type packet_type; + work_t *work; nni_mtx_lock(&s->mtx); @@ -527,27 +688,6 @@ mqtt_send_start(mqtt_sock_t *s, nni_aio *aio) return; } - // only allow to send PUBLISH and SUBSCRIBE packet - nni_msg *msg = nni_aio_get_msg(aio); - packet_type = nni_mqtt_msg_get_packet_type(msg); - - switch (packet_type) { - case MQTT_CONNECT: - work->state = WORK_CONNECT; - break; - case MQTT_PUBLISH: - work->state = WORK_PUBLISH; - break; - case MQTT_SUBSCRIBE: - work->state = WORK_SUBSCRIBE; - break; - default: - work->state = WORK_ERROR; - nni_mtx_unlock(&s->mtx); - nni_aio_finish_error(aio, NNG_EPROTO); - return; - } - work->user_aio = aio; nni_list_remove(&s->free_list, work); nni_list_append(&s->send_queue, work); // enqueue to send @@ -572,6 +712,7 @@ mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) } work->user_aio = aio; + work->state = WORK_PUBLISH; nni_list_remove(&s->free_list, work); nni_list_append(&s->recv_queue, work); // enqueue to recv mqtt_run_recv_queue(s); @@ -585,22 +726,30 @@ mqtt_run_recv_queue(mqtt_sock_t *s) { work_t * work = nni_list_first(&s->recv_queue); mqtt_pipe_t *p = s->mqtt_pipe; + nni_msg * msg; while (NULL != work) { + if (nni_lmq_getq(&p->recv_messages, &msg)) { + break; + } nni_list_remove(&s->recv_queue, work); - nni_pipe_recv(p->pipe, &work->recv_aio); + // nni_pipe_recv(p->pipe, &work->recv_aio); + nni_aio_set_msg(work->user_aio, msg); + nni_aio_finish_sync(work->user_aio, 0, nni_msg_len(msg)); + nni_list_append(&s->free_list, work); work = nni_list_first(&s->recv_queue); } return; } -// Note: This routine should be called with the pipe lock held. +// Note: This routine should be called with the sock lock held. static void mqtt_run_send_queue(mqtt_sock_t *s) { work_t * work; mqtt_pipe_t *p = s->mqtt_pipe; + uint16_t packet_type; // no open pipe if (NULL == p) { @@ -611,8 +760,43 @@ mqtt_run_send_queue(mqtt_sock_t *s) while (NULL != (work = nni_list_first(&s->send_queue))) { nni_list_remove(&s->send_queue, work); nni_msg *msg = nni_aio_get_msg(work->user_aio); + packet_type = nni_mqtt_msg_get_packet_type(msg); + + // only allow to send PUBLISH, SUBSCRIBE and UNSUBSCRIBE packet + switch (packet_type) { + case MQTT_CONNECT: + work->state = WORK_CONNECT; + break; + case MQTT_PUBLISH: + work->state = WORK_PUBLISH; + work->packet_id = mqtt_pipe_get_next_packet_id(p); + nni_mqtt_msg_set_publish_packet_id( + msg, work->packet_id); + work->qos = nni_mqtt_msg_get_publish_qos(msg); + break; + case MQTT_SUBSCRIBE: + work->state = WORK_SUBSCRIBE; + work->packet_id = mqtt_pipe_get_next_packet_id(p); + nni_mqtt_msg_set_subscribe_packet_id( + msg, work->packet_id); + break; + case MQTT_UNSUBSCRIBE: + work->state = WORK_UNSUBSCRIBE; + work->packet_id = mqtt_pipe_get_next_packet_id(p); + nni_mqtt_msg_set_unsubscribe_packet_id( + msg, work->packet_id); + break; + default: + work->state = WORK_ERROR; + nni_mtx_unlock(&s->mtx); + nni_aio_finish_error(work->user_aio, NNG_EPROTO); + return; + } + + nni_msg_clone(msg); nni_aio_set_msg(work->user_aio, NULL); nni_aio_bump_count(work->user_aio, nni_msg_len(msg)); + work->msg = msg; nni_aio_set_msg(&work->send_aio, msg); nni_pipe_send(p->pipe, &work->send_aio); } @@ -646,22 +830,16 @@ mqtt_ctx_send(void *arg, nni_aio *aio) { mqtt_ctx_t * ctx = arg; mqtt_sock_t *s = ctx->mqtt_sock; - mqtt_pipe_t *p; if (nni_aio_begin(aio) != 0) { return; } if (nni_atomic_get_bool(&s->closed)) { - nni_mtx_unlock(&s->mtx); nni_aio_finish_error(aio, NNG_ECLOSED); return; } - nni_mtx_lock(&s->mtx); - p = s->mqtt_pipe; - nni_mtx_unlock(&s->mtx); - mqtt_send_start(s, aio); } @@ -670,22 +848,16 @@ mqtt_ctx_recv(void *arg, nni_aio *aio) { mqtt_ctx_t * ctx = arg; mqtt_sock_t *s = ctx->mqtt_sock; - mqtt_pipe_t *p; if (nni_aio_begin(aio) != 0) { return; } if (nni_atomic_get_bool(&s->closed)) { - nni_mtx_unlock(&s->mtx); nni_aio_finish_error(aio, NNG_ECLOSED); return; } - nni_mtx_lock(&s->mtx); - p = s->mqtt_pipe; - nni_mtx_unlock(&s->mtx); - mqtt_recv_start(s, aio); } From 160cb071ec538f3efca15702090087a817e91d66 Mon Sep 17 00:00:00 2001 From: eeff Date: Fri, 29 Oct 2021 11:59:59 +0800 Subject: [PATCH 085/180] Fix mqtt_tcp receive callback when rxlen contains more than one packet --- src/sp/transport/mqtt/mqtt_tcp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 63bbb6e45..8c4c0fcce 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -387,9 +387,9 @@ mqtt_tcptran_pipe_recv_cb(void *arg) // field, plus the remaining length. size_t tot = 1 + byte_number_for_variable_length(len) + len; nni_msg_alloc(&p->rxmsg, tot); - memcpy(nni_msg_body(p->rxmsg), p->rxlen, p->gotrxhead); if (tot > p->gotrxhead) { // schedule to receive the bulk of the packet + memcpy(nni_msg_body(p->rxmsg), p->rxlen, p->gotrxhead); iov.iov_buf = nni_msg_body(p->rxmsg) + p->gotrxhead; iov.iov_len = tot - p->gotrxhead; p->gotrxhead = 0; @@ -397,9 +397,15 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; + } else if (tot < p->gotrxhead) { + // rxlen contains more than one packet + memcpy(nni_msg_body(p->rxmsg), p->rxlen, tot); + p->gotrxhead -= tot; + memmove(p->rxlen, p->rxlen + tot, p->gotrxhead); } else { // good news, this is very small packet // we have done receiving + memcpy(nni_msg_body(p->rxmsg), p->rxlen, tot); p->gotrxhead = 0; } } else { @@ -709,8 +715,8 @@ mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *p) // Schedule a read of the header. rxaio = p->rxaio; - iov.iov_buf = p->rxlen; - iov.iov_len = sizeof(p->rxlen); + iov.iov_buf = p->rxlen + p->gotrxhead; + iov.iov_len = sizeof(p->rxlen) - p->gotrxhead; nni_aio_set_iov(rxaio, 1, &iov); nng_stream_recv(p->conn, rxaio); From e1d1375ec1b026972bc79fb309cca1650782000d Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Thu, 28 Oct 2021 10:54:57 +0800 Subject: [PATCH 086/180] Add support connmsg set/get --- demo/mqtt/mqtt_client.c | 17 +++++--- src/sp/transport/mqtt/mqtt_tcp.c | 69 ++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index e2a4ca06c..3412af49c 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -86,6 +86,7 @@ client_connect(nng_socket *sock, const char *url, bool verbose) nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); // create a CONNECT message + /* CONNECT */ nng_msg *connmsg; nng_mqtt_msg_alloc(&connmsg, 0); nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); @@ -111,13 +112,17 @@ client_connect(nng_socket *sock, const char *url, bool verbose) printf("%s\n", buff); } - printf("Connecting to server ..."); - if ((rv = nng_sendmsg(*sock, connmsg, 0)) != 0) { - fatal("nng_sendmsg", rv); - } - printf("connected\n"); + nng_dialer_set_ptr(dialer, "connmsg", connmsg); + nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); + +// printf("Connecting to server ..."); +// if ((rv = nng_sendmsg(*sock, connmsg, 0)) != 0) { +// fatal("nng_sendmsg", rv); +// } +// printf("connected\n"); - nng_msg_free(connmsg); +// Free in dialer cb or connect finite +// nng_msg_free(connmsg); return (0); } diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 8c4c0fcce..aab9228b8 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -71,6 +71,8 @@ struct mqtt_tcptran_ep { nni_reap_node reap; nng_stream_dialer * dialer; nng_stream_listener *listener; + nni_dialer * ndialer; + void * connmsg; #ifdef NNG_ENABLE_STATS nni_stat_item st_rcv_max; @@ -310,6 +312,7 @@ mqtt_tcptran_pipe_send_cb(void *arg) nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->sendq); + fprintf(stderr, "mqtt_tcptran_pipe_send_cb.\n"); if ((rv = nni_aio_result(txaio)) != 0) { nni_pipe_bump_error(p->npipe, rv); @@ -767,7 +770,9 @@ mqtt_tcptran_pipe_start( mqtt_tcptran_pipe *p, nng_stream *conn, mqtt_tcptran_ep *ep) { nni_iov iov; - nni_msg * cmsg; + nni_msg * connmsg; + char * buf; + uint32_t buf_len; ep->refcnt++; @@ -775,12 +780,28 @@ mqtt_tcptran_pipe_start( p->ep = ep; p->proto = ep->proto; + fprintf(stderr, "mqtt_tcptran_pipe_start\n"); + int rv = nni_dialer_getopt(ep->ndialer, "connmsg", &connmsg, NULL, NNI_TYPE_POINTER); + if (rv != 0) { + fprintf(stderr, "connmsg ptr error [%d] \n", rv); + } + buf = nni_msg_get_proto_data(connmsg); + buf_len = strlen(buf); + + p->gotrxhead = 0; + p->gottxhead = 0; + p->wantrxhead = 2; // TODO + p->wanttxhead = buf_len; + iov.iov_len = buf_len; + iov.iov_buf = buf; + // CONNECT packet // nni_msg_alloc(&cmsg, 0); // nni_mqtt_msg_set_packet_type(cmsg, MQTT_CONNECT); // nni_mqtt_msg_set_connect_proto_version(cmsg, MQTT_VERSION_3_1_1); // nni_mqtt_msg_encode(cmsg); + /* p->txlen[0] = 0; p->txlen[1] = 'S'; p->txlen[2] = 'P'; @@ -794,16 +815,18 @@ mqtt_tcptran_pipe_start( p->wanttxhead = 8; iov.iov_len = 8; iov.iov_buf = &p->txlen[0]; + */ + nni_aio_set_iov(p->negoaio, 1, &iov); nni_list_append(&ep->negopipes, p); nni_list_remove(&ep->negopipes, p); nni_list_append(&ep->waitpipes, p); - mqtt_tcptran_ep_match(ep); + // mqtt_tcptran_ep_match(ep); // nni_mtx_unlock(&ep->mtx); // nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate - // nng_stream_send(p->conn, p->negoaio); + nng_stream_send(p->conn, p->negoaio); } static void @@ -1083,6 +1106,7 @@ mqtt_tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) if ((rv = mqtt_tcptran_ep_init(&ep, url, sock)) != 0) { return (rv); } + ep->ndialer = ndialer; if ((rv != 0) || ((rv = nni_aio_alloc(&ep->connaio, mqtt_tcptran_dial_cb, ep)) != @@ -1156,6 +1180,7 @@ mqtt_tcptran_ep_connect(void *arg, nni_aio *aio) { mqtt_tcptran_ep *ep = arg; int rv; + fprintf(stderr, "mqtt_tcptran_ep_connect\n"); if (nni_aio_begin(aio) != 0) { return; @@ -1242,6 +1267,38 @@ mqtt_tcptran_ep_set_recvmaxsz( return (rv); } +static int +mqtt_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + +// nni_mtx_lock(&ep->mtx); + nni_copyout_ptr(ep->connmsg, v, szp, t); + fprintf(stderr, "connmsgp [%p] v [%p] \n", ep->connmsg, v); +// ep->connmsg = NULL; +// nni_mtx_unlock(&ep->mtx); + rv = 0; + + return (rv); +} + +static int +mqtt_tcptran_ep_set_connmsg( + void *arg, const void *v, size_t sz, nni_opt_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + nni_copyin_ptr(&ep->connmsg, v, sz, t); + fprintf(stderr, "set connmsg [%p] v [%p] \n", ep->connmsg, v); + nni_mtx_unlock(&ep->mtx); + rv = 0; + + return (rv); +} + static int mqtt_tcptran_ep_bind(void *arg) { @@ -1311,6 +1368,11 @@ static const nni_option mqtt_tcptran_ep_opts[] = { .o_name = NNG_OPT_URL, .o_get = mqtt_tcptran_ep_get_url, }, + { + .o_name = "connmsg", + .o_get = mqtt_tcptran_ep_get_connmsg, + .o_set = mqtt_tcptran_ep_set_connmsg, + }, // terminate list { .o_name = NULL, @@ -1431,6 +1493,7 @@ nng_mqtt_tcp_register(void) void nni_mqtt_tcp_register(void) { + fprintf(stderr, "==============mqtt tcp register=========\n"); nni_sp_tran_register(&mqtt_tcp_tran); nni_sp_tran_register(&mqtt_tcp4_tran); nni_sp_tran_register(&mqtt_tcp6_tran); From 11b6f7aff7048694db701837288fc05f749421a3 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Fri, 29 Oct 2021 12:17:16 +0800 Subject: [PATCH 087/180] Add connmsg sent in dialer --- demo/mqtt/mqtt_client.c | 10 ++- src/sp/transport/mqtt/mqtt_tcp.c | 106 ++++++++++++++++++------------- 2 files changed, 67 insertions(+), 49 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index 3412af49c..ce552dd2b 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -112,17 +112,15 @@ client_connect(nng_socket *sock, const char *url, bool verbose) printf("%s\n", buff); } + printf("Connecting to server ..."); nng_dialer_set_ptr(dialer, "connmsg", connmsg); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); -// printf("Connecting to server ..."); -// if ((rv = nng_sendmsg(*sock, connmsg, 0)) != 0) { -// fatal("nng_sendmsg", rv); -// } -// printf("connected\n"); + printf("connected\n"); -// Free in dialer cb or connect finite +// TODO Connmsg would be free when client disconnected // nng_msg_free(connmsg); + nni_mqtt_msg_proto_data_free(connmsg); return (0); } diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index aab9228b8..9f4dca17f 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -36,7 +36,7 @@ struct mqtt_tcptran_pipe { nni_atomic_flag reaped; nni_reap_node reap; uint8_t txlen[sizeof(uint64_t)]; - uint8_t rxlen[sizeof(uint64_t)]; + uint8_t rxlen[sizeof(uint64_t)]; // fixed header size_t gottxhead; size_t gotrxhead; size_t wanttxhead; @@ -49,6 +49,7 @@ struct mqtt_tcptran_pipe { nni_msg * rxmsg; nni_msg * smsg; nni_mtx mtx; + void * conn_buf; }; struct mqtt_tcptran_ep { @@ -241,13 +242,15 @@ mqtt_tcptran_pipe_nego_cb(void *arg) if ((rv = nni_aio_result(aio)) != 0) { goto error; } - printf("mqtt_tcptran_pipe_nego_cb \n"); + printf("mqtt_tcptran_pipe_nego_cb \n"); // We start transmitting before we receive. if (p->gottxhead < p->wanttxhead) { p->gottxhead += nni_aio_count(aio); } else if (p->gotrxhead < p->wantrxhead) { p->gotrxhead += nni_aio_count(aio); } + printf("mqtt_tcptran_pipe_nego_cb gotrx %ld wantrx %ld gottx %ld wanttx %ld.\n", + p->gotrxhead, p->wantrxhead, p->gottxhead, p->wanttxhead); if (p->gottxhead < p->wanttxhead) { nni_iov iov; @@ -259,7 +262,9 @@ mqtt_tcptran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); return; } - if (p->gotrxhead < p->wantrxhead) { + + // receving fixed header + if (p->gotrxhead < 4) { nni_iov iov; iov.iov_len = p->wantrxhead - p->gotrxhead; iov.iov_buf = &p->rxlen[p->gotrxhead]; @@ -268,16 +273,55 @@ mqtt_tcptran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); return; } - // We have both sent and received the headers. Lets check the - // receive side header. - if ((p->rxlen[0] != 0) || (p->rxlen[1] != 'S') || - (p->rxlen[2] != 'P') || (p->rxlen[3] != 0) || (p->rxlen[6] != 0) || - (p->rxlen[7] != 0)) { - rv = NNG_EPROTO; - goto error; + // finish recevied fixed header + if (p->gotrxhead == 4) { + if ((p->rxlen[0] & 0x20) != 0x20) { + fprintf(stderr, "not recv connack [%x].\n", p->rxlen[0]); + rv = NNG_EPROTO; + goto error; + } + int var_int; + uint8_t * pos = p->rxlen + 1; + int rv = mqtt_msg_read_variable_int(p->rxlen + 1, 4, &var_int, pos); + int len = pos - (p->rxlen + 1); + p->wantrxhead = var_int + 1 + len; + if ((rv = (p->wantrxhead < 4) ? 0 : NNG_EPROTO) != 0) { + fprintf(stderr, "wantrxhead error rv[%d].\n", rv); + goto error; + } + } + // remaining length + if (p->gotrxhead < p->wantrxhead) { + nni_iov iov; + iov.iov_len = p->wantrxhead - p->gotrxhead; + if (p->conn_buf == NULL) { + p->conn_buf = nni_alloc(p->wantrxhead); + memcpy(p->conn_buf, p->rxlen, p->gotrxhead); + } + iov.iov_buf = &p->conn_buf[p->gotrxhead]; + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + if (p->gotrxhead >= p->wantrxhead) { + fprintf(stderr, "finish recv connack. [%ld]\n", p->gotrxhead); + nng_free(p->conn_buf, p->gotrxhead); + p->conn_buf = NULL; + // nng_msg_free(ep->connmsg); } - NNI_GET16(&p->rxlen[4], p->peer); +/* + if (p->gotrxhead < p->wantrxhead) { + nni_iov iov; + iov.iov_len = p->wantrxhead - p->gotrxhead; + iov.iov_buf = &p->rxlen[p->gotrxhead]; + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } +*/ // We are all ready now. We put this in the wait list, and // then try to run the matcher. @@ -773,6 +817,7 @@ mqtt_tcptran_pipe_start( nni_msg * connmsg; char * buf; uint32_t buf_len; + int rv; ep->refcnt++; @@ -780,49 +825,25 @@ mqtt_tcptran_pipe_start( p->ep = ep; p->proto = ep->proto; - fprintf(stderr, "mqtt_tcptran_pipe_start\n"); - int rv = nni_dialer_getopt(ep->ndialer, "connmsg", &connmsg, NULL, NNI_TYPE_POINTER); + rv = nni_dialer_getopt(ep->ndialer, + "connmsg", &connmsg, NULL, NNI_TYPE_POINTER); if (rv != 0) { - fprintf(stderr, "connmsg ptr error [%d] \n", rv); + fprintf(stderr, "Connmsg get error [%d] \n", rv); } - buf = nni_msg_get_proto_data(connmsg); - buf_len = strlen(buf); + buf = nni_msg_body(connmsg); + buf_len = nni_msg_len(connmsg); p->gotrxhead = 0; p->gottxhead = 0; - p->wantrxhead = 2; // TODO + p->wantrxhead = 4; // TODO p->wanttxhead = buf_len; + iov.iov_len = buf_len; iov.iov_buf = buf; - // CONNECT packet - // nni_msg_alloc(&cmsg, 0); - // nni_mqtt_msg_set_packet_type(cmsg, MQTT_CONNECT); - // nni_mqtt_msg_set_connect_proto_version(cmsg, MQTT_VERSION_3_1_1); - // nni_mqtt_msg_encode(cmsg); - - /* - p->txlen[0] = 0; - p->txlen[1] = 'S'; - p->txlen[2] = 'P'; - p->txlen[3] = 0; - NNI_PUT16(&p->txlen[4], p->proto); - NNI_PUT16(&p->txlen[6], 0); - - p->gotrxhead = 0; - p->gottxhead = 0; - p->wantrxhead = 8; - p->wanttxhead = 8; - iov.iov_len = 8; - iov.iov_buf = &p->txlen[0]; - */ - nni_aio_set_iov(p->negoaio, 1, &iov); nni_list_append(&ep->negopipes, p); - nni_list_remove(&ep->negopipes, p); - nni_list_append(&ep->waitpipes, p); - // mqtt_tcptran_ep_match(ep); // nni_mtx_unlock(&ep->mtx); // nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate @@ -1493,7 +1514,6 @@ nng_mqtt_tcp_register(void) void nni_mqtt_tcp_register(void) { - fprintf(stderr, "==============mqtt tcp register=========\n"); nni_sp_tran_register(&mqtt_tcp_tran); nni_sp_tran_register(&mqtt_tcp4_tran); nni_sp_tran_register(&mqtt_tcp6_tran); From 5059e3c80e87015b1ae3a0355a53e85f6413baab Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 29 Oct 2021 18:08:08 +0800 Subject: [PATCH 088/180] * MDF [nng/mqtt] branches merged --- mqtt/mqtt_client.c | 275 +++++++++++++++++++++++++++++++ src/mqtt/CMakeLists.txt | 1 - src/mqtt/mqtt.h | 2 +- src/sp/transport/mqtt/mqtt_tcp.c | 18 +- 4 files changed, 286 insertions(+), 10 deletions(-) create mode 100644 mqtt/mqtt_client.c diff --git a/mqtt/mqtt_client.c b/mqtt/mqtt_client.c new file mode 100644 index 000000000..8bdd95c5f --- /dev/null +++ b/mqtt/mqtt_client.c @@ -0,0 +1,275 @@ +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +// +// This is just a simple MQTT client demonstration application. +// +// The application has two sub-commands: `pub` and `sub`. The `pub` +// sub-command publishes a given message to the server and then exits. +// The `sub` sub-command subscribes to the given topic filter and blocks +// waiting for incoming messages. +// +// # Example: +// +// Publish 'hello' to `topic` with QoS `0`: +// ``` +// $ ./mqtt_client pub mqtt-tcp://127.0.0.1:1883 0 topic hello +// ``` +// +// Subscribe to `topic` with QoS `0` and waiting for messages: +// ``` +// $ ./mqtt_client sub mqtt-tcp://127.0.0.1:1883 0 topic +// ``` +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Subcommands +#define PUBLISH "pub" +#define SUBSCRIBE "sub" + +void +fatal(const char *msg, int rv) +{ + fprintf(stderr, "%s: %s\n", msg, nng_strerror(rv)); + exit(1); +} + +// Print the given string limited to 80 columns. +// +// The `prefix` should be a null terminated string much smaller than 80, +// `str` and `len` designates the string to be printed, `quote` specifies +// whether to print in single quotes. +void +print80(const char *prefix, const char *str, size_t len, bool quote) +{ + size_t max_len = 80 - strlen(prefix) - (quote ? 2 : 0); + char * q = quote ? "'" : ""; + if (len <= max_len) { + // case the output fit in a line + printf("%s%s%.*s%s\n", prefix, q, len, str, q); + } else { + // case we truncate the payload with ellipses + printf("%s%s%.*s%s...\n", prefix, q, max_len - 3, str, q); + } +} + +// Connect to the given address. +int +client_connect(nng_socket *sock, const char *url, bool verbose) +{ + nng_dialer dialer; + int rv; + + if ((rv = nng_mqtt_client_open(sock)) != 0) { + fatal("nng_socket", rv); + } + + if ((rv = nng_dialer_create(&dialer, *sock, url)) != 0) { + fatal("nng_dialer_create", rv); + } + + // create a CONNECT message + /* CONNECT */ + nng_msg *connmsg; + nng_mqtt_msg_alloc(&connmsg, 0); + nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); + nng_mqtt_msg_set_connect_proto_version(connmsg, 4); + nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); + nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); + nng_mqtt_msg_set_connect_password(connmsg, "secrets"); + nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); + nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); + nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); + nng_mqtt_msg_set_connect_clean_session(connmsg, true); + + rv = nng_mqtt_msg_encode(connmsg); + + if (rv != 0) { + printf("Problem on building CONNECT message: %d\n", rv); + } + + uint8_t buff[1024] = { 0 }; + + if (verbose) { + nng_mqtt_msg_dump(connmsg, buff, sizeof(buff), true); + printf("%s\n", buff); + } + + printf("Connecting to server ..."); + nng_dialer_set_ptr(dialer, "connmsg", connmsg); + nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); + +// TODO Connmsg would be free when client disconnected +// nng_msg_free(connmsg); + nni_mqtt_msg_proto_data_free(connmsg); + + return (0); +} + +// Subscribe to the given subscriptions, and start receiving messages forever. +int +client_subscribe(nng_socket sock, nng_mqtt_topic_qos *subscriptions, int count, + bool verbose) +{ + int rv; + + // create a SUBSCRIBE message + nng_msg *submsg; + nng_mqtt_msg_alloc(&submsg, 0); + nng_mqtt_msg_set_packet_type(submsg, NNG_MQTT_SUBSCRIBE); + nng_mqtt_msg_set_subscribe_topics(submsg, subscriptions, count); + + rv = nng_mqtt_msg_encode(submsg); + + if (rv != 0) { + fatal("Problem on building SUBSCRIBE message: %d\n", rv); + } + + uint8_t buff[1024] = { 0 }; + + if (verbose) { + nng_mqtt_msg_dump(submsg, buff, sizeof(buff), true); + printf("%s\n", buff); + } + + if ((rv = nng_sendmsg(sock, submsg, 0)) != 0) { + fatal("nng_sendmsg", rv); + } + printf("Subscription done.\n"); + + nng_msg_free(submsg); + + printf("Start receiving loop:\n"); + while (true) { + nng_msg *msg; + uint8_t *payload; + uint32_t payload_len; + + if ((rv = nng_recvmsg(sock, &msg, 0)) != 0) { + fatal("nng_recvmsg", rv); + } + + // we should only receive publish messages + assert(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBLISH); + + payload = nng_mqtt_msg_get_publish_payload(msg, &payload_len); + + print80("Received: ", (char *) payload, payload_len, true); + + if (verbose) { + nng_mqtt_msg_decode(msg); + memset(buff, 0, sizeof(buff)); + nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); + printf("%s\n", buff); + } + + nng_msg_free(msg); + } + + return rv; +} + +// Publish a message to the given topic and with the given QoS. +int +client_publish(nng_socket sock, const char *topic, const char *payload, + uint8_t qos, bool verbose) +{ + int rv; + + // create a PUBLISH message + nng_msg *pubmsg; + nng_mqtt_msg_alloc(&pubmsg, 0); + nng_mqtt_msg_set_packet_type(pubmsg, NNG_MQTT_PUBLISH); + nng_mqtt_msg_set_publish_dup(pubmsg, 0); + nng_mqtt_msg_set_publish_qos(pubmsg, qos); + nng_mqtt_msg_set_publish_retain(pubmsg, 0); + nng_mqtt_msg_set_publish_payload( + pubmsg, (uint8_t *) payload, sizeof(payload)); + nng_mqtt_msg_set_publish_topic(pubmsg, topic); + + rv = nng_mqtt_msg_encode(pubmsg); + + if (rv != 0) { + fatal("Problem on building PUBLISH message: %d\n", rv); + } + + uint8_t print[1024] = { 0 }; + + if (verbose) { + nng_mqtt_msg_dump(pubmsg, print, 1024, true); + printf("%s\n", print); + } + + printf("Publishing to '%s' ...", topic); + if ((rv = nng_sendmsg(sock, pubmsg, 0)) != 0) { + fatal("nng_sendmsg", rv); + } + printf(" done\n"); + + nng_msg_free(pubmsg); + return rv; +} + +int +main(const int argc, const char **argv) +{ + nng_socket sock; + + const char *exe = argv[0]; + + const char *cmd; + + if (5 == argc && 0 == strcmp(argv[1], SUBSCRIBE)) { + cmd = SUBSCRIBE; + } else if (6 == argc && 0 == strcmp(argv[1], PUBLISH)) { + cmd = PUBLISH; + } else { + goto error; + } + + const char *url = argv[2]; + uint8_t qos = atoi(argv[3]); + const char *topic = argv[4]; + int rv = 0; + char * verbose_env = getenv("VERBOSE"); + bool verbose = verbose_env && strlen(verbose_env) > 0; + + client_connect(&sock, url, verbose); + + if (PUBLISH == cmd) { + const char *data = argv[5]; + rv = client_publish(sock, topic, data, qos, verbose); + } else if (SUBSCRIBE == cmd) { + // nng_mqtt_topic_qos *subscriptions = + // nng_mqtt_topic_qos_array_create(1); + // nng_mqtt_topic_qos_array_set(subscriptions, 0, topic, qos); + // rv = client_subscribe(sock, subscriptions, 1, verbose); + // nng_mqtt_topic_qos_array_free(subscriptions, 1); + } + + nng_msleep(100000); + nng_close(sock); + + return 0; + +error: + fprintf(stderr, + "Usage: %s %s \n" + " %s %s \n", + exe, PUBLISH, exe, SUBSCRIBE); + return 1; +} diff --git a/src/mqtt/CMakeLists.txt b/src/mqtt/CMakeLists.txt index 5e024d724..2a4bd4314 100644 --- a/src/mqtt/CMakeLists.txt +++ b/src/mqtt/CMakeLists.txt @@ -17,7 +17,6 @@ nng_check_sym(strncasecmp string.h NNG_HAVE_STRNCASECMP) nng_sources_if( NNG_TRANSPORT_MQTT_TCP - mqtt_codec.c mqtt.c mqtt.h diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index 1ecec626e..0f227cf0c 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -389,4 +389,4 @@ extern void nni_mqtt_topic_qos_array_free(nni_mqtt_topic_qos *, size_t); } #endif -#endif \ No newline at end of file +#endif diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 9f4dca17f..9dd16417a 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -14,6 +14,7 @@ #include #include "core/nng_impl.h" +#include "mqtt/mqtt.h" // TCP transport. Platform specific TCP operations must be // supplied as well. @@ -282,7 +283,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) } int var_int; uint8_t * pos = p->rxlen + 1; - int rv = mqtt_msg_read_variable_int(p->rxlen + 1, 4, &var_int, pos); + int rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, &var_int, NULL); int len = pos - (p->rxlen + 1); p->wantrxhead = var_int + 1 + len; if ((rv = (p->wantrxhead < 4) ? 0 : NNG_EPROTO) != 0) { @@ -681,11 +682,11 @@ mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *p) // iov[0].iov_buf = p->txlen; // iov[0].iov_len = sizeof(p->txlen); // niov++; - if (nni_msg_header_len(msg) > 0) { - iov[niov].iov_buf = nni_msg_header(msg); - iov[niov].iov_len = nni_msg_header_len(msg); - niov++; - } + // if (nni_msg_header_len(msg) > 0) { + // iov[niov].iov_buf = nni_msg_header(msg); + // iov[niov].iov_len = nni_msg_header_len(msg); + // niov++; + // } if (nni_msg_len(msg) > 0) { iov[niov].iov_buf = nni_msg_body(msg); iov[niov].iov_len = nni_msg_len(msg); @@ -846,8 +847,9 @@ mqtt_tcptran_pipe_start( // mqtt_tcptran_ep_match(ep); // nni_mtx_unlock(&ep->mtx); - // nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate - nng_stream_send(p->conn, p->negoaio); + nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate + printf("send connect\n"); + nng_stream_send(p->conn, p->negoaio); } static void From b03a63c2ad5814d915c1661f47b291d4b0e2b4e2 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Sat, 30 Oct 2021 12:14:57 +0800 Subject: [PATCH 089/180] * FIX [mqtt_codec] fix connect packet --- mqtt/mqtt_client.c | 275 ------------------------------- src/mqtt/mqtt_codec.c | 9 +- src/nng.c | 2 +- src/sp/transport/mqtt/mqtt_tcp.c | 68 ++++---- 4 files changed, 38 insertions(+), 316 deletions(-) delete mode 100644 mqtt/mqtt_client.c diff --git a/mqtt/mqtt_client.c b/mqtt/mqtt_client.c deleted file mode 100644 index 8bdd95c5f..000000000 --- a/mqtt/mqtt_client.c +++ /dev/null @@ -1,275 +0,0 @@ -// -// This software is supplied under the terms of the MIT License, a -// copy of which should be located in the distribution where this -// file was obtained (LICENSE.txt). A copy of the license may also be -// found online at https://opensource.org/licenses/MIT. -// - -// -// This is just a simple MQTT client demonstration application. -// -// The application has two sub-commands: `pub` and `sub`. The `pub` -// sub-command publishes a given message to the server and then exits. -// The `sub` sub-command subscribes to the given topic filter and blocks -// waiting for incoming messages. -// -// # Example: -// -// Publish 'hello' to `topic` with QoS `0`: -// ``` -// $ ./mqtt_client pub mqtt-tcp://127.0.0.1:1883 0 topic hello -// ``` -// -// Subscribe to `topic` with QoS `0` and waiting for messages: -// ``` -// $ ./mqtt_client sub mqtt-tcp://127.0.0.1:1883 0 topic -// ``` -// - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// Subcommands -#define PUBLISH "pub" -#define SUBSCRIBE "sub" - -void -fatal(const char *msg, int rv) -{ - fprintf(stderr, "%s: %s\n", msg, nng_strerror(rv)); - exit(1); -} - -// Print the given string limited to 80 columns. -// -// The `prefix` should be a null terminated string much smaller than 80, -// `str` and `len` designates the string to be printed, `quote` specifies -// whether to print in single quotes. -void -print80(const char *prefix, const char *str, size_t len, bool quote) -{ - size_t max_len = 80 - strlen(prefix) - (quote ? 2 : 0); - char * q = quote ? "'" : ""; - if (len <= max_len) { - // case the output fit in a line - printf("%s%s%.*s%s\n", prefix, q, len, str, q); - } else { - // case we truncate the payload with ellipses - printf("%s%s%.*s%s...\n", prefix, q, max_len - 3, str, q); - } -} - -// Connect to the given address. -int -client_connect(nng_socket *sock, const char *url, bool verbose) -{ - nng_dialer dialer; - int rv; - - if ((rv = nng_mqtt_client_open(sock)) != 0) { - fatal("nng_socket", rv); - } - - if ((rv = nng_dialer_create(&dialer, *sock, url)) != 0) { - fatal("nng_dialer_create", rv); - } - - // create a CONNECT message - /* CONNECT */ - nng_msg *connmsg; - nng_mqtt_msg_alloc(&connmsg, 0); - nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); - nng_mqtt_msg_set_connect_proto_version(connmsg, 4); - nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); - nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); - nng_mqtt_msg_set_connect_password(connmsg, "secrets"); - nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); - nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); - nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); - nng_mqtt_msg_set_connect_clean_session(connmsg, true); - - rv = nng_mqtt_msg_encode(connmsg); - - if (rv != 0) { - printf("Problem on building CONNECT message: %d\n", rv); - } - - uint8_t buff[1024] = { 0 }; - - if (verbose) { - nng_mqtt_msg_dump(connmsg, buff, sizeof(buff), true); - printf("%s\n", buff); - } - - printf("Connecting to server ..."); - nng_dialer_set_ptr(dialer, "connmsg", connmsg); - nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); - -// TODO Connmsg would be free when client disconnected -// nng_msg_free(connmsg); - nni_mqtt_msg_proto_data_free(connmsg); - - return (0); -} - -// Subscribe to the given subscriptions, and start receiving messages forever. -int -client_subscribe(nng_socket sock, nng_mqtt_topic_qos *subscriptions, int count, - bool verbose) -{ - int rv; - - // create a SUBSCRIBE message - nng_msg *submsg; - nng_mqtt_msg_alloc(&submsg, 0); - nng_mqtt_msg_set_packet_type(submsg, NNG_MQTT_SUBSCRIBE); - nng_mqtt_msg_set_subscribe_topics(submsg, subscriptions, count); - - rv = nng_mqtt_msg_encode(submsg); - - if (rv != 0) { - fatal("Problem on building SUBSCRIBE message: %d\n", rv); - } - - uint8_t buff[1024] = { 0 }; - - if (verbose) { - nng_mqtt_msg_dump(submsg, buff, sizeof(buff), true); - printf("%s\n", buff); - } - - if ((rv = nng_sendmsg(sock, submsg, 0)) != 0) { - fatal("nng_sendmsg", rv); - } - printf("Subscription done.\n"); - - nng_msg_free(submsg); - - printf("Start receiving loop:\n"); - while (true) { - nng_msg *msg; - uint8_t *payload; - uint32_t payload_len; - - if ((rv = nng_recvmsg(sock, &msg, 0)) != 0) { - fatal("nng_recvmsg", rv); - } - - // we should only receive publish messages - assert(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBLISH); - - payload = nng_mqtt_msg_get_publish_payload(msg, &payload_len); - - print80("Received: ", (char *) payload, payload_len, true); - - if (verbose) { - nng_mqtt_msg_decode(msg); - memset(buff, 0, sizeof(buff)); - nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); - printf("%s\n", buff); - } - - nng_msg_free(msg); - } - - return rv; -} - -// Publish a message to the given topic and with the given QoS. -int -client_publish(nng_socket sock, const char *topic, const char *payload, - uint8_t qos, bool verbose) -{ - int rv; - - // create a PUBLISH message - nng_msg *pubmsg; - nng_mqtt_msg_alloc(&pubmsg, 0); - nng_mqtt_msg_set_packet_type(pubmsg, NNG_MQTT_PUBLISH); - nng_mqtt_msg_set_publish_dup(pubmsg, 0); - nng_mqtt_msg_set_publish_qos(pubmsg, qos); - nng_mqtt_msg_set_publish_retain(pubmsg, 0); - nng_mqtt_msg_set_publish_payload( - pubmsg, (uint8_t *) payload, sizeof(payload)); - nng_mqtt_msg_set_publish_topic(pubmsg, topic); - - rv = nng_mqtt_msg_encode(pubmsg); - - if (rv != 0) { - fatal("Problem on building PUBLISH message: %d\n", rv); - } - - uint8_t print[1024] = { 0 }; - - if (verbose) { - nng_mqtt_msg_dump(pubmsg, print, 1024, true); - printf("%s\n", print); - } - - printf("Publishing to '%s' ...", topic); - if ((rv = nng_sendmsg(sock, pubmsg, 0)) != 0) { - fatal("nng_sendmsg", rv); - } - printf(" done\n"); - - nng_msg_free(pubmsg); - return rv; -} - -int -main(const int argc, const char **argv) -{ - nng_socket sock; - - const char *exe = argv[0]; - - const char *cmd; - - if (5 == argc && 0 == strcmp(argv[1], SUBSCRIBE)) { - cmd = SUBSCRIBE; - } else if (6 == argc && 0 == strcmp(argv[1], PUBLISH)) { - cmd = PUBLISH; - } else { - goto error; - } - - const char *url = argv[2]; - uint8_t qos = atoi(argv[3]); - const char *topic = argv[4]; - int rv = 0; - char * verbose_env = getenv("VERBOSE"); - bool verbose = verbose_env && strlen(verbose_env) > 0; - - client_connect(&sock, url, verbose); - - if (PUBLISH == cmd) { - const char *data = argv[5]; - rv = client_publish(sock, topic, data, qos, verbose); - } else if (SUBSCRIBE == cmd) { - // nng_mqtt_topic_qos *subscriptions = - // nng_mqtt_topic_qos_array_create(1); - // nng_mqtt_topic_qos_array_set(subscriptions, 0, topic, qos); - // rv = client_subscribe(sock, subscriptions, 1, verbose); - // nng_mqtt_topic_qos_array_free(subscriptions, 1); - } - - nng_msleep(100000); - nng_close(sock); - - return 0; - -error: - fprintf(stderr, - "Usage: %s %s \n" - " %s %s \n", - exe, PUBLISH, exe, SUBSCRIBE); - return 1; -} diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index 9b445dc58..df394c907 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -157,13 +157,16 @@ nni_mqtt_msg_encode_fixed_header(nni_msg *msg, nni_mqtt_proto_data *data) static int nni_mqtt_msg_encode_connect(nni_msg *msg) { - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + char name[4] = "MQTT"; nni_msg_clear(msg); int poslength = 6; - mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; + mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; + var_header->protocol_name.buf = name; + var_header->protocol_name.length = 4; /* length of protocol-name (consider "MQTT" by default */ poslength += (var_header->protocol_name.length == 0) @@ -172,6 +175,8 @@ nni_mqtt_msg_encode_connect(nni_msg *msg) /* add the length of payload part */ mqtt_connect_payload *payload = &mqtt->payload.connect; + /* Clientid length */ + poslength += payload->client_id.length + 2; /* Will Topic */ if (payload->will_topic.length > 0) { diff --git a/src/nng.c b/src/nng.c index a5b1287bf..9aca8583d 100644 --- a/src/nng.c +++ b/src/nng.c @@ -2302,7 +2302,7 @@ nng_mqtt_topic_array_free(nng_mqtt_topic *topic, size_t n) nng_mqtt_topic_qos * nng_mqtt_topic_qos_array_create(size_t n) { - return nni_mqtt_topic_qos_array_create(n); + return nni_mqtt_topic_qos_array_create(n); } void diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 9dd16417a..afe849a01 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -239,11 +239,9 @@ mqtt_tcptran_pipe_nego_cb(void *arg) nni_mtx_lock(&ep->mtx); -// connack if ((rv = nni_aio_result(aio)) != 0) { goto error; } - printf("mqtt_tcptran_pipe_nego_cb \n"); // We start transmitting before we receive. if (p->gottxhead < p->wanttxhead) { p->gottxhead += nni_aio_count(aio); @@ -312,18 +310,6 @@ mqtt_tcptran_pipe_nego_cb(void *arg) // nng_msg_free(ep->connmsg); } -/* - if (p->gotrxhead < p->wantrxhead) { - nni_iov iov; - iov.iov_len = p->wantrxhead - p->gotrxhead; - iov.iov_buf = &p->rxlen[p->gotrxhead]; - nni_aio_set_iov(aio, 1, &iov); - nng_stream_recv(p->conn, aio); - nni_mtx_unlock(&ep->mtx); - return; - } -*/ - // We are all ready now. We put this in the wait list, and // then try to run the matcher. nni_list_remove(&ep->negopipes, p); @@ -682,11 +668,11 @@ mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *p) // iov[0].iov_buf = p->txlen; // iov[0].iov_len = sizeof(p->txlen); // niov++; - // if (nni_msg_header_len(msg) > 0) { - // iov[niov].iov_buf = nni_msg_header(msg); - // iov[niov].iov_len = nni_msg_header_len(msg); - // niov++; - // } + if (nni_msg_header_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_header(msg); + iov[niov].iov_len = 1; + niov++; + } if (nni_msg_len(msg) > 0) { iov[niov].iov_buf = nni_msg_body(msg); iov[niov].iov_len = nni_msg_len(msg); @@ -814,11 +800,10 @@ static void mqtt_tcptran_pipe_start( mqtt_tcptran_pipe *p, nng_stream *conn, mqtt_tcptran_ep *ep) { - nni_iov iov; + nni_iov iov[2]; nni_msg * connmsg; - char * buf; uint32_t buf_len; - int rv; + int rv, niov = 0; ep->refcnt++; @@ -826,29 +811,36 @@ mqtt_tcptran_pipe_start( p->ep = ep; p->proto = ep->proto; - rv = nni_dialer_getopt(ep->ndialer, - "connmsg", &connmsg, NULL, NNI_TYPE_POINTER); - if (rv != 0) { + rv = nni_dialer_getopt( + ep->ndialer, "connmsg", &connmsg, NULL, NNI_TYPE_POINTER); + if (!connmsg) { fprintf(stderr, "Connmsg get error [%d] \n", rv); + nni_list_append(&ep->waitpipes, p); + mqtt_tcptran_ep_match(ep); + mqtt_tcptran_ep_match(ep); + return; } - buf = nni_msg_body(connmsg); - buf_len = nni_msg_len(connmsg); - p->gotrxhead = 0; - p->gottxhead = 0; - p->wantrxhead = 4; // TODO - p->wanttxhead = buf_len; + p->gotrxhead = 0; + p->gottxhead = 0; + // TODO TX length for MQTT 5 + p->wantrxhead = 4; + p->wanttxhead = nni_msg_header_len(connmsg) + nni_msg_len(connmsg); - iov.iov_len = buf_len; - iov.iov_buf = buf; - - nni_aio_set_iov(p->negoaio, 1, &iov); + if (nni_msg_header_len(connmsg) > 0) { + iov[niov].iov_buf = nni_msg_header(connmsg); + iov[niov].iov_len = nni_msg_header_len(connmsg); + niov++; + } + if (nni_msg_len(connmsg) > 0) { + iov[niov].iov_buf = nni_msg_body(connmsg); + iov[niov].iov_len = nni_msg_len(connmsg); + niov++; + } + nni_aio_set_iov(p->negoaio, niov, iov); nni_list_append(&ep->negopipes, p); - // mqtt_tcptran_ep_match(ep); - // nni_mtx_unlock(&ep->mtx); nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate - printf("send connect\n"); nng_stream_send(p->conn, p->negoaio); } From 64c0cfa9259079e1dbb8ac69d6b3995c78a6f577 Mon Sep 17 00:00:00 2001 From: eeff Date: Sat, 30 Oct 2021 14:37:03 +0800 Subject: [PATCH 090/180] Remove nng msg header guard --- include/nng/nng.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index ca4f065a9..9270ffad7 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1298,7 +1298,6 @@ typedef struct mqtt_buf_t nng_mqtt_buffer; typedef struct mqtt_buf_t nng_mqtt_topic; typedef struct mqtt_topic_qos_t nng_mqtt_topic_qos; -#ifdef NNG_TRANSPORT_MQTT_TCP NNG_DECL int nng_mqtt_msg_alloc(nng_msg **, size_t); NNG_DECL int nng_mqtt_msg_encode(nng_msg *); NNG_DECL int nng_mqtt_msg_decode(nng_msg *); @@ -1355,7 +1354,6 @@ NNG_DECL void nng_mqtt_topic_qos_array_set( nng_mqtt_topic_qos *, size_t, const char *, uint8_t); NNG_DECL void nng_mqtt_topic_qos_array_free(nng_mqtt_topic_qos *, size_t); NNG_DECL void nng_mqtt_msg_dump(nng_msg *, uint8_t *, uint32_t, bool); -#endif // NNG_TRANSPORT_MQTT_TCP #endif From 8e8d372f8af4e0b12e7664aebf47590711ba71a2 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Sat, 30 Oct 2021 16:42:47 +0800 Subject: [PATCH 091/180] * MDF [mqtt/transport] adapt mqtt_tcp to new msg API style (fixedheader in HEADER) --- src/sp/transport/mqtt/mqtt_tcp.c | 192 +++++++++---------------------- 1 file changed, 57 insertions(+), 135 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index afe849a01..8e1f4df75 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -273,6 +273,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) return; } // finish recevied fixed header + //TODO only deal with CONNACK, so just use rxlen at all time if (p->gotrxhead == 4) { if ((p->rxlen[0] & 0x20) != 0x20) { fprintf(stderr, "not recv connack [%x].\n", p->rxlen[0]); @@ -280,16 +281,17 @@ mqtt_tcptran_pipe_nego_cb(void *arg) goto error; } int var_int; - uint8_t * pos = p->rxlen + 1; - int rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, &var_int, NULL); - int len = pos - (p->rxlen + 1); - p->wantrxhead = var_int + 1 + len; - if ((rv = (p->wantrxhead < 4) ? 0 : NNG_EPROTO) != 0) { + uint8_t pos = 0; + int rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, &var_int, &pos); + p->wantrxhead = var_int + 1 + pos; + if ((rv = (p->wantrxhead <= 4) ? 0 : NNG_EPROTO) != 0) { fprintf(stderr, "wantrxhead error rv[%d].\n", rv); + // TODO BUG here goto error; } } // remaining length + // TODO CPU Waste if (p->gotrxhead < p->wantrxhead) { nni_iov iov; iov.iov_len = p->wantrxhead - p->gotrxhead; @@ -384,8 +386,8 @@ mqtt_tcptran_pipe_recv_cb(void *arg) { nni_aio * aio; nni_iov iov; - uint8_t type; - uint32_t len = 0, rv, pos = 1; + uint8_t type, pos; + uint32_t len = 0, rv; size_t n; nni_msg * msg; mqtt_tcptran_pipe *p = arg; @@ -400,142 +402,63 @@ mqtt_tcptran_pipe_recv_cb(void *arg) goto recv_error; } + n = nni_aio_count(rxaio); + p->gotrxhead += n; + + nni_aio_iov_advance(rxaio, n); + + rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, &len, &pos); + p->wantrxhead = len + 1 + pos; + if (p->gotrxhead <= 5 && p->rxlen[p->gotrxhead - 1] > 0x7f) { + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { + rv = NNG_EMSGSIZE; + goto recv_error; + } + // same packet, continue receving next byte of remaining length + iov.iov_buf = &p->rxlen[p->gotrxhead]; + iov.iov_len = 1; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + + //fixed header finished if (NULL == p->rxmsg) { - // receiving the header first to determine the packet size - n = nni_aio_count(rxaio); - p->gotrxhead += n; - - struct pos_buf buf = { .curpos = p->rxlen + 1, - .endpos = p->rxlen + p->gotrxhead }; - if (read_packet_length(&buf, &len) != 0) { - // not enough header, schedule another receive - nni_aio_bump_count(rxaio, n); - nng_stream_recv(p->conn, rxaio); - nni_mtx_unlock(&p->mtx); - return; + // Make sure the message payload is not too big. If it is + // the caller will shut down the pipe. + // if ((len > p->rcvmax) && (p->rcvmax > 0)) { + // rv = NNG_EMSGSIZE; + // goto recv_error; + // } + + if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + goto recv_error; } - // we have decode the remaining length from the header - // the total packet length is one byte for the packet type, - // plus the number of bytes to encode the remaining length - // field, plus the remaining length. - size_t tot = 1 + byte_number_for_variable_length(len) + len; - nni_msg_alloc(&p->rxmsg, tot); - if (tot > p->gotrxhead) { - // schedule to receive the bulk of the packet - memcpy(nni_msg_body(p->rxmsg), p->rxlen, p->gotrxhead); - iov.iov_buf = nni_msg_body(p->rxmsg) + p->gotrxhead; - iov.iov_len = tot - p->gotrxhead; - p->gotrxhead = 0; + // Submit the rest of the data for a read -- seperate Fixed + // header with variable header and so on + // we want to read the entire message now. + if (len != 0) { + iov.iov_buf = nni_msg_body(p->rxmsg); + iov.iov_len = (size_t) len; + nni_aio_set_iov(rxaio, 1, &iov); - nng_stream_recv(p->conn, rxaio); - nni_mtx_unlock(&p->mtx); - return; - } else if (tot < p->gotrxhead) { - // rxlen contains more than one packet - memcpy(nni_msg_body(p->rxmsg), p->rxlen, tot); - p->gotrxhead -= tot; - memmove(p->rxlen, p->rxlen + tot, p->gotrxhead); - } else { - // good news, this is very small packet - // we have done receiving - memcpy(nni_msg_body(p->rxmsg), p->rxlen, tot); - p->gotrxhead = 0; - } - } else { - // we are receiving the bulk of the packet - n = nni_aio_count(rxaio); - nni_aio_bump_count(rxaio, n); - if (nni_aio_iov_advance(rxaio, n) > 0) { - // still data remaining, schedule to receive + // second recv action nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; } - // good news, the whole packet is received - } - - //// not receive enough bytes, deal with remaining length - // read_packet_length(p->rxlen, &len); - // printf("new %ld recevied %ld header %x %d len : %d", n, - // p->gotrxhead, - // p->rxlen[0], p->rxlen[1], len); - // printf("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); - - // //if (nni_aio_iov_count(rxaio) > 0) { - // printf("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], - // strlen((char *) p->rxlen)); - // nng_stream_recv(p->conn, rxaio); - // nni_mtx_unlock(&p->mtx); - // return; - //} else if (p->gotrxhead <= NNI_NANO_MAX_HEADER_SIZE && - // p->rxlen[p->gotrxhead - 1] > 0x7f) { - // // length error - // if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { - // rv = NNG_EMSGSIZE; - // goto recv_error; - // } - // // same packet, continue receving next byte of remaining length - // iov.iov_buf = &p->rxlen[p->gotrxhead]; - // iov.iov_len = 1; - // nni_aio_set_iov(rxaio, 1, &iov); - // nng_stream_recv(p->conn, rxaio); - // nni_mtx_unlock(&p->mtx); - // return; - //} - - // finish fixed header - // p->wantrxhead = len + p->gotrxhead; - // - // if (p->rxmsg == NULL) { - // // We should have gotten a message header. len -> - // remaining - // // length to define how many bytes left - // printf("pipe %p header got: %x %x %x %x %x, %ld!!\n", - // p, p->rxlen[0], p->rxlen[1], p->rxlen[2], p->rxlen[3], - // p->rxlen[4], p->wantrxhead); - // // Make sure the message payload is not too big. If it - // is - // // the caller will shut down the pipe. - // if ((len > p->rcvmax) && (p->rcvmax > 0)) { - // printf("size error\n"); - // rv = NNG_EMSGSIZE; - // goto recv_error; - // } - // - // if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) - //{ printf("mem error %ld\n", (size_t) len); - // goto recv_error; - // } - // - // // Submit the rest of the data for a read -- seperate - // Fixed - // // header with variable header and so on - // // we want to read the entire message now. - // if (len != 0) { - // iov.iov_buf = nni_msg_body(p->rxmsg); - // iov.iov_len = (size_t) len; - // - // nni_aio_set_iov(rxaio, 1, &iov); - // // second recv action - // nng_stream_recv(p->conn, rxaio); - // nni_mtx_unlock(&p->mtx); - // return; - // } - // } + } // We read a message completely. Let the user know the good news. use // as application message callback of users nni_aio_list_remove(aio); + nni_msg_header_append(p->rxmsg, p->rxlen, pos + 1); msg = p->rxmsg; p->rxmsg = NULL; n = nni_msg_len(msg); - // type = p->rxlen[0] & 0xf0; - - // fixed_header_adaptor(p->rxlen, msg); - // read_packet_length(p->rxlen, &len); - // nni_msg_header_append(msg, p->rxlen, len); - + type = p->rxlen[0] & 0xf0; // set the payload pointer of msg according to packet_type // if (type == CMD_PUBLISH) { // uint8_t qos_pac; @@ -665,12 +588,10 @@ mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *p) txaio = p->txaio; niov = 0; - // iov[0].iov_buf = p->txlen; - // iov[0].iov_len = sizeof(p->txlen); - // niov++; + if (nni_msg_header_len(msg) > 0) { iov[niov].iov_buf = nni_msg_header(msg); - iov[niov].iov_len = 1; + iov[niov].iov_len = nni_msg_header_len(msg); niov++; } if (nni_msg_len(msg) > 0) { @@ -749,10 +670,11 @@ mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *p) // Schedule a read of the header. rxaio = p->rxaio; - iov.iov_buf = p->rxlen + p->gotrxhead; - iov.iov_len = sizeof(p->rxlen) - p->gotrxhead; + p->gotrxhead = 0; + p->wantrxhead = 2; + iov.iov_buf = p->rxlen; + iov.iov_len = 2; nni_aio_set_iov(rxaio, 1, &iov); - nng_stream_recv(p->conn, rxaio); } From b345fdda0b6b78d958eae7aa6df19a0a3246a8be Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Sat, 30 Oct 2021 18:20:32 +0800 Subject: [PATCH 092/180] * MDF [mqtt/transport] move qos ack/rec/rel/comp to transport --- src/core/message.c | 18 ++++ src/core/message.h | 2 + src/sp/transport/mqtt/mqtt_tcp.c | 180 ++++++++++++++++++------------- 3 files changed, 126 insertions(+), 74 deletions(-) diff --git a/src/core/message.c b/src/core/message.c index be12cf838..54c6f7eed 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -673,3 +673,21 @@ nni_msg_get_proto_data(nng_msg *m) { return (m->m_proto_data); } + +uint8_t +nni_msg_cmd_type(nni_msg *m) +{ + return ((uint8_t)m->m_header_buf[0] & 0xF0); +} + +uint8_t +nni_msg_get_pub_qos(nni_msg *m) +{ + uint8_t qos; + + if (nni_msg_cmd_type(m) != 0x30) { + return -1; + } + qos = (m->m_header_buf[0] & 0x06) >> 1; + return qos; +} \ No newline at end of file diff --git a/src/core/message.h b/src/core/message.h index d8999dd5d..789f29ce9 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -91,4 +91,6 @@ extern void nni_msg_set_proto_data(nng_msg *, nni_proto_msg_ops *, void *); // the message is set by it alone. extern void *nni_msg_get_proto_data(nng_msg *); +extern uint8_t nni_msg_get_pub_qos(nng_msg *m); + #endif // CORE_SOCKET_H diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 8e1f4df75..2d0e46d38 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -46,9 +46,12 @@ struct mqtt_tcptran_pipe { nni_list sendq; nni_aio * txaio; nni_aio * rxaio; + nni_aio * rsaio; + nni_aio * qsaio; + nni_aio * rpaio; nni_aio * negoaio; nni_msg * rxmsg; - nni_msg * smsg; + nni_msg * smsg; nni_mtx mtx; void * conn_buf; }; @@ -88,7 +91,7 @@ static void mqtt_tcptran_pipe_recv_cb(void *); static void mqtt_tcptran_pipe_nego_cb(void *); static void mqtt_tcptran_ep_fini(void *); static void mqtt_tcptran_pipe_fini(void *); - +uint16_t nni_msg_get_pub_pid(nni_msg *m); static nni_reap_list tcptran_ep_reap_list = { .rl_offset = offsetof(mqtt_tcptran_ep, reap), @@ -110,6 +113,18 @@ mqtt_tcptran_fini(void) { } +uint16_t +nni_msg_get_pub_pid(nni_msg *m) +{ + uint16_t pid; + uint8_t *pos, len; + + pos = nni_msg_body(m); + NNI_GET16(pos, len); + NNI_GET16(pos + len + 2, pid); + return pid; +} + static void mqtt_tcptran_pipe_close(void *arg) { @@ -120,7 +135,10 @@ mqtt_tcptran_pipe_close(void *arg) nni_mtx_unlock(&p->mtx); nni_aio_close(p->rxaio); + nni_aio_close(p->rsaio); + nni_aio_close(p->qsaio); nni_aio_close(p->txaio); + nni_aio_close(p->rpaio); nni_aio_close(p->negoaio); nng_stream_close(p->conn); @@ -132,6 +150,9 @@ mqtt_tcptran_pipe_stop(void *arg) mqtt_tcptran_pipe *p = arg; nni_aio_stop(p->rxaio); + nni_aio_stop(p->rsaio); + nni_aio_stop(p->qsaio); + nni_aio_stop(p->rpaio); nni_aio_stop(p->txaio); nni_aio_stop(p->negoaio); } @@ -164,6 +185,9 @@ mqtt_tcptran_pipe_fini(void *arg) nni_aio_free(p->rxaio); nni_aio_free(p->txaio); + nni_aio_free(p->rsaio); + nni_aio_free(p->qsaio); + nni_aio_free(p->rpaio); nni_aio_free(p->negoaio); nng_stream_free(p->conn); nni_msg_free(p->rxmsg); @@ -196,6 +220,9 @@ mqtt_tcptran_pipe_alloc(mqtt_tcptran_pipe **pipep) 0) || ((rv = nni_aio_alloc(&p->rxaio, mqtt_tcptran_pipe_recv_cb, p)) != 0) || + ((rv = nni_aio_alloc(&p->rsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rpaio, NULL, p)) != 0) || ((rv = nni_aio_alloc(&p->negoaio, mqtt_tcptran_pipe_nego_cb, p)) != 0)) { mqtt_tcptran_pipe_fini(p); @@ -248,7 +275,8 @@ mqtt_tcptran_pipe_nego_cb(void *arg) } else if (p->gotrxhead < p->wantrxhead) { p->gotrxhead += nni_aio_count(aio); } - printf("mqtt_tcptran_pipe_nego_cb gotrx %ld wantrx %ld gottx %ld wanttx %ld.\n", + printf("mqtt_tcptran_pipe_nego_cb gotrx %ld wantrx %ld gottx %ld " + "wanttx %ld.\n", p->gotrxhead, p->wantrxhead, p->gottxhead, p->wanttxhead); if (p->gottxhead < p->wanttxhead) { @@ -273,25 +301,27 @@ mqtt_tcptran_pipe_nego_cb(void *arg) return; } // finish recevied fixed header - //TODO only deal with CONNACK, so just use rxlen at all time + // TODO only deal with CONNACK, so just use rxlen at all time if (p->gotrxhead == 4) { if ((p->rxlen[0] & 0x20) != 0x20) { - fprintf(stderr, "not recv connack [%x].\n", p->rxlen[0]); + fprintf( + stderr, "not recv connack [%x].\n", p->rxlen[0]); rv = NNG_EPROTO; goto error; } - int var_int; + int var_int; uint8_t pos = 0; - int rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, &var_int, &pos); + int rv = mqtt_get_remaining_length( + p->rxlen, p->gotrxhead, &var_int, &pos); p->wantrxhead = var_int + 1 + pos; if ((rv = (p->wantrxhead <= 4) ? 0 : NNG_EPROTO) != 0) { fprintf(stderr, "wantrxhead error rv[%d].\n", rv); - // TODO BUG here + // TODO BUG here goto error; } } // remaining length - // TODO CPU Waste + // TODO CPU Waste if (p->gotrxhead < p->wantrxhead) { nni_iov iov; iov.iov_len = p->wantrxhead - p->gotrxhead; @@ -384,14 +414,14 @@ mqtt_tcptran_pipe_send_cb(void *arg) static void mqtt_tcptran_pipe_recv_cb(void *arg) { - nni_aio * aio; - nni_iov iov; - uint8_t type, pos; - uint32_t len = 0, rv; - size_t n; - nni_msg * msg; + nni_aio * aio; + nni_iov iov; + uint8_t type, pos; + uint32_t len = 0, rv; + size_t n; + nni_msg * msg; mqtt_tcptran_pipe *p = arg; - nni_aio * rxaio = p->rxaio; + nni_aio * rxaio = p->rxaio; printf("tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); @@ -423,7 +453,7 @@ mqtt_tcptran_pipe_recv_cb(void *arg) return; } - //fixed header finished + // fixed header finished if (NULL == p->rxmsg) { // Make sure the message payload is not too big. If it is // the caller will shut down the pipe. @@ -460,48 +490,50 @@ mqtt_tcptran_pipe_recv_cb(void *arg) n = nni_msg_len(msg); type = p->rxlen[0] & 0xf0; // set the payload pointer of msg according to packet_type - // if (type == CMD_PUBLISH) { - // uint8_t qos_pac; - // uint16_t pid; - - // qos_pac = nni_msg_get_pub_qos(msg); - // if (qos_pac > 0) { - // nng_aio_wait(p->rsaio); - // if (qos_pac == 1) { - // p->txlen[0] = CMD_PUBACK; - // } else if (qos_pac == 2) { - // p->txlen[0] = CMD_PUBREC; - // } - // p->txlen[1] = 0x02; - // pid = nni_msg_get_pub_pid(msg); - // NNI_PUT16(p->txlen + 2, pid); - // iov.iov_len = 4; - // iov.iov_buf = &p->txlen; - // // send it down... - // nni_aio_set_iov(p->rsaio, 1, &iov); - // nng_stream_send(p->conn, p->rsaio); - // } - // } else if (type == CMD_PUBREC) { - // nng_aio_wait(p->rpaio); - // p->txlen[0] = 0X62; - // p->txlen[1] = 0x02; - // memcpy(p->txlen + 2, nni_msg_body(msg), 2); - // iov.iov_len = 4; - // iov.iov_buf = &p->txlen; - // // send it down... - // nni_aio_set_iov(p->rpaio, 1, &iov); - // nng_stream_send(p->conn, p->rpaio); - // } else if (type == CMD_PUBREL) { - // nng_aio_wait(p->qsaio); - // p->txlen[0] = CMD_PUBCOMP; - // p->txlen[1] = 0x02; - // memcpy(p->txlen + 2, nni_msg_body(msg), 2); - // iov.iov_len = 4; - // iov.iov_buf = &p->txlen; - // // send it down... - // nni_aio_set_iov(p->qsaio, 1, &iov); - // nng_stream_send(p->conn, p->qsaio); - // } + if (type == 0x30) { + uint8_t qos_pac; + uint16_t pid; + + qos_pac = nni_msg_get_pub_qos(msg); + if (qos_pac > 0) { + nng_aio_wait(p->rsaio); + if (qos_pac == 1) { + p->txlen[0] = 0X40; + } else if (qos_pac == 2) { + p->txlen[0] = 0X50; + } + p->txlen[1] = 0x02; + pid = nni_msg_get_pub_pid(msg); + NNI_PUT16(p->txlen + 2, pid); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + printf("PUBRECV\n"); + nni_aio_set_iov(p->rsaio, 1, &iov); + nng_stream_send(p->conn, p->rsaio); + } + } else if (type == 0x50) { + nng_aio_wait(p->qsaio); + p->txlen[0] = 0X62; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(msg), 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->qsaio, 1, &iov); + nng_stream_send(p->conn, p->qsaio); + } else if (type == 0x60) { + nng_aio_wait(p->rpaio); + p->txlen[0] = 0x70; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(msg), 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + printf("PUBCOMP\n"); + nni_aio_set_iov(p->rpaio, 1, &iov); + nng_stream_send(p->conn, p->rpaio); + } // keep connection & Schedule next receive // nni_pipe_bump_rx(p->npipe, n); @@ -669,11 +701,11 @@ mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *p) } // Schedule a read of the header. - rxaio = p->rxaio; - p->gotrxhead = 0; - p->wantrxhead = 2; - iov.iov_buf = p->rxlen; - iov.iov_len = 2; + rxaio = p->rxaio; + p->gotrxhead = 0; + p->wantrxhead = 2; + iov.iov_buf = p->rxlen; + iov.iov_len = 2; nni_aio_set_iov(rxaio, 1, &iov); nng_stream_recv(p->conn, rxaio); } @@ -722,10 +754,10 @@ static void mqtt_tcptran_pipe_start( mqtt_tcptran_pipe *p, nng_stream *conn, mqtt_tcptran_ep *ep) { - nni_iov iov[2]; - nni_msg * connmsg; - uint32_t buf_len; - int rv, niov = 0; + nni_iov iov[2]; + nni_msg *connmsg; + uint32_t buf_len; + int rv, niov = 0; ep->refcnt++; @@ -763,7 +795,7 @@ mqtt_tcptran_pipe_start( nni_list_append(&ep->negopipes, p); nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate - nng_stream_send(p->conn, p->negoaio); + nng_stream_send(p->conn, p->negoaio); } static void @@ -848,7 +880,7 @@ mqtt_tcptran_url_parse_source( return (0); } - len = (size_t) (semi - url->u_hostname); + len = (size_t)(semi - url->u_hostname); url->u_hostname = semi + 1; if (strcmp(surl->u_scheme, "tcp") == 0) { @@ -1210,11 +1242,11 @@ mqtt_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) mqtt_tcptran_ep *ep = arg; int rv; -// nni_mtx_lock(&ep->mtx); + // nni_mtx_lock(&ep->mtx); nni_copyout_ptr(ep->connmsg, v, szp, t); fprintf(stderr, "connmsgp [%p] v [%p] \n", ep->connmsg, v); -// ep->connmsg = NULL; -// nni_mtx_unlock(&ep->mtx); + // ep->connmsg = NULL; + // nni_mtx_unlock(&ep->mtx); rv = 0; return (rv); @@ -1337,7 +1369,7 @@ mqtt_tcptran_dialer_setopt( mqtt_tcptran_ep *ep = arg; int rv; - //TODO get mqtt dialer's option + // TODO get mqtt dialer's option rv = nni_stream_dialer_set(ep->dialer, name, buf, sz, t); if (rv == NNG_ENOTSUP) { rv = nni_setopt(mqtt_tcptran_ep_opts, name, ep, buf, sz, t); From 767f68d67702e51bef4fd532f84ac6daa2e79387 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 1 Nov 2021 10:45:57 +0800 Subject: [PATCH 093/180] Expose nng_mqtt_topic & nng_mqtt_topic_qos data structures (cherry picked from commit 56c7ad3450903101dec8a021a2ef7bd135625b32) --- demo/mqtt/mqtt_client.c | 1 + include/nng/nng.h | 32 +++++++++++---- src/mqtt/mqtt.h | 66 ++++++++---------------------- src/mqtt/mqtt_codec.c | 34 +++++++-------- src/mqtt/mqtt_test.c | 91 ++++++++++++++++++++++++----------------- 5 files changed, 112 insertions(+), 112 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index ce552dd2b..0c5167ebc 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -136,6 +136,7 @@ client_subscribe(nng_socket sock, nng_mqtt_topic_qos *subscriptions, int count, nng_msg *submsg; nng_mqtt_msg_alloc(&submsg, 0); nng_mqtt_msg_set_packet_type(submsg, NNG_MQTT_SUBSCRIBE); + nng_mqtt_msg_set_subscribe_topics(submsg, subscriptions, count); rv = nng_mqtt_msg_encode(submsg); diff --git a/include/nng/nng.h b/include/nng/nng.h index 9270ffad7..99917bb56 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1276,6 +1276,8 @@ NNG_DECL int nng_pipe_getopt_string(nng_pipe, const char *, char **); // a library; it will affect all sockets. NNG_DECL void nng_closeall(void); +#ifdef NNG_TRANSPORT_MQTT_TCP + typedef enum { NNG_MQTT_CONNECT = 0x01, NNG_MQTT_CONNACK = 0x02, @@ -1294,8 +1296,20 @@ typedef enum { NNG_MQTT_AUTH = 0x0F } nng_mqtt_packet_type; -typedef struct mqtt_buf_t nng_mqtt_buffer; -typedef struct mqtt_buf_t nng_mqtt_topic; +struct mqtt_buf_t { + uint32_t length; + uint8_t *buf; +}; + +typedef struct mqtt_buf_t mqtt_buf; +typedef struct mqtt_buf_t nng_mqtt_buffer; +typedef struct mqtt_buf_t nng_mqtt_topic; + +typedef struct mqtt_topic_qos_t { + nng_mqtt_topic topic; + uint8_t qos; +} mqtt_topic_qos; + typedef struct mqtt_topic_qos_t nng_mqtt_topic_qos; NNG_DECL int nng_mqtt_msg_alloc(nng_msg **, size_t); @@ -1346,13 +1360,13 @@ NNG_DECL void nng_mqtt_msg_set_unsubscribe_topics( nng_msg *, nng_mqtt_topic *, uint32_t); NNG_DECL nng_mqtt_topic *nng_mqtt_msg_get_unsubscribe_topics( nng_msg *, uint32_t *); -NNG_DECL nng_mqtt_topic *nng_mqtt_topic_array_create(size_t); -NNG_DECL void nng_mqtt_topic_array_set(nng_mqtt_topic *, size_t, const char *); -NNG_DECL void nng_mqtt_topic_array_free(nng_mqtt_topic *, size_t); -NNG_DECL nng_mqtt_topic_qos *nng_mqtt_topic_qos_array_create(size_t); -NNG_DECL void nng_mqtt_topic_qos_array_set( - nng_mqtt_topic_qos *, size_t, const char *, uint8_t); -NNG_DECL void nng_mqtt_topic_qos_array_free(nng_mqtt_topic_qos *, size_t); +// NNG_DECL nng_mqtt_topic *nng_mqtt_topic_array_create(size_t); +// NNG_DECL void nng_mqtt_topic_array_set(nng_mqtt_topic *, size_t, const char +// *); NNG_DECL void nng_mqtt_topic_array_free(nng_mqtt_topic *, size_t); +// NNG_DECL nng_mqtt_topic_qos *nng_mqtt_topic_qos_array_create(size_t); +// NNG_DECL void nng_mqtt_topic_qos_array_set( +// nng_mqtt_topic_qos *, size_t, const char *, uint8_t); +// NNG_DECL void nng_mqtt_topic_qos_array_free(nng_mqtt_topic_qos *, size_t); NNG_DECL void nng_mqtt_msg_dump(nng_msg *, uint8_t *, uint32_t, bool); #endif diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index 0f227cf0c..a10c475af 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -29,31 +29,12 @@ extern "C" { #define MQTT_LENGTH_CONTINUATION_BIT 0x80 #define MQTT_LENGTH_SHIFT 7 -typedef struct mqtt_msg_t nni_mqtt_proto_data; -typedef enum mqtt_packet_type_t nni_mqtt_packet_type; -typedef union mqtt_payload nni_mqtt_payload; -typedef struct mqtt_topic_qos_t nni_mqtt_topic_qos; -typedef struct mqtt_buf_t nni_mqtt_buffer; -typedef struct mqtt_buf_t nni_mqtt_topic; - -/* Packet types */ -typedef enum mqtt_packet_type_t { - MQTT_CONNECT = 0x01, - MQTT_CONNACK = 0x02, - MQTT_PUBLISH = 0x03, - MQTT_PUBACK = 0x04, - MQTT_PUBREC = 0x05, - MQTT_PUBREL = 0x06, - MQTT_PUBCOMP = 0x07, - MQTT_SUBSCRIBE = 0x08, - MQTT_SUBACK = 0x09, - MQTT_UNSUBSCRIBE = 0x0A, - MQTT_UNSUBACK = 0x0B, - MQTT_PINGREQ = 0x0C, - MQTT_PINGRESP = 0x0D, - MQTT_DISCONNECT = 0x0E, - MQTT_AUTH = 0x0F -} mqtt_packet_type; +typedef struct mqtt_msg_t nni_mqtt_proto_data; +typedef nng_mqtt_packet_type nni_mqtt_packet_type; +typedef union mqtt_payload nni_mqtt_payload; +typedef nng_mqtt_topic_qos nni_mqtt_topic_qos; +typedef nng_mqtt_buffer nni_mqtt_buffer; +typedef nng_mqtt_topic nni_mqtt_topic; /* Quality of Service types. */ #define MQTT_QOS_0_AT_MOST_ONCE 0 @@ -83,12 +64,6 @@ struct pos_buf { uint8_t *endpos; }; -/* Compact string type */ -typedef struct mqtt_buf_t { - uint32_t length; - uint8_t *buf; -} mqtt_buf; - /* CONNECT flags */ typedef struct conn_flags_t { uint8_t reserved : 1; @@ -169,11 +144,6 @@ union mqtt_variable_header { mqtt_unsuback_vhdr unsuback; }; -typedef struct mqtt_topic_qos_t { - mqtt_buf topic; - uint8_t qos; -} mqtt_topic_qos; - /***************************************************************************** * Payloads ****************************************************************************/ @@ -217,18 +187,18 @@ union mqtt_payload { }; typedef struct { - uint8_t bit_0 : 1; - uint8_t bit_1 : 1; - uint8_t bit_2 : 1; - uint8_t bit_3 : 1; - mqtt_packet_type packet_type : 4; + uint8_t bit_0 : 1; + uint8_t bit_1 : 1; + uint8_t bit_2 : 1; + uint8_t bit_3 : 1; + nni_mqtt_packet_type packet_type : 4; } mqtt_common_hdr; typedef struct { - uint8_t retain : 1; - uint8_t qos : 2; - uint8_t dup : 1; - mqtt_packet_type packet_type : 4; + uint8_t retain : 1; + uint8_t qos : 2; + uint8_t dup : 1; + nni_mqtt_packet_type packet_type : 4; } mqtt_pub_hdr; typedef struct mqtt_fixed_hdr_t { @@ -256,8 +226,8 @@ typedef struct mqtt_msg_t { } mqtt_msg; -extern int mqtt_get_remaining_length(uint8_t *packet, uint32_t len, - uint32_t *remainning_length, uint8_t *used_bytes); +extern int mqtt_get_remaining_length( + uint8_t *, uint32_t, uint32_t *, uint8_t *); extern int byte_number_for_variable_length(uint32_t); extern int write_variable_length_value(uint32_t, struct pos_buf *); extern int write_byte(uint8_t, struct pos_buf *); @@ -273,7 +243,7 @@ extern int read_packet_length(struct pos_buf *, uint32_t *); extern mqtt_buf mqtt_buf_dup(const mqtt_buf *); extern void mqtt_buf_free(mqtt_buf *); -extern mqtt_msg *mqtt_msg_create(mqtt_packet_type); +extern mqtt_msg *mqtt_msg_create(nni_mqtt_packet_type); extern int mqtt_msg_dump(mqtt_msg *, mqtt_buf *, mqtt_buf *, bool); diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index df394c907..fd3c6750a 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -1188,7 +1188,7 @@ mqtt_msg_create_empty(void) } mqtt_msg * -mqtt_msg_create(mqtt_packet_type packet_type) +mqtt_msg_create(nni_mqtt_packet_type packet_type) { mqtt_msg *msg = mqtt_msg_create_empty(); msg->fixed_header.common.packet_type = packet_type; @@ -1205,7 +1205,7 @@ mqtt_msg_destroy(mqtt_msg *self) } const char * -get_packet_type_str(mqtt_packet_type packtype) +get_packet_type_str(nni_mqtt_packet_type packtype) { static const char *packTypeNames[16] = { "Forbidden-0", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", @@ -1242,7 +1242,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) /* Print variable header part */ switch (msg->fixed_header.common.packet_type) { - case MQTT_CONNECT: { + case NNG_MQTT_CONNECT: { ret = sprintf((char *) &buf->buf[pos], "protocol name : %.*s\n" "protocol version : %d\n" @@ -1317,7 +1317,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) pos += ret; } break; - case MQTT_CONNACK: + case NNG_MQTT_CONNACK: ret = sprintf((char *) &buf->buf[pos], "connack flags : %d\n" "connack return-code: %d\n", @@ -1329,7 +1329,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) pos += ret; break; - case MQTT_PUBLISH: { + case NNG_MQTT_PUBLISH: { ret = sprintf((char *) &buf->buf[pos], "publis flags:\n" @@ -1358,7 +1358,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) pos += ret; } break; - case MQTT_PUBACK: + case NNG_MQTT_PUBACK: ret = sprintf((char *) &buf->buf[pos], "packet-id: %d\n", msg->var_header.puback.packet_id); if ((ret < 0) || ((pos + ret) > buf->length)) { @@ -1367,7 +1367,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) pos += ret; break; - case MQTT_PUBREC: + case NNG_MQTT_PUBREC: ret = sprintf((char *) &buf->buf[pos], "packet-id: %d\n", msg->var_header.pubrec.packet_id); if ((ret < 0) || ((pos + ret) > buf->length)) { @@ -1376,7 +1376,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) pos += ret; break; - case MQTT_PUBREL: + case NNG_MQTT_PUBREL: ret = sprintf((char *) &buf->buf[pos], "packet-id: %d\n", msg->var_header.pubrel.packet_id); if ((ret < 0) || ((pos + ret) > buf->length)) { @@ -1385,7 +1385,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) pos += ret; break; - case MQTT_PUBCOMP: + case NNG_MQTT_PUBCOMP: ret = sprintf((char *) &buf->buf[pos], "packet-id: %d\n", msg->var_header.pubcomp.packet_id); if ((ret < 0) || ((pos + ret) > buf->length)) { @@ -1394,7 +1394,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) pos += ret; break; - case MQTT_SUBSCRIBE: { + case NNG_MQTT_SUBSCRIBE: { ret = sprintf((char *) &buf->buf[pos], "packet-id : %d\n", msg->var_header.subscribe.packet_id); @@ -1418,7 +1418,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) } } break; - case MQTT_SUBACK: { + case NNG_MQTT_SUBACK: { ret = sprintf((char *) &buf->buf[pos], "packet-id : %d\n", msg->var_header.suback.packet_id); @@ -1438,7 +1438,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) } } break; - case MQTT_UNSUBSCRIBE: { + case NNG_MQTT_UNSUBSCRIBE: { ret = sprintf((char *) &buf->buf[pos], "packet-id : %d\n", msg->var_header.unsubscribe.packet_id); @@ -1459,7 +1459,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) } } break; - case MQTT_UNSUBACK: + case NNG_MQTT_UNSUBACK: ret = sprintf((char *) &buf->buf[pos], "packet-id : %d\n", msg->var_header.unsuback.packet_id); @@ -1469,14 +1469,14 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) pos += ret; break; - case MQTT_PINGREQ: - case MQTT_PINGRESP: + case NNG_MQTT_PINGREQ: + case NNG_MQTT_PINGRESP: break; - case MQTT_DISCONNECT: + case NNG_MQTT_DISCONNECT: break; - case MQTT_AUTH: + case NNG_MQTT_AUTH: break; } diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 60a3c7277..725fd508c 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -23,26 +23,28 @@ test_dup(void) nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); - size_t sz = 2; - nng_mqtt_topic_qos *topic_qos = nng_mqtt_topic_qos_array_create(sz); - nng_mqtt_topic_qos_array_set(topic_qos, 0, "/nanomq/mqtt/msg/0", 1); - nng_mqtt_topic_qos_array_set(topic_qos, 1, "/nanomq/mqtt/msg/1", 1); - - nng_mqtt_msg_set_subscribe_topics(msg, topic_qos, sz); + nng_mqtt_topic_qos topic_qos[] = { + { .qos = 0, + .topic = { .buf = (uint8_t *) "/nanomq/mqtt/msg/0", + .length = strlen("/nanomq/mqtt/msg/0") } }, + { .qos = 1, + .topic = { .buf = (uint8_t *) "/nanomq/mqtt/msg/1", + .length = strlen("/nanomq/mqtt/msg/1") } } + }; + nng_mqtt_msg_set_subscribe_topics( + msg, topic_qos, sizeof(topic_qos) / sizeof(nng_mqtt_topic_qos)); NUTS_PASS(nng_mqtt_msg_encode(msg)); nng_msg *msg2; NUTS_PASS(nng_msg_dup(&msg2, msg)); - // uint8_t print_buf[1024] = { 0 }; - // nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("msg: \n%s\n", print_buf); - - // nng_mqtt_msg_dump(msg2, print_buf, 1024, true); - // printf("msg2: \n%s\n", print_buf); + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("msg: \n%s\n", print_buf); - nng_mqtt_topic_qos_array_free(topic_qos, sz); + nng_mqtt_msg_dump(msg2, print_buf, 1024, true); + printf("msg2: \n%s\n", print_buf); nng_msg_free(msg); nng_msg_free(msg2); @@ -66,10 +68,15 @@ test_encode_connect(void) uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); + printf("%s\n", print_buf); nng_msg_free(msg); } +void test_encode_publish(void) +{ + +} + void test_encode_subscribe(void) { @@ -80,20 +87,24 @@ test_encode_subscribe(void) nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); - size_t sz = 2; - nng_mqtt_topic_qos *topic_qos = nng_mqtt_topic_qos_array_create(sz); - nng_mqtt_topic_qos_array_set(topic_qos, 0, "/nanomq/mqtt/msg/0", 1); - nng_mqtt_topic_qos_array_set(topic_qos, 1, "/nanomq/mqtt/msg/1", 1); + nng_mqtt_topic_qos topic_qos[] = { + { .qos = 0, + .topic = { .buf = (uint8_t *) "/nanomq/mqtt/msg/0", + .length = strlen("/nanomq/mqtt/msg/0") } }, + { .qos = 1, + .topic = { .buf = (uint8_t *) "/nanomq/mqtt/msg/1", + .length = strlen("/nanomq/mqtt/msg/1") } } + }; - nng_mqtt_msg_set_subscribe_topics(msg, topic_qos, sz); + nng_mqtt_msg_set_subscribe_topics( + msg, topic_qos, sizeof(topic_qos) / sizeof(nng_mqtt_topic_qos)); NUTS_PASS(nng_mqtt_msg_encode(msg)); uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); - nng_mqtt_topic_qos_array_free(topic_qos, sz); - // printf("%s\n", print_buf); + printf("%s\n", print_buf); nng_msg_free(msg); } @@ -107,19 +118,21 @@ test_encode_unsubscribe(void) nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); - size_t sz = 2; - nng_mqtt_topic *topic_qos = nng_mqtt_topic_array_create(sz); - nng_mqtt_topic_array_set(topic_qos, 0, "/nanomq/mqtt/1"); - nng_mqtt_topic_array_set(topic_qos, 1, "/nanomq/mqtt/2"); + nng_mqtt_topic topic_qos[] = { + { .buf = (uint8_t *) "/nanomq/mqtt/1", + .length = strlen("/nanomq/mqtt/1") }, + { .buf = (uint8_t *) "/nanomq/mqtt/2", + .length = strlen("/nanomq/mqtt/2") }, + }; - nng_mqtt_msg_set_unsubscribe_topics(msg, topic_qos, sz); + nng_mqtt_msg_set_unsubscribe_topics( + msg, topic_qos, sizeof(topic_qos) / sizeof(nng_mqtt_topic)); NUTS_PASS(nng_mqtt_msg_encode(msg)); uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); - nng_mqtt_topic_array_free(topic_qos, sz); - // printf("%s\n", print_buf); + printf("%s\n", print_buf); nng_msg_free(msg); } @@ -136,7 +149,7 @@ test_encode_disconnect(void) uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); + printf("%s\n", print_buf); nng_msg_free(msg); } @@ -166,9 +179,9 @@ test_decode_connect(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - // uint8_t print_buf[1024] = { 0 }; - // nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); nng_msg_free(msg); } @@ -231,9 +244,9 @@ test_decode_publish(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - // uint8_t print_buf[2048] = { 0 }; - // nng_mqtt_msg_dump(msg, print_buf, 2048, true); - // printf("%s\n", print_buf); + uint8_t print_buf[2048] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 2048, true); + printf("%s\n", print_buf); nng_msg_free(msg); } @@ -251,13 +264,15 @@ test_decode_disconnect(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - // uint8_t print_buf[1024] = { 0 }; - // nng_mqtt_msg_dump(msg, print_buf, 1024, true); - // printf("%s\n", print_buf); + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); nng_msg_free(msg); } TEST_LIST = { + { "alloc message", test_alloc }, + { "dup message", test_dup }, { "encode connect", test_encode_connect }, { "encode disconnect", test_encode_disconnect }, { "encode subscribe", test_encode_subscribe }, From cd28587d39d38edada0cb945de5dedd90a09b705 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 1 Nov 2021 16:30:14 +0800 Subject: [PATCH 094/180] Add publish encode test & Resolve conflicts --- demo/mqtt/mqtt_client.c | 12 +++++---- include/nng/nng.h | 2 -- src/mqtt/mqtt_codec.c | 8 ++++-- src/mqtt/mqtt_test.c | 41 ++++++++++++++++++++++++++++-- src/sp/protocol/mqtt/mqtt_client.c | 32 +++++++++++------------ src/sp/transport/mqtt/mqtt_tcp.c | 2 +- 6 files changed, 69 insertions(+), 28 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index 0c5167ebc..5a28d2547 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -120,7 +120,7 @@ client_connect(nng_socket *sock, const char *url, bool verbose) // TODO Connmsg would be free when client disconnected // nng_msg_free(connmsg); - nni_mqtt_msg_proto_data_free(connmsg); + nng_mqtt_msg_proto_data_free(connmsg); return (0); } @@ -261,11 +261,13 @@ main(const int argc, const char **argv) const char *data = argv[5]; rv = client_publish(sock, topic, data, qos, verbose); } else if (SUBSCRIBE == cmd) { - nng_mqtt_topic_qos *subscriptions = - nng_mqtt_topic_qos_array_create(1); - nng_mqtt_topic_qos_array_set(subscriptions, 0, topic, qos); + nng_mqtt_topic_qos subscriptions[] = { + { .qos = qos, + .topic = { .buf = (uint8_t *) topic, + .length = strlen(topic) } }, + }; + rv = client_subscribe(sock, subscriptions, 1, verbose); - nng_mqtt_topic_qos_array_free(subscriptions, 1); } nng_msleep(1000); diff --git a/include/nng/nng.h b/include/nng/nng.h index 99917bb56..2fff0bf7d 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1276,8 +1276,6 @@ NNG_DECL int nng_pipe_getopt_string(nng_pipe, const char *, char **); // a library; it will affect all sockets. NNG_DECL void nng_closeall(void); -#ifdef NNG_TRANSPORT_MQTT_TCP - typedef enum { NNG_MQTT_CONNECT = 0x01, NNG_MQTT_CONNACK = 0x02, diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index fd3c6750a..96b6d666f 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -150,7 +150,7 @@ nni_mqtt_msg_encode_fixed_header(nni_msg *msg, nni_mqtt_proto_data *data) int len = write_variable_length_value( data->fixed_header.remaining_length, &buf); - + data->used_bytes = len; nni_msg_header_append(msg, rlen, len); } @@ -165,9 +165,13 @@ nni_mqtt_msg_encode_connect(nni_msg *msg) int poslength = 6; mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; - var_header->protocol_name.buf = name; + var_header->protocol_name.buf = (uint8_t *) name; var_header->protocol_name.length = 4; + if (var_header->protocol_version == 0) { + var_header->protocol_version = 4; + } + /* length of protocol-name (consider "MQTT" by default */ poslength += (var_header->protocol_name.length == 0) ? 4 diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 725fd508c..9bea22dba 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -64,6 +64,20 @@ test_encode_connect(void) NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), "nanomq-mqtt") == 0); + char will_topic[] = "/nanomq/will_msg"; + nng_mqtt_msg_set_connect_will_topic(msg, will_topic); + + char will_msg[] = "Bye-bye"; + nng_mqtt_msg_set_connect_will_msg(msg, will_msg); + + char user[] = "alvin"; + char passwd[] = "HHH0000"; + + nng_mqtt_msg_set_connect_user_name(msg, user); + nng_mqtt_msg_set_connect_password(msg, passwd); + + nng_mqtt_msg_set_connect_keep_alive(msg, 60); + NUTS_PASS(nng_mqtt_msg_encode(msg)); uint8_t print_buf[1024] = { 0 }; @@ -72,9 +86,31 @@ test_encode_connect(void) nng_msg_free(msg); } -void test_encode_publish(void) +void +test_encode_publish(void) { - + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBLISH); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBLISH); + + nng_mqtt_msg_set_publish_qos(msg, 2); + + char *topic = "/nanomq/msg/18234"; + nng_mqtt_msg_set_publish_topic(msg, topic); + + char *payload = "hello"; + nng_mqtt_msg_set_publish_payload( + msg, (uint8_t *) payload, strlen(payload)); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); + nng_msg_free(msg); } void @@ -274,6 +310,7 @@ TEST_LIST = { { "alloc message", test_alloc }, { "dup message", test_dup }, { "encode connect", test_encode_connect }, + { "encode publish", test_encode_publish }, { "encode disconnect", test_encode_disconnect }, { "encode subscribe", test_encode_subscribe }, { "encode unsubscribe", test_encode_unsubscribe }, diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 0409710c7..baaa0273d 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -535,28 +535,28 @@ mqtt_recv_cb(void *arg) // state transitions switch (packet_type) { - case MQTT_CONNACK: + case NNG_MQTT_CONNACK: // FIXME // we have received the CONNACK nni_mtx_unlock(&s->mtx); return; - case MQTT_PUBACK: + case NNG_MQTT_PUBACK: // we have received a PUBACK, successful delivery of a QoS 1 // fall through - case MQTT_PUBCOMP: + case NNG_MQTT_PUBCOMP: // we have received a PUBCOMP, successful delivery of a QoS 2 // fall through - case MQTT_SUBACK: + case NNG_MQTT_SUBACK: // we have received a SUBACK, successful subcription // fall through - case MQTT_UNSUBACK: + case NNG_MQTT_UNSUBACK: // we have received a UNSUBACK, successful unsubcription // FIXME: check packet type match packet_id = nni_mqtt_msg_get_unsuback_packet_id(msg); @@ -572,7 +572,7 @@ mqtt_recv_cb(void *arg) work->state = WORK_END; break; - case MQTT_PUBREC: + case NNG_MQTT_PUBREC: // we have received a PUBRECV in the QoS 2 delivery, // then send a PUBREL packet_id = nni_mqtt_msg_get_pubrec_packet_id(msg); @@ -585,14 +585,14 @@ mqtt_recv_cb(void *arg) } work->state = WORK_PUBREL; // reuse msg - nni_mqtt_msg_set_packet_type(msg, MQTT_PUBREL); + nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBREL); nni_mqtt_msg_set_pubrel_packet_id(msg, packet_id); nni_mqtt_msg_encode(msg); nni_aio_set_msg(&work->send_aio, msg); nni_pipe_send(p->pipe, &work->send_aio); break; - case MQTT_PUBREL: + case NNG_MQTT_PUBREL: // we have received a PUBREL, then send a PUBCOMP packet_id = nni_mqtt_msg_get_pubrel_packet_id(msg); work = nni_id_get(&p->recv_unack, packet_id); @@ -604,14 +604,14 @@ mqtt_recv_cb(void *arg) } work->state = WORK_PUBCOMP; // reuse msg - nni_mqtt_msg_set_packet_type(msg, MQTT_PUBCOMP); + nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBCOMP); nni_mqtt_msg_set_pubcomp_packet_id(msg, packet_id); nni_mqtt_msg_encode(msg); nni_aio_set_msg(&work->send_aio, msg); nni_pipe_send(p->pipe, &work->send_aio); break; - case MQTT_PUBLISH: + case NNG_MQTT_PUBLISH: // we have received a PUBLISH qos = nni_mqtt_msg_get_publish_qos(msg); if (0 == qos) { @@ -633,13 +633,13 @@ mqtt_recv_cb(void *arg) if (1 == qos) { // QoS 1, then send a PUBACK work->state = WORK_PUBACK; - nni_mqtt_msg_set_packet_type(msg, MQTT_PUBACK); + nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBACK); nni_mqtt_msg_set_puback_packet_id( msg, work->packet_id); } else { // QoS 2, then send a PUBRECV work->state = WORK_PUBRECV; - nni_mqtt_msg_set_packet_type(msg, MQTT_PUBREC); + nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBREC); nni_mqtt_msg_set_pubrec_packet_id( msg, work->packet_id); } @@ -764,23 +764,23 @@ mqtt_run_send_queue(mqtt_sock_t *s) // only allow to send PUBLISH, SUBSCRIBE and UNSUBSCRIBE packet switch (packet_type) { - case MQTT_CONNECT: + case NNG_MQTT_CONNECT: work->state = WORK_CONNECT; break; - case MQTT_PUBLISH: + case NNG_MQTT_PUBLISH: work->state = WORK_PUBLISH; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_publish_packet_id( msg, work->packet_id); work->qos = nni_mqtt_msg_get_publish_qos(msg); break; - case MQTT_SUBSCRIBE: + case NNG_MQTT_SUBSCRIBE: work->state = WORK_SUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_subscribe_packet_id( msg, work->packet_id); break; - case MQTT_UNSUBSCRIBE: + case NNG_MQTT_UNSUBSCRIBE: work->state = WORK_UNSUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_unsubscribe_packet_id( diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 2d0e46d38..4165283c8 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -312,7 +312,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) int var_int; uint8_t pos = 0; int rv = mqtt_get_remaining_length( - p->rxlen, p->gotrxhead, &var_int, &pos); + p->rxlen, p->gotrxhead, (uint32_t *) &var_int, &pos); p->wantrxhead = var_int + 1 + pos; if ((rv = (p->wantrxhead <= 4) ? 0 : NNG_EPROTO) != 0) { fprintf(stderr, "wantrxhead error rv[%d].\n", rv); From 8885d2d4adfbea0035090b46f20c750056758795 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 1 Nov 2021 16:32:33 +0800 Subject: [PATCH 095/180] Add default client id & New unit tests --- include/nng/nng.h | 9 +-- src/mqtt/mqtt_codec.c | 19 +++-- src/mqtt/mqtt_test.c | 166 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 177 insertions(+), 17 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index 2fff0bf7d..a58a60b9e 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1311,6 +1311,8 @@ typedef struct mqtt_topic_qos_t { typedef struct mqtt_topic_qos_t nng_mqtt_topic_qos; NNG_DECL int nng_mqtt_msg_alloc(nng_msg **, size_t); +NNG_DECL int nng_mqtt_msg_proto_data_alloc(nng_msg *); +NNG_DECL void nng_mqtt_msg_proto_data_free(nng_msg *); NNG_DECL int nng_mqtt_msg_encode(nng_msg *); NNG_DECL int nng_mqtt_msg_decode(nng_msg *); NNG_DECL void nng_mqtt_msg_set_packet_type(nng_msg *, nng_mqtt_packet_type); @@ -1358,13 +1360,6 @@ NNG_DECL void nng_mqtt_msg_set_unsubscribe_topics( nng_msg *, nng_mqtt_topic *, uint32_t); NNG_DECL nng_mqtt_topic *nng_mqtt_msg_get_unsubscribe_topics( nng_msg *, uint32_t *); -// NNG_DECL nng_mqtt_topic *nng_mqtt_topic_array_create(size_t); -// NNG_DECL void nng_mqtt_topic_array_set(nng_mqtt_topic *, size_t, const char -// *); NNG_DECL void nng_mqtt_topic_array_free(nng_mqtt_topic *, size_t); -// NNG_DECL nng_mqtt_topic_qos *nng_mqtt_topic_qos_array_create(size_t); -// NNG_DECL void nng_mqtt_topic_qos_array_set( -// nng_mqtt_topic_qos *, size_t, const char *, uint8_t); -// NNG_DECL void nng_mqtt_topic_qos_array_free(nng_mqtt_topic_qos *, size_t); NNG_DECL void nng_mqtt_msg_dump(nng_msg *, uint8_t *, uint32_t, bool); #endif diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index 96b6d666f..b2e79efa0 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -157,8 +157,9 @@ nni_mqtt_msg_encode_fixed_header(nni_msg *msg, nni_mqtt_proto_data *data) static int nni_mqtt_msg_encode_connect(nni_msg *msg) { - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - char name[4] = "MQTT"; + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + char name[4] = "MQTT"; + char client_id[20] = { 0 }; nni_msg_clear(msg); @@ -172,6 +173,12 @@ nni_mqtt_msg_encode_connect(nni_msg *msg) var_header->protocol_version = 4; } + if (mqtt->payload.connect.client_id.length == 0) { + snprintf(client_id, 20, "nanomq-%04x", nni_random()); + mqtt->payload.connect.client_id.buf = (uint8_t *) client_id; + mqtt->payload.connect.client_id.length = strlen(client_id); + } + /* length of protocol-name (consider "MQTT" by default */ poslength += (var_header->protocol_name.length == 0) ? 4 @@ -502,11 +509,11 @@ nni_mqtt_msg_encode_unsubscribe(nni_msg *msg) mqtt->fixed_header.common.bit_1 = 1; nni_mqtt_msg_encode_fixed_header(msg, mqtt); - mqtt_subscribe_vhdr *var_header = &mqtt->var_header.subscribe; + mqtt_unsubscribe_vhdr *var_header = &mqtt->var_header.unsubscribe; /* Packet Id */ nni_mqtt_msg_append_u16(msg, var_header->packet_id); - /* Subscribe topic_arr */ + /* Unsubscribe topic_arr */ for (size_t i = 0; i < uspld->topic_count; i++) { mqtt_buf *topic = &uspld->topic_arr[i]; nni_mqtt_msg_append_byte_str(msg, topic); @@ -921,7 +928,7 @@ nni_mqtt_msg_decode_unsubscribe(nni_msg *msg) /* Topic Name */ ret = read_utf8_str(&buf, &uspld->topic_arr[uspld->topic_count]); - if (ret != 0) { + if (ret != MQTT_SUCCESS) { ret = MQTT_ERR_PROTOCOL; goto ERROR; } @@ -1280,7 +1287,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) } pos += ret; ret = sprintf((char *) &buf->buf[pos], - "client identifier : %.*s\n", + "client id : %.*s\n", msg->payload.connect.client_id.length, msg->payload.connect.client_id.buf); if ((ret < 0) || ((pos + ret) > buf->length)) { diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 9bea22dba..182912a23 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -60,9 +60,9 @@ test_encode_connect(void) nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); - nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); - NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), - "nanomq-mqtt") == 0); + // nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); + // NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), + // "nanomq-mqtt") == 0); char will_topic[] = "/nanomq/will_msg"; nng_mqtt_msg_set_connect_will_topic(msg, will_topic); @@ -75,11 +75,42 @@ test_encode_connect(void) nng_mqtt_msg_set_connect_user_name(msg, user); nng_mqtt_msg_set_connect_password(msg, passwd); - + nng_mqtt_msg_set_connect_clean_session(msg, true); nng_mqtt_msg_set_connect_keep_alive(msg, 60); NUTS_PASS(nng_mqtt_msg_encode(msg)); + nng_msg *dup_msg; + nng_msg_dup(&dup_msg, msg); + NUTS_PASS(nng_mqtt_msg_decode(dup_msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("msg:\n%s\n", print_buf); + + nng_mqtt_msg_dump(dup_msg, print_buf, 1024, true); + printf("dup msg:\n%s\n", print_buf); + + nng_msg_free(msg); + nng_msg_free(dup_msg); +} + +void +test_encode_connack(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNACK); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNACK); + + nng_mqtt_msg_set_conack_flags(msg, 1); + + nng_mqtt_msg_set_conack_return_code(msg, 0); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + uint8_t print_buf[1024] = { 0 }; nng_mqtt_msg_dump(msg, print_buf, 1024, true); printf("%s\n", print_buf); @@ -97,6 +128,7 @@ test_encode_publish(void) NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBLISH); nng_mqtt_msg_set_publish_qos(msg, 2); + nng_mqtt_msg_set_publish_retain(msg, true); char *topic = "/nanomq/msg/18234"; nng_mqtt_msg_set_publish_topic(msg, topic); @@ -113,6 +145,24 @@ test_encode_publish(void) nng_msg_free(msg); } +void +test_encode_puback(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBACK); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBACK); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); + nng_msg_free(msg); +} + void test_encode_subscribe(void) { @@ -144,6 +194,29 @@ test_encode_subscribe(void) nng_msg_free(msg); } +void +test_encode_suback(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBACK); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBACK); + + uint8_t ret_codes[] = { 0, 1, 2, 3 }; + + nng_mqtt_msg_set_suback_return_codes( + msg, ret_codes, sizeof(ret_codes) / sizeof(uint8_t)); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); + nng_msg_free(msg); +} + void test_encode_unsubscribe(void) { @@ -287,6 +360,85 @@ test_decode_publish(void) nng_msg_free(msg); } +void +test_decode_puback(void) +{ + nng_msg *msg; + + uint8_t puback[] = { 0x40, 0x02, 0x01, 0x20 }; + size_t sz = sizeof(puback) / sizeof(uint8_t); + nng_mqtt_msg_alloc(&msg, 0); + + nng_msg_header_append(msg, puback, sz - 2); + + nng_msg_append(msg, puback + 2, sz - 2); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); + nng_msg_free(msg); +} + +void +test_decode_subscribe(void) +{ + nng_msg *msg; + + uint8_t subscribe[] = { 0x82, 0x2c, 0x02, 0x10, 0x00, 0x12, 0x2f, 0x6e, + 0x61, 0x6e, 0x6f, 0x6d, 0x71, 0x2f, 0x6d, 0x71, 0x74, 0x74, + 0x2f, 0x6d, 0x73, 0x67, 0x2f, 0x30, 0x00, 0x00, 0x12, 0x2f, + 0x6e, 0x61, 0x6e, 0x6f, 0x6d, 0x71, 0x2f, 0x6d, 0x71, 0x74, + 0x74, 0x2f, 0x6d, 0x73, 0x67, 0x2f, 0x31, 0x01 }; + + size_t sz = sizeof(subscribe) / sizeof(uint8_t); + nng_mqtt_msg_alloc(&msg, 0); + + nng_msg_header_append(msg, subscribe, sz - 2); + + nng_msg_append(msg, subscribe + 2, sz - 2); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); + + uint32_t count; + nng_mqtt_topic_qos *tq = + nng_mqtt_msg_get_subscribe_topics(msg, &count); + + nng_free(tq, count); + + nng_msg_free(msg); +} + +void +test_decode_unsubscribe(void) +{ + nng_msg *msg; + + uint8_t unsubscribe[] = { 0xa2, 0x22, 0x01, 0x10, 0x00, 0x0e, 0x2f, + 0x6e, 0x61, 0x6e, 0x6f, 0x6d, 0x71, 0x2f, 0x6d, 0x71, 0x74, + 0x74, 0x2f, 0x31, 0x00, 0x0e, 0x2f, 0x6e, 0x61, 0x6e, 0x6f, + 0x6d, 0x71, 0x2f, 0x6d, 0x71, 0x74, 0x74, 0x2f, 0x32 }; + + size_t sz = sizeof(unsubscribe) / sizeof(uint8_t); + nng_mqtt_msg_alloc(&msg, 0); + + nng_msg_header_append(msg, unsubscribe, sz - 2); + nng_msg_append(msg, unsubscribe + 2, sz - 2); + + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); + + nng_msg_free(msg); +} + void test_decode_disconnect(void) { @@ -310,12 +462,18 @@ TEST_LIST = { { "alloc message", test_alloc }, { "dup message", test_dup }, { "encode connect", test_encode_connect }, + { "encode conack", test_encode_connack }, { "encode publish", test_encode_publish }, + { "encode puback", test_encode_puback }, { "encode disconnect", test_encode_disconnect }, { "encode subscribe", test_encode_subscribe }, + { "encode suback", test_encode_suback }, { "encode unsubscribe", test_encode_unsubscribe }, { "decode connect", test_decode_connect }, + { "decode subscribe", test_decode_subscribe }, + { "decode unsubscribe", test_decode_unsubscribe }, { "decode disconnect", test_decode_disconnect }, { "decode publish", test_decode_publish }, + { "decode puback", test_decode_puback }, { NULL, NULL }, }; From 3a5078b9657ad431f5c08b1754e7369079764503 Mon Sep 17 00:00:00 2001 From: eeff Date: Sun, 31 Oct 2021 13:58:08 +0800 Subject: [PATCH 096/180] Fix mqtt protocol according to mqtt transport 1. When receiving PUBLISH, PUBACK, PUBRECV and PUBCOMP was sent by the transport. 2. When sending PUBLISH, PUBREL was sent by the transport. --- src/sp/protocol/mqtt/mqtt_client.c | 74 ++++++++++++++++-------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index baaa0273d..28e4921bb 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -578,18 +578,21 @@ mqtt_recv_cb(void *arg) packet_id = nni_mqtt_msg_get_pubrec_packet_id(msg); work = nni_id_get(&p->send_unack, packet_id); if (NULL == work) { + // ignore this message nni_msg_free(msg); nni_mtx_unlock(&s->mtx); - nni_pipe_close(p->pipe); return; } - work->state = WORK_PUBREL; + // the transport handled sending the PUBREL for us + // work->state = WORK_PUBREL; // reuse msg - nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBREL); - nni_mqtt_msg_set_pubrel_packet_id(msg, packet_id); - nni_mqtt_msg_encode(msg); - nni_aio_set_msg(&work->send_aio, msg); - nni_pipe_send(p->pipe, &work->send_aio); + // nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBREL); + // nni_mqtt_msg_set_pubrel_packet_id(msg, packet_id); + // nni_mqtt_msg_encode(msg); + // nni_aio_set_msg(&work->send_aio, msg); + // nni_pipe_send(p->pipe, &work->send_aio); + nni_id_remove(&p->send_unack, packet_id); + work->state = WORK_PUBCOMP; break; case NNG_MQTT_PUBREL: @@ -597,25 +600,36 @@ mqtt_recv_cb(void *arg) packet_id = nni_mqtt_msg_get_pubrel_packet_id(msg); work = nni_id_get(&p->recv_unack, packet_id); if (NULL == work) { + // ignore this message nni_msg_free(msg); nni_mtx_unlock(&s->mtx); - nni_pipe_close(p->pipe); return; } - work->state = WORK_PUBCOMP; + // the transport handled sending the PUBCOMP for us + work->state = WORK_END; + nni_id_remove(&p->recv_unack, work->packet_id); + nni_lmq_putq(&p->recv_messages, work->msg); + mqtt_run_recv_queue(s); + work->msg = msg; + work_reset(work); + nni_list_append(&s->free_list, work); + nni_mtx_unlock(&s->mtx); + return; + // work->state = WORK_PUBCOMP; // reuse msg - nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBCOMP); - nni_mqtt_msg_set_pubcomp_packet_id(msg, packet_id); - nni_mqtt_msg_encode(msg); - nni_aio_set_msg(&work->send_aio, msg); - nni_pipe_send(p->pipe, &work->send_aio); + // nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBCOMP); + // nni_mqtt_msg_set_pubcomp_packet_id(msg, packet_id); + // nni_mqtt_msg_encode(msg); + // nni_aio_set_msg(&work->send_aio, msg); + // nni_pipe_send(p->pipe, &work->send_aio); break; case NNG_MQTT_PUBLISH: // we have received a PUBLISH qos = nni_mqtt_msg_get_publish_qos(msg); - if (0 == qos) { + if (2 > qos) { // QoS 0, successful receipt + // QoS 1, the transport handled sending a PUBACK nni_lmq_putq(&p->recv_messages, msg); mqtt_run_recv_queue(s); nni_mtx_unlock(&s->mtx); @@ -628,26 +642,18 @@ mqtt_recv_cb(void *arg) work->msg = msg; work->packet_id = nni_mqtt_msg_get_publish_packet_id(msg); - nni_mqtt_msg_alloc(&msg, 0); - - if (1 == qos) { - // QoS 1, then send a PUBACK - work->state = WORK_PUBACK; - nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBACK); - nni_mqtt_msg_set_puback_packet_id( - msg, work->packet_id); - } else { - // QoS 2, then send a PUBRECV - work->state = WORK_PUBRECV; - nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBREC); - nni_mqtt_msg_set_pubrec_packet_id( - msg, work->packet_id); - } - - nni_mqtt_msg_encode(msg); - nni_aio_set_msg(&work->send_aio, msg); + // the transport handled sending PUBACK/PUBRECV + work->state = WORK_PUBREL; nni_id_set(&p->recv_unack, work->packet_id, work); - nni_pipe_send(p->pipe, &work->send_aio); + // nni_mqtt_msg_alloc(&msg, 0); + // QoS 2, then send a PUBRECV + // work->state = WORK_PUBRECV; + // nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBREC); + // nni_mqtt_msg_set_pubrec_packet_id(msg, + // work->packet_id); + // nni_mqtt_msg_encode(msg); + // nni_aio_set_msg(&work->send_aio, msg); + // nni_pipe_send(p->pipe, &work->send_aio); } break; From f57acd6aca0e27f38e5f403206393cf7cf6c40c6 Mon Sep 17 00:00:00 2001 From: eeff Date: Sun, 31 Oct 2021 16:45:04 +0800 Subject: [PATCH 097/180] Fix mqtt protocol wrong sock mutex unlocking --- src/sp/protocol/mqtt/mqtt_client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 28e4921bb..1ee8d1380 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -794,7 +794,6 @@ mqtt_run_send_queue(mqtt_sock_t *s) break; default: work->state = WORK_ERROR; - nni_mtx_unlock(&s->mtx); nni_aio_finish_error(work->user_aio, NNG_EPROTO); return; } From b3daeda7aa5022b1f8462b37529ee541b40e37fc Mon Sep 17 00:00:00 2001 From: eeff Date: Sun, 31 Oct 2021 17:47:16 +0800 Subject: [PATCH 098/180] Add nni_mqtt_msg_get_packet_id and nni_mqtt_msg_set_packet_id --- src/mqtt/mqtt.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ src/mqtt/mqtt.h | 5 +++++ 2 files changed, 62 insertions(+) diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index 7f3caec82..fc7d203fa 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -87,6 +87,63 @@ nni_mqtt_msg_get_packet_type(nni_msg *msg) return proto_data->fixed_header.common.packet_type; } +void +nni_mqtt_msg_set_packet_id(nni_msg *msg, uint16_t packet_id) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + switch (proto_data->fixed_header.common.packet_type) { + case NNG_MQTT_PUBACK: + proto_data->var_header.puback.packet_id = packet_id; + break; + case NNG_MQTT_PUBCOMP: + proto_data->var_header.pubcomp.packet_id = packet_id; + break; + case NNG_MQTT_PUBREC: + proto_data->var_header.pubrec.packet_id = packet_id; + break; + case NNG_MQTT_PUBREL: + proto_data->var_header.pubrel.packet_id = packet_id; + break; + case NNG_MQTT_PUBLISH: + proto_data->var_header.publish.packet_id = packet_id; + break; + case NNG_MQTT_SUBACK: + proto_data->var_header.suback.packet_id = packet_id; + break; + case NNG_MQTT_SUBSCRIBE: + proto_data->var_header.subscribe.packet_id = packet_id; + break; + default: + // logic error + NNI_ASSERT(false); + } +} + +uint16_t +nni_mqtt_msg_get_packet_id(nni_msg *msg) +{ + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + switch (proto_data->fixed_header.common.packet_type) { + case NNG_MQTT_PUBACK: + return proto_data->var_header.puback.packet_id; + case NNG_MQTT_PUBCOMP: + return proto_data->var_header.pubcomp.packet_id; + case NNG_MQTT_PUBREC: + return proto_data->var_header.pubrec.packet_id; + case NNG_MQTT_PUBREL: + return proto_data->var_header.pubrel.packet_id; + case NNG_MQTT_PUBLISH: + return proto_data->var_header.publish.packet_id; + case NNG_MQTT_SUBACK: + return proto_data->var_header.suback.packet_id; + case NNG_MQTT_SUBSCRIBE: + return proto_data->var_header.subscribe.packet_id; + default: + // logic error + NNI_ASSERT(false); + } +} + void nni_mqtt_msg_set_publish_qos(nni_msg *msg, uint8_t qos) { diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index a10c475af..8da7fdf50 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -260,6 +260,11 @@ extern int nni_mqtt_msg_decode(nni_msg *); extern void nni_mqtt_msg_set_packet_type(nni_msg *, nni_mqtt_packet_type); extern nni_mqtt_packet_type nni_mqtt_msg_get_packet_type(nni_msg *); +// mqtt packet id +// NOTE: not all packet have a packet id field +extern void nni_mqtt_msg_set_packet_id(nni_msg *, uint16_t); +extern uint16_t nni_mqtt_msg_get_packet_id(nni_msg *); + // mqtt connect extern void nni_mqtt_msg_set_connect_clean_session(nni_msg *, bool); extern void nni_mqtt_msg_set_connect_will_retain(nni_msg *, bool); From 8411872a8ea356a8f226709dfaa43c3451635294 Mon Sep 17 00:00:00 2001 From: eeff Date: Sun, 31 Oct 2021 17:50:54 +0800 Subject: [PATCH 099/180] Fix mqtt protocol pipe receive callback getting wrong packet id --- src/sp/protocol/mqtt/mqtt_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 1ee8d1380..8d63641fd 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -559,7 +559,7 @@ mqtt_recv_cb(void *arg) case NNG_MQTT_UNSUBACK: // we have received a UNSUBACK, successful unsubcription // FIXME: check packet type match - packet_id = nni_mqtt_msg_get_unsuback_packet_id(msg); + packet_id = nni_mqtt_msg_get_packet_id(msg); work = nni_id_get(&p->send_unack, packet_id); if (NULL == work) { nni_msg_free(msg); From 3e3a4ef8bbf6da8212412cf473b271ad1183a11b Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 1 Nov 2021 12:30:55 +0800 Subject: [PATCH 100/180] Fix mqtt_client demo 1. Fix client_connect duplicate dialer start and msg free 2. Fix client_publish payload length --- demo/mqtt/mqtt_client.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index 5a28d2547..729e660b2 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -83,8 +83,6 @@ client_connect(nng_socket *sock, const char *url, bool verbose) fatal("nng_dialer_create", rv); } - nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); - // create a CONNECT message /* CONNECT */ nng_msg *connmsg; @@ -118,9 +116,8 @@ client_connect(nng_socket *sock, const char *url, bool verbose) printf("connected\n"); -// TODO Connmsg would be free when client disconnected -// nng_msg_free(connmsg); - nng_mqtt_msg_proto_data_free(connmsg); + // TODO: connmsg would be free when client disconnected + // nng_msg_free(connmsg); return (0); } @@ -205,7 +202,7 @@ client_publish(nng_socket sock, const char *topic, const char *payload, nng_mqtt_msg_set_publish_qos(pubmsg, qos); nng_mqtt_msg_set_publish_retain(pubmsg, 0); nng_mqtt_msg_set_publish_payload( - pubmsg, (uint8_t *) payload, sizeof(payload)); + pubmsg, (uint8_t *) payload, strlen(payload)); nng_mqtt_msg_set_publish_topic(pubmsg, topic); rv = nng_mqtt_msg_encode(pubmsg); From 9b9bf72a4d41e9e53c15f7b4f9df5ba5ed474636 Mon Sep 17 00:00:00 2001 From: eeff Date: Sun, 31 Oct 2021 17:58:30 +0800 Subject: [PATCH 101/180] Refactor mqtt protocol Move sending aio from state machine to mqtt pipe --- src/sp/protocol/mqtt/mqtt_client.c | 94 ++++++++++++++++-------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 8d63641fd..3730ac633 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -35,9 +35,8 @@ static void mqtt_sock_send(void *arg, nni_aio *aio); static void mqtt_sock_recv(void *arg, nni_aio *aio); static void mqtt_send_cb(void *arg); static void mqtt_recv_cb(void *arg); -static void mqtt_send_start(mqtt_sock_t *s, nni_aio *aio); +static void mqtt_send_start(mqtt_sock_t *s); static void mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio); -static void mqtt_run_send_queue(mqtt_sock_t *s); static void mqtt_run_recv_queue(mqtt_sock_t *s); static int mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s); @@ -78,8 +77,7 @@ typedef struct { mqtt_sock_t * mqtt_sock; nni_msg * msg; nni_aio * user_aio; - nni_aio send_aio; // send aio to the underlying transport - nni_list_node node; // in one of send_queue, free_list + nni_list_node node; // in one of send_queue, free_list } work_t; // A mqtt_ctx_s is our per-ctx protocol private state. @@ -93,8 +91,10 @@ struct mqtt_pipe_s { nni_atomic_int next_packet_id; // next packet id to use nni_pipe * pipe; mqtt_sock_t * mqtt_sock; + work_t * work; nni_id_map send_unack; // send messages unacknowledged nni_id_map recv_unack; // recv messages unacknowledged + nni_aio send_aio; // send aio to the underlying transport nni_aio recv_aio; // recv aio to the underlying transport nni_lmq recv_messages; // recv messages queue }; @@ -125,7 +125,6 @@ work_init(work_t *work, mqtt_sock_t *s) work->packet_id = 0; work->msg = NULL; work->user_aio = NULL; - nni_aio_init(&work->send_aio, mqtt_send_cb, work); work->mqtt_sock = s; NNI_LIST_NODE_INIT(&work->node); } @@ -133,7 +132,7 @@ work_init(work_t *work, mqtt_sock_t *s) static inline void work_fini(work_t *work) { - nni_aio_fini(&work->send_aio); + NNI_ARG_UNUSED(work); } static inline void @@ -153,7 +152,6 @@ work_reset(work_t *work) static inline void work_stop(work_t *work) { - nni_aio_stop(&work->send_aio); nni_list_node_remove(&work->node); } @@ -162,7 +160,6 @@ work_stop(work_t *work) static inline void work_close(work_t *work) { - nni_aio_close(&work->send_aio); if (NULL != work->user_aio) { nni_aio_finish_error(work->user_aio, NNG_ECONNRESET); work->msg = NULL; @@ -290,6 +287,8 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) nni_atomic_set(&p->next_packet_id, 0); p->pipe = pipe; p->mqtt_sock = s; + p->work = NULL; + nni_aio_init(&p->send_aio, mqtt_send_cb, p); nni_aio_init(&p->recv_aio, mqtt_recv_cb, p); // Packet IDs are 16 bits // We start at a random point, to minimize likelihood of @@ -304,6 +303,7 @@ static void mqtt_pipe_fini(void *arg) { mqtt_pipe_t *p = arg; + nni_aio_fini(&p->send_aio); nni_aio_fini(&p->recv_aio); nni_id_map_fini(&p->send_unack); nni_id_map_fini(&p->recv_unack); @@ -322,7 +322,7 @@ mqtt_pipe_start(void *arg) // } nni_mtx_lock(&s->mtx); - mqtt_run_send_queue(s); + mqtt_send_start(s); nni_mtx_unlock(&s->mtx); nni_pipe_recv(p->pipe, &p->recv_aio); @@ -337,6 +337,7 @@ mqtt_pipe_stop(void *arg) mqtt_sock_t *s = p->mqtt_sock; nni_mtx_lock(&s->mtx); + nni_aio_stop(&p->send_aio); nni_aio_stop(&p->recv_aio); work_stop_queue(&s->send_queue); work_stop_queue(&s->recv_queue); @@ -352,6 +353,8 @@ mqtt_pipe_close(void *arg) nni_mtx_lock(&s->mtx); mqtt_sock_close(s); s->mqtt_pipe = NULL; + p->work = NULL; + nni_aio_close(&p->send_aio); nni_aio_close(&p->recv_aio); work_close_queue(&s->send_queue); work_close_queue(&s->recv_queue); @@ -374,17 +377,16 @@ mqtt_pipe_get_next_packet_id(mqtt_pipe_t *p) static void mqtt_send_cb(void *arg) { - work_t * work = arg; - mqtt_sock_t *s = work->mqtt_sock; - mqtt_pipe_t *p; + mqtt_pipe_t *p = arg; + mqtt_sock_t *s = p->mqtt_sock; + work_t * work = p->work; nni_mtx_lock(&s->mtx); - p = s->mqtt_pipe; - if (nni_aio_result(&work->send_aio) != 0) { + if (nni_aio_result(&p->send_aio) != 0) { // We failed to send... clean up and deal with it. - nni_msg_free(nni_aio_get_msg(&work->send_aio)); - nni_aio_set_msg(&work->send_aio, NULL); + nni_msg_free(nni_aio_get_msg(&p->send_aio)); + nni_aio_set_msg(&p->send_aio, NULL); nni_mtx_unlock(&s->mtx); nni_pipe_close(p->pipe); return; @@ -430,6 +432,7 @@ mqtt_send_cb(void *arg) work->msg = NULL; work_reset(work); nni_list_append(&s->free_list, work); + mqtt_send_start(s); nni_mtx_unlock(&s->mtx); return; @@ -494,6 +497,7 @@ mqtt_send_cb(void *arg) nni_list_append(&s->free_list, work); } + mqtt_send_start(s); nni_mtx_unlock(&s->mtx); } @@ -680,28 +684,6 @@ mqtt_recv_cb(void *arg) return; } -static void -mqtt_send_start(mqtt_sock_t *s, nni_aio *aio) -{ - work_t *work; - - nni_mtx_lock(&s->mtx); - - work = nni_list_first(&s->free_list); - if (NULL == work) { - nni_mtx_unlock(&s->mtx); - nni_aio_finish_error(aio, NNG_EBUSY); - return; - } - - work->user_aio = aio; - nni_list_remove(&s->free_list, work); - nni_list_append(&s->send_queue, work); // enqueue to send - mqtt_run_send_queue(s); - - nni_mtx_unlock(&s->mtx); -} - static void mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) { @@ -751,7 +733,7 @@ mqtt_run_recv_queue(mqtt_sock_t *s) // Note: This routine should be called with the sock lock held. static void -mqtt_run_send_queue(mqtt_sock_t *s) +mqtt_send_start(mqtt_sock_t *s) { work_t * work; mqtt_pipe_t *p = s->mqtt_pipe; @@ -763,16 +745,18 @@ mqtt_run_send_queue(mqtt_sock_t *s) } // TODO: handle retry - while (NULL != (work = nni_list_first(&s->send_queue))) { + if (NULL != (work = nni_list_first(&s->send_queue))) { nni_list_remove(&s->send_queue, work); nni_msg *msg = nni_aio_get_msg(work->user_aio); packet_type = nni_mqtt_msg_get_packet_type(msg); - // only allow to send PUBLISH, SUBSCRIBE and UNSUBSCRIBE packet + // only allow to send CONNECT, PUBLISH, SUBSCRIBE, UNSUBSCRIBE switch (packet_type) { case NNG_MQTT_CONNECT: + // NOTE: the transport dialer will send a CONNECT work->state = WORK_CONNECT; break; + case NNG_MQTT_PUBLISH: work->state = WORK_PUBLISH; work->packet_id = mqtt_pipe_get_next_packet_id(p); @@ -780,18 +764,21 @@ mqtt_run_send_queue(mqtt_sock_t *s) msg, work->packet_id); work->qos = nni_mqtt_msg_get_publish_qos(msg); break; + case NNG_MQTT_SUBSCRIBE: work->state = WORK_SUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_subscribe_packet_id( msg, work->packet_id); break; + case NNG_MQTT_UNSUBSCRIBE: work->state = WORK_UNSUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_unsubscribe_packet_id( msg, work->packet_id); break; + default: work->state = WORK_ERROR; nni_aio_finish_error(work->user_aio, NNG_EPROTO); @@ -802,8 +789,9 @@ mqtt_run_send_queue(mqtt_sock_t *s) nni_aio_set_msg(work->user_aio, NULL); nni_aio_bump_count(work->user_aio, nni_msg_len(msg)); work->msg = msg; - nni_aio_set_msg(&work->send_aio, msg); - nni_pipe_send(p->pipe, &work->send_aio); + p->work = work; + nni_aio_set_msg(&p->send_aio, msg); + nni_pipe_send(p->pipe, &p->send_aio); } return; @@ -835,17 +823,35 @@ mqtt_ctx_send(void *arg, nni_aio *aio) { mqtt_ctx_t * ctx = arg; mqtt_sock_t *s = ctx->mqtt_sock; + work_t * work; if (nni_aio_begin(aio) != 0) { return; } + nni_mtx_lock(&s->mtx); + if (nni_atomic_get_bool(&s->closed)) { nni_aio_finish_error(aio, NNG_ECLOSED); return; } - mqtt_send_start(s, aio); + work = nni_list_first(&s->free_list); + if (NULL == work) { + nni_mtx_unlock(&s->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + + work->user_aio = aio; + nni_list_remove(&s->free_list, work); + nni_list_append(&s->send_queue, work); // enqueue to send + + if (nni_list_first(&s->send_queue) == work) { + mqtt_send_start(s); + } + + nni_mtx_unlock(&s->mtx); } static void From 41ee2280bfe9521a57661d0eefeee470e8a7182f Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 1 Nov 2021 00:24:08 +0800 Subject: [PATCH 102/180] Fix mqtt protocol msg len calculation --- src/sp/protocol/mqtt/mqtt_client.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 3730ac633..53196c840 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -723,7 +723,8 @@ mqtt_run_recv_queue(mqtt_sock_t *s) nni_list_remove(&s->recv_queue, work); // nni_pipe_recv(p->pipe, &work->recv_aio); nni_aio_set_msg(work->user_aio, msg); - nni_aio_finish_sync(work->user_aio, 0, nni_msg_len(msg)); + nni_aio_finish_sync(work->user_aio, 0, + nni_msg_header_len(msg) + nni_msg_len(msg)); nni_list_append(&s->free_list, work); work = nni_list_first(&s->recv_queue); } @@ -787,7 +788,8 @@ mqtt_send_start(mqtt_sock_t *s) nni_msg_clone(msg); nni_aio_set_msg(work->user_aio, NULL); - nni_aio_bump_count(work->user_aio, nni_msg_len(msg)); + nni_aio_bump_count(work->user_aio, + nni_msg_header_len(msg) + nni_msg_len(msg)); work->msg = msg; p->work = work; nni_aio_set_msg(&p->send_aio, msg); From 451312912e91e3ff2b221b961ce2f7c0421b75f2 Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 1 Nov 2021 00:40:00 +0800 Subject: [PATCH 103/180] Fix mqtt protocol to correctly release messages --- src/sp/protocol/mqtt/mqtt_client.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 53196c840..7c64ea4be 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -132,7 +132,7 @@ work_init(work_t *work, mqtt_sock_t *s) static inline void work_fini(work_t *work) { - NNI_ARG_UNUSED(work); + nni_msg_free(work->msg); } static inline void @@ -162,6 +162,7 @@ work_close(work_t *work) { if (NULL != work->user_aio) { nni_aio_finish_error(work->user_aio, NNG_ECONNRESET); + nni_msg_free(work->msg); work->msg = NULL; work->user_aio = NULL; } @@ -429,7 +430,7 @@ mqtt_send_cb(void *arg) nni_id_remove(&p->recv_unack, work->packet_id); nni_lmq_putq(&p->recv_messages, work->msg); mqtt_run_recv_queue(s); - work->msg = NULL; + work->msg = NULL; // ownership to the lmq work_reset(work); nni_list_append(&s->free_list, work); mqtt_send_start(s); @@ -564,14 +565,13 @@ mqtt_recv_cb(void *arg) // we have received a UNSUBACK, successful unsubcription // FIXME: check packet type match packet_id = nni_mqtt_msg_get_packet_id(msg); - work = nni_id_get(&p->send_unack, packet_id); + nni_msg_free(msg); + work = nni_id_get(&p->send_unack, packet_id); if (NULL == work) { - nni_msg_free(msg); nni_mtx_unlock(&s->mtx); nni_pipe_close(p->pipe); return; } - nni_msg_free(msg); nni_id_remove(&p->send_unack, packet_id); work->state = WORK_END; break; @@ -580,10 +580,10 @@ mqtt_recv_cb(void *arg) // we have received a PUBRECV in the QoS 2 delivery, // then send a PUBREL packet_id = nni_mqtt_msg_get_pubrec_packet_id(msg); - work = nni_id_get(&p->send_unack, packet_id); + nni_msg_free(msg); + work = nni_id_get(&p->send_unack, packet_id); if (NULL == work) { // ignore this message - nni_msg_free(msg); nni_mtx_unlock(&s->mtx); return; } @@ -614,8 +614,8 @@ mqtt_recv_cb(void *arg) nni_id_remove(&p->recv_unack, work->packet_id); nni_lmq_putq(&p->recv_messages, work->msg); mqtt_run_recv_queue(s); - work->msg = msg; - work_reset(work); + work->msg = msg; // ownership of work->msg to the lmq + work_reset(work); // will release msg nni_list_append(&s->free_list, work); nni_mtx_unlock(&s->mtx); return; From 84a94710c2b6c4dec2f3242b9cca1711fc0d1ab1 Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 1 Nov 2021 11:28:28 +0800 Subject: [PATCH 104/180] Add mqtt protocol keep alive support --- src/sp/protocol/mqtt/mqtt_client.c | 122 +++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 24 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 7c64ea4be..b6591487e 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -35,6 +35,8 @@ static void mqtt_sock_send(void *arg, nni_aio *aio); static void mqtt_sock_recv(void *arg, nni_aio *aio); static void mqtt_send_cb(void *arg); static void mqtt_recv_cb(void *arg); +static void mqtt_keep_alive_cb(void *arg); +static void mqtt_timer_cb(void *arg); static void mqtt_send_start(mqtt_sock_t *s); static void mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio); static void mqtt_run_recv_queue(mqtt_sock_t *s); @@ -56,6 +58,7 @@ typedef enum { WORK_CONNECT, WORK_CONNACK, WORK_DISCONNECT, // send DISCONNECT + WORK_PINGREQ, // send PINGREQ WORK_PUBACK, // send/recv PUBACK WORK_PUBCOMP, // send/recv PUBCOMP WORK_PUBLISH, // send/recv PUBLISH @@ -71,13 +74,15 @@ typedef enum { // A work_t represents an asynchronous send/recv of MQTT packet. typedef struct { - work_state_t state; - uint8_t qos; // QoS of the MQTT PUBLISH packet - uint16_t packet_id; // packet id of the message that have it - mqtt_sock_t * mqtt_sock; - nni_msg * msg; - nni_aio * user_aio; - nni_list_node node; // in one of send_queue, free_list + work_state_t state; + uint8_t qos; // QoS of the MQTT PUBLISH packet + uint16_t packet_id; // packet id of the message that have it + mqtt_sock_t * mqtt_sock; + nni_msg * msg; // message to send, or receive from pipe + nni_aio * user_aio; // if not null, the aio that starts this work + nni_duration timeout; // time out in milliseconds + nni_timer_node timer; // timer + nni_list_node node; // in one of send_queue, recv_queue or free_list } work_t; // A mqtt_ctx_s is our per-ctx protocol private state. @@ -91,7 +96,8 @@ struct mqtt_pipe_s { nni_atomic_int next_packet_id; // next packet id to use nni_pipe * pipe; mqtt_sock_t * mqtt_sock; - work_t * work; + work_t * work; // work the pipe is sending + work_t ping_work; // work to send a ping request nni_id_map send_unack; // send messages unacknowledged nni_id_map recv_unack; // recv messages unacknowledged nni_aio send_aio; // send aio to the underlying transport @@ -118,7 +124,8 @@ struct mqtt_sock_s { ******************************************************************************/ static inline void -work_init(work_t *work, mqtt_sock_t *s) +work_init( + work_t *work, mqtt_sock_t *s, nni_duration timeout_ms, nni_cb timer_cb) { work->state = WORK_START; work->qos = 0; @@ -126,12 +133,16 @@ work_init(work_t *work, mqtt_sock_t *s) work->msg = NULL; work->user_aio = NULL; work->mqtt_sock = s; + work->timeout = timeout_ms; + nni_timer_init(&work->timer, timer_cb, work); NNI_LIST_NODE_INIT(&work->node); } static inline void work_fini(work_t *work) { + nni_timer_cancel(&work->timer); + nni_timer_fini(&work->timer); nni_msg_free(work->msg); } @@ -144,6 +155,7 @@ work_reset(work_t *work) nni_msg_free(work->msg); work->msg = NULL; work->user_aio = NULL; + // NOTE: keep the timeout nni_list_node_remove(&work->node); } @@ -187,6 +199,12 @@ work_close_queue(nni_list *queue) } } +static inline void +work_timer_schedule(work_t *work) +{ + nni_timer_schedule(&work->timer, nni_clock() + work->timeout); +} + /****************************************************************************** * Sock Implementation * ******************************************************************************/ @@ -216,7 +234,7 @@ mqtt_sock_init(void *arg, nni_sock *sock) NNI_LIST_INIT(&s->recv_queue, work_t, node); NNI_LIST_INIT(&s->free_list, work_t, node); for (int i = 0; i < MQTT_WORK_NUM; ++i) { - work_init(&s->works[i], s); + work_init(&s->works[i], s, s->retry, mqtt_timer_cb); nni_list_append(&s->free_list, &s->works[i]); } @@ -289,6 +307,11 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) p->pipe = pipe; p->mqtt_sock = s; p->work = NULL; + // FIXME: passing keep alive timeout + work_init(&p->ping_work, s, sock->retry, mqtt_keep_alive_cb); + nni_mqtt_msg_alloc(&p->ping_work.msg, 0); + nni_mqtt_msg_set_packet_type(p->ping_work.msg, MQTT_PINGREQ); + nni_mqtt_msg_encode(p->ping_work.msg); nni_aio_init(&p->send_aio, mqtt_send_cb, p); nni_aio_init(&p->recv_aio, mqtt_recv_cb, p); // Packet IDs are 16 bits @@ -304,6 +327,7 @@ static void mqtt_pipe_fini(void *arg) { mqtt_pipe_t *p = arg; + work_fini(&p->ping_work); nni_aio_fini(&p->send_aio); nni_aio_fini(&p->recv_aio); nni_id_map_fini(&p->send_unack); @@ -375,6 +399,38 @@ mqtt_pipe_get_next_packet_id(mqtt_pipe_t *p) return packet_id & 0xFFFF; } +// Keep alive timer callback to send ping request. +static void +mqtt_keep_alive_cb(void *arg) +{ + work_t * work = arg; + mqtt_sock_t *s = work->mqtt_sock; + + nni_mtx_lock(&s->mtx); + + mqtt_pipe_t *p = s->mqtt_pipe; + + if (NULL == p || nni_atomic_get_bool(&p->closed)) { + return; + } + + // keep alive time out + // if there is work in the send queue, no need to send PINGREQ + if (nni_list_empty(&s->send_queue)) { + // no work in send queue, then send a PINGREQ + nni_list_append(&s->send_queue, &p->ping_work); + mqtt_send_start(s); + } + + nni_mtx_unlock(&s->mtx); +} + +static void +mqtt_timer_cb(void *arg) +{ + // TODO: handle retry +} + static void mqtt_send_cb(void *arg) { @@ -437,6 +493,12 @@ mqtt_send_cb(void *arg) nni_mtx_unlock(&s->mtx); return; + case WORK_PINGREQ: + // we have sent a PINGREQ + mqtt_send_start(s); + nni_mtx_unlock(&s->mtx); + return; + case WORK_PUBLISH: // TODO: handle retry // we have sent a PUBLISH @@ -498,6 +560,7 @@ mqtt_send_cb(void *arg) nni_list_append(&s->free_list, work); } + p->work = NULL; mqtt_send_start(s); nni_mtx_unlock(&s->mtx); } @@ -576,6 +639,11 @@ mqtt_recv_cb(void *arg) work->state = WORK_END; break; + case NNG_MQTT_PINGRESP: + // do nothing + nni_mtx_unlock(&s->mtx); + return; + case NNG_MQTT_PUBREC: // we have received a PUBRECV in the QoS 2 delivery, // then send a PUBREL @@ -748,36 +816,40 @@ mqtt_send_start(mqtt_sock_t *s) // TODO: handle retry if (NULL != (work = nni_list_first(&s->send_queue))) { nni_list_remove(&s->send_queue, work); - nni_msg *msg = nni_aio_get_msg(work->user_aio); - packet_type = nni_mqtt_msg_get_packet_type(msg); + packet_type = nni_mqtt_msg_get_packet_type(work->msg); - // only allow to send CONNECT, PUBLISH, SUBSCRIBE, UNSUBSCRIBE + // only allow to send CONNECT, PINGREQ, PUBLISH, SUBSCRIBE + // and UNSUBSCRIBE switch (packet_type) { case NNG_MQTT_CONNECT: // NOTE: the transport dialer will send a CONNECT work->state = WORK_CONNECT; break; + case NNG_MQTT_PINGREQ: + work->state = WORK_PINGREQ; + break; + case NNG_MQTT_PUBLISH: work->state = WORK_PUBLISH; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_publish_packet_id( - msg, work->packet_id); - work->qos = nni_mqtt_msg_get_publish_qos(msg); + work->msg, work->packet_id); + work->qos = nni_mqtt_msg_get_publish_qos(work->msg); break; case NNG_MQTT_SUBSCRIBE: work->state = WORK_SUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_subscribe_packet_id( - msg, work->packet_id); + work->msg, work->packet_id); break; case NNG_MQTT_UNSUBSCRIBE: work->state = WORK_UNSUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_unsubscribe_packet_id( - msg, work->packet_id); + work->msg, work->packet_id); break; default: @@ -786,14 +858,13 @@ mqtt_send_start(mqtt_sock_t *s) return; } - nni_msg_clone(msg); - nni_aio_set_msg(work->user_aio, NULL); - nni_aio_bump_count(work->user_aio, - nni_msg_header_len(msg) + nni_msg_len(msg)); - work->msg = msg; - p->work = work; - nni_aio_set_msg(&p->send_aio, msg); + nni_msg_clone(work->msg); + p->work = work; + nni_aio_set_msg(&p->send_aio, work->msg); nni_pipe_send(p->pipe, &p->send_aio); + } else { + // no packet to send, start the ping request timer + work_timer_schedule(&p->ping_work); } return; @@ -846,6 +917,9 @@ mqtt_ctx_send(void *arg, nni_aio *aio) } work->user_aio = aio; + work->msg = nni_aio_get_msg(aio); + nni_aio_bump_count( + aio, nni_msg_header_len(work->msg) + nni_msg_len(work->msg)); nni_list_remove(&s->free_list, work); nni_list_append(&s->send_queue, work); // enqueue to send From 44f892750a8ca86d0cfff07296f7ccfab3807cb1 Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 1 Nov 2021 15:46:06 +0800 Subject: [PATCH 105/180] Fix mqtt protocol to encode send packet id --- src/sp/protocol/mqtt/mqtt_client.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index b6591487e..85e3c5bc7 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -831,11 +831,15 @@ mqtt_send_start(mqtt_sock_t *s) break; case NNG_MQTT_PUBLISH: - work->state = WORK_PUBLISH; - work->packet_id = mqtt_pipe_get_next_packet_id(p); - nni_mqtt_msg_set_publish_packet_id( - work->msg, work->packet_id); - work->qos = nni_mqtt_msg_get_publish_qos(work->msg); + work->state = WORK_PUBLISH; + work->qos = nni_mqtt_msg_get_publish_qos(work->msg); + if (work->qos > 0) { + work->packet_id = + mqtt_pipe_get_next_packet_id(p); + nni_mqtt_msg_set_publish_packet_id( + work->msg, work->packet_id); + nni_mqtt_msg_encode(work->msg); + } break; case NNG_MQTT_SUBSCRIBE: @@ -843,6 +847,7 @@ mqtt_send_start(mqtt_sock_t *s) work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_subscribe_packet_id( work->msg, work->packet_id); + nni_mqtt_msg_encode(work->msg); break; case NNG_MQTT_UNSUBSCRIBE: @@ -850,6 +855,7 @@ mqtt_send_start(mqtt_sock_t *s) work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_unsubscribe_packet_id( work->msg, work->packet_id); + nni_mqtt_msg_encode(work->msg); break; default: From 70a31998c15782f9499ba9a71618523301391c80 Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 1 Nov 2021 18:00:25 +0800 Subject: [PATCH 106/180] Fix mqtt protocol compilation error Use NNG_MQTT_PINGREQ instead of MQTT_PINGREQ --- src/sp/protocol/mqtt/mqtt_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 85e3c5bc7..687f7022b 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -310,7 +310,7 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) // FIXME: passing keep alive timeout work_init(&p->ping_work, s, sock->retry, mqtt_keep_alive_cb); nni_mqtt_msg_alloc(&p->ping_work.msg, 0); - nni_mqtt_msg_set_packet_type(p->ping_work.msg, MQTT_PINGREQ); + nni_mqtt_msg_set_packet_type(p->ping_work.msg, NNG_MQTT_PINGREQ); nni_mqtt_msg_encode(p->ping_work.msg); nni_aio_init(&p->send_aio, mqtt_send_cb, p); nni_aio_init(&p->recv_aio, mqtt_recv_cb, p); From f956ccbbb6a1b1a1d560cf78c988556801db3ec3 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Mon, 1 Nov 2021 17:44:43 +0800 Subject: [PATCH 107/180] * NEW [demo] connack msg could be access in connect callback. * NEW [dialer] support new connect callback. * NEW [mqtt_tcp] update the process of recving connack in nego_cb. --- demo/mqtt/mqtt_client.c | 14 +++++ include/nng/nng.h | 3 + src/core/dialer.c | 9 +++ src/core/dialer.h | 3 + src/nng.c | 14 +++++ src/sp/transport.h | 3 + src/sp/transport/mqtt/mqtt_tcp.c | 100 +++++++++++++++++++++---------- 7 files changed, 116 insertions(+), 30 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index 729e660b2..0e5410864 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -68,6 +68,19 @@ print80(const char *prefix, const char *str, size_t len, bool quote) } } +static void +connect_cb(void *arg, nng_msg *ackmsg) +{ + char * userarg = (char *)arg; + uint8_t status = nng_mqtt_msg_get_conack_return_code(ackmsg); + printf("Connected cb. \n" + " -> Status [%d]\n" + " -> Userarg [%s].\n", status, userarg); + + // Free ConnAck msg + nng_msg_free(ackmsg); +} + // Connect to the given address. int client_connect(nng_socket *sock, const char *url, bool verbose) @@ -112,6 +125,7 @@ client_connect(nng_socket *sock, const char *url, bool verbose) printf("Connecting to server ..."); nng_dialer_set_ptr(dialer, "connmsg", connmsg); + nng_dialer_setcb(dialer, connect_cb, "Yeap"); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); printf("connected\n"); diff --git a/include/nng/nng.h b/include/nng/nng.h index a58a60b9e..ee109478b 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -279,6 +279,9 @@ NNG_DECL int nng_dialer_create(nng_dialer *, nng_socket, const char *); // nng_listener_create creates a new listener, that is not yet started. NNG_DECL int nng_listener_create(nng_listener *, nng_socket, const char *); +// nng_dialer_setcb set the cb to the dialer. Cb runs when dialer finished. +NNG_DECL int nng_dialer_setcb(nng_dialer, void (*)(void *, nng_msg *), void *); + // nng_dialer_start starts the endpoint dialing. This is only possible if // the dialer is not already dialing. NNG_DECL int nng_dialer_start(nng_dialer, int); diff --git a/src/core/dialer.c b/src/core/dialer.c index 3a7490859..fc8c464d9 100644 --- a/src/core/dialer.c +++ b/src/core/dialer.c @@ -570,3 +570,12 @@ nni_dialer_add_stat(nni_dialer *d, nni_stat_item *item) NNI_ARG_UNUSED(item); #endif } + +// NNG-MQTT + +void +nni_dialer_setcb(nni_dialer *d, void (*cb)(void *, nng_msg *), void *arg) +{ + d->d_ops.d_connsetcb(d->d_data, cb, arg); +} + diff --git a/src/core/dialer.h b/src/core/dialer.h index b6ba657b5..4f03ff5e6 100644 --- a/src/core/dialer.h +++ b/src/core/dialer.h @@ -30,4 +30,7 @@ extern int nni_dialer_getopt( extern void nni_dialer_add_stat(nni_dialer *, nni_stat_item *); extern void nni_dialer_bump_error(nni_dialer *, int); +// NNG-MQTT +extern void nni_dialer_setcb(nni_dialer *, void (*cb)(void *, nng_msg *), void *); + #endif // CORE_DIALER_H diff --git a/src/nng.c b/src/nng.c index 9aca8583d..4677abb72 100644 --- a/src/nng.c +++ b/src/nng.c @@ -578,6 +578,20 @@ nng_dialer_create(nng_dialer *dp, nng_socket sid, const char *addr) return (0); } +int +nng_dialer_setcb(nng_dialer did, void (*cb)(void *, nng_msg *), void *arg) +{ + nni_dialer *d; + int rv; + + if ((rv = nni_dialer_find(&d, did.id)) != 0) { + return (rv); + } + + nni_dialer_setcb(d, cb, arg); + return (0); +} + int nng_dialer_start(nng_dialer did, int flags) { diff --git a/src/sp/transport.h b/src/sp/transport.h index 76d8d36ab..deea685e1 100644 --- a/src/sp/transport.h +++ b/src/sp/transport.h @@ -49,6 +49,9 @@ struct nni_sp_dialer_ops { // d_setopt is used to set or change an option. int (*d_setopt)(void *, const char *, const void *, size_t, nni_type); + //d_setconncb is used to set callback for connection. + int (*d_connsetcb)(void *, void (*)(void *, nng_msg *), void *); + // d_options is an array of dialer options. The final // element must have a NULL name. If this member is NULL, then // no dialer specific options are available. diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 4165283c8..bad6ede27 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -53,7 +53,6 @@ struct mqtt_tcptran_pipe { nni_msg * rxmsg; nni_msg * smsg; nni_mtx mtx; - void * conn_buf; }; struct mqtt_tcptran_ep { @@ -78,6 +77,8 @@ struct mqtt_tcptran_ep { nng_stream_listener *listener; nni_dialer * ndialer; void * connmsg; + void (*conncb)(void *, nng_msg *); + void * arg; #ifdef NNG_ENABLE_STATS nni_stat_item st_rcv_max; @@ -263,6 +264,8 @@ mqtt_tcptran_pipe_nego_cb(void *arg) nni_aio * aio = p->negoaio; nni_aio * uaio; int rv; + uint8_t pos = 0; + int var_int; nni_mtx_lock(&ep->mtx); @@ -291,28 +294,44 @@ mqtt_tcptran_pipe_nego_cb(void *arg) } // receving fixed header - if (p->gotrxhead < 4) { + if (p->gotrxhead == 0 || + (p->gotrxhead <= 5 && + p->rxlen[p->gotrxhead - 1] > 0x7f && + p->rxmsg == NULL)) { nni_iov iov; - iov.iov_len = p->wantrxhead - p->gotrxhead; iov.iov_buf = &p->rxlen[p->gotrxhead]; + if (p->gotrxhead == 0) { + iov.iov_len = p->wantrxhead - p->gotrxhead; + } else { + iov.iov_len = 1; + } nni_aio_set_iov(aio, 1, &iov); nng_stream_recv(p->conn, aio); nni_mtx_unlock(&ep->mtx); return; } // finish recevied fixed header - // TODO only deal with CONNACK, so just use rxlen at all time - if (p->gotrxhead == 4) { + //TODO only deal with CONNACK, so just use rxlen at all time + if (p->rxmsg == NULL) { if ((p->rxlen[0] & 0x20) != 0x20) { - fprintf( - stderr, "not recv connack [%x].\n", p->rxlen[0]); + fprintf(stderr, "not recv connack [%x].\n", p->rxlen[0]); rv = NNG_EPROTO; goto error; } - int var_int; - uint8_t pos = 0; - int rv = mqtt_get_remaining_length( - p->rxlen, p->gotrxhead, (uint32_t *) &var_int, &pos); + + pos = 0; + if ((rv = mqtt_get_remaining_length(p->rxlen, + p->gotrxhead, &var_int, &pos)) != 0) { + goto error; + } + + if ((rv = nni_mqtt_msg_alloc(&p->rxmsg, var_int)) != 0) { + rv = NNG_ENOMEM; + goto error; + } + + nni_msg_header_append(p->rxmsg, p->rxlen, pos + 1); + p->wantrxhead = var_int + 1 + pos; if ((rv = (p->wantrxhead <= 4) ? 0 : NNG_EPROTO) != 0) { fprintf(stderr, "wantrxhead error rv[%d].\n", rv); @@ -325,11 +344,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) if (p->gotrxhead < p->wantrxhead) { nni_iov iov; iov.iov_len = p->wantrxhead - p->gotrxhead; - if (p->conn_buf == NULL) { - p->conn_buf = nni_alloc(p->wantrxhead); - memcpy(p->conn_buf, p->rxlen, p->gotrxhead); - } - iov.iov_buf = &p->conn_buf[p->gotrxhead]; + iov.iov_buf = nni_msg_body(p->rxmsg); nni_aio_set_iov(aio, 1, &iov); nng_stream_recv(p->conn, aio); nni_mtx_unlock(&ep->mtx); @@ -337,9 +352,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) } if (p->gotrxhead >= p->wantrxhead) { fprintf(stderr, "finish recv connack. [%ld]\n", p->gotrxhead); - nng_free(p->conn_buf, p->gotrxhead); - p->conn_buf = NULL; - // nng_msg_free(ep->connmsg); + nni_mqtt_msg_decode(p->rxmsg); } // We are all ready now. We put this in the wait list, and @@ -350,11 +363,22 @@ mqtt_tcptran_pipe_nego_cb(void *arg) mqtt_tcptran_ep_match(ep); nni_mtx_unlock(&ep->mtx); + // Run user callback + if (ep->conncb != NULL) { + ep->conncb(ep->arg, p->rxmsg); + } + p->rxmsg = NULL; + return; error: nng_stream_close(p->conn); + if (p->rxmsg != NULL) { + nni_msg_free(p->rxmsg); + p->rxmsg = NULL; + } + if ((uaio = ep->useraio) != NULL) { ep->useraio = NULL; nni_aio_finish_error(uaio, rv); @@ -754,10 +778,9 @@ static void mqtt_tcptran_pipe_start( mqtt_tcptran_pipe *p, nng_stream *conn, mqtt_tcptran_ep *ep) { - nni_iov iov[2]; - nni_msg *connmsg; - uint32_t buf_len; - int rv, niov = 0; + nni_iov iov[2]; + nni_msg * connmsg; + int rv, niov = 0; ep->refcnt++; @@ -778,8 +801,9 @@ mqtt_tcptran_pipe_start( p->gotrxhead = 0; p->gottxhead = 0; // TODO TX length for MQTT 5 - p->wantrxhead = 4; + p->wantrxhead = 2; p->wanttxhead = nni_msg_header_len(connmsg) + nni_msg_len(connmsg); + p->rxmsg = NULL; if (nni_msg_header_len(connmsg) > 0) { iov[niov].iov_buf = nni_msg_header(connmsg); @@ -1252,6 +1276,21 @@ mqtt_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) return (rv); } +static int +mqtt_tcptran_dialer_setcb(void *arg, void (*cb)(void *, nng_msg *), void *args) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + ep->conncb = cb; + ep->arg = args; + nni_mtx_unlock(&ep->mtx); + + rv = 0; + return (rv); +} + static int mqtt_tcptran_ep_set_connmsg( void *arg, const void *v, size_t sz, nni_opt_type t) @@ -1406,12 +1445,13 @@ mqtt_tcptran_listener_setopt( } static nni_sp_dialer_ops mqtt_tcptran_dialer_ops = { - .d_init = mqtt_tcptran_dialer_init, - .d_fini = mqtt_tcptran_ep_fini, - .d_connect = mqtt_tcptran_ep_connect, - .d_close = mqtt_tcptran_ep_close, - .d_getopt = mqtt_tcptran_dialer_getopt, - .d_setopt = mqtt_tcptran_dialer_setopt, + .d_init = mqtt_tcptran_dialer_init, + .d_fini = mqtt_tcptran_ep_fini, + .d_connect = mqtt_tcptran_ep_connect, + .d_close = mqtt_tcptran_ep_close, + .d_getopt = mqtt_tcptran_dialer_getopt, + .d_setopt = mqtt_tcptran_dialer_setopt, + .d_connsetcb = mqtt_tcptran_dialer_setcb, }; static nni_sp_listener_ops mqtt_tcptran_listener_ops = { From d586e19d6325586f3c2c582de5b1bc5ea3afd3df Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Mon, 1 Nov 2021 18:56:29 +0800 Subject: [PATCH 108/180] * FIX [mqtt_tcp] set default value for elements added in struct mqtt_trantcp_ep. --- src/sp/transport/mqtt/mqtt_tcp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index bad6ede27..03c784b1a 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -321,7 +321,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) pos = 0; if ((rv = mqtt_get_remaining_length(p->rxlen, - p->gotrxhead, &var_int, &pos)) != 0) { + p->gotrxhead, (uint32_t *)&var_int, &pos)) != 0) { goto error; } @@ -622,7 +622,7 @@ mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *p) nni_msg *msg; int niov; nni_iov iov[3]; - uint64_t len; + // uint64_t len; if (p->closed) { while ((aio = nni_list_first(&p->sendq)) != NULL) { @@ -638,8 +638,8 @@ mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *p) // This runs to send the message. msg = nni_aio_get_msg(aio); - len = nni_msg_len(msg) + nni_msg_header_len(msg); + // len = nni_msg_len(msg) + nni_msg_header_len(msg); // NNI_PUT64(p->txlen, len); txaio = p->txaio; @@ -1055,8 +1055,10 @@ mqtt_tcptran_ep_init(mqtt_tcptran_ep **epp, nng_url *url, nni_sock *sock) NNI_LIST_INIT(&ep->waitpipes, mqtt_tcptran_pipe, node); NNI_LIST_INIT(&ep->negopipes, mqtt_tcptran_pipe, node); - ep->proto = nni_sock_proto_id(sock); - ep->url = url; + ep->proto = nni_sock_proto_id(sock); + ep->url = url; + ep->conncb = NULL; + ep->arg = NULL; #ifdef NNG_ENABLE_STATS static const nni_stat_info rcv_max_info = { From fa03015d044b85d47dafe48084283d6d3bfa29f6 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 1 Nov 2021 11:57:30 +0800 Subject: [PATCH 109/180] Add publish encode test & Resolve conflicts --- demo/mqtt/mqtt_client.c | 14 ++++++++------ src/mqtt/mqtt_test.c | 14 ++++++++++++++ src/sp/protocol/mqtt/mqtt_client.c | 1 - 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index 0e5410864..e72efa124 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -71,11 +71,12 @@ print80(const char *prefix, const char *str, size_t len, bool quote) static void connect_cb(void *arg, nng_msg *ackmsg) { - char * userarg = (char *)arg; - uint8_t status = nng_mqtt_msg_get_conack_return_code(ackmsg); + char * userarg = (char *) arg; + uint8_t status = nng_mqtt_msg_get_conack_return_code(ackmsg); printf("Connected cb. \n" " -> Status [%d]\n" - " -> Userarg [%s].\n", status, userarg); + " -> Userarg [%s].\n", + status, userarg); // Free ConnAck msg nng_msg_free(ackmsg); @@ -103,8 +104,8 @@ client_connect(nng_socket *sock, const char *url, bool verbose) nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); nng_mqtt_msg_set_connect_proto_version(connmsg, 4); nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); - nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); - nng_mqtt_msg_set_connect_password(connmsg, "secrets"); + nng_mqtt_msg_set_connect_user_name(connmsg, "alvin"); + nng_mqtt_msg_set_connect_password(connmsg, "HHH0000"); nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); @@ -130,8 +131,9 @@ client_connect(nng_socket *sock, const char *url, bool verbose) printf("connected\n"); - // TODO: connmsg would be free when client disconnected + // TODO Connmsg would be free when client disconnected // nng_msg_free(connmsg); + nng_mqtt_msg_proto_data_free(connmsg); return (0); } diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 182912a23..660e5212b 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -137,6 +137,20 @@ test_encode_publish(void) nng_mqtt_msg_set_publish_payload( msg, (uint8_t *) payload, strlen(payload)); + char will_topic[] = "/nanomq/will_msg"; + nng_mqtt_msg_set_connect_will_topic(msg, will_topic); + + char will_msg[] = "Bye-bye"; + nng_mqtt_msg_set_connect_will_msg(msg, will_msg); + + char user[] = "alvin"; + char passwd[] = "HHH0000"; + + nng_mqtt_msg_set_connect_user_name(msg, user); + nng_mqtt_msg_set_connect_password(msg, passwd); + + nng_mqtt_msg_set_connect_keep_alive(msg, 60); + NUTS_PASS(nng_mqtt_msg_encode(msg)); uint8_t print_buf[1024] = { 0 }; diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 687f7022b..cde4c5552 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -849,7 +849,6 @@ mqtt_send_start(mqtt_sock_t *s) work->msg, work->packet_id); nni_mqtt_msg_encode(work->msg); break; - case NNG_MQTT_UNSUBSCRIBE: work->state = WORK_UNSUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); From a5984a9ee15f642b0a37f3965464c74f34d44bf6 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 1 Nov 2021 16:09:35 +0800 Subject: [PATCH 110/180] Add default client id & New unit tests --- demo/mqtt/mqtt_client.c | 6 +++--- src/mqtt/mqtt_test.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index e72efa124..41872a173 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -104,8 +104,8 @@ client_connect(nng_socket *sock, const char *url, bool verbose) nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); nng_mqtt_msg_set_connect_proto_version(connmsg, 4); nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); - nng_mqtt_msg_set_connect_user_name(connmsg, "alvin"); - nng_mqtt_msg_set_connect_password(connmsg, "HHH0000"); + nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); + nng_mqtt_msg_set_connect_password(connmsg, "secrets"); nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); @@ -131,7 +131,7 @@ client_connect(nng_socket *sock, const char *url, bool verbose) printf("connected\n"); - // TODO Connmsg would be free when client disconnected + // TODO Connmsg would be free when client disconnected // nng_msg_free(connmsg); nng_mqtt_msg_proto_data_free(connmsg); diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 660e5212b..4b1be0fa8 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -177,6 +177,24 @@ test_encode_puback(void) nng_msg_free(msg); } +void +test_encode_puback(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBACK); + NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBACK); + + NUTS_PASS(nng_mqtt_msg_encode(msg)); + + uint8_t print_buf[1024] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, 1024, true); + printf("%s\n", print_buf); + nng_msg_free(msg); +} + void test_encode_subscribe(void) { From 96dba39852d0f77d2cd9e6ce8fbde44323476cb9 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Tue, 2 Nov 2021 11:24:24 +0800 Subject: [PATCH 111/180] * FIX [mqtt_codec] read freed memory --- src/mqtt/mqtt.c | 1 + src/mqtt/mqtt_codec.c | 32 ++++++++++++------------- src/mqtt/mqtt_test.c | 54 +++++++++++++++++++++---------------------- 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index fc7d203fa..c2d358ae1 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -142,6 +142,7 @@ nni_mqtt_msg_get_packet_id(nni_msg *msg) // logic error NNI_ASSERT(false); } + return 0; } void diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index b2e79efa0..5d8215956 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -730,7 +730,6 @@ nni_mqtt_msg_decode_subscribe(nni_msg *msg) ret = read_utf8_str( &buf, &spld->topic_arr[spld->topic_count].topic); if (ret != MQTT_SUCCESS) { - ret = MQTT_ERR_PROTOCOL; goto ERROR; } @@ -742,10 +741,10 @@ nni_mqtt_msg_decode_subscribe(nni_msg *msg) } spld->topic_count++; } - return ret; + return MQTT_SUCCESS; ERROR: - nni_free(spld->topic_arr, topic_count); + nni_free(spld->topic_arr, sizeof(mqtt_topic_qos) * topic_count); return ret; } @@ -934,9 +933,10 @@ nni_mqtt_msg_decode_unsubscribe(nni_msg *msg) } uspld->topic_count++; } + return MQTT_SUCCESS; ERROR: - nni_free(uspld->topic_arr, topic_count); + nni_free(uspld->topic_arr, topic_count * sizeof(mqtt_buf)); return ret; } @@ -1270,12 +1270,12 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) ret = sprintf((char *) &buf->buf[pos], "connect flags:\n" - " clean session flag : %s,\n" - " will flag : %s,\n" - " will retain flag : %s,\n" - " will qos flag : %d,\n" - " user name flag : %s,\n" - " password flag : %s\n", + " clean session flag : %s\n" + " will flag : %s\n" + " will retain flag : %s\n" + " will qos flag : %d\n" + " user name flag : %s\n" + " password flag : %s\n", ((flags_set.clean_session) ? "true" : "false"), ((flags_set.will_flag) ? "true" : "false"), ((flags_set.will_retain) ? "true" : "false"), @@ -1287,7 +1287,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) } pos += ret; ret = sprintf((char *) &buf->buf[pos], - "client id : %.*s\n", + "client id : %.*s\n", msg->payload.connect.client_id.length, msg->payload.connect.client_id.buf); if ((ret < 0) || ((pos + ret) > buf->length)) { @@ -1344,9 +1344,9 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) ret = sprintf((char *) &buf->buf[pos], "publis flags:\n" - " retain : %s\n" - " qos : %d\n" - " dup : %s\n", + " retain : %s\n" + " qos : %d\n" + " dup : %s\n", ((msg->fixed_header.publish.retain) ? "true" : "false"), msg->fixed_header.publish.qos, ((msg->fixed_header.publish.dup) ? "true" : "false")); @@ -1407,7 +1407,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) case NNG_MQTT_SUBSCRIBE: { ret = sprintf((char *) &buf->buf[pos], - "packet-id : %d\n", + "packet-id : %d\n", msg->var_header.subscribe.packet_id); if ((ret < 0) || ((pos + ret) > buf->length)) { return 1; @@ -1431,7 +1431,7 @@ mqtt_msg_dump(mqtt_msg *msg, mqtt_buf *buf, mqtt_buf *packet, bool print_bytes) case NNG_MQTT_SUBACK: { ret = sprintf((char *) &buf->buf[pos], - "packet-id : %d\n", + "packet-id : %d\n", msg->var_header.suback.packet_id); if ((ret < 0) || ((pos + ret) > buf->length)) { return 1; diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 4b1be0fa8..04d1c286e 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -177,24 +177,6 @@ test_encode_puback(void) nng_msg_free(msg); } -void -test_encode_puback(void) -{ - nng_msg *msg; - - NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); - - nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBACK); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBACK); - - NUTS_PASS(nng_mqtt_msg_encode(msg)); - - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); - nng_msg_free(msg); -} - void test_encode_subscribe(void) { @@ -208,10 +190,10 @@ test_encode_subscribe(void) nng_mqtt_topic_qos topic_qos[] = { { .qos = 0, .topic = { .buf = (uint8_t *) "/nanomq/mqtt/msg/0", - .length = strlen("/nanomq/mqtt/msg/0") } }, + .length = strlen("/nanomq/mqtt/msg/0") + 1 } }, { .qos = 1, .topic = { .buf = (uint8_t *) "/nanomq/mqtt/msg/1", - .length = strlen("/nanomq/mqtt/msg/1") } } + .length = strlen("/nanomq/mqtt/msg/1") + 1 } } }; nng_mqtt_msg_set_subscribe_topics( @@ -261,9 +243,9 @@ test_encode_unsubscribe(void) nng_mqtt_topic topic_qos[] = { { .buf = (uint8_t *) "/nanomq/mqtt/1", - .length = strlen("/nanomq/mqtt/1") }, + .length = strlen("/nanomq/mqtt/1") + 1 }, { .buf = (uint8_t *) "/nanomq/mqtt/2", - .length = strlen("/nanomq/mqtt/2") }, + .length = strlen("/nanomq/mqtt/2") + 1 }, }; nng_mqtt_msg_set_unsubscribe_topics( @@ -427,7 +409,7 @@ test_decode_subscribe(void) size_t sz = sizeof(subscribe) / sizeof(uint8_t); nng_mqtt_msg_alloc(&msg, 0); - nng_msg_header_append(msg, subscribe, sz - 2); + nng_msg_header_append(msg, subscribe, 2); nng_msg_append(msg, subscribe + 2, sz - 2); @@ -441,7 +423,12 @@ test_decode_subscribe(void) nng_mqtt_topic_qos *tq = nng_mqtt_msg_get_subscribe_topics(msg, &count); - nng_free(tq, count); + for (size_t i = 0; i < count; i++) { + printf("[%ld]: %.*s, qos: %d\n", i, tq[i].topic.length, + (char *) tq[i].topic.buf, tq[i].qos); + } + + nng_free(tq, count * sizeof(nng_mqtt_topic_qos)); nng_msg_free(msg); } @@ -451,15 +438,16 @@ test_decode_unsubscribe(void) { nng_msg *msg; - uint8_t unsubscribe[] = { 0xa2, 0x22, 0x01, 0x10, 0x00, 0x0e, 0x2f, + uint8_t unsubscribe[] = { 0xa2, 0x24, 0x00, 0x00, 0x00, 0x0f, 0x2f, 0x6e, 0x61, 0x6e, 0x6f, 0x6d, 0x71, 0x2f, 0x6d, 0x71, 0x74, - 0x74, 0x2f, 0x31, 0x00, 0x0e, 0x2f, 0x6e, 0x61, 0x6e, 0x6f, - 0x6d, 0x71, 0x2f, 0x6d, 0x71, 0x74, 0x74, 0x2f, 0x32 }; + 0x74, 0x2f, 0x31, 0x00, 0x00, 0x0f, 0x2f, 0x6e, 0x61, 0x6e, + 0x6f, 0x6d, 0x71, 0x2f, 0x6d, 0x71, 0x74, 0x74, 0x2f, 0x32, + 0x00 }; size_t sz = sizeof(unsubscribe) / sizeof(uint8_t); nng_mqtt_msg_alloc(&msg, 0); - nng_msg_header_append(msg, unsubscribe, sz - 2); + nng_msg_header_append(msg, unsubscribe, 2); nng_msg_append(msg, unsubscribe + 2, sz - 2); NUTS_PASS(nng_mqtt_msg_decode(msg)); @@ -468,7 +456,17 @@ test_decode_unsubscribe(void) nng_mqtt_msg_dump(msg, print_buf, 1024, true); printf("%s\n", print_buf); + uint32_t count; + nng_mqtt_topic *topics = + nng_mqtt_msg_get_unsubscribe_topics(msg, &count); + + for (size_t i = 0; i < count; i++) { + printf("[%ld]: %.*s\n", i, topics[i].length, + (char *) topics[i].buf); + } + nng_msg_free(msg); + nni_free(topics, count * sizeof(nng_mqtt_topic)); } void From 018a52a0f498c8824470a7ed2dc4c8606420336b Mon Sep 17 00:00:00 2001 From: eeff Date: Tue, 2 Nov 2021 16:26:00 +0800 Subject: [PATCH 112/180] Fix mqtt procotol PUBLISH QoS 2 message error The error was caused by removing the unacknowledged message when receiving a PUBREC, should defer the removal to PUBCOMP received. --- src/sp/protocol/mqtt/mqtt_client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index cde4c5552..e595c6533 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -663,7 +663,6 @@ mqtt_recv_cb(void *arg) // nni_mqtt_msg_encode(msg); // nni_aio_set_msg(&work->send_aio, msg); // nni_pipe_send(p->pipe, &work->send_aio); - nni_id_remove(&p->send_unack, packet_id); work->state = WORK_PUBCOMP; break; From 5955bc48f2a090c16067a44806bb306c8bdd6c88 Mon Sep 17 00:00:00 2001 From: eeff Date: Wed, 3 Nov 2021 14:47:53 +0800 Subject: [PATCH 113/180] Fix mqtt protocol pipe send data race Only remove from the send queue in mqtt_send_cb, so to keep the pipe send aio safe. --- src/sp/protocol/mqtt/mqtt_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index e595c6533..74f4908fd 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -440,6 +440,8 @@ mqtt_send_cb(void *arg) nni_mtx_lock(&s->mtx); + nni_list_remove(&s->send_queue, work); + if (nni_aio_result(&p->send_aio) != 0) { // We failed to send... clean up and deal with it. nni_msg_free(nni_aio_get_msg(&p->send_aio)); @@ -814,7 +816,6 @@ mqtt_send_start(mqtt_sock_t *s) // TODO: handle retry if (NULL != (work = nni_list_first(&s->send_queue))) { - nni_list_remove(&s->send_queue, work); packet_type = nni_mqtt_msg_get_packet_type(work->msg); // only allow to send CONNECT, PINGREQ, PUBLISH, SUBSCRIBE From ca6c0fe5bba539646396f1d1688613cd6d22880f Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Thu, 4 Nov 2021 11:20:31 +0800 Subject: [PATCH 114/180] * FIX [mqtt_tcp] fix the conflict on p->rxmsg. --- src/sp/transport/mqtt/mqtt_tcp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 03c784b1a..10e81d3b9 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -266,6 +266,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) int rv; uint8_t pos = 0; int var_int; + nni_msg * rmsg = p->rxmsg; nni_mtx_lock(&ep->mtx); @@ -353,6 +354,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) if (p->gotrxhead >= p->wantrxhead) { fprintf(stderr, "finish recv connack. [%ld]\n", p->gotrxhead); nni_mqtt_msg_decode(p->rxmsg); + p->rxmsg = NULL; } // We are all ready now. We put this in the wait list, and @@ -365,9 +367,8 @@ mqtt_tcptran_pipe_nego_cb(void *arg) // Run user callback if (ep->conncb != NULL) { - ep->conncb(ep->arg, p->rxmsg); + ep->conncb(ep->arg, rmsg); } - p->rxmsg = NULL; return; @@ -440,7 +441,7 @@ mqtt_tcptran_pipe_recv_cb(void *arg) { nni_aio * aio; nni_iov iov; - uint8_t type, pos; + uint8_t type, pos = 0; uint32_t len = 0, rv; size_t n; nni_msg * msg; From 0d5741f3e14ec5aea23d721208ce8f252c4b06e3 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Fri, 5 Nov 2021 15:33:51 +0800 Subject: [PATCH 115/180] * FIX [mqtt_tcp] Make a defination for connmsg. --- demo/mqtt/mqtt_client.c | 2 +- include/nng/nng.h | 3 +++ src/sp/transport/mqtt/mqtt_tcp.c | 8 ++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index 41872a173..aa4ede8e1 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -125,7 +125,7 @@ client_connect(nng_socket *sock, const char *url, bool verbose) } printf("Connecting to server ..."); - nng_dialer_set_ptr(dialer, "connmsg", connmsg); + nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, connmsg); nng_dialer_setcb(dialer, connect_cb, "Yeap"); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); diff --git a/include/nng/nng.h b/include/nng/nng.h index ee109478b..f2fd0650e 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -686,6 +686,9 @@ NNG_DECL nng_listener nng_pipe_listener(nng_pipe); #define NNG_OPT_RECONNMINT "reconnect-time-min" #define NNG_OPT_RECONNMAXT "reconnect-time-max" +// NNG-MQTT +#define NNG_OPT_MQTT_CONNMSG "mqtt-connect-msg" + // TLS options are only used when the underlying transport supports TLS. // NNG_OPT_TLS_CONFIG is a pointer to an nng_tls_config object. Generally diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 10e81d3b9..b184a49d4 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -790,7 +790,7 @@ mqtt_tcptran_pipe_start( p->proto = ep->proto; rv = nni_dialer_getopt( - ep->ndialer, "connmsg", &connmsg, NULL, NNI_TYPE_POINTER); + ep->ndialer, NNG_OPT_MQTT_CONNMSG, &connmsg, NULL, NNI_TYPE_POINTER); if (!connmsg) { fprintf(stderr, "Connmsg get error [%d] \n", rv); nni_list_append(&ep->waitpipes, p); @@ -1271,7 +1271,7 @@ mqtt_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) // nni_mtx_lock(&ep->mtx); nni_copyout_ptr(ep->connmsg, v, szp, t); - fprintf(stderr, "connmsgp [%p] v [%p] \n", ep->connmsg, v); +// fprintf(stderr, "connmsgp [%p] v [%p] \n", ep->connmsg, v); // ep->connmsg = NULL; // nni_mtx_unlock(&ep->mtx); rv = 0; @@ -1303,7 +1303,7 @@ mqtt_tcptran_ep_set_connmsg( nni_mtx_lock(&ep->mtx); nni_copyin_ptr(&ep->connmsg, v, sz, t); - fprintf(stderr, "set connmsg [%p] v [%p] \n", ep->connmsg, v); +// fprintf(stderr, "set connmsg [%p] v [%p] \n", ep->connmsg, v); nni_mtx_unlock(&ep->mtx); rv = 0; @@ -1380,7 +1380,7 @@ static const nni_option mqtt_tcptran_ep_opts[] = { .o_get = mqtt_tcptran_ep_get_url, }, { - .o_name = "connmsg", + .o_name = NNG_OPT_MQTT_CONNMSG, .o_get = mqtt_tcptran_ep_get_connmsg, .o_set = mqtt_tcptran_ep_set_connmsg, }, From 0d1e8b339e09deae1afc45b05adbcd88f0655471 Mon Sep 17 00:00:00 2001 From: eeff Date: Wed, 3 Nov 2021 17:19:11 +0800 Subject: [PATCH 116/180] Fix mqtt protocol pipe receive dead lock The bug was caused by user callback calling into the protocol while holding the lock, fix by moving callback invocation outside the critical section. --- src/sp/protocol/mqtt/mqtt_client.c | 67 ++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 74f4908fd..2e5e8b83a 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -5,7 +5,6 @@ // file was obtained (LICENSE.txt). A copy of the license may also be // found online at https://opensource.org/licenses/MIT. // -#include #include "core/nng_impl.h" @@ -319,7 +318,7 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) // accidental collision across restarts. nni_id_map_init(&p->send_unack, 0x0000u, 0xffffu, true); nni_id_map_init(&p->recv_unack, 0x0000u, 0xffffu, true); - nni_lmq_init(&p->recv_messages, 1024); // FIXME: remove hard code value + nni_lmq_init(&p->recv_messages, 128); // FIXME: remove hard code value return (0); } @@ -399,6 +398,23 @@ mqtt_pipe_get_next_packet_id(mqtt_pipe_t *p) return packet_id & 0xFFFF; } +static inline void +mqtt_pipe_recv_msgq_putq(mqtt_pipe_t *p, nni_msg *msg) +{ + if (0 != nni_lmq_putq(&p->recv_messages, msg)) { + // resize to ensure we do not lost messages + // TODO: add option to drop messages + if (0 != + nni_lmq_resize(&p->recv_messages, + nni_lmq_len(&p->recv_messages) * 2)) { + // drop the message when no memory available + nni_msg_free(msg); + return; + } + nni_lmq_putq(&p->recv_messages, msg); + } +} + // Keep alive timer callback to send ping request. static void mqtt_keep_alive_cb(void *arg) @@ -486,7 +502,7 @@ mqtt_send_cb(void *arg) // indicating a successful receipt of a QoS 2 message work->state = WORK_END; nni_id_remove(&p->recv_unack, work->packet_id); - nni_lmq_putq(&p->recv_messages, work->msg); + mqtt_pipe_recv_msgq_putq(p, work->msg); mqtt_run_recv_queue(s); work->msg = NULL; // ownership to the lmq work_reset(work); @@ -555,16 +571,21 @@ mqtt_send_cb(void *arg) return; } else if (WORK_END == work->state) { // good news, protocol state machine run to the end - if (NULL != work->user_aio) { - nni_aio_finish_sync(work->user_aio, 0, 0); - } + nni_aio *aio = work->user_aio; work_reset(work); + p->work = NULL; nni_list_append(&s->free_list, work); + mqtt_send_start(s); + nni_mtx_unlock(&s->mtx); + if (NULL != aio) { + nni_aio_finish(aio, 0, 0); + } + return; } - p->work = NULL; mqtt_send_start(s); nni_mtx_unlock(&s->mtx); + return; } static void @@ -633,8 +654,9 @@ mqtt_recv_cb(void *arg) nni_msg_free(msg); work = nni_id_get(&p->send_unack, packet_id); if (NULL == work) { + // ignore this message nni_mtx_unlock(&s->mtx); - nni_pipe_close(p->pipe); + // nni_pipe_close(p->pipe); return; } nni_id_remove(&p->send_unack, packet_id); @@ -681,7 +703,7 @@ mqtt_recv_cb(void *arg) // the transport handled sending the PUBCOMP for us work->state = WORK_END; nni_id_remove(&p->recv_unack, work->packet_id); - nni_lmq_putq(&p->recv_messages, work->msg); + mqtt_pipe_recv_msgq_putq(p, work->msg); mqtt_run_recv_queue(s); work->msg = msg; // ownership of work->msg to the lmq work_reset(work); // will release msg @@ -703,7 +725,7 @@ mqtt_recv_cb(void *arg) if (2 > qos) { // QoS 0, successful receipt // QoS 1, the transport handled sending a PUBACK - nni_lmq_putq(&p->recv_messages, msg); + mqtt_pipe_recv_msgq_putq(p, msg); mqtt_run_recv_queue(s); nni_mtx_unlock(&s->mtx); return; @@ -737,15 +759,18 @@ mqtt_recv_cb(void *arg) if (WORK_ERROR == work->state) { // protocol error, just close the connection - nni_aio_finish_error(work->user_aio, NNG_EPROTO); nni_mtx_unlock(&s->mtx); + nni_aio_finish_error(work->user_aio, NNG_EPROTO); nni_pipe_close(p->pipe); return; } else if (WORK_END == work->state) { // good news, protocol state machine run to the end - nni_aio_finish_sync(work->user_aio, 0, 0); + nni_aio *aio = work->user_aio; work_reset(work); nni_list_append(&s->free_list, work); + nni_mtx_unlock(&s->mtx); + nni_aio_finish(aio, 0, 0); + return; } nni_mtx_unlock(&s->mtx); @@ -753,12 +778,16 @@ mqtt_recv_cb(void *arg) return; } +// Note: This routine should be called with the sock lock held. static void mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) { - work_t *work; + mqtt_pipe_t *p = s->mqtt_pipe; + work_t * work; - nni_mtx_lock(&s->mtx); + if (NULL == p || nni_atomic_get_bool(&p->closed)) { + return; + } work = nni_list_first(&s->free_list); @@ -773,8 +802,6 @@ mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) nni_list_remove(&s->free_list, work); nni_list_append(&s->recv_queue, work); // enqueue to recv mqtt_run_recv_queue(s); - - nni_mtx_unlock(&s->mtx); } // Note: This routine should be called with the sock lock held. @@ -786,13 +813,13 @@ mqtt_run_recv_queue(mqtt_sock_t *s) nni_msg * msg; while (NULL != work) { - if (nni_lmq_getq(&p->recv_messages, &msg)) { + if (0 != nni_lmq_getq(&p->recv_messages, &msg)) { break; } nni_list_remove(&s->recv_queue, work); // nni_pipe_recv(p->pipe, &work->recv_aio); nni_aio_set_msg(work->user_aio, msg); - nni_aio_finish_sync(work->user_aio, 0, + nni_aio_finish(work->user_aio, 0, nni_msg_header_len(msg) + nni_msg_len(msg)); nni_list_append(&s->free_list, work); work = nni_list_first(&s->recv_queue); @@ -941,6 +968,8 @@ mqtt_ctx_recv(void *arg, nni_aio *aio) mqtt_ctx_t * ctx = arg; mqtt_sock_t *s = ctx->mqtt_sock; + nni_mtx_lock(&s->mtx); + if (nni_aio_begin(aio) != 0) { return; } @@ -951,6 +980,8 @@ mqtt_ctx_recv(void *arg, nni_aio *aio) } mqtt_recv_start(s, aio); + + nni_mtx_unlock(&s->mtx); } /****************************************************************************** From 42789a2c2c86f96a6dd1796da9cd226fab4c7846 Mon Sep 17 00:00:00 2001 From: eeff Date: Thu, 4 Nov 2021 23:34:06 +0800 Subject: [PATCH 117/180] Remove mqtt protocol pipe useless data member --- src/sp/protocol/mqtt/mqtt_client.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 2e5e8b83a..10f111864 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -95,7 +95,6 @@ struct mqtt_pipe_s { nni_atomic_int next_packet_id; // next packet id to use nni_pipe * pipe; mqtt_sock_t * mqtt_sock; - work_t * work; // work the pipe is sending work_t ping_work; // work to send a ping request nni_id_map send_unack; // send messages unacknowledged nni_id_map recv_unack; // recv messages unacknowledged @@ -305,7 +304,6 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) nni_atomic_set(&p->next_packet_id, 0); p->pipe = pipe; p->mqtt_sock = s; - p->work = NULL; // FIXME: passing keep alive timeout work_init(&p->ping_work, s, sock->retry, mqtt_keep_alive_cb); nni_mqtt_msg_alloc(&p->ping_work.msg, 0); @@ -377,7 +375,6 @@ mqtt_pipe_close(void *arg) nni_mtx_lock(&s->mtx); mqtt_sock_close(s); s->mqtt_pipe = NULL; - p->work = NULL; nni_aio_close(&p->send_aio); nni_aio_close(&p->recv_aio); work_close_queue(&s->send_queue); @@ -450,12 +447,13 @@ mqtt_timer_cb(void *arg) static void mqtt_send_cb(void *arg) { - mqtt_pipe_t *p = arg; - mqtt_sock_t *s = p->mqtt_sock; - work_t * work = p->work; + mqtt_pipe_t *p = arg; + mqtt_sock_t *s = p->mqtt_sock; + work_t * work; nni_mtx_lock(&s->mtx); + work = nni_list_first(&s->send_queue); // will not be NULL nni_list_remove(&s->send_queue, work); if (nni_aio_result(&p->send_aio) != 0) { @@ -573,7 +571,6 @@ mqtt_send_cb(void *arg) // good news, protocol state machine run to the end nni_aio *aio = work->user_aio; work_reset(work); - p->work = NULL; nni_list_append(&s->free_list, work); mqtt_send_start(s); nni_mtx_unlock(&s->mtx); @@ -891,7 +888,6 @@ mqtt_send_start(mqtt_sock_t *s) } nni_msg_clone(work->msg); - p->work = work; nni_aio_set_msg(&p->send_aio, work->msg); nni_pipe_send(p->pipe, &p->send_aio); } else { From 5fd6cb03fc0044e667ec516d31f7666e83afc52c Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Wed, 3 Nov 2021 15:56:41 +0800 Subject: [PATCH 118/180] * NEW [mqtt_async] add nng-style (with context) MQTT demo --- demo/mqtt_async/CMakeLists.txt | 17 ++ demo/mqtt_async/mqtt_async.c | 273 +++++++++++++++++++++++++++++++ src/mqtt/mqtt_codec.c | 2 +- src/mqtt/mqtt_test.c | 3 + src/sp/transport/mqtt/mqtt_tcp.c | 42 +++-- 5 files changed, 314 insertions(+), 23 deletions(-) create mode 100644 demo/mqtt_async/CMakeLists.txt create mode 100644 demo/mqtt_async/mqtt_async.c diff --git a/demo/mqtt_async/CMakeLists.txt b/demo/mqtt_async/CMakeLists.txt new file mode 100644 index 000000000..ca7d3caf6 --- /dev/null +++ b/demo/mqtt_async/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. + +cmake_minimum_required (VERSION 2.8.7) + +project(mqtt_async) + +find_package(nng CONFIG REQUIRED) + +find_package(Threads) + +add_executable(mqtt_async mqtt_async.c) +target_link_libraries(mqtt_async nng) +target_link_libraries(mqtt_async ${CMAKE_THREAD_LIBS_INIT}) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c new file mode 100644 index 000000000..93fea47d5 --- /dev/null +++ b/demo/mqtt_async/mqtt_async.c @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef PARALLEL +#define PARALLEL 4 +#endif + +static void subscribe(void *arg, nng_mqtt_topic_qos *array, uint32_t count); + +struct work { + enum { INIT, RECV, WAIT, SEND } state; + nng_aio *aio; + nng_msg *msg; + nng_ctx ctx; + uint32_t index; +}; + +#define SUB_TOPIC1 "/nanomq/msg/1" +#define SUB_TOPIC2 "/nanomq/msg/2" +#define SUB_TOPIC3 "/nanomq/msg/3" +#define SUB_TOPIC4 "/nanomq/msg/4" + +static nng_mqtt_topic_qos topic_qos[] = { + { .qos = 0, + .topic = { .buf = (uint8_t *) SUB_TOPIC1, + .length = strlen(SUB_TOPIC1) } }, + { .qos = 0, + .topic = { .buf = (uint8_t *) SUB_TOPIC2, + .length = strlen(SUB_TOPIC2) } }, + { .qos = 0, + .topic = { .buf = (uint8_t *) SUB_TOPIC3, + .length = strlen(SUB_TOPIC3) } }, + { .qos = 0, + .topic = { .buf = (uint8_t *) SUB_TOPIC4, + .length = strlen(SUB_TOPIC4) } } + +}; + +static size_t topic_qos_count = sizeof(topic_qos) / sizeof(nng_mqtt_topic_qos); + +void +fatal(const char *msg, int rv) +{ + fprintf(stderr, "%s: %s\n", msg, nng_strerror(rv)); + exit(1); +} + +void +client_cb(void *arg) +{ + struct work *work = arg; + nng_msg * msg; + int rv; + printf(" work[%d]: ", work->index); + size_t topic_index = 0; + + // uint8_t buff[1024] = { 0 }; + switch (work->state) { + case INIT: + printf("INIT\n"); + + if (work->index == 0) { + nng_mqtt_msg_alloc(&msg, 0); + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); + nng_mqtt_msg_set_subscribe_topics( + msg, topic_qos, topic_qos_count); + nng_mqtt_msg_encode(msg); + // nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); + // printf("%s\n", buff); + work->msg = msg; + nng_aio_set_msg(work->aio, work->msg); + work->msg = NULL; + work->state = SEND; + nng_ctx_send(work->ctx, work->aio); + } else { + work->state = RECV; + nng_ctx_recv(work->ctx, work->aio); + } + break; + case RECV: + printf("RECV\n"); + if ((rv = nng_aio_result(work->aio)) != 0) { + fatal("nng_recv_aio", rv); + } + msg = nng_aio_get_msg(work->aio); + + if (nng_mqtt_msg_decode(msg) != 0) { + printf("nng_mqtt_msg_decode failed"); + nng_msg_free(msg); + nng_ctx_recv(work->ctx, work->aio); + return; + } + + uint8_t buff[1024] = { 0 }; + nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); + printf("%s\n", buff); + + work->msg = msg; + work->state = WAIT; + // nng_sleep_aio(50, work->aio); + break; + case WAIT: + printf("WAIT\n"); + // We could add more data to the message here. + nng_aio_set_msg(work->aio, work->msg); + work->msg = NULL; + work->state = SEND; + nng_ctx_send(work->ctx, work->aio); + break; + case SEND: + printf("SEND\n"); + if ((rv = nng_aio_result(work->aio)) != 0) { + nng_msg_free(work->msg); + fatal("nng_send_aio", rv); + } + work->state = RECV; + nng_ctx_recv(work->ctx, work->aio); + break; + default: + fatal("bad state!", NNG_ESTATE); + break; + } +} + +struct work * +alloc_work(nng_socket sock, uint32_t index) +{ + struct work *w; + int rv; + + if ((w = nng_alloc(sizeof(*w))) == NULL) { + fatal("nng_alloc", NNG_ENOMEM); + } + if ((rv = nng_aio_alloc(&w->aio, client_cb, w)) != 0) { + fatal("nng_aio_alloc", rv); + } + if ((rv = nng_ctx_open(&w->ctx, sock)) != 0) { + fatal("nng_ctx_open", rv); + } + w->state = INIT; + w->index = index; + return (w); +} + +static void +connect_cb(void *arg, nng_msg *ackmsg) +{ + char * userarg = (char *) arg; + uint8_t status = nng_mqtt_msg_get_conack_return_code(ackmsg); + printf("Connected cb. \n" + " -> Status [%d]\n" + " -> Userarg [%p].\n", + status, userarg); + + // Free ConnAck msg + nng_msg_free(ackmsg); +} + +static void +subscribe(void *arg, nng_mqtt_topic_qos *array, uint32_t count) +{ + struct work *work = (struct work *) arg; + + int rv; + + // create a SUBSCRIBE message + nng_msg *submsg; + nng_mqtt_msg_alloc(&submsg, 0); + nng_mqtt_msg_set_packet_type(submsg, NNG_MQTT_SUBSCRIBE); + + nng_mqtt_msg_set_subscribe_topics(submsg, array, count); + + rv = nng_mqtt_msg_encode(submsg); + + if (rv != 0) { + fatal("problem on building SUBSCRIBE message: %d\n", rv); + } + + uint8_t buff[1024] = { 0 }; + + // nng_mqtt_msg_dump(submsg, buff, sizeof(buff), true); + // printf("%s\n", buff); + + printf("subscribing ..."); + work->msg = submsg; + + nng_aio_set_msg(work->aio, work->msg); + work->msg = NULL; + work->state = SEND; + nng_ctx_send(work->ctx, work->aio); + + printf("done.\n"); + + // nng_msg_free(submsg); +} + +int +client(const char *url) +{ + nng_socket sock; + nng_dialer dialer; + struct work *works[PARALLEL]; + int i; + int rv; + + if ((rv = nng_mqtt_client_open(&sock)) != 0) { + fatal("nng_socket", rv); + } + + for (i = 0; i < PARALLEL; i++) { + works[i] = alloc_work(sock, i); + } + + if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { + fatal("nng_dialer_create", rv); + } + + nng_msg *connmsg; + nng_mqtt_msg_alloc(&connmsg, 0); + nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); + nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); + nng_mqtt_msg_set_connect_user_name(connmsg, "alvin"); + nng_mqtt_msg_set_connect_password(connmsg, "HHH0000"); + nng_mqtt_msg_set_connect_clean_session(connmsg, true); + + rv = nng_mqtt_msg_encode(connmsg); + if (rv != 0) { + printf("nng_mqtt_msg_encode failed: %d\n", rv); + } + + // uint8_t dump[1024] = { 0 }; + // nng_mqtt_msg_dump(connmsg, dump, sizeof(dump), true); + // printf("%s\n", dump); + + nng_dialer_set_ptr(dialer, "connmsg", connmsg); + nng_dialer_setcb(dialer, connect_cb, works[0]); + nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); + + nng_msleep(1000); // neither pause() nor sleep() portable + + for (i = 0; i < PARALLEL; i++) { + client_cb(works[i]); // this starts them going (INIT state) + // nng_msleep(100); + } + + for (;;) { + nng_msleep(3600000); // neither pause() nor sleep() portable + } +} + +int +main(int argc, const char **argv) +{ + + int rc; + + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + client(argv[1]); + + return 0; +} \ No newline at end of file diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index 5d8215956..aecf66e9d 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -141,7 +141,7 @@ nni_mqtt_msg_encode_fixed_header(nni_msg *msg, nni_mqtt_proto_data *data) { uint8_t rlen[4] = { 0 }; struct pos_buf buf = { .curpos = &rlen[0], - .endpos = &rlen[sizeof(rlen) / sizeof(rlen[0]) - 1] }; + .endpos = &rlen[sizeof(rlen)] }; nni_msg_header_clear(msg); uint8_t header = *(uint8_t *) &data->fixed_header.common; diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 04d1c286e..e29295bd3 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -91,6 +91,9 @@ test_encode_connect(void) nng_mqtt_msg_dump(dup_msg, print_buf, 1024, true); printf("dup msg:\n%s\n", print_buf); + NUTS_ASSERT(memcmp(nng_msg_body(msg), nng_msg_body(dup_msg), + nng_msg_len(msg)) == 0); + nng_msg_free(msg); nng_msg_free(dup_msg); } diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index b184a49d4..18452cdd0 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -77,8 +77,8 @@ struct mqtt_tcptran_ep { nng_stream_listener *listener; nni_dialer * ndialer; void * connmsg; - void (*conncb)(void *, nng_msg *); - void * arg; + void (*conncb)(void *, nng_msg *); + void *arg; #ifdef NNG_ENABLE_STATS nni_stat_item st_rcv_max; @@ -296,9 +296,8 @@ mqtt_tcptran_pipe_nego_cb(void *arg) // receving fixed header if (p->gotrxhead == 0 || - (p->gotrxhead <= 5 && - p->rxlen[p->gotrxhead - 1] > 0x7f && - p->rxmsg == NULL)) { + (p->gotrxhead <= 5 && p->rxlen[p->gotrxhead - 1] > 0x7f && + p->rxmsg == NULL)) { nni_iov iov; iov.iov_buf = &p->rxlen[p->gotrxhead]; if (p->gotrxhead == 0) { @@ -312,17 +311,18 @@ mqtt_tcptran_pipe_nego_cb(void *arg) return; } // finish recevied fixed header - //TODO only deal with CONNACK, so just use rxlen at all time + // TODO only deal with CONNACK, so just use rxlen at all time if (p->rxmsg == NULL) { if ((p->rxlen[0] & 0x20) != 0x20) { - fprintf(stderr, "not recv connack [%x].\n", p->rxlen[0]); + fprintf( + stderr, "not recv connack [%x].\n", p->rxlen[0]); rv = NNG_EPROTO; goto error; } pos = 0; - if ((rv = mqtt_get_remaining_length(p->rxlen, - p->gotrxhead, (uint32_t *)&var_int, &pos)) != 0) { + if ((rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, + (uint32_t *) &var_int, &pos)) != 0) { goto error; } @@ -448,7 +448,7 @@ mqtt_tcptran_pipe_recv_cb(void *arg) mqtt_tcptran_pipe *p = arg; nni_aio * rxaio = p->rxaio; - printf("tcptran_pipe_recv_cb %p\n", p); + printf("mqtt_tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->recvq); @@ -563,11 +563,11 @@ mqtt_tcptran_pipe_recv_cb(void *arg) // keep connection & Schedule next receive // nni_pipe_bump_rx(p->npipe, n); mqtt_tcptran_pipe_recv_start(p); - nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, n); - printf("end of tcptran_pipe_recv_cb: synch! %p\n", p); + nni_mtx_unlock(&p->mtx); + printf("end of mqtt_tcptran_pipe_recv_cb: synch! %p\n", p); return; recv_error: @@ -579,12 +579,12 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_msg_free(msg); nni_aio_finish_error(aio, rv); - printf("tcptran_pipe_recv_cb: recv error rv: %d\n", rv); + printf("mqtt_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); return; notify: // nni_pipe_bump_rx(p->npipe, n); nni_aio_list_remove(aio); - tcptran_pipe_recv_start(p); + mqtt_tcptran_pipe_recv_start(p); nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, NULL); nni_aio_finish(aio, 0, 0); @@ -779,9 +779,9 @@ static void mqtt_tcptran_pipe_start( mqtt_tcptran_pipe *p, nng_stream *conn, mqtt_tcptran_ep *ep) { - nni_iov iov[2]; - nni_msg * connmsg; - int rv, niov = 0; + nni_iov iov[2]; + nni_msg *connmsg; + int rv, niov = 0; ep->refcnt++; @@ -804,7 +804,7 @@ mqtt_tcptran_pipe_start( // TODO TX length for MQTT 5 p->wantrxhead = 2; p->wanttxhead = nni_msg_header_len(connmsg) + nni_msg_len(connmsg); - p->rxmsg = NULL; + p->rxmsg = NULL; if (nni_msg_header_len(connmsg) > 0) { iov[niov].iov_buf = nni_msg_header(connmsg); @@ -1176,7 +1176,7 @@ mqtt_tcptran_ep_connect(void *arg, nni_aio *aio) { mqtt_tcptran_ep *ep = arg; int rv; - fprintf(stderr, "mqtt_tcptran_ep_connect\n"); + // fprintf(stderr, "mqtt_tcptran_ep_connect\n"); if (nni_aio_begin(aio) != 0) { return; @@ -1271,7 +1271,6 @@ mqtt_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) // nni_mtx_lock(&ep->mtx); nni_copyout_ptr(ep->connmsg, v, szp, t); -// fprintf(stderr, "connmsgp [%p] v [%p] \n", ep->connmsg, v); // ep->connmsg = NULL; // nni_mtx_unlock(&ep->mtx); rv = 0; @@ -1287,7 +1286,7 @@ mqtt_tcptran_dialer_setcb(void *arg, void (*cb)(void *, nng_msg *), void *args) nni_mtx_lock(&ep->mtx); ep->conncb = cb; - ep->arg = args; + ep->arg = args; nni_mtx_unlock(&ep->mtx); rv = 0; @@ -1303,7 +1302,6 @@ mqtt_tcptran_ep_set_connmsg( nni_mtx_lock(&ep->mtx); nni_copyin_ptr(&ep->connmsg, v, sz, t); -// fprintf(stderr, "set connmsg [%p] v [%p] \n", ep->connmsg, v); nni_mtx_unlock(&ep->mtx); rv = 0; From 2bdc5d268c1fc8b86acafd50fa37a4c08070c81b Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Thu, 4 Nov 2021 12:21:13 +0800 Subject: [PATCH 119/180] * FIX [mqtt_tcp] handle received invalid packet & update mqtt_async demo --- demo/mqtt_async/mqtt_async.c | 62 ++++++++------------------------ src/mqtt/mqtt_codec.c | 21 +++++++++-- src/mqtt/mqtt_test.c | 27 ++++++++++++++ src/sp/transport/mqtt/mqtt_tcp.c | 8 ++--- 4 files changed, 64 insertions(+), 54 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index 93fea47d5..0076de224 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -10,7 +10,7 @@ #include #ifndef PARALLEL -#define PARALLEL 4 +#define PARALLEL 32 #endif static void subscribe(void *arg, nng_mqtt_topic_qos *array, uint32_t count); @@ -66,7 +66,6 @@ client_cb(void *arg) switch (work->state) { case INIT: printf("INIT\n"); - if (work->index == 0) { nng_mqtt_msg_alloc(&msg, 0); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); @@ -99,13 +98,20 @@ client_cb(void *arg) return; } - uint8_t buff[1024] = { 0 }; - nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); - printf("%s\n", buff); + printf("packet type: %d\n", nng_mqtt_msg_get_packet_type(msg)); + + nng_msg_free(msg); + work->msg = NULL; + work->state = RECV; + nng_ctx_recv(work->ctx, work->aio); + + // uint8_t buff[1024] = { 0 }; + // nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); + // printf("%s\n", buff); - work->msg = msg; - work->state = WAIT; - // nng_sleep_aio(50, work->aio); + // work->msg = msg; + // work->state = WAIT; + // nng_sleep_aio(1, work->aio); break; case WAIT: printf("WAIT\n"); @@ -164,44 +170,6 @@ connect_cb(void *arg, nng_msg *ackmsg) nng_msg_free(ackmsg); } -static void -subscribe(void *arg, nng_mqtt_topic_qos *array, uint32_t count) -{ - struct work *work = (struct work *) arg; - - int rv; - - // create a SUBSCRIBE message - nng_msg *submsg; - nng_mqtt_msg_alloc(&submsg, 0); - nng_mqtt_msg_set_packet_type(submsg, NNG_MQTT_SUBSCRIBE); - - nng_mqtt_msg_set_subscribe_topics(submsg, array, count); - - rv = nng_mqtt_msg_encode(submsg); - - if (rv != 0) { - fatal("problem on building SUBSCRIBE message: %d\n", rv); - } - - uint8_t buff[1024] = { 0 }; - - // nng_mqtt_msg_dump(submsg, buff, sizeof(buff), true); - // printf("%s\n", buff); - - printf("subscribing ..."); - work->msg = submsg; - - nng_aio_set_msg(work->aio, work->msg); - work->msg = NULL; - work->state = SEND; - nng_ctx_send(work->ctx, work->aio); - - printf("done.\n"); - - // nng_msg_free(submsg); -} - int client(const char *url) { @@ -241,7 +209,7 @@ client(const char *url) // printf("%s\n", dump); nng_dialer_set_ptr(dialer, "connmsg", connmsg); - nng_dialer_setcb(dialer, connect_cb, works[0]); + // nng_dialer_setcb(dialer, connect_cb, works[0]); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); nng_msleep(1000); // neither pause() nor sleep() portable diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index aecf66e9d..f63feffc2 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -874,6 +874,13 @@ nni_mqtt_msg_decode_pubrel(nni_msg *msg) { nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + if (!mqtt->fixed_header.common.bit_0 && + mqtt->fixed_header.common.bit_1 && + !mqtt->fixed_header.common.bit_2 && + !mqtt->fixed_header.common.bit_3) { + return MQTT_ERR_PROTOCOL; + } + return nni_mqtt_msg_decode_base_with_packet_id( msg, &mqtt->var_header.pubrel.packet_id); } @@ -890,9 +897,17 @@ nni_mqtt_msg_decode_pubcomp(nni_msg *msg) static int nni_mqtt_msg_decode_unsubscribe(nni_msg *msg) { - nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - uint8_t * body = nni_msg_body(msg); - size_t length = nni_msg_len(msg); + nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); + + if (!mqtt->fixed_header.common.bit_0 && + mqtt->fixed_header.common.bit_1 && + !mqtt->fixed_header.common.bit_2 && + !mqtt->fixed_header.common.bit_3) { + return MQTT_ERR_PROTOCOL; + } + + uint8_t *body = nni_msg_body(msg); + size_t length = nni_msg_len(msg); struct pos_buf buf; buf.curpos = &body[0]; diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index e29295bd3..f540b9796 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -50,6 +50,32 @@ test_dup(void) nng_msg_free(msg2); } +// FIXME remove later +void +test_get_remaining_length(void) +{ + uint8_t invalid_buf[] = { 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x61, 0x61 }; + + uint32_t len; + uint8_t used_bytes; + + mqtt_get_remaining_length( + invalid_buf, sizeof(invalid_buf), &len, &used_bytes); + + NUTS_ASSERT(len == 97); + NUTS_ASSERT(used_bytes == 1); +} + void test_encode_connect(void) { @@ -494,6 +520,7 @@ test_decode_disconnect(void) TEST_LIST = { { "alloc message", test_alloc }, { "dup message", test_dup }, + { "remain length", test_get_remaining_length }, { "encode connect", test_encode_connect }, { "encode conack", test_encode_connack }, { "encode publish", test_encode_publish }, diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 18452cdd0..70204dc47 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -441,14 +441,14 @@ mqtt_tcptran_pipe_recv_cb(void *arg) { nni_aio * aio; nni_iov iov; - uint8_t type, pos = 0; + uint8_t type, pos, flags; uint32_t len = 0, rv; size_t n; nni_msg * msg; mqtt_tcptran_pipe *p = arg; nni_aio * rxaio = p->rxaio; - printf("mqtt_tcptran_pipe_recv_cb %p\n", p); + // printf("mqtt_tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->recvq); @@ -514,6 +514,7 @@ mqtt_tcptran_pipe_recv_cb(void *arg) p->rxmsg = NULL; n = nni_msg_len(msg); type = p->rxlen[0] & 0xf0; + flags = p->rxlen[0] & 0x0f; // set the payload pointer of msg according to packet_type if (type == 0x30) { uint8_t qos_pac; @@ -547,7 +548,7 @@ mqtt_tcptran_pipe_recv_cb(void *arg) // send it down... nni_aio_set_iov(p->qsaio, 1, &iov); nng_stream_send(p->conn, p->qsaio); - } else if (type == 0x60) { + } else if (type == 0x60 && flags == 0x02) { nng_aio_wait(p->rpaio); p->txlen[0] = 0x70; p->txlen[1] = 0x02; @@ -567,7 +568,6 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, n); nni_mtx_unlock(&p->mtx); - printf("end of mqtt_tcptran_pipe_recv_cb: synch! %p\n", p); return; recv_error: From a2734e44b66b13063c940ffeb527fc6b04460a9e Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Thu, 4 Nov 2021 17:01:16 +0800 Subject: [PATCH 120/180] * FIX [mqtt_codec] decode pubrel/unsubscribe * MDF [mqtt_async] publish message after receiving data --- demo/mqtt_async/mqtt_async.c | 36 ++++----- src/mqtt/mqtt_codec.c | 16 ++-- src/mqtt/mqtt_test.c | 134 +++++++++++++------------------ src/sp/transport/mqtt/mqtt_tcp.c | 2 +- 4 files changed, 83 insertions(+), 105 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index 0076de224..bdfd0747f 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -59,13 +59,10 @@ client_cb(void *arg) struct work *work = arg; nng_msg * msg; int rv; - printf(" work[%d]: ", work->index); - size_t topic_index = 0; - // uint8_t buff[1024] = { 0 }; switch (work->state) { case INIT: - printf("INIT\n"); + printf("INIT: work[%02d]\n", work->index); if (work->index == 0) { nng_mqtt_msg_alloc(&msg, 0); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); @@ -85,7 +82,6 @@ client_cb(void *arg) } break; case RECV: - printf("RECV\n"); if ((rv = nng_aio_result(work->aio)) != 0) { fatal("nng_recv_aio", rv); } @@ -98,23 +94,24 @@ client_cb(void *arg) return; } - printf("packet type: %d\n", nng_mqtt_msg_get_packet_type(msg)); + work->msg = msg; + work->state = WAIT; + nng_sleep_aio(1, work->aio); + break; + case WAIT: + nng_msg_header_clear(work->msg); + nng_msg_clear(work->msg); - nng_msg_free(msg); - work->msg = NULL; - work->state = RECV; - nng_ctx_recv(work->ctx, work->aio); + char topic[50] = { 0 }; - // uint8_t buff[1024] = { 0 }; - // nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); - // printf("%s\n", buff); + snprintf(topic, 50, "/nanomq/msg/%02d/rep", work->index); - // work->msg = msg; - // work->state = WAIT; - // nng_sleep_aio(1, work->aio); - break; - case WAIT: - printf("WAIT\n"); + nng_mqtt_msg_set_packet_type(work->msg, NNG_MQTT_PUBLISH); + nng_mqtt_msg_set_publish_topic(work->msg, topic); + nng_mqtt_msg_set_publish_payload( + work->msg, (uint8_t *) topic, strlen(topic)); + + nng_mqtt_msg_encode(work->msg); // We could add more data to the message here. nng_aio_set_msg(work->aio, work->msg); work->msg = NULL; @@ -122,7 +119,6 @@ client_cb(void *arg) nng_ctx_send(work->ctx, work->aio); break; case SEND: - printf("SEND\n"); if ((rv = nng_aio_result(work->aio)) != 0) { nng_msg_free(work->msg); fatal("nng_send_aio", rv); diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index f63feffc2..1df243ce1 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -874,10 +874,10 @@ nni_mqtt_msg_decode_pubrel(nni_msg *msg) { nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - if (!mqtt->fixed_header.common.bit_0 && - mqtt->fixed_header.common.bit_1 && - !mqtt->fixed_header.common.bit_2 && - !mqtt->fixed_header.common.bit_3) { + if (mqtt->fixed_header.common.bit_0 != 0 || + mqtt->fixed_header.common.bit_1 != 1 || + mqtt->fixed_header.common.bit_2 != 0 || + mqtt->fixed_header.common.bit_3 != 0) { return MQTT_ERR_PROTOCOL; } @@ -899,10 +899,10 @@ nni_mqtt_msg_decode_unsubscribe(nni_msg *msg) { nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - if (!mqtt->fixed_header.common.bit_0 && - mqtt->fixed_header.common.bit_1 && - !mqtt->fixed_header.common.bit_2 && - !mqtt->fixed_header.common.bit_3) { + if (mqtt->fixed_header.common.bit_0 != 0 || + mqtt->fixed_header.common.bit_1 != 1 || + mqtt->fixed_header.common.bit_2 != 0 || + mqtt->fixed_header.common.bit_3 != 0) { return MQTT_ERR_PROTOCOL; } diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index f540b9796..b85aec0ee 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -5,6 +5,26 @@ #include "mqtt.h" #include "nuts.h" +#define MQTT_MSG_DUMP 0 + +#if MQTT_MSG_DUMP +static void +#define DUMP_LENGTH 2048 +print_mqtt_msg(nng_msg *msg) +{ + uint8_t print_buf[DUMP_LENGTH] = { 0 }; + nng_mqtt_msg_dump(msg, print_buf, DUMP_LENGTH, true); + printf("\nmsg: \n%s\n", (char *) print_buf); +} +#else +static void +print_mqtt_msg(nng_msg *msg) +{ + NNI_ARG_UNUSED(msg); + return; +} +#endif + void test_alloc(void) { @@ -39,12 +59,14 @@ test_dup(void) nng_msg *msg2; NUTS_PASS(nng_msg_dup(&msg2, msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("msg: \n%s\n", print_buf); + print_mqtt_msg(msg); + print_mqtt_msg(msg2); - nng_mqtt_msg_dump(msg2, print_buf, 1024, true); - printf("msg2: \n%s\n", print_buf); + NUTS_ASSERT(memcmp(nng_msg_header(msg), nng_msg_header(msg2), + nng_msg_header_len(msg)) == 0); + + NUTS_ASSERT(memcmp(nng_msg_body(msg), nng_msg_body(msg2), + nng_msg_len(msg)) == 0); nng_msg_free(msg); nng_msg_free(msg2); @@ -69,8 +91,8 @@ test_get_remaining_length(void) uint32_t len; uint8_t used_bytes; - mqtt_get_remaining_length( - invalid_buf, sizeof(invalid_buf), &len, &used_bytes); + NUTS_ASSERT(mqtt_get_remaining_length(invalid_buf, sizeof(invalid_buf), + &len, &used_bytes) == 0); NUTS_ASSERT(len == 97); NUTS_ASSERT(used_bytes == 1); @@ -86,9 +108,9 @@ test_encode_connect(void) nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); - // nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); - // NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), - // "nanomq-mqtt") == 0); + nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); + NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), + "nanomq-mqtt") == 0); char will_topic[] = "/nanomq/will_msg"; nng_mqtt_msg_set_connect_will_topic(msg, will_topic); @@ -96,8 +118,8 @@ test_encode_connect(void) char will_msg[] = "Bye-bye"; nng_mqtt_msg_set_connect_will_msg(msg, will_msg); - char user[] = "alvin"; - char passwd[] = "HHH0000"; + char user[] = "nanomq"; + char passwd[] = "nanomq"; nng_mqtt_msg_set_connect_user_name(msg, user); nng_mqtt_msg_set_connect_password(msg, passwd); @@ -105,23 +127,19 @@ test_encode_connect(void) nng_mqtt_msg_set_connect_keep_alive(msg, 60); NUTS_PASS(nng_mqtt_msg_encode(msg)); + print_mqtt_msg(msg); - nng_msg *dup_msg; - nng_msg_dup(&dup_msg, msg); - NUTS_PASS(nng_mqtt_msg_decode(dup_msg)); + nng_msg *decode_msg; + nng_msg_dup(&decode_msg, msg); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("msg:\n%s\n", print_buf); + NUTS_PASS(nng_mqtt_msg_decode(decode_msg)); + print_mqtt_msg(decode_msg); - nng_mqtt_msg_dump(dup_msg, print_buf, 1024, true); - printf("dup msg:\n%s\n", print_buf); - - NUTS_ASSERT(memcmp(nng_msg_body(msg), nng_msg_body(dup_msg), + NUTS_ASSERT(memcmp(nng_msg_body(msg), nng_msg_body(decode_msg), nng_msg_len(msg)) == 0); nng_msg_free(msg); - nng_msg_free(dup_msg); + nng_msg_free(decode_msg); } void @@ -140,9 +158,7 @@ test_encode_connack(void) NUTS_PASS(nng_mqtt_msg_encode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } @@ -172,8 +188,8 @@ test_encode_publish(void) char will_msg[] = "Bye-bye"; nng_mqtt_msg_set_connect_will_msg(msg, will_msg); - char user[] = "alvin"; - char passwd[] = "HHH0000"; + char user[] = "nanomq"; + char passwd[] = "nanomq"; nng_mqtt_msg_set_connect_user_name(msg, user); nng_mqtt_msg_set_connect_password(msg, passwd); @@ -182,9 +198,8 @@ test_encode_publish(void) NUTS_PASS(nng_mqtt_msg_encode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); + nng_msg_free(msg); } @@ -200,9 +215,7 @@ test_encode_puback(void) NUTS_PASS(nng_mqtt_msg_encode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } @@ -230,10 +243,7 @@ test_encode_subscribe(void) NUTS_PASS(nng_mqtt_msg_encode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } @@ -254,9 +264,7 @@ test_encode_suback(void) NUTS_PASS(nng_mqtt_msg_encode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } @@ -281,10 +289,7 @@ test_encode_unsubscribe(void) msg, topic_qos, sizeof(topic_qos) / sizeof(nng_mqtt_topic)); NUTS_PASS(nng_mqtt_msg_encode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } @@ -299,9 +304,7 @@ test_encode_disconnect(void) NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); NUTS_PASS(nng_mqtt_msg_encode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } @@ -331,9 +334,8 @@ test_decode_connect(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); + nng_msg_free(msg); } @@ -396,9 +398,7 @@ test_decode_publish(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[2048] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 2048, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } @@ -418,9 +418,7 @@ test_decode_puback(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } @@ -444,19 +442,12 @@ test_decode_subscribe(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); uint32_t count; nng_mqtt_topic_qos *tq = nng_mqtt_msg_get_subscribe_topics(msg, &count); - for (size_t i = 0; i < count; i++) { - printf("[%ld]: %.*s, qos: %d\n", i, tq[i].topic.length, - (char *) tq[i].topic.buf, tq[i].qos); - } - nng_free(tq, count * sizeof(nng_mqtt_topic_qos)); nng_msg_free(msg); @@ -481,19 +472,12 @@ test_decode_unsubscribe(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); uint32_t count; nng_mqtt_topic *topics = nng_mqtt_msg_get_unsubscribe_topics(msg, &count); - for (size_t i = 0; i < count; i++) { - printf("[%ld]: %.*s\n", i, topics[i].length, - (char *) topics[i].buf); - } - nng_msg_free(msg); nni_free(topics, count * sizeof(nng_mqtt_topic)); } @@ -511,9 +495,7 @@ test_decode_disconnect(void) NUTS_PASS(nng_mqtt_msg_decode(msg)); - uint8_t print_buf[1024] = { 0 }; - nng_mqtt_msg_dump(msg, print_buf, 1024, true); - printf("%s\n", print_buf); + print_mqtt_msg(msg); nng_msg_free(msg); } diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 70204dc47..0f3f68e09 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -400,7 +400,7 @@ mqtt_tcptran_pipe_send_cb(void *arg) nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->sendq); - fprintf(stderr, "mqtt_tcptran_pipe_send_cb.\n"); + // fprintf(stderr, "mqtt_tcptran_pipe_send_cb.\n"); if ((rv = nni_aio_result(txaio)) != 0) { nni_pipe_bump_error(p->npipe, rv); From 65cd616aecb24c3efaa63ffd85aa903624799b5d Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Fri, 5 Nov 2021 15:38:11 +0800 Subject: [PATCH 121/180] * MDF [mqtt] nng_mqtt_msg_get_publish_topic() & demo/mqtt_async --- demo/mqtt_async/mqtt_async.c | 77 ++++++++++++++++-------------------- include/nng/nng.h | 7 ++-- src/mqtt/mqtt.c | 3 +- src/mqtt/mqtt.h | 2 +- src/nng.c | 8 ++-- 5 files changed, 46 insertions(+), 51 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index bdfd0747f..5978f1661 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -9,12 +9,13 @@ #include #include +// Can't be modified +#define NNG_MQTT_CONNECT_MSG "connmsg" + #ifndef PARALLEL #define PARALLEL 32 #endif -static void subscribe(void *arg, nng_mqtt_topic_qos *array, uint32_t count); - struct work { enum { INIT, RECV, WAIT, SEND } state; nng_aio *aio; @@ -28,6 +29,7 @@ struct work { #define SUB_TOPIC3 "/nanomq/msg/3" #define SUB_TOPIC4 "/nanomq/msg/4" +// Mqtt subscribe array of topic with qos static nng_mqtt_topic_qos topic_qos[] = { { .qos = 0, .topic = { .buf = (uint8_t *) SUB_TOPIC1, @@ -41,7 +43,6 @@ static nng_mqtt_topic_qos topic_qos[] = { { .qos = 0, .topic = { .buf = (uint8_t *) SUB_TOPIC4, .length = strlen(SUB_TOPIC4) } } - }; static size_t topic_qos_count = sizeof(topic_qos) / sizeof(nng_mqtt_topic_qos); @@ -62,15 +63,13 @@ client_cb(void *arg) switch (work->state) { case INIT: - printf("INIT: work[%02d]\n", work->index); if (work->index == 0) { + // Send subscribe message by work[0] nng_mqtt_msg_alloc(&msg, 0); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); nng_mqtt_msg_set_subscribe_topics( msg, topic_qos, topic_qos_count); nng_mqtt_msg_encode(msg); - // nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); - // printf("%s\n", buff); work->msg = msg; nng_aio_set_msg(work->aio, work->msg); work->msg = NULL; @@ -86,13 +85,21 @@ client_cb(void *arg) fatal("nng_recv_aio", rv); } msg = nng_aio_get_msg(work->aio); - if (nng_mqtt_msg_decode(msg) != 0) { printf("nng_mqtt_msg_decode failed"); nng_msg_free(msg); nng_ctx_recv(work->ctx, work->aio); return; } + uint32_t payload_len; + uint8_t *payload = + nng_mqtt_msg_get_publish_payload(msg, &payload_len); + uint32_t topic_len; + const char *recv_topic = + nng_mqtt_msg_get_publish_topic(msg, &topic_len); + + printf("Recv '%.*s' from topic '%.*s'\n", payload_len, + (char *) payload, topic_len, recv_topic); work->msg = msg; work->state = WAIT; @@ -101,18 +108,15 @@ client_cb(void *arg) case WAIT: nng_msg_header_clear(work->msg); nng_msg_clear(work->msg); - + // Send message to another topic char topic[50] = { 0 }; - snprintf(topic, 50, "/nanomq/msg/%02d/rep", work->index); - nng_mqtt_msg_set_packet_type(work->msg, NNG_MQTT_PUBLISH); nng_mqtt_msg_set_publish_topic(work->msg, topic); nng_mqtt_msg_set_publish_payload( work->msg, (uint8_t *) topic, strlen(topic)); - nng_mqtt_msg_encode(work->msg); - // We could add more data to the message here. + nng_aio_set_msg(work->aio, work->msg); work->msg = NULL; work->state = SEND; @@ -152,18 +156,14 @@ alloc_work(nng_socket sock, uint32_t index) return (w); } +// Connack message callback function static void -connect_cb(void *arg, nng_msg *ackmsg) +connect_cb(void *arg, nng_msg *msg) { - char * userarg = (char *) arg; - uint8_t status = nng_mqtt_msg_get_conack_return_code(ackmsg); - printf("Connected cb. \n" - " -> Status [%d]\n" - " -> Userarg [%p].\n", - status, userarg); - - // Free ConnAck msg - nng_msg_free(ackmsg); + (void) arg; + printf( + "connack status: %d\n", nng_mqtt_msg_get_conack_return_code(msg)); + nng_msg_free(msg); } int @@ -187,32 +187,25 @@ client(const char *url) fatal("nng_dialer_create", rv); } - nng_msg *connmsg; - nng_mqtt_msg_alloc(&connmsg, 0); - nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); - nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); - nng_mqtt_msg_set_connect_user_name(connmsg, "alvin"); - nng_mqtt_msg_set_connect_password(connmsg, "HHH0000"); - nng_mqtt_msg_set_connect_clean_session(connmsg, true); - - rv = nng_mqtt_msg_encode(connmsg); - if (rv != 0) { - printf("nng_mqtt_msg_encode failed: %d\n", rv); - } + // Mqtt connect message + nng_msg *msg; + nng_mqtt_msg_alloc(&msg, 0); + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); + nng_mqtt_msg_set_connect_keep_alive(msg, 60); + nng_mqtt_msg_set_connect_clean_session(msg, true); - // uint8_t dump[1024] = { 0 }; - // nng_mqtt_msg_dump(connmsg, dump, sizeof(dump), true); - // printf("%s\n", dump); + if ((rv = nng_mqtt_msg_encode(msg)) != 0) { + fprintf(stderr, "nng_mqtt_msg_encode failed: %d\n", rv); + } - nng_dialer_set_ptr(dialer, "connmsg", connmsg); - // nng_dialer_setcb(dialer, connect_cb, works[0]); + nng_dialer_set_ptr(dialer, NNG_MQTT_CONNECT_MSG, msg); + nng_dialer_set_cb(dialer, connect_cb, NULL); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); - nng_msleep(1000); // neither pause() nor sleep() portable + nng_msleep(1000); for (i = 0; i < PARALLEL; i++) { - client_cb(works[i]); // this starts them going (INIT state) - // nng_msleep(100); + client_cb(works[i]); } for (;;) { diff --git a/include/nng/nng.h b/include/nng/nng.h index f2fd0650e..6ec802875 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -279,8 +279,9 @@ NNG_DECL int nng_dialer_create(nng_dialer *, nng_socket, const char *); // nng_listener_create creates a new listener, that is not yet started. NNG_DECL int nng_listener_create(nng_listener *, nng_socket, const char *); -// nng_dialer_setcb set the cb to the dialer. Cb runs when dialer finished. -NNG_DECL int nng_dialer_setcb(nng_dialer, void (*)(void *, nng_msg *), void *); +// nng_dialer_set_cb set the cb to the dialer. Cb runs when dialer finished. +NNG_DECL int nng_dialer_set_cb( + nng_dialer, void (*)(void *, nng_msg *), void *); // nng_dialer_start starts the endpoint dialing. This is only possible if // the dialer is not already dialing. @@ -1352,7 +1353,7 @@ NNG_DECL bool nng_mqtt_msg_get_publish_retain(nng_msg *); NNG_DECL void nng_mqtt_msg_set_publish_dup(nng_msg *, bool); NNG_DECL bool nng_mqtt_msg_get_publish_dup(nng_msg *); NNG_DECL void nng_mqtt_msg_set_publish_topic(nng_msg *, const char *); -NNG_DECL const char *nng_mqtt_msg_get_publish_topic(nng_msg *); +NNG_DECL const char *nng_mqtt_msg_get_publish_topic(nng_msg *, uint32_t *); NNG_DECL void nng_mqtt_msg_set_publish_payload(nng_msg *, uint8_t *, uint32_t); NNG_DECL uint8_t *nng_mqtt_msg_get_publish_payload(nng_msg *, uint32_t *); NNG_DECL nng_mqtt_topic_qos *nng_mqtt_msg_get_subscribe_topics( diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index c2d358ae1..0cf140d47 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -198,9 +198,10 @@ nni_mqtt_msg_set_publish_topic(nni_msg *msg, const char *topic) } const char * -nni_mqtt_msg_get_publish_topic(nni_msg *msg) +nni_mqtt_msg_get_publish_topic(nni_msg *msg, uint32_t *topic_len) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + *topic_len = proto_data->var_header.publish.topic_name.length; return (const char *) proto_data->var_header.publish.topic_name.buf; } diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index 8da7fdf50..bb2342c81 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -299,7 +299,7 @@ extern bool nni_mqtt_msg_get_publish_retain(nni_msg *); extern void nni_mqtt_msg_set_publish_dup(nni_msg *, bool); extern bool nni_mqtt_msg_get_publish_dup(nni_msg *); extern void nni_mqtt_msg_set_publish_topic(nni_msg *, const char *); -extern const char *nni_mqtt_msg_get_publish_topic(nni_msg *); +extern const char *nni_mqtt_msg_get_publish_topic(nni_msg *, uint32_t *); extern void nni_mqtt_msg_set_publish_packet_id(nni_msg *, uint16_t); extern uint16_t nni_mqtt_msg_get_publish_packet_id(nni_msg *); extern void nni_mqtt_msg_set_publish_payload(nni_msg *, uint8_t *, uint32_t); diff --git a/src/nng.c b/src/nng.c index 4677abb72..3bff9c78e 100644 --- a/src/nng.c +++ b/src/nng.c @@ -579,7 +579,7 @@ nng_dialer_create(nng_dialer *dp, nng_socket sid, const char *addr) } int -nng_dialer_setcb(nng_dialer did, void (*cb)(void *, nng_msg *), void *arg) +nng_dialer_set_cb(nng_dialer did, void (*cb)(void *, nng_msg *), void *arg) { nni_dialer *d; int rv; @@ -2127,9 +2127,9 @@ nng_mqtt_msg_set_publish_topic(nng_msg *msg, const char *topic) } const char * -nng_mqtt_msg_get_publish_topic(nng_msg *msg) +nng_mqtt_msg_get_publish_topic(nng_msg *msg, uint32_t *topic_len) { - return nni_mqtt_msg_get_publish_topic(msg); + return nni_mqtt_msg_get_publish_topic(msg, topic_len); } void @@ -2316,7 +2316,7 @@ nng_mqtt_topic_array_free(nng_mqtt_topic *topic, size_t n) nng_mqtt_topic_qos * nng_mqtt_topic_qos_array_create(size_t n) { - return nni_mqtt_topic_qos_array_create(n); + return nni_mqtt_topic_qos_array_create(n); } void From 739302960f1b763be2b12a1925f35c0ddd997753 Mon Sep 17 00:00:00 2001 From: alvin Date: Fri, 5 Nov 2021 18:54:53 +0800 Subject: [PATCH 122/180] * NEW [docs/man] Update MQTT message docs --- docs/man/libnng.3.adoc | 20 ++++++ docs/man/nng_mqtt_msg_alloc.3.adoc | 57 +++++++++++++++ docs/man/nng_mqtt_msg_decode.3.adoc | 54 ++++++++++++++ docs/man/nng_mqtt_msg_encode.3.adoc | 54 ++++++++++++++ docs/man/nng_mqtt_msg_get_connect.3.adoc | 75 +++++++++++++++++++ docs/man/nng_mqtt_msg_get_packet_type.3.adoc | 76 ++++++++++++++++++++ docs/man/nng_mqtt_msg_get_publish.3.adoc | 68 ++++++++++++++++++ docs/man/nng_mqtt_msg_get_subscribe.3.adoc | 64 +++++++++++++++++ docs/man/nng_mqtt_msg_get_unsubscribe.3.adoc | 64 +++++++++++++++++ docs/man/nng_mqtt_msg_set_connect.3.adoc | 75 +++++++++++++++++++ docs/man/nng_mqtt_msg_set_packet_type.3.adoc | 76 ++++++++++++++++++++ docs/man/nng_mqtt_msg_set_publish.3.adoc | 68 ++++++++++++++++++ docs/man/nng_mqtt_msg_set_subscribe.3.adoc | 64 +++++++++++++++++ docs/man/nng_mqtt_msg_set_unsubscribe.3.adoc | 64 +++++++++++++++++ 14 files changed, 879 insertions(+) create mode 100644 docs/man/nng_mqtt_msg_alloc.3.adoc create mode 100644 docs/man/nng_mqtt_msg_decode.3.adoc create mode 100644 docs/man/nng_mqtt_msg_encode.3.adoc create mode 100644 docs/man/nng_mqtt_msg_get_connect.3.adoc create mode 100644 docs/man/nng_mqtt_msg_get_packet_type.3.adoc create mode 100644 docs/man/nng_mqtt_msg_get_publish.3.adoc create mode 100644 docs/man/nng_mqtt_msg_get_subscribe.3.adoc create mode 100644 docs/man/nng_mqtt_msg_get_unsubscribe.3.adoc create mode 100644 docs/man/nng_mqtt_msg_set_connect.3.adoc create mode 100644 docs/man/nng_mqtt_msg_set_packet_type.3.adoc create mode 100644 docs/man/nng_mqtt_msg_set_publish.3.adoc create mode 100644 docs/man/nng_mqtt_msg_set_subscribe.3.adoc create mode 100644 docs/man/nng_mqtt_msg_set_unsubscribe.3.adoc diff --git a/docs/man/libnng.3.adoc b/docs/man/libnng.3.adoc index 712bf0fb9..226ec8941 100644 --- a/docs/man/libnng.3.adoc +++ b/docs/man/libnng.3.adoc @@ -136,6 +136,26 @@ mode may need to access the header of messages. |xref:nng_msg_header_trim.3.adoc[nng_msg_header_trim()]|remove data from start of message header |=== +==== MQTT Message Handling + +TIP: + +|=== +|xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc()]|allocate a message with proto_data for mqtt +|xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode()]|decode a mqtt bytes stream from nng_msg_body and nng_msg_header to proto_data +|xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode()]|encode a mqtt message from proto_data to nng_msg_body and nng_msg_header +|xref:nng_mqtt_msg_get_connect.3.adoc[nng_mqtt_msg_get_connect()]|get mqtt connect message +|xref:nng_mqtt_msg_get_packet_type.3.adoc[nng_mqtt_msg_get_packet_type()]|get mqtt packet type +|xref:nng_mqtt_msg_get_publish.3.adoc[nng_mqtt_msg_get_publish()]|get mqtt publish message +|xref:nng_mqtt_msg_get_subscribe.3.adoc[nng_mqtt_msg_get_subscribe()]|get mqtt subscribe message +|xref:nng_mqtt_msg_get_unsubscribe.3.adoc[nng_mqtt_msg_get_unsubscribe()]|get mqtt unsubscribe message +|xref:nng_mqtt_msg_set_connect.3.adoc[nng_mqtt_msg_set_connect()]|set mqtt connect message +|xref:nng_mqtt_msg_set_packet_type.3.adoc[nng_mqtt_msg_set_packet_type()]|set mqtt packet type +|xref:nng_mqtt_msg_set_publish.3.adoc[nng_mqtt_msg_set_publish()]|set mqtt publish message +|xref:nng_mqtt_msg_set_subscribe.3.adoc[nng_mqtt_msg_set_subscribe()]|set mqtt subscribe message +|xref:nng_mqtt_msg_set_unsubscribe.3.adoc[nng_mqtt_msg_set_unsubscribe()]|set mqtt unsubscribe message +|=== + === Asynchronous Operations Most applications will interact with _NNG_ synchronously; that is that diff --git a/docs/man/nng_mqtt_msg_alloc.3.adoc b/docs/man/nng_mqtt_msg_alloc.3.adoc new file mode 100644 index 000000000..d3eef8abe --- /dev/null +++ b/docs/man/nng_mqtt_msg_alloc.3.adoc @@ -0,0 +1,57 @@ += nng_mqtt_msg_alloc(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_alloc - allocate a message with __proto_data__ for __mqtt__ + +== SYNOPSIS + +[source, c] +---- +#include + +int nng_mqtt_msg_alloc(nng_msg **msgp, size_t size); +---- + +== DESCRIPTION + +The `nng_mqtt_msg_alloc()` function allocates a new message with body length _size_ +and stores the result in __msgp__. +Messages allocated with this function contain a body and optionally a header and __proto_data__. +They are used with receive and transmit functions. + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +`NNG_ENOMEM`:: Insufficient free memory exists to allocate a message. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_decode.3.adoc b/docs/man/nng_mqtt_msg_decode.3.adoc new file mode 100644 index 000000000..4ee40c5d3 --- /dev/null +++ b/docs/man/nng_mqtt_msg_decode.3.adoc @@ -0,0 +1,54 @@ += nng_mqtt_msg_decode(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_decode - decode a __mqtt__ bytes stream from nng_msg_body and nng_msg_header to __proto_data__ + +== SYNOPSIS + +[source, c] +---- +#include + +int nng_mqtt_msg_decode(nng_msg **msgp); +---- + +== DESCRIPTION +The `nng_mqtt_msg_decode()` function decode body and header data to __proto_data__ (mqtt message structure), then functions __nng_mqtt_msg_get_xxx___xxx() can be allowed to get mqtt message infomations. + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +// TODO +// `NNG_ENOMEM`:: Insufficient free memory exists to allocate a message. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_encode.3.adoc b/docs/man/nng_mqtt_msg_encode.3.adoc new file mode 100644 index 000000000..d0d391b45 --- /dev/null +++ b/docs/man/nng_mqtt_msg_encode.3.adoc @@ -0,0 +1,54 @@ += nng_mqtt_msg_encode(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_encode - encode a __mqtt__ message from __proto_data__ to nng_msg_body and nng_msg_header + +== SYNOPSIS + +[source, c] +---- +#include + +int nng_mqtt_msg_encode(nng_msg **msgp); +---- + +== DESCRIPTION +The `nng_mqtt_msg_encode()` function encodes a mqtt message to body and header. + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +// TODO +// `NNG_ENOMEM`:: Insufficient free memory exists to allocate a message. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_get_connect.3.adoc b/docs/man/nng_mqtt_msg_get_connect.3.adoc new file mode 100644 index 000000000..1b5c25449 --- /dev/null +++ b/docs/man/nng_mqtt_msg_get_connect.3.adoc @@ -0,0 +1,75 @@ += nng_mqtt_msg_get_connect(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_get_connect - get mqtt connect message + +== SYNOPSIS + +[source, c] +---- +#include + +bool nng_mqtt_msg_get_connect_clean_session(nng_msg *msgp); +bool nng_mqtt_msg_get_connect_will_retain(nng_msg *msgp); +uint8_t nng_mqtt_msg_get_connect_proto_version(nng_msg *msgp); +uint16_t nng_mqtt_msg_get_connect_keep_alive(nng_msg *msgp); +const char * nng_mqtt_msg_get_connect_client_id(nng_msg *msgp); +const char * nng_mqtt_msg_get_connect_will_topic(nng_msg *msgp); +const char * nng_mqtt_msg_get_connect_will_msg(nng_msg *msgp); +const char * nng_mqtt_msg_get_connect_user_name(nng_msg *msgp); +const char * nng_mqtt_msg_get_connect_password(nng_msg *msgp); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_get_connect_xxx()` function is used to get mqtt connect message options after finishing __nng_mqtt_msg_decode()__: + + proto_version, + keep_alive, + client_id, + will_topic, + will_msg, + will_retain, + user_name, + password, + clean_session; + + +== RETURN VALUES + + + +== ERRORS + +None. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_set_connect.3.adoc[nng_mqtt_msg_set_connect(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_get_packet_type.3.adoc b/docs/man/nng_mqtt_msg_get_packet_type.3.adoc new file mode 100644 index 000000000..f4e86c5b2 --- /dev/null +++ b/docs/man/nng_mqtt_msg_get_packet_type.3.adoc @@ -0,0 +1,76 @@ += nng_mqtt_msg_get_packet_type(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_get_packet_type - get mqtt packet type + +== SYNOPSIS + +[source, c] +---- +#include + +typedef enum { + NNG_MQTT_CONNECT = 0x01, + NNG_MQTT_CONNACK = 0x02, + NNG_MQTT_PUBLISH = 0x03, + NNG_MQTT_PUBACK = 0x04, + NNG_MQTT_PUBREC = 0x05, + NNG_MQTT_PUBREL = 0x06, + NNG_MQTT_PUBCOMP = 0x07, + NNG_MQTT_SUBSCRIBE = 0x08, + NNG_MQTT_SUBACK = 0x09, + NNG_MQTT_UNSUBSCRIBE = 0x0A, + NNG_MQTT_UNSUBACK = 0x0B, + NNG_MQTT_PINGREQ = 0x0C, + NNG_MQTT_PINGRESP = 0x0D, + NNG_MQTT_DISCONNECT = 0x0E, + NNG_MQTT_AUTH = 0x0F +} nng_mqtt_packet_type; + +nng_mqtt_packet_type nng_mqtt_msg_get_packet_type(nng_msg *); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_get_packet_type()` function is normally used to get mqtt packet type after finishing __nng_mqtt_msg_decode()__ + +== RETURN VALUES + +This function returns value of __nng_mqtt_packet_type__ on success; + +== ERRORS + +[horizontal] +// TODO +// `NNG_ENOMEM`:: Insufficient free memory exists to allocate a message. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_set_packet_type.3.adoc[nng_mqtt_msg_set_packet_type(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_get_publish.3.adoc b/docs/man/nng_mqtt_msg_get_publish.3.adoc new file mode 100644 index 000000000..2ff4ad70f --- /dev/null +++ b/docs/man/nng_mqtt_msg_get_publish.3.adoc @@ -0,0 +1,68 @@ += nng_mqtt_msg_get_publish(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_get_publish - set mqtt publish message + +== SYNOPSIS + +[source, c] +---- +#include + +uint8_t nng_mqtt_msg_get_publish_qos(nng_msg *msgp); +bool nng_mqtt_msg_get_publish_retain(nng_msg *msgp); +bool nng_mqtt_msg_get_publish_dup(nng_msg *msgp); +const char * nng_mqtt_msg_get_publish_topic(nng_msg *msgp, uint32_t *topic_len); +uint8_t * nng_mqtt_msg_get_publish_payload(nng_msg *msgp, uint32_t *len); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_get_publish_xxx()` function is used to get mqtt publish message options after finishing __nng_mqtt_msg_decode()__: + + qos + retain + dup + topic + payload + ; + + +== RETURN VALUES + +None. + +== ERRORS + +None. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_set_publish.3.adoc[nng_mqtt_msg_set_publish(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_get_subscribe.3.adoc b/docs/man/nng_mqtt_msg_get_subscribe.3.adoc new file mode 100644 index 000000000..afbce3bc2 --- /dev/null +++ b/docs/man/nng_mqtt_msg_get_subscribe.3.adoc @@ -0,0 +1,64 @@ += nng_mqtt_msg_get_subscribe(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_get_subscribe - get mqtt subscribe message + +== SYNOPSIS + +[source, c] +---- +#include + +typedef struct mqtt_topic_qos_t { + nng_mqtt_topic topic; + uint8_t qos; +} mqtt_topic_qos; + +typedef struct mqtt_topic_qos_t nng_mqtt_topic_qos; + +nng_mqtt_topic_qos *nng_mqtt_msg_get_subscribe_topics(nng_msg *msg, uint32_t *topics_count); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_get_subscribe_topics()` function is used to get mqtt subscribe __array__ with topic and qos after finishing __nng_mqtt_msg_decode()__; + + +== RETURN VALUES + +None. + +== ERRORS + +None. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_set_subscribe.3.adoc[nng_mqtt_msg_set_subscribe(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_get_unsubscribe.3.adoc b/docs/man/nng_mqtt_msg_get_unsubscribe.3.adoc new file mode 100644 index 000000000..70430cfad --- /dev/null +++ b/docs/man/nng_mqtt_msg_get_unsubscribe.3.adoc @@ -0,0 +1,64 @@ += nng_mqtt_msg_get_unsubscribe(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_get_unsubscribe - get mqtt subscribe message + +== SYNOPSIS + +[source, c] +---- +#include + +struct mqtt_buf_t { + uint32_t length; + uint8_t *buf; +}; + +typedef struct mqtt_buf_t nng_mqtt_topic; + +nng_mqtt_topic *nng_mqtt_msg_get_unsubscribe_topics(nng_msg *msg, uint32_t *topics_count); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_get_unsubscribe_topics()` function is used to get mqtt subscribe __array__ with topic after finishing __nng_mqtt_msg_decode()__; + + +== RETURN VALUES + +None. + +== ERRORS + +None. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_set_unsubscribe.3.adoc[nng_mqtt_msg_set_unsubscribe(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_set_connect.3.adoc b/docs/man/nng_mqtt_msg_set_connect.3.adoc new file mode 100644 index 000000000..d2e91c80b --- /dev/null +++ b/docs/man/nng_mqtt_msg_set_connect.3.adoc @@ -0,0 +1,75 @@ += nng_mqtt_msg_set_connect(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_set_connect - set mqtt connect message + +== SYNOPSIS + +[source, c] +---- +#include + +void nng_mqtt_msg_set_connect_proto_version(nng_msg *msgp, uint8_t proto_version); +void nng_mqtt_msg_set_connect_keep_alive(nng_msg *msgp, uint16_t keep_alive); +void nng_mqtt_msg_set_connect_client_id(nng_msg *msgp, const char * client_id); +void nng_mqtt_msg_set_connect_will_topic(nng_msg *msgp, const char * will_topic); +void nng_mqtt_msg_set_connect_will_msg(nng_msg *msgp, const char * will_msg); +void nng_mqtt_msg_set_connect_will_retain(nng_msg *msgp, bool will_retain) ; +void nng_mqtt_msg_set_connect_user_name(nng_msg *msgp, const char *user_name); +void nng_mqtt_msg_set_connect_password(nng_msg *msgp, const char *password); +void nng_mqtt_msg_set_connect_clean_session(nng_msg *msgp, bool clean_session); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_set_connect_xxx()` function is used to set mqtt connect message options before finishing __nng_mqtt_msg_encode()__: + + proto_version, + keep_alive, + client_id, + will_topic, + will_msg, + will_retain, + user_name, + password, + clean_session; + + +== RETURN VALUES + +None. + +== ERRORS + +None. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_get_connect.3.adoc[nng_mqtt_msg_get_connect(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_set_packet_type.3.adoc b/docs/man/nng_mqtt_msg_set_packet_type.3.adoc new file mode 100644 index 000000000..cd6c0860b --- /dev/null +++ b/docs/man/nng_mqtt_msg_set_packet_type.3.adoc @@ -0,0 +1,76 @@ += nng_mqtt_msg_set_packet_type(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_set_packet_type - set mqtt packet type + +== SYNOPSIS + +[source, c] +---- +#include + +typedef enum { + NNG_MQTT_CONNECT = 0x01, + NNG_MQTT_CONNACK = 0x02, + NNG_MQTT_PUBLISH = 0x03, + NNG_MQTT_PUBACK = 0x04, + NNG_MQTT_PUBREC = 0x05, + NNG_MQTT_PUBREL = 0x06, + NNG_MQTT_PUBCOMP = 0x07, + NNG_MQTT_SUBSCRIBE = 0x08, + NNG_MQTT_SUBACK = 0x09, + NNG_MQTT_UNSUBSCRIBE = 0x0A, + NNG_MQTT_UNSUBACK = 0x0B, + NNG_MQTT_PINGREQ = 0x0C, + NNG_MQTT_PINGRESP = 0x0D, + NNG_MQTT_DISCONNECT = 0x0E, + NNG_MQTT_AUTH = 0x0F +} nng_mqtt_packet_type; + +nng_mqtt_msg_set_packet_type(nng_msg *msg, nng_mqtt_packet_type packet_type); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_set_packet_type()` function is used to set mqtt packet type with enum nng_mqtt_packet_type + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +// TODO +// `NNG_ENOMEM`:: Insufficient free memory exists to allocate a message. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_get_packet_type.3.adoc[nng_mqtt_msg_get_packet_type(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_set_publish.3.adoc b/docs/man/nng_mqtt_msg_set_publish.3.adoc new file mode 100644 index 000000000..25aaee9bb --- /dev/null +++ b/docs/man/nng_mqtt_msg_set_publish.3.adoc @@ -0,0 +1,68 @@ += nng_mqtt_msg_set_publish(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_set_publish - set mqtt publish message + +== SYNOPSIS + +[source, c] +---- +#include + +void nng_mqtt_msg_set_publish_qos(nng_msg *msgp, uint8_t qos); +void nng_mqtt_msg_set_publish_retain(nng_msg *msgp, bool retain); +void nng_mqtt_msg_set_publish_dup(nng_msg *msgp, bool dup); +void nng_mqtt_msg_set_publish_topic(nng_msg *msgp, const char *topic); +void nng_mqtt_msg_set_publish_payload(nng_msg *msgp, uint8_t *payload, uint32_t len); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_set_publish_xxx()` function is used to set mqtt publish message options before finishing __nng_mqtt_msg_encode()__: + + qos + retain + dup + topic + payload + ; + + +== RETURN VALUES + +None. + +== ERRORS + +None. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_get_publish.3.adoc[nng_mqtt_msg_get_publish(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_set_subscribe.3.adoc b/docs/man/nng_mqtt_msg_set_subscribe.3.adoc new file mode 100644 index 000000000..5393f704e --- /dev/null +++ b/docs/man/nng_mqtt_msg_set_subscribe.3.adoc @@ -0,0 +1,64 @@ += nng_mqtt_msg_set_subscribe(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_set_subscribe - set mqtt subscribe message + +== SYNOPSIS + +[source, c] +---- +#include + +typedef struct mqtt_topic_qos_t { + nng_mqtt_topic topic; + uint8_t qos; +} mqtt_topic_qos; + +typedef struct mqtt_topic_qos_t nng_mqtt_topic_qos; + +void nng_mqtt_msg_set_subscribe_topics(nng_msg *msg, nng_mqtt_topic_qos *topics, uint32_t topics_count); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_set_subscribe_topics()` function is used to set mqtt subscribe __array__ with topic and qos before finishing __nng_mqtt_msg_encode()__; + + +== RETURN VALUES + +None. + +== ERRORS + +None. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_get_subscribe.3.adoc[nng_mqtt_msg_get_subscribe(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_msg_set_unsubscribe.3.adoc b/docs/man/nng_mqtt_msg_set_unsubscribe.3.adoc new file mode 100644 index 000000000..3e3c333d2 --- /dev/null +++ b/docs/man/nng_mqtt_msg_set_unsubscribe.3.adoc @@ -0,0 +1,64 @@ += nng_mqtt_msg_set_unsubscribe(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_msg_set_unsubscribe - set mqtt unsubscribe message + +== SYNOPSIS + +[source, c] +---- +#include + +struct mqtt_buf_t { + uint32_t length; + uint8_t *buf; +}; + +typedef struct mqtt_buf_t nng_mqtt_topic; + +void nng_mqtt_msg_set_unsubscribe_topics(nng_msg *msg, nng_mqtt_topic *topics, uint32_t topics_count); + +---- + +== DESCRIPTION + +The `nng_mqtt_msg_set_unsubscribe_topics()` function is used to set mqtt unsubscribe __array__ with topic before finishing __nng_mqtt_msg_encode()__; + + +== RETURN VALUES + +None. + +== ERRORS + +None. + +== SEE ALSO + +[.text-left] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc(3)], +xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode(3)], +xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode(3)], +xref:nng_mqtt_msg_get_unsubscribe.3.adoc[nng_mqtt_msg_get_unsubscribe(3)], +xref:nng_msg_free.3.adoc[nng_msg_free(3)], +xref:nng_msg_body.3.adoc[nng_msg_body(3)], +xref:nng_msg_dup.3.adoc[nng_msg_dup(3)], +xref:nng_msg_header.3.adoc[nng_msg_header(3)], +xref:nng_msg_header_len.3.adoc[nng_msg_header_len(3)], +xref:nng_msg_len.3.adoc[nng_msg_len(3)], +xref:nng_msg_capacity.3.adoc[nng_msg_capacity(3)], +xref:nng_msg_reserve.3.adoc[nng_msg_reserve(3)], +xref:nng_msg_realloc.3.adoc[nng_msg_realloc(3)], +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_msg.5.adoc[nng_msg(5)], +xref:nng.7.adoc[nng(7)] From 60a29978aca3ba6d49b48050cd579d5bbfe63657 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Mon, 8 Nov 2021 15:20:04 +0800 Subject: [PATCH 123/180] * TEST: help passing nng test. --- demo/mqtt/mqtt_client.c | 2 +- src/sp/transport.c | 1 - src/sp/transport/mqtt/mqtt_tcp.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index aa4ede8e1..1388f1dd0 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -126,7 +126,7 @@ client_connect(nng_socket *sock, const char *url, bool verbose) printf("Connecting to server ..."); nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, connmsg); - nng_dialer_setcb(dialer, connect_cb, "Yeap"); + nng_dialer_set_cb(dialer, connect_cb, "Yeap"); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); printf("connected\n"); diff --git a/src/sp/transport.c b/src/sp/transport.c index 14577716c..e69030bd8 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -36,7 +36,6 @@ nni_sp_tran_find(nni_url *url) nni_rwlock_rdlock(&sp_tran_lk); NNI_LIST_FOREACH (&sp_tran_list, t) { - printf("tran %s %s\n", url->u_scheme, t->tran_scheme); if (strcmp(url->u_scheme, t->tran_scheme) == 0) { nni_rwlock_unlock(&sp_tran_lk); return (t); diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 0f3f68e09..cdf82cd2b 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -564,10 +564,10 @@ mqtt_tcptran_pipe_recv_cb(void *arg) // keep connection & Schedule next receive // nni_pipe_bump_rx(p->npipe, n); mqtt_tcptran_pipe_recv_start(p); + nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, n); - nni_mtx_unlock(&p->mtx); return; recv_error: From 5a536f7eef503e780c05d12af1de14934f90f5a2 Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 8 Nov 2021 11:23:35 +0800 Subject: [PATCH 124/180] Remove mqtt protocol useless comments --- src/sp/protocol/mqtt/mqtt_client.c | 33 +++++------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 10f111864..ef57f359f 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -676,14 +676,8 @@ mqtt_recv_cb(void *arg) nni_mtx_unlock(&s->mtx); return; } - // the transport handled sending the PUBREL for us - // work->state = WORK_PUBREL; - // reuse msg - // nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBREL); - // nni_mqtt_msg_set_pubrel_packet_id(msg, packet_id); - // nni_mqtt_msg_encode(msg); - // nni_aio_set_msg(&work->send_aio, msg); - // nni_pipe_send(p->pipe, &work->send_aio); + // the transport handled sending the PUBREL for us, + // expect to receive a PUBCOMP work->state = WORK_PUBCOMP; break; @@ -707,14 +701,6 @@ mqtt_recv_cb(void *arg) nni_list_append(&s->free_list, work); nni_mtx_unlock(&s->mtx); return; - // work->state = WORK_PUBCOMP; - // reuse msg - // nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBCOMP); - // nni_mqtt_msg_set_pubcomp_packet_id(msg, packet_id); - // nni_mqtt_msg_encode(msg); - // nni_aio_set_msg(&work->send_aio, msg); - // nni_pipe_send(p->pipe, &work->send_aio); - break; case NNG_MQTT_PUBLISH: // we have received a PUBLISH @@ -729,23 +715,14 @@ mqtt_recv_cb(void *arg) } else { work = nni_list_first(&s->free_list); nni_list_remove(&s->free_list, work); - // keep the message, and alloc a new ack message work->qos = qos; - work->msg = msg; + work->msg = msg; // keep the message work->packet_id = nni_mqtt_msg_get_publish_packet_id(msg); - // the transport handled sending PUBACK/PUBRECV + // the transport handled sending PUBRECV, + // expect to receive a PUBREL work->state = WORK_PUBREL; nni_id_set(&p->recv_unack, work->packet_id, work); - // nni_mqtt_msg_alloc(&msg, 0); - // QoS 2, then send a PUBRECV - // work->state = WORK_PUBRECV; - // nni_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBREC); - // nni_mqtt_msg_set_pubrec_packet_id(msg, - // work->packet_id); - // nni_mqtt_msg_encode(msg); - // nni_aio_set_msg(&work->send_aio, msg); - // nni_pipe_send(p->pipe, &work->send_aio); } break; From 49f5c91f873a28ef68f2f913f1a62deaab10665d Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 8 Nov 2021 11:24:57 +0800 Subject: [PATCH 125/180] Fix mqtt protocol typos --- src/sp/protocol/mqtt/mqtt_client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index ef57f359f..2391e5f69 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -61,7 +61,7 @@ typedef enum { WORK_PUBACK, // send/recv PUBACK WORK_PUBCOMP, // send/recv PUBCOMP WORK_PUBLISH, // send/recv PUBLISH - WORK_PUBRECV, // send/recv PUBRECV + WORK_PUBRECV, // send/recv PUBREC WORK_PUBREL, // send/recv PUBREL WORK_SUBSCRIBE, // send SUBSCRIBE WORK_SUBACK, // recv SUBACK @@ -523,7 +523,7 @@ mqtt_send_cb(void *arg) work->state = WORK_END; } else { // for QoS 1, expect receiving a PUBACK - // for QoS 2, expect receiving a PUBRECV + // for QoS 2, expect receiving a PUBREC work->state = (1 == work->qos) ? WORK_PUBACK : WORK_PUBRECV; if (0 != @@ -535,7 +535,7 @@ mqtt_send_cb(void *arg) break; case WORK_PUBRECV: - // we have sent a PUBRECV, expect receiving a PUBREL + // we have sent a PUBREC, expect receiving a PUBREL work->state = WORK_PUBREL; break; @@ -666,7 +666,7 @@ mqtt_recv_cb(void *arg) return; case NNG_MQTT_PUBREC: - // we have received a PUBRECV in the QoS 2 delivery, + // we have received a PUBREC in the QoS 2 delivery, // then send a PUBREL packet_id = nni_mqtt_msg_get_pubrec_packet_id(msg); nni_msg_free(msg); @@ -719,7 +719,7 @@ mqtt_recv_cb(void *arg) work->msg = msg; // keep the message work->packet_id = nni_mqtt_msg_get_publish_packet_id(msg); - // the transport handled sending PUBRECV, + // the transport handled sending PUBREC, // expect to receive a PUBREL work->state = WORK_PUBREL; nni_id_set(&p->recv_unack, work->packet_id, work); From 7eed4cd1081c1f2eee306260d3f9316229eef78f Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 8 Nov 2021 11:45:56 +0800 Subject: [PATCH 126/180] Refactor mqtt protocol Simplify work state enum, now it may contains the packet type. --- src/sp/protocol/mqtt/mqtt_client.c | 139 ++++++++++++++++------------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 2391e5f69..68bf2cd13 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -52,24 +52,27 @@ static void mqtt_ctx_send(void *arg, nni_aio *aio); static void mqtt_ctx_recv(void *arg, nni_aio *aio); // Work state indicating what MQTT packet we *expect* to send/recv. -typedef enum { - WORK_START, // start state - WORK_CONNECT, - WORK_CONNACK, - WORK_DISCONNECT, // send DISCONNECT - WORK_PINGREQ, // send PINGREQ - WORK_PUBACK, // send/recv PUBACK - WORK_PUBCOMP, // send/recv PUBCOMP - WORK_PUBLISH, // send/recv PUBLISH - WORK_PUBRECV, // send/recv PUBREC - WORK_PUBREL, // send/recv PUBREL - WORK_SUBSCRIBE, // send SUBSCRIBE - WORK_SUBACK, // recv SUBACK - WORK_UNSUBSCRIBE, // send UNSUBSCRIBE - WORK_UNSUBACK, // recv UNSUBACK - WORK_ERROR, // error state - WORK_END, // terminal state -} work_state_t; +// +// bits: 7 6 5 4 3 2 1 0 +// error <_/ | | | +// final <___/ | | +// init <_____/ |________> lower nib encoding packet type +// +typedef uint8_t work_state_t; + +#define WORK_STATE_INIT 0x20 // start state +#define WORK_STATE_FINAL 0x40 // final state +#define WORK_STATE_ERROR 0x80 // error state + +#define work_is_error(work) ((work)->state & WORK_STATE_ERROR) +#define work_is_final(work) ((work)->state & WORK_STATE_FINAL) +#define work_packet_type(work) ((work)->state & 0xEF) + +#define work_set_init(work) ((work)->state = WORK_STATE_INIT) +#define work_set_send(work, packet) ((work)->state = (packet)) +#define work_set_recv(work, packet) ((work)->state = (packet)) +#define work_set_error(work) ((work)->state = WORK_STATE_ERROR) +#define work_set_final(work) ((work)->state = WORK_STATE_FINAL) // A work_t represents an asynchronous send/recv of MQTT packet. typedef struct { @@ -125,7 +128,7 @@ static inline void work_init( work_t *work, mqtt_sock_t *s, nni_duration timeout_ms, nni_cb timer_cb) { - work->state = WORK_START; + work_set_init(work); work->qos = 0; work->packet_id = 0; work->msg = NULL; @@ -147,7 +150,7 @@ work_fini(work_t *work) static inline void work_reset(work_t *work) { - work->state = WORK_START; + work_set_init(work); work->qos = 0; work->packet_id = 0; nni_msg_free(work->msg); @@ -474,31 +477,31 @@ mqtt_send_cb(void *arg) } // state transitions - switch (work->state) { - case WORK_CONNECT: + switch (work_packet_type(work)) { + case NNG_MQTT_CONNECT: // we have sent a CONNECT, expect receiving a CONNACK - work->state = WORK_CONNACK; + work_set_recv(work, NNG_MQTT_CONNACK); // FIXME - work->state = WORK_END; + work_set_final(work); break; - case WORK_DISCONNECT: + case NNG_MQTT_DISCONNECT: // we have sent a DISCONNECT, just close the socket. - work->state = WORK_END; + work_set_final(work); // FIXME: close the socket break; - case WORK_PUBACK: + case NNG_MQTT_PUBACK: // we have sent a PUBACK, // indicating a successful receipt of a QoS 1 message // fall through - case WORK_PUBCOMP: + case NNG_MQTT_PUBCOMP: // FIXME: check packet id // we have sent a PUBCOMP, // indicating a successful receipt of a QoS 2 message - work->state = WORK_END; + work_set_final(work); nni_id_remove(&p->recv_unack, work->packet_id); mqtt_pipe_recv_msgq_putq(p, work->msg); mqtt_run_recv_queue(s); @@ -509,23 +512,26 @@ mqtt_send_cb(void *arg) nni_mtx_unlock(&s->mtx); return; - case WORK_PINGREQ: + case NNG_MQTT_PINGREQ: // we have sent a PINGREQ mqtt_send_start(s); nni_mtx_unlock(&s->mtx); return; - case WORK_PUBLISH: + case NNG_MQTT_PUBLISH: // TODO: handle retry // we have sent a PUBLISH if (0 == work->qos) { // QoS 0, no further actions - work->state = WORK_END; + work_set_final(work); } else { - // for QoS 1, expect receiving a PUBACK - // for QoS 2, expect receiving a PUBREC - work->state = - (1 == work->qos) ? WORK_PUBACK : WORK_PUBRECV; + if (1 == work->qos) { + // for QoS 1, expect receiving a PUBACK + work_set_recv(work, NNG_MQTT_PUBACK); + } else { + // for QoS 2, expect receiving a PUBREC + work_set_recv(work, NNG_MQTT_PUBREC); + } if (0 != nni_id_set( &p->send_unack, work->packet_id, work)) { @@ -534,40 +540,40 @@ mqtt_send_cb(void *arg) } break; - case WORK_PUBRECV: + case NNG_MQTT_PUBREC: // we have sent a PUBREC, expect receiving a PUBREL - work->state = WORK_PUBREL; + work_set_recv(work, NNG_MQTT_PUBREL); break; - case WORK_PUBREL: + case NNG_MQTT_PUBREL: // we have sent a PUBREL, expect receiving a PUBCOMP - work->state = WORK_PUBCOMP; + work_set_recv(work, NNG_MQTT_PUBCOMP); break; - case WORK_SUBSCRIBE: + case NNG_MQTT_SUBSCRIBE: // we have sent a SUBSCRIBE, expect receiving a SUBACK - work->state = WORK_SUBACK; + work_set_recv(work, NNG_MQTT_SUBACK); nni_id_set(&p->send_unack, work->packet_id, work); break; - case WORK_UNSUBSCRIBE: + case NNG_MQTT_UNSUBSCRIBE: // we have sent a UNSUBSCRIBE, expect receiving a UNSUBACK - work->state = WORK_UNSUBACK; + work_set_recv(work, NNG_MQTT_UNSUBACK); nni_id_set(&p->send_unack, work->packet_id, work); break; default: - work->state = WORK_ERROR; + work_set_error(work); break; } - if (WORK_ERROR == work->state) { + if (work_is_error(work)) { // MQTT protocol error, terminate the connection nni_aio_finish_error(work->user_aio, NNG_EPROTO); nni_mtx_unlock(&s->mtx); nni_pipe_close(p->pipe); return; - } else if (WORK_END == work->state) { + } else if (work_is_final(work)) { // good news, protocol state machine run to the end nni_aio *aio = work->user_aio; work_reset(work); @@ -646,7 +652,6 @@ mqtt_recv_cb(void *arg) case NNG_MQTT_UNSUBACK: // we have received a UNSUBACK, successful unsubcription - // FIXME: check packet type match packet_id = nni_mqtt_msg_get_packet_id(msg); nni_msg_free(msg); work = nni_id_get(&p->send_unack, packet_id); @@ -657,7 +662,11 @@ mqtt_recv_cb(void *arg) return; } nni_id_remove(&p->send_unack, packet_id); - work->state = WORK_END; + if (work_packet_type(work) == packet_type) { + work_set_final(work); + } else { + work_set_error(work); + } break; case NNG_MQTT_PINGRESP: @@ -678,7 +687,11 @@ mqtt_recv_cb(void *arg) } // the transport handled sending the PUBREL for us, // expect to receive a PUBCOMP - work->state = WORK_PUBCOMP; + if (work_packet_type(work) == packet_type) { + work_set_recv(work, NNG_MQTT_PUBCOMP); + } else { + work_set_error(work); + } break; case NNG_MQTT_PUBREL: @@ -692,7 +705,7 @@ mqtt_recv_cb(void *arg) return; } // the transport handled sending the PUBCOMP for us - work->state = WORK_END; + work_set_final(work); nni_id_remove(&p->recv_unack, work->packet_id); mqtt_pipe_recv_msgq_putq(p, work->msg); mqtt_run_recv_queue(s); @@ -721,23 +734,25 @@ mqtt_recv_cb(void *arg) nni_mqtt_msg_get_publish_packet_id(msg); // the transport handled sending PUBREC, // expect to receive a PUBREL - work->state = WORK_PUBREL; + work_set_recv(work, NNG_MQTT_PUBREL); nni_id_set(&p->recv_unack, work->packet_id, work); } break; default: - // something bad happen - break; + // unexpected packet type, server misbehaviour + nni_mtx_unlock(&s->mtx); + nni_pipe_close(p->pipe); + return; } - if (WORK_ERROR == work->state) { + if (work_is_error(work)) { // protocol error, just close the connection nni_mtx_unlock(&s->mtx); nni_aio_finish_error(work->user_aio, NNG_EPROTO); nni_pipe_close(p->pipe); return; - } else if (WORK_END == work->state) { + } else if (work_is_final(work)) { // good news, protocol state machine run to the end nni_aio *aio = work->user_aio; work_reset(work); @@ -772,7 +787,7 @@ mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) } work->user_aio = aio; - work->state = WORK_PUBLISH; + work_set_recv(work, NNG_MQTT_PUBLISH); nni_list_remove(&s->free_list, work); nni_list_append(&s->recv_queue, work); // enqueue to recv mqtt_run_recv_queue(s); @@ -824,16 +839,13 @@ mqtt_send_start(mqtt_sock_t *s) switch (packet_type) { case NNG_MQTT_CONNECT: // NOTE: the transport dialer will send a CONNECT - work->state = WORK_CONNECT; break; case NNG_MQTT_PINGREQ: - work->state = WORK_PINGREQ; break; case NNG_MQTT_PUBLISH: - work->state = WORK_PUBLISH; - work->qos = nni_mqtt_msg_get_publish_qos(work->msg); + work->qos = nni_mqtt_msg_get_publish_qos(work->msg); if (work->qos > 0) { work->packet_id = mqtt_pipe_get_next_packet_id(p); @@ -844,14 +856,12 @@ mqtt_send_start(mqtt_sock_t *s) break; case NNG_MQTT_SUBSCRIBE: - work->state = WORK_SUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_subscribe_packet_id( work->msg, work->packet_id); nni_mqtt_msg_encode(work->msg); break; case NNG_MQTT_UNSUBSCRIBE: - work->state = WORK_UNSUBSCRIBE; work->packet_id = mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_unsubscribe_packet_id( work->msg, work->packet_id); @@ -859,11 +869,12 @@ mqtt_send_start(mqtt_sock_t *s) break; default: - work->state = WORK_ERROR; + work_set_error(work); nni_aio_finish_error(work->user_aio, NNG_EPROTO); return; } + work_set_send(work, packet_type); nni_msg_clone(work->msg); nni_aio_set_msg(&p->send_aio, work->msg); nni_pipe_send(p->pipe, &p->send_aio); From b181c486c9615e199813aa3662635f52a11d8da1 Mon Sep 17 00:00:00 2001 From: eeff Date: Mon, 8 Nov 2021 14:58:05 +0800 Subject: [PATCH 127/180] Add mqtt protocol retransmit support When the mqtt client sends certain kinds of packets e.g. PUBLISH and don't get the acknowledgement within a time window, we will retransmit the packet. --- src/sp/protocol/mqtt/mqtt_client.c | 105 +++++++++++++++++++---------- 1 file changed, 71 insertions(+), 34 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 68bf2cd13..9bccf5333 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -77,6 +77,7 @@ typedef uint8_t work_state_t; // A work_t represents an asynchronous send/recv of MQTT packet. typedef struct { work_state_t state; + uint8_t ntrial; // number of times we transmit uint8_t qos; // QoS of the MQTT PUBLISH packet uint16_t packet_id; // packet id of the message that have it mqtt_sock_t * mqtt_sock; @@ -129,6 +130,7 @@ work_init( work_t *work, mqtt_sock_t *s, nni_duration timeout_ms, nni_cb timer_cb) { work_set_init(work); + work->ntrial = 0; work->qos = 0; work->packet_id = 0; work->msg = NULL; @@ -151,6 +153,7 @@ static inline void work_reset(work_t *work) { work_set_init(work); + work->ntrial = 0; work->qos = 0; work->packet_id = 0; nni_msg_free(work->msg); @@ -203,9 +206,16 @@ work_close_queue(nni_list *queue) static inline void work_timer_schedule(work_t *work) { + ++work->ntrial; nni_timer_schedule(&work->timer, nni_clock() + work->timeout); } +static inline void +work_timer_cancel(work_t *work) +{ + nni_timer_schedule(&work->timer, NNI_TIME_NEVER); +} + /****************************************************************************** * Sock Implementation * ******************************************************************************/ @@ -311,6 +321,7 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) work_init(&p->ping_work, s, sock->retry, mqtt_keep_alive_cb); nni_mqtt_msg_alloc(&p->ping_work.msg, 0); nni_mqtt_msg_set_packet_type(p->ping_work.msg, NNG_MQTT_PINGREQ); + work_set_send(&p->ping_work, NNG_MQTT_PINGREQ); nni_mqtt_msg_encode(p->ping_work.msg); nni_aio_init(&p->send_aio, mqtt_send_cb, p); nni_aio_init(&p->recv_aio, mqtt_recv_cb, p); @@ -441,10 +452,36 @@ mqtt_keep_alive_cb(void *arg) nni_mtx_unlock(&s->mtx); } +// Timer callback, we use it for retransmitting. static void mqtt_timer_cb(void *arg) { - // TODO: handle retry + work_t * work = arg; + mqtt_sock_t *s = work->mqtt_sock; + + nni_mtx_lock(&s->mtx); + + mqtt_pipe_t *p = s->mqtt_pipe; + + if (NULL == p || nni_atomic_get_bool(&p->closed)) { + return; + } + + if (work->ntrial < nni_atomic_get(&s->ttl)) { + // try again + nni_list_append(&s->send_queue, work); + if (nni_list_first(&s->send_queue) == work) { + mqtt_send_start(s); + } + } else { + // reach max retransmitting, quit + nni_aio_finish_error(work->user_aio, NNG_EAGAIN); + nni_id_remove(&p->send_unack, work->packet_id); + work_reset(work); + nni_list_append(&s->free_list, work); + } + + nni_mtx_unlock(&s->mtx); } static void @@ -537,6 +574,7 @@ mqtt_send_cb(void *arg) &p->send_unack, work->packet_id, work)) { // FIXME } + work_timer_schedule(work); } break; @@ -554,12 +592,14 @@ mqtt_send_cb(void *arg) // we have sent a SUBSCRIBE, expect receiving a SUBACK work_set_recv(work, NNG_MQTT_SUBACK); nni_id_set(&p->send_unack, work->packet_id, work); + work_timer_schedule(work); break; case NNG_MQTT_UNSUBSCRIBE: // we have sent a UNSUBSCRIBE, expect receiving a UNSUBACK work_set_recv(work, NNG_MQTT_UNSUBACK); nni_id_set(&p->send_unack, work->packet_id, work); + work_timer_schedule(work); break; default: @@ -667,6 +707,7 @@ mqtt_recv_cb(void *arg) } else { work_set_error(work); } + work_timer_cancel(work); break; case NNG_MQTT_PINGRESP: @@ -692,6 +733,7 @@ mqtt_recv_cb(void *arg) } else { work_set_error(work); } + work_timer_cancel(work); break; case NNG_MQTT_PUBREL: @@ -834,44 +876,39 @@ mqtt_send_start(mqtt_sock_t *s) if (NULL != (work = nni_list_first(&s->send_queue))) { packet_type = nni_mqtt_msg_get_packet_type(work->msg); - // only allow to send CONNECT, PINGREQ, PUBLISH, SUBSCRIBE - // and UNSUBSCRIBE - switch (packet_type) { - case NNG_MQTT_CONNECT: - // NOTE: the transport dialer will send a CONNECT - break; - - case NNG_MQTT_PINGREQ: - break; - - case NNG_MQTT_PUBLISH: - work->qos = nni_mqtt_msg_get_publish_qos(work->msg); - if (work->qos > 0) { + // we are not retransmitting the work + if (0 == work->ntrial) { + // only allow to send CONNECT, PINGREQ, PUBLISH, + // SUBSCRIBE and UNSUBSCRIBE + switch (packet_type) { + case NNG_MQTT_CONNECT: + // NOTE: the transport dialer handle CONNECT + // fall through + case NNG_MQTT_PINGREQ: + break; + + case NNG_MQTT_PUBLISH: + work->qos = + nni_mqtt_msg_get_publish_qos(work->msg); + if (0 == work->qos) { + break; // QoS 0 need no packet id + } + // fall through + case NNG_MQTT_SUBSCRIBE: + case NNG_MQTT_UNSUBSCRIBE: work->packet_id = mqtt_pipe_get_next_packet_id(p); - nni_mqtt_msg_set_publish_packet_id( + nni_mqtt_msg_set_packet_id( work->msg, work->packet_id); nni_mqtt_msg_encode(work->msg); - } - break; - - case NNG_MQTT_SUBSCRIBE: - work->packet_id = mqtt_pipe_get_next_packet_id(p); - nni_mqtt_msg_set_subscribe_packet_id( - work->msg, work->packet_id); - nni_mqtt_msg_encode(work->msg); - break; - case NNG_MQTT_UNSUBSCRIBE: - work->packet_id = mqtt_pipe_get_next_packet_id(p); - nni_mqtt_msg_set_unsubscribe_packet_id( - work->msg, work->packet_id); - nni_mqtt_msg_encode(work->msg); - break; + break; - default: - work_set_error(work); - nni_aio_finish_error(work->user_aio, NNG_EPROTO); - return; + default: + work_set_error(work); + nni_aio_finish_error( + work->user_aio, NNG_EPROTO); + return; + } } work_set_send(work, packet_type); From 88fe857fa68f952998c9cb80b7b69af666d86a66 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Wed, 10 Nov 2021 16:31:23 +0800 Subject: [PATCH 128/180] * FIX [mqtt_tcp] deadlock in mqtt_tcptran_pipe_recv_cb --- demo/mqtt_async/mqtt_async.c | 5 +---- src/sp/transport/mqtt/mqtt_tcp.c | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index 5978f1661..cd0efb4d7 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -9,9 +9,6 @@ #include #include -// Can't be modified -#define NNG_MQTT_CONNECT_MSG "connmsg" - #ifndef PARALLEL #define PARALLEL 32 #endif @@ -198,7 +195,7 @@ client(const char *url) fprintf(stderr, "nng_mqtt_msg_encode failed: %d\n", rv); } - nng_dialer_set_ptr(dialer, NNG_MQTT_CONNECT_MSG, msg); + nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); nng_dialer_set_cb(dialer, connect_cb, NULL); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index cdf82cd2b..bf17a1101 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -567,6 +567,7 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, msg); + nni_mtx_unlock(&p->mtx); nni_aio_finish_sync(aio, 0, n); return; From cec38a00d1b45e1922fd691cb71f14323e640c2f Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Wed, 10 Nov 2021 11:16:58 +0800 Subject: [PATCH 129/180] * NEW [mqtt_codec] free/dup methods for some mqtt packets in need --- demo/mqtt_async/mqtt_async.c | 6 +- include/nng/nng.h | 8 +- src/mqtt/mqtt.c | 98 +++++------ src/mqtt/mqtt.h | 17 +- src/mqtt/mqtt_codec.c | 289 +++++++++++++++++++++++++++++-- src/mqtt/mqtt_test.c | 89 ++++------ src/nng.c | 16 +- src/sp/transport/mqtt/mqtt_tcp.c | 1 - 8 files changed, 380 insertions(+), 144 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index cd0efb4d7..46d9d36ec 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -31,10 +31,10 @@ static nng_mqtt_topic_qos topic_qos[] = { { .qos = 0, .topic = { .buf = (uint8_t *) SUB_TOPIC1, .length = strlen(SUB_TOPIC1) } }, - { .qos = 0, + { .qos = 1, .topic = { .buf = (uint8_t *) SUB_TOPIC2, .length = strlen(SUB_TOPIC2) } }, - { .qos = 0, + { .qos = 2, .topic = { .buf = (uint8_t *) SUB_TOPIC3, .length = strlen(SUB_TOPIC3) } }, { .qos = 0, @@ -159,7 +159,7 @@ connect_cb(void *arg, nng_msg *msg) { (void) arg; printf( - "connack status: %d\n", nng_mqtt_msg_get_conack_return_code(msg)); + "connack status: %d\n", nng_mqtt_msg_get_connack_return_code(msg)); nng_msg_free(msg); } diff --git a/include/nng/nng.h b/include/nng/nng.h index 6ec802875..1bd9d0063 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1342,10 +1342,10 @@ NNG_DECL const char *nng_mqtt_msg_get_connect_will_topic(nng_msg *); NNG_DECL const char *nng_mqtt_msg_get_connect_will_msg(nng_msg *); NNG_DECL const char *nng_mqtt_msg_get_connect_user_name(nng_msg *); NNG_DECL const char *nng_mqtt_msg_get_connect_password(nng_msg *); -NNG_DECL void nng_mqtt_msg_set_conack_return_code(nng_msg *, uint8_t); -NNG_DECL void nng_mqtt_msg_set_conack_flags(nng_msg *, uint8_t); -NNG_DECL uint8_t nng_mqtt_msg_get_conack_return_code(nng_msg *); -NNG_DECL uint8_t nng_mqtt_msg_get_conack_flags(nng_msg *); +NNG_DECL void nng_mqtt_msg_set_connack_return_code(nng_msg *, uint8_t); +NNG_DECL void nng_mqtt_msg_set_connack_flags(nng_msg *, uint8_t); +NNG_DECL uint8_t nng_mqtt_msg_get_connack_return_code(nng_msg *); +NNG_DECL uint8_t nng_mqtt_msg_get_connack_flags(nng_msg *); NNG_DECL void nng_mqtt_msg_set_publish_qos(nng_msg *, uint8_t); NNG_DECL uint8_t nng_mqtt_msg_get_publish_qos(nng_msg *); NNG_DECL void nng_mqtt_msg_set_publish_retain(nng_msg *, bool); diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index 0cf140d47..195f82889 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -2,9 +2,6 @@ #include #include -static int nni_mqtt_msg_free(void *); -static int nni_mqtt_msg_dup(void **, const void *); - static nni_proto_msg_ops proto_msg_ops = { .msg_free = nni_mqtt_msg_free, @@ -12,27 +9,6 @@ static nni_proto_msg_ops proto_msg_ops = { .msg_dup = nni_mqtt_msg_dup }; -static int -nni_mqtt_msg_free(void *self) -{ - if (self) { - free(self); - return (0); - } - return (1); -} - -static int -nni_mqtt_msg_dup(void **dest, const void *src) -{ - nni_mqtt_proto_data *mqtt; - - mqtt = NNI_ALLOC_STRUCT(mqtt); - memcpy(mqtt, (nni_mqtt_proto_data *) src, sizeof(nni_mqtt_proto_data)); - *dest = mqtt; - - return (0); -} int nni_mqtt_msg_proto_data_alloc(nni_msg *msg) @@ -52,7 +28,7 @@ void nni_mqtt_msg_proto_data_free(nni_msg *msg) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - NNI_FREE_STRUCT(proto_data); + nni_mqtt_msg_free(proto_data); } int @@ -193,8 +169,8 @@ void nni_mqtt_msg_set_publish_topic(nni_msg *msg, const char *topic) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->var_header.publish.topic_name.buf = (uint8_t *) topic; - proto_data->var_header.publish.topic_name.length = strlen(topic); + mqtt_buf_create(&proto_data->var_header.publish.topic_name, + (uint8_t *) topic, strlen(topic)); } const char * @@ -208,9 +184,8 @@ nni_mqtt_msg_get_publish_topic(nni_msg *msg, uint32_t *topic_len) void nni_mqtt_msg_set_publish_payload(nni_msg *msg, uint8_t *payload, uint32_t len) { - nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.publish.payload.buf = payload; - proto_data->payload.publish.payload.length = len; + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + mqtt_buf_create(&proto_data->payload.publish.payload, payload, len); } uint8_t * @@ -307,11 +282,19 @@ nni_mqtt_msg_set_subscribe_packet_id(nni_msg *msg, uint16_t packet_id) void nni_mqtt_msg_set_subscribe_topics( - nni_msg *msg, nni_mqtt_topic_qos *topic, uint32_t topic_count) + nni_msg *msg, nni_mqtt_topic_qos *topics, uint32_t topic_count) { - nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.subscribe.topic_arr = topic; + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + + proto_data->payload.subscribe.topic_arr = + nni_mqtt_topic_qos_array_create(topic_count); proto_data->payload.subscribe.topic_count = topic_count; + + for (size_t i = 0; i < topic_count; i++) { + nni_mqtt_topic_qos_array_set( + proto_data->payload.subscribe.topic_arr, i, + (const char *) topics[i].topic.buf, topics[i].qos); + } } nni_mqtt_topic_qos * @@ -341,7 +324,9 @@ nni_mqtt_msg_set_suback_return_codes( nni_msg *msg, uint8_t *ret_codes, uint32_t ret_codes_count) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.suback.ret_code_arr = ret_codes; + proto_data->payload.suback.ret_code_arr = nni_alloc(ret_codes_count); + memcpy(proto_data->payload.suback.ret_code_arr, ret_codes, + ret_codes_count); proto_data->payload.suback.ret_code_count = ret_codes_count; } @@ -369,11 +354,19 @@ nni_mqtt_msg_set_unsubscribe_packet_id(nni_msg *msg, uint16_t packet_id) void nni_mqtt_msg_set_unsubscribe_topics( - nni_msg *msg, nni_mqtt_topic *topic, uint32_t topic_count) + nni_msg *msg, nni_mqtt_topic *topics, uint32_t topic_count) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.unsubscribe.topic_arr = (nni_mqtt_topic *) topic; + + proto_data->payload.unsubscribe.topic_arr = + nni_mqtt_topic_array_create(topic_count); proto_data->payload.unsubscribe.topic_count = topic_count; + + for (size_t i = 0; i < topic_count; i++) { + nni_mqtt_topic_array_set( + proto_data->payload.unsubscribe.topic_arr, i, + (const char *) topics[i].buf); + } } nni_mqtt_topic * @@ -459,40 +452,40 @@ void nni_mqtt_msg_set_connect_client_id(nni_msg *msg, const char *client_id) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.connect.client_id.buf = (uint8_t *) client_id; - proto_data->payload.connect.client_id.length = strlen(client_id); + mqtt_buf_create(&proto_data->payload.connect.client_id, + (const uint8_t *) client_id, strlen(client_id) + 1); } void nni_mqtt_msg_set_connect_will_topic(nni_msg *msg, const char *will_topic) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.connect.will_topic.buf = (uint8_t *) will_topic; - proto_data->payload.connect.will_topic.length = strlen(will_topic); + mqtt_buf_create(&proto_data->payload.connect.will_topic, + (const uint8_t *) will_topic, strlen(will_topic) + 1); } void nni_mqtt_msg_set_connect_will_msg(nni_msg *msg, const char *will_msg) { - nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.connect.will_msg.buf = (uint8_t *) will_msg; - proto_data->payload.connect.will_msg.length = strlen(will_msg); + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + mqtt_buf_create(&proto_data->payload.connect.will_msg, + (const uint8_t *) will_msg, strlen(will_msg) + 1); } void nni_mqtt_msg_set_connect_user_name(nni_msg *msg, const char *user_name) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.connect.user_name.buf = (uint8_t *) user_name; - proto_data->payload.connect.user_name.length = strlen(user_name); + mqtt_buf_create(&proto_data->payload.connect.user_name, + (const uint8_t *) user_name, strlen(user_name) + 1); } void nni_mqtt_msg_set_connect_password(nni_msg *msg, const char *password) { - nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - proto_data->payload.connect.password.buf = (uint8_t *) password; - proto_data->payload.connect.password.length = strlen(password); + nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); + mqtt_buf_create(&proto_data->payload.connect.password, + (const uint8_t *) password, strlen(password) + 1); } const char * @@ -531,28 +524,28 @@ nni_mqtt_msg_get_connect_password(nni_msg *msg) } void -nni_mqtt_msg_set_conack_return_code(nni_msg *msg, uint8_t code) +nni_mqtt_msg_set_connack_return_code(nni_msg *msg, uint8_t code) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); proto_data->var_header.connack.conn_return_code = code; } void -nni_mqtt_msg_set_conack_flags(nni_msg *msg, uint8_t flags) +nni_mqtt_msg_set_connack_flags(nni_msg *msg, uint8_t flags) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); proto_data->var_header.connack.connack_flags = flags; } uint8_t -nni_mqtt_msg_get_conack_return_code(nni_msg *msg) +nni_mqtt_msg_get_connack_return_code(nni_msg *msg) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); return proto_data->var_header.connack.conn_return_code; } uint8_t -nni_mqtt_msg_get_conack_flags(nni_msg *msg) +nni_mqtt_msg_get_connack_flags(nni_msg *msg) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); return proto_data->var_header.connack.connack_flags; @@ -628,6 +621,7 @@ nni_mqtt_topic_qos_array_free(nni_mqtt_topic_qos *topic_qos, size_t n) { for (size_t i = 0; i < n; i++) { nni_strfree((char *) topic_qos[i].topic.buf); + topic_qos[i].topic.length = 0; } NNI_FREE_STRUCTS(topic_qos, n); } diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index bb2342c81..92738ea62 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -221,7 +221,7 @@ typedef struct mqtt_msg_t { packetType and packetFlags) may be used to jump the point where the actual data starts */ bool is_decoded : 1; /* message is obtained from decoded or encoded */ - bool attached_raw : 1; /* indicates if entire_raw_msg is to be owned */ + bool is_copied : 1; /* indicates string or array members are copied */ uint8_t _unused : 2; } mqtt_msg; @@ -240,8 +240,9 @@ extern int read_utf8_str(struct pos_buf *, mqtt_buf *); extern int read_str_data(struct pos_buf *, mqtt_buf *); extern int read_packet_length(struct pos_buf *, uint32_t *); -extern mqtt_buf mqtt_buf_dup(const mqtt_buf *); -extern void mqtt_buf_free(mqtt_buf *); +extern int mqtt_buf_create(mqtt_buf *, const uint8_t *, uint32_t); +extern int mqtt_buf_dup(mqtt_buf *, const mqtt_buf *); +extern void mqtt_buf_free(mqtt_buf *); extern mqtt_msg *mqtt_msg_create(nni_mqtt_packet_type); @@ -250,6 +251,8 @@ extern int mqtt_msg_dump(mqtt_msg *, mqtt_buf *, mqtt_buf *, bool); // nni_msg proto_data alloc/free extern int nni_mqtt_msg_proto_data_alloc(nni_msg *); extern void nni_mqtt_msg_proto_data_free(nni_msg *); +extern int nni_mqtt_msg_free(void *self); +extern int nni_mqtt_msg_dup(void **dest, const void *src); // mqtt message alloc/encode/decode extern int nni_mqtt_msg_alloc(nni_msg **, size_t); @@ -286,10 +289,10 @@ extern const char *nni_mqtt_msg_get_connect_user_name(nni_msg *); extern const char *nni_mqtt_msg_get_connect_password(nni_msg *); // mqtt conack -extern void nni_mqtt_msg_set_conack_return_code(nni_msg *, uint8_t); -extern void nni_mqtt_msg_set_conack_flags(nni_msg *, uint8_t); -extern uint8_t nni_mqtt_msg_get_conack_return_code(nni_msg *); -extern uint8_t nni_mqtt_msg_get_conack_flags(nni_msg *); +extern void nni_mqtt_msg_set_connack_return_code(nni_msg *, uint8_t); +extern void nni_mqtt_msg_set_connack_flags(nni_msg *, uint8_t); +extern uint8_t nni_mqtt_msg_get_connack_return_code(nni_msg *); +extern uint8_t nni_mqtt_msg_get_connack_flags(nni_msg *); // mqtt publish extern void nni_mqtt_msg_set_publish_qos(nni_msg *, uint8_t); diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index 1df243ce1..f522dd070 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -37,6 +37,20 @@ static int nni_mqtt_msg_decode_unsubscribe(nni_msg *); static int nni_mqtt_msg_decode_unsuback(nni_msg *); static int nni_mqtt_msg_decode_base(nni_msg *); +static void destory_connect(nni_mqtt_proto_data *); +static void destory_publish(nni_mqtt_proto_data *); +static void destory_subscribe(nni_mqtt_proto_data *); +static void destory_suback(nni_mqtt_proto_data *); +static void destory_unsubscribe(nni_mqtt_proto_data *); + +static void dup_connect(nni_mqtt_proto_data *, nni_mqtt_proto_data *); +static void dup_publish(nni_mqtt_proto_data *, nni_mqtt_proto_data *); +static void dup_subscribe(nni_mqtt_proto_data *, nni_mqtt_proto_data *); +static void dup_suback(nni_mqtt_proto_data *, nni_mqtt_proto_data *); +static void dup_unsubscribe(nni_mqtt_proto_data *, nni_mqtt_proto_data *); + +static void mqtt_msg_content_free(nni_mqtt_proto_data *); + typedef struct { nni_mqtt_packet_type packet_type; int (*encode)(nni_msg *); @@ -86,6 +100,8 @@ nni_mqtt_msg_encode(nni_msg *msg) i < sizeof(codec_handler) / sizeof(mqtt_msg_codec_handler); i++) { if (codec_handler[i].packet_type == mqtt->fixed_header.common.packet_type) { + mqtt->is_decoded = false; + mqtt->is_copied = true; return codec_handler[i].encode(msg); } } @@ -107,6 +123,8 @@ nni_mqtt_msg_decode(nni_msg *msg) i < sizeof(codec_handler) / sizeof(mqtt_msg_codec_handler); i++) { if (codec_handler[i].packet_type == mqtt->fixed_header.common.packet_type) { + mqtt_msg_content_free(mqtt); + mqtt->is_copied = false; mqtt->is_decoded = true; return codec_handler[i].decode(msg); } @@ -115,6 +133,236 @@ nni_mqtt_msg_decode(nni_msg *msg) return MQTT_ERR_PROTOCOL; } +static void +mqtt_msg_content_free(nni_mqtt_proto_data *mqtt) +{ + switch (mqtt->fixed_header.common.packet_type) { + case NNG_MQTT_CONNECT: + if (mqtt->is_copied) { + destory_connect(mqtt); + } + break; + case NNG_MQTT_PUBLISH: + if (mqtt->is_copied) { + destory_publish(mqtt); + } + break; + case NNG_MQTT_SUBSCRIBE: + if (mqtt->is_copied) { + destory_subscribe(mqtt); + } else { + nni_free(mqtt->payload.subscribe.topic_arr, + mqtt->payload.subscribe.topic_count * + sizeof(nni_mqtt_topic_qos)); + mqtt->payload.subscribe.topic_count = 0; + } + break; + case NNG_MQTT_SUBACK: + destory_suback(mqtt); + break; + case NNG_MQTT_UNSUBSCRIBE: + if (mqtt->is_copied) { + destory_unsubscribe(mqtt); + } else { + nni_free(mqtt->payload.unsubscribe.topic_arr, + mqtt->payload.unsubscribe.topic_count * + sizeof(nni_mqtt_topic)); + mqtt->payload.unsubscribe.topic_count = 0; + } + break; + + default: + break; + } +} + +int +nni_mqtt_msg_free(void *self) +{ + if (self) { + nni_mqtt_proto_data *mqtt = self; + mqtt_msg_content_free(mqtt); + free(mqtt); + return (0); + } + return (1); +} + +int +nni_mqtt_msg_dup(void **dest, const void *src) +{ + nni_mqtt_proto_data *mqtt = (nni_mqtt_proto_data *) *dest; + nni_mqtt_proto_data *s = (nni_mqtt_proto_data *) src; + + mqtt = NNI_ALLOC_STRUCT(mqtt); + memcpy(mqtt, (nni_mqtt_proto_data *) src, sizeof(nni_mqtt_proto_data)); + + switch (mqtt->fixed_header.common.packet_type) { + case NNG_MQTT_CONNECT: + if (mqtt->is_copied) { + dup_connect(mqtt, s); + } + break; + case NNG_MQTT_PUBLISH: + if (mqtt->is_copied) { + dup_publish(mqtt, s); + } + break; + case NNG_MQTT_SUBSCRIBE: + if (mqtt->is_copied) { + dup_subscribe(mqtt, s); + } else { + mqtt->payload.subscribe.topic_arr = + nni_alloc(s->payload.subscribe.topic_count * + sizeof(nni_mqtt_topic_qos)); + mqtt->payload.subscribe.topic_count = + s->payload.subscribe.topic_count; + memcpy(mqtt->payload.subscribe.topic_arr, + s->payload.subscribe.topic_arr, + s->payload.subscribe.topic_count * + sizeof(nni_mqtt_topic_qos)); + } + break; + case NNG_MQTT_SUBACK: + dup_suback(mqtt, s); + break; + case NNG_MQTT_UNSUBSCRIBE: + if (mqtt->is_copied) { + dup_unsubscribe(mqtt, s); + } else { + mqtt->payload.unsubscribe.topic_arr = + nni_alloc(s->payload.unsubscribe.topic_count * + sizeof(nni_mqtt_topic)); + mqtt->payload.unsubscribe.topic_count = + s->payload.unsubscribe.topic_count; + memcpy(mqtt->payload.unsubscribe.topic_arr, + s->payload.unsubscribe.topic_arr, + s->payload.unsubscribe.topic_count * + sizeof(nni_mqtt_topic)); + } + break; + + default: + break; + } + + *dest = mqtt; + + return (0); +} + +static void +dup_connect(nni_mqtt_proto_data *dest, nni_mqtt_proto_data *src) +{ + mqtt_buf_dup( + &dest->payload.connect.client_id, &src->payload.connect.client_id); + mqtt_buf_dup( + &dest->payload.connect.user_name, &src->payload.connect.user_name); + mqtt_buf_dup( + &dest->payload.connect.password, &src->payload.connect.password); + mqtt_buf_dup(&dest->payload.connect.will_topic, + &src->payload.connect.will_topic); + mqtt_buf_dup( + &dest->payload.connect.will_msg, &src->payload.connect.will_msg); +} + +static void +dup_publish(nni_mqtt_proto_data *dest, nni_mqtt_proto_data *src) +{ + mqtt_buf_dup(&dest->var_header.publish.topic_name, + &src->var_header.publish.topic_name); + mqtt_buf_dup( + &dest->payload.publish.payload, &src->payload.publish.payload); +} + +static void +dup_subscribe(nni_mqtt_proto_data *dest, nni_mqtt_proto_data *src) +{ + dest->payload.subscribe.topic_arr = nni_mqtt_topic_qos_array_create( + src->payload.subscribe.topic_count); + dest->payload.subscribe.topic_count = + src->payload.subscribe.topic_count; + + for (size_t i = 0; i < src->payload.subscribe.topic_count; i++) { + nni_mqtt_topic_qos_array_set(dest->payload.subscribe.topic_arr, + i, + (const char *) src->payload.subscribe.topic_arr[i] + .topic.buf, + src->payload.subscribe.topic_arr[i].qos); + } +} + +static void +dup_suback(nni_mqtt_proto_data *dest, nni_mqtt_proto_data *src) +{ + dest->payload.suback.ret_code_arr = + nni_alloc(src->payload.suback.ret_code_count); + dest->payload.suback.ret_code_count = + src->payload.suback.ret_code_count; + memcpy(dest->payload.suback.ret_code_arr, + src->payload.suback.ret_code_arr, + src->payload.suback.ret_code_count); +} + +static void +dup_unsubscribe(nni_mqtt_proto_data *dest, nni_mqtt_proto_data *src) +{ + dest->payload.unsubscribe.topic_arr = + nni_mqtt_topic_array_create(src->payload.unsubscribe.topic_count); + dest->payload.unsubscribe.topic_count = + src->payload.unsubscribe.topic_count; + + for (size_t i = 0; i < src->payload.unsubscribe.topic_count; i++) { + nni_mqtt_topic_array_set(dest->payload.unsubscribe.topic_arr, + i, + (const char *) src->payload.unsubscribe.topic_arr[i].buf); + } +} + +static void +destory_connect(nni_mqtt_proto_data *mqtt) +{ + mqtt_buf_free(&mqtt->payload.connect.client_id); + mqtt_buf_free(&mqtt->payload.connect.user_name); + mqtt_buf_free(&mqtt->payload.connect.password); + mqtt_buf_free(&mqtt->payload.connect.will_topic); + mqtt_buf_free(&mqtt->payload.connect.will_msg); +} + +static void +destory_publish(nni_mqtt_proto_data *mqtt) +{ + mqtt_buf_free(&mqtt->var_header.publish.topic_name); + mqtt_buf_free(&mqtt->payload.publish.payload); +} + +static void +destory_subscribe(nni_mqtt_proto_data *mqtt) +{ + nni_mqtt_topic_qos_array_free(mqtt->payload.subscribe.topic_arr, + mqtt->payload.subscribe.topic_count); + mqtt->payload.subscribe.topic_count = 0; +} + +static void +destory_suback(nni_mqtt_proto_data *mqtt) +{ + if (mqtt->payload.suback.ret_code_count > 0) { + nni_free(mqtt->payload.suback.ret_code_arr, + mqtt->payload.suback.ret_code_count); + mqtt->payload.suback.ret_code_arr = NULL; + mqtt->payload.suback.ret_code_count = 0; + } +} + +static void +destory_unsubscribe(nni_mqtt_proto_data *mqtt) +{ + nni_mqtt_topic_array_free(mqtt->payload.unsubscribe.topic_arr, + mqtt->payload.unsubscribe.topic_count); + mqtt->payload.unsubscribe.topic_count = 0; +} + static void nni_mqtt_msg_append_u8(nni_msg *msg, uint8_t val) { @@ -769,8 +1017,8 @@ nni_mqtt_msg_decode_suback(nni_msg *msg) /* Suback Return Codes */ mqtt->payload.suback.ret_code_count = buf.endpos - buf.curpos; - mqtt->payload.suback.ret_code_arr = (uint8_t *) nni_alloc( - mqtt->payload.suback.ret_code_count * sizeof(uint8_t)); + mqtt->payload.suback.ret_code_arr = + (uint8_t *) nni_alloc(mqtt->payload.suback.ret_code_count); uint8_t *ptr = mqtt->payload.suback.ret_code_arr; for (uint32_t i = 0; i < mqtt->payload.suback.ret_code_count; i++) { @@ -781,11 +1029,12 @@ nni_mqtt_msg_decode_suback(nni_msg *msg) } ptr++; } + return MQTT_SUCCESS; ERROR: nni_free(mqtt->payload.suback.ret_code_arr, - mqtt->payload.suback.ret_code_count * sizeof(uint8_t)); + mqtt->payload.suback.ret_code_count); return ret; } @@ -1187,21 +1436,39 @@ mqtt_get_remaining_length(uint8_t *packet, uint32_t len, return MQTT_ERR_INVAL; } -mqtt_buf -mqtt_buf_dup(const mqtt_buf *src) +int +mqtt_buf_create(mqtt_buf *mbuf, const uint8_t *buf, uint32_t length) { - mqtt_buf dest; + if ((mbuf->buf = nni_alloc(length)) != NULL) { + mbuf->length = length; + memcpy(mbuf->buf, buf, mbuf->length); + return (0); + } + return NNG_ENOMEM; +} - dest.length = src->length; - dest.buf = malloc(dest.length); - memcpy(dest.buf, src->buf, dest.length); - return dest; +int +mqtt_buf_dup(mqtt_buf *dest, const mqtt_buf *src) +{ + if (src->length <= 0) { + return 0; + } + if ((dest->buf = nni_alloc(src->length)) != NULL) { + dest->length = src->length; + memcpy(dest->buf, src->buf, src->length); + return (0); + } + return NNG_ENOMEM; } void mqtt_buf_free(mqtt_buf *buf) { - free(buf->buf); + if (buf->length > 0) { + nni_free(buf->buf, buf->length); + buf->length = 0; + buf->buf = NULL; + } } static mqtt_msg * diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index b85aec0ee..1ac171e04 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -72,32 +72,6 @@ test_dup(void) nng_msg_free(msg2); } -// FIXME remove later -void -test_get_remaining_length(void) -{ - uint8_t invalid_buf[] = { 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, - 0x61, 0x61 }; - - uint32_t len; - uint8_t used_bytes; - - NUTS_ASSERT(mqtt_get_remaining_length(invalid_buf, sizeof(invalid_buf), - &len, &used_bytes) == 0); - - NUTS_ASSERT(len == 97); - NUTS_ASSERT(used_bytes == 1); -} - void test_encode_connect(void) { @@ -109,8 +83,9 @@ test_encode_connect(void) NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); - NUTS_ASSERT(strcmp(nng_mqtt_msg_get_connect_client_id(msg), - "nanomq-mqtt") == 0); + + NUTS_ASSERT(strncmp(nng_mqtt_msg_get_connect_client_id(msg), + "nanomq-mqtt", 12) == 0); char will_topic[] = "/nanomq/will_msg"; nng_mqtt_msg_set_connect_will_topic(msg, will_topic); @@ -131,14 +106,14 @@ test_encode_connect(void) nng_msg *decode_msg; nng_msg_dup(&decode_msg, msg); + nng_msg_free(msg); NUTS_PASS(nng_mqtt_msg_decode(decode_msg)); print_mqtt_msg(decode_msg); - NUTS_ASSERT(memcmp(nng_msg_body(msg), nng_msg_body(decode_msg), - nng_msg_len(msg)) == 0); + // NUTS_ASSERT(memcmp(nng_msg_body(msg), nng_msg_body(decode_msg), + // nng_msg_len(msg)) == 0); - nng_msg_free(msg); nng_msg_free(decode_msg); } @@ -152,9 +127,9 @@ test_encode_connack(void) nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNACK); NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNACK); - nng_mqtt_msg_set_conack_flags(msg, 1); + nng_mqtt_msg_set_connack_flags(msg, 1); - nng_mqtt_msg_set_conack_return_code(msg, 0); + nng_mqtt_msg_set_connack_return_code(msg, 0); NUTS_PASS(nng_mqtt_msg_encode(msg)); @@ -182,20 +157,6 @@ test_encode_publish(void) nng_mqtt_msg_set_publish_payload( msg, (uint8_t *) payload, strlen(payload)); - char will_topic[] = "/nanomq/will_msg"; - nng_mqtt_msg_set_connect_will_topic(msg, will_topic); - - char will_msg[] = "Bye-bye"; - nng_mqtt_msg_set_connect_will_msg(msg, will_msg); - - char user[] = "nanomq"; - char passwd[] = "nanomq"; - - nng_mqtt_msg_set_connect_user_name(msg, user); - nng_mqtt_msg_set_connect_password(msg, passwd); - - nng_mqtt_msg_set_connect_keep_alive(msg, 60); - NUTS_PASS(nng_mqtt_msg_encode(msg)); print_mqtt_msg(msg); @@ -444,11 +405,9 @@ test_decode_subscribe(void) print_mqtt_msg(msg); - uint32_t count; - nng_mqtt_topic_qos *tq = - nng_mqtt_msg_get_subscribe_topics(msg, &count); - - nng_free(tq, count * sizeof(nng_mqtt_topic_qos)); + // uint32_t count; + // nng_mqtt_topic_qos *tq = + // nng_mqtt_msg_get_subscribe_topics(msg, &count); nng_msg_free(msg); } @@ -474,12 +433,11 @@ test_decode_unsubscribe(void) print_mqtt_msg(msg); - uint32_t count; - nng_mqtt_topic *topics = - nng_mqtt_msg_get_unsubscribe_topics(msg, &count); + // uint32_t count; + // nng_mqtt_topic *topics = + // nng_mqtt_msg_get_unsubscribe_topics(msg, &count); nng_msg_free(msg); - nni_free(topics, count * sizeof(nng_mqtt_topic)); } void @@ -499,10 +457,25 @@ test_decode_disconnect(void) nng_msg_free(msg); } +void +test_decode_suback(void) +{ + nng_msg *msg; + uint8_t suback[] = { 0x90, 0x04, 0x02, 0x10, 0x00, 0x01 }; + size_t sz = sizeof(suback) / sizeof(uint8_t); + + nng_mqtt_msg_alloc(&msg, sz - 2); + nng_msg_header_append(msg, suback, 2); + memcpy(nng_msg_body(msg), suback + 2, sz - 2); + NUTS_PASS(nng_mqtt_msg_decode(msg)); + + print_mqtt_msg(msg); + nng_msg_free(msg); +} + TEST_LIST = { { "alloc message", test_alloc }, { "dup message", test_dup }, - { "remain length", test_get_remaining_length }, { "encode connect", test_encode_connect }, { "encode conack", test_encode_connack }, { "encode publish", test_encode_publish }, @@ -517,5 +490,5 @@ TEST_LIST = { { "decode disconnect", test_decode_disconnect }, { "decode publish", test_decode_publish }, { "decode puback", test_decode_puback }, - { NULL, NULL }, + { "decode suback", test_decode_suback }, }; diff --git a/src/nng.c b/src/nng.c index 3bff9c78e..91c55afb2 100644 --- a/src/nng.c +++ b/src/nng.c @@ -2061,27 +2061,27 @@ nng_mqtt_msg_get_connect_password(nng_msg *msg) } void -nng_mqtt_msg_set_conack_return_code(nng_msg *msg, uint8_t return_code) +nng_mqtt_msg_set_connack_return_code(nng_msg *msg, uint8_t return_code) { - nni_mqtt_msg_set_conack_return_code(msg, return_code); + nni_mqtt_msg_set_connack_return_code(msg, return_code); } void -nng_mqtt_msg_set_conack_flags(nng_msg *msg, uint8_t flags) +nng_mqtt_msg_set_connack_flags(nng_msg *msg, uint8_t flags) { - nni_mqtt_msg_set_conack_flags(msg, flags); + nni_mqtt_msg_set_connack_flags(msg, flags); } uint8_t -nng_mqtt_msg_get_conack_return_code(nng_msg *msg) +nng_mqtt_msg_get_connack_return_code(nng_msg *msg) { - return nni_mqtt_msg_get_conack_return_code(msg); + return nni_mqtt_msg_get_connack_return_code(msg); } uint8_t -nng_mqtt_msg_get_conack_flags(nng_msg *msg) +nng_mqtt_msg_get_connack_flags(nng_msg *msg) { - return nni_mqtt_msg_get_conack_flags(msg); + return nni_mqtt_msg_get_connack_flags(msg); } void diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index bf17a1101..e745eaa64 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -564,7 +564,6 @@ mqtt_tcptran_pipe_recv_cb(void *arg) // keep connection & Schedule next receive // nni_pipe_bump_rx(p->npipe, n); mqtt_tcptran_pipe_recv_start(p); - nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, msg); nni_mtx_unlock(&p->mtx); From 4f143be43f07803ad5930feb9018ac71b5bbe842 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 11 Oct 2021 08:51:42 -0700 Subject: [PATCH 130/180] Remove unused eq_len member. --- src/core/aio.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/core/aio.c b/src/core/aio.c index dfab8f608..9d6c904bd 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -15,7 +15,6 @@ struct nni_aio_expire_q { nni_mtx eq_mtx; nni_cv eq_cv; nni_list eq_list; - uint32_t eq_len; nni_thr eq_thr; nni_time eq_next; // next expiration bool eq_exit; @@ -38,8 +37,8 @@ static int nni_aio_expire_q_cnt; // free to examine the aio for list membership, etc. The provider must // not call finish more than once though. // -// We use an array of expiration queues, each with it's own lock and -// condition variable, and expiration thread. By default this is one +// We use an array of expiration queues, each with its own lock and +// condition variable, and expiration thread. By default, this is one // per CPU core present -- the goal being to reduce overall pressure // caused by a single lock. The number of queues (and threads) can // be tuned using the NNG_EXPIRE_THREADS tunable. @@ -89,8 +88,8 @@ static int nni_aio_expire_q_cnt; #define aio_safe_lock(l) nni_mtx_lock(l) #define aio_safe_unlock(l) nni_mtx_unlock(l) #else -#define aio_safe_lock(l) -#define aio_safe_unlock(l) +#define aio_safe_lock(l) ((void) 1) +#define aio_safe_unlock(l) ((void) 1) #endif static nni_reap_list aio_reap_list = { @@ -331,7 +330,7 @@ nni_aio_begin(nni_aio *aio) NNI_ASSERT(aio->a_cancel_fn == NULL); NNI_ASSERT(!nni_list_node_active(&aio->a_expire_node)); - // Some initialization can be done outside of the lock, because + // Some initialization can be done outside the lock, because // we must have exclusive access to the aio. for (unsigned i = 0; i < NNI_NUM_ELEMENTS(aio->a_outputs); i++) { aio->a_outputs[i] = NULL; @@ -546,8 +545,8 @@ nni_aio_expire_loop(void *arg) int rv; nni_time next; - next = q->eq_next; - now = nni_clock(); + next = q->eq_next; + now = nni_clock(); // Each time we wake up, we scan the entire list of elements. // We scan forward, moving up to NNI_EXPIRE_Q_SIZE elements @@ -566,7 +565,7 @@ nni_aio_expire_loop(void *arg) continue; } q->eq_next = NNI_TIME_NEVER; - exp_idx = 0; + exp_idx = 0; while (aio != NULL) { if ((aio->a_expire < now) && (exp_idx < NNI_EXPIRE_BATCH)) { @@ -591,7 +590,7 @@ nni_aio_expire_loop(void *arg) for (uint32_t i = 0; i < exp_idx; i++) { aio = expires[i]; - rv = aio->a_expire_ok ? 0 : NNG_ETIMEDOUT; + rv = aio->a_expire_ok ? 0 : NNG_ETIMEDOUT; nni_aio_cancel_fn cancel_fn = aio->a_cancel_fn; void *cancel_arg = aio->a_cancel_arg; From 718ae5b0d4b936d6598daedc2ecb131cfeee877b Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 16 Oct 2021 23:27:35 -0700 Subject: [PATCH 131/180] fixes #1518 Disconnect during negotiation breaks listener --- src/sp/transport/ipc/ipc.c | 21 +++++++++++++-------- src/sp/transport/tcp/tcp.c | 14 ++++++++++---- src/sp/transport/tls/tls.c | 13 ++++++++++--- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/sp/transport/ipc/ipc.c b/src/sp/transport/ipc/ipc.c index 8ed4ac942..df27ad238 100644 --- a/src/sp/transport/ipc/ipc.c +++ b/src/sp/transport/ipc/ipc.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2019 Devolutions // @@ -10,7 +10,6 @@ // #include -#include #include "core/nng_impl.h" @@ -251,8 +250,8 @@ ipc_pipe_neg_cb(void *arg) nni_mtx_unlock(&p->ep->mtx); return; } - // We have both sent and received the headers. Lets check the - // receive side header. + // We have both sent and received the headers. Let's check the + // receiver. if ((p->rx_head[0] != 0) || (p->rx_head[1] != 'S') || (p->rx_head[2] != 'P') || (p->rx_head[3] != 0) || (p->rx_head[6] != 0) || (p->rx_head[7] != 0)) { @@ -262,7 +261,7 @@ ipc_pipe_neg_cb(void *arg) NNI_GET16(&p->rx_head[4], p->peer); - // We are all ready now. We put this in the wait list, and + // We are ready now. We put this in the wait list, and // then try to run the matcher. nni_list_remove(&ep->neg_pipes, p); nni_list_append(&ep->wait_pipes, p); @@ -272,7 +271,13 @@ ipc_pipe_neg_cb(void *arg) return; error: - + // If the connection is closed, we need to pass back a different + // error code. This is necessary to avoid a problem where the + // closed status is confused with the accept file descriptor + // being closed. + if (rv == NNG_ECLOSED) { + rv = NNG_ECONNSHUT; + } nng_stream_close(p->conn); // If we are waiting to negotiate on a client side, then a failure // here has to be passed to the user app. @@ -347,7 +352,7 @@ ipc_pipe_recv_cb(void *arg) if ((rv = nni_aio_result(rx_aio)) != 0) { // Error on receive. This has to cause an error back - // to the user. Also, if we had allocated an rx_msg, lets + // to the user. Also, if we had an allocated rx_msg, lets // toss it. goto error; } @@ -406,7 +411,7 @@ ipc_pipe_recv_cb(void *arg) } } - // Otherwise we got a message read completely. Let the user know the + // Otherwise, we got a message read completely. Let the user know the // good news. aio = nni_list_first(&p->recv_q); diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index e2e7fbce8..624403a75 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -9,7 +9,6 @@ // found online at https://opensource.org/licenses/MIT. // -#include #include #include @@ -259,8 +258,8 @@ tcptran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); return; } - // We have both sent and received the headers. Lets check the - // receive side header. + // We have both sent and received the headers. Let's check the + // receiver. if ((p->rxlen[0] != 0) || (p->rxlen[1] != 'S') || (p->rxlen[2] != 'P') || (p->rxlen[3] != 0) || (p->rxlen[6] != 0) || (p->rxlen[7] != 0)) { @@ -270,7 +269,7 @@ tcptran_pipe_nego_cb(void *arg) NNI_GET16(&p->rxlen[4], p->peer); - // We are all ready now. We put this in the wait list, and + // We are ready now. We put this in the wait list, and // then try to run the matcher. nni_list_remove(&ep->negopipes, p); nni_list_append(&ep->waitpipes, p); @@ -281,6 +280,13 @@ tcptran_pipe_nego_cb(void *arg) return; error: + // If the connection is closed, we need to pass back a different + // error code. This is necessary to avoid a problem where the + // closed status is confused with the accept file descriptor + // being closed. + if (rv == NNG_ECLOSED) { + rv = NNG_ECONNSHUT; + } nng_stream_close(p->conn); if ((uaio = ep->useraio) != NULL) { diff --git a/src/sp/transport/tls/tls.c b/src/sp/transport/tls/tls.c index 75858839f..4db9170d1 100644 --- a/src/sp/transport/tls/tls.c +++ b/src/sp/transport/tls/tls.c @@ -258,8 +258,8 @@ tlstran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); return; } - // We have both sent and received the headers. Lets check the - // receive side header. + // We have both sent and received the headers. Let's check the + // receiver. if ((p->rxlen[0] != 0) || (p->rxlen[1] != 'S') || (p->rxlen[2] != 'P') || (p->rxlen[3] != 0) || (p->rxlen[6] != 0) || (p->rxlen[7] != 0)) { @@ -269,7 +269,7 @@ tlstran_pipe_nego_cb(void *arg) NNI_GET16(&p->rxlen[4], p->peer); - // We are all ready now. We put this in the wait list, and + // We are ready now. We put this in the wait list, and // then try to run the matcher. nni_list_remove(&ep->negopipes, p); nni_list_append(&ep->waitpipes, p); @@ -280,6 +280,13 @@ tlstran_pipe_nego_cb(void *arg) return; error: + // If the connection is closed, we need to pass back a different + // error code. This is necessary to avoid a problem where the + // closed status is confused with the accept file descriptor + // being closed. + if (rv == NNG_ECLOSED) { + rv = NNG_ECONNSHUT; + } nng_stream_close(p->tls); if ((uaio = ep->useraio) != NULL) { From d45cdb1cac2191c029b71f7cebc1fab72895ed5d Mon Sep 17 00:00:00 2001 From: Leonard Pollak Date: Wed, 27 Oct 2021 07:53:02 +0200 Subject: [PATCH 132/180] Use env shebangs everywhere (#1515) Change all shebangs to use '#!/usr/bin/env bash'. This increases portability to platforms which do not cohere to the FHS. --- demo/async/run.sh | 2 +- etc/codecov.sh | 2 +- etc/coverage.sh | 2 +- etc/format-check.sh | 2 +- src/tools/nngcat/nngcat_ambiguous_test.sh | 2 +- src/tools/nngcat/nngcat_async_test.sh | 2 +- src/tools/nngcat/nngcat_dup_proto_test.sh | 2 +- src/tools/nngcat/nngcat_help_test.sh | 2 +- src/tools/nngcat/nngcat_incompat_test.sh | 2 +- src/tools/nngcat/nngcat_pubsub_test.sh | 2 +- src/tools/nngcat/nngcat_recvmaxsz_test.sh | 2 +- src/tools/nngcat/nngcat_stdin_pipe_test.sh | 2 +- src/tools/nngcat/nngcat_unlimited_test.sh | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/demo/async/run.sh b/demo/async/run.sh index 856fea9f4..b5128eb02 100755 --- a/demo/async/run.sh +++ b/demo/async/run.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ADDR=ipc:///tmp/async_demo COUNT=10 diff --git a/etc/codecov.sh b/etc/codecov.sh index 5ecdc55f3..7bddcd502 100755 --- a/etc/codecov.sh +++ b/etc/codecov.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright 2017 Garrett D'Amore # Copyright 2017 Capitar IT Group BV diff --git a/etc/coverage.sh b/etc/coverage.sh index 6f7355dca..73e71098e 100755 --- a/etc/coverage.sh +++ b/etc/coverage.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright 2017 Garrett D'Amore # Copyright 2017 Capitar IT Group BV diff --git a/etc/format-check.sh b/etc/format-check.sh index 68b3d8eb1..aca847c93 100755 --- a/etc/format-check.sh +++ b/etc/format-check.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # # Copyright 2016 Garrett D'Amore # diff --git a/src/tools/nngcat/nngcat_ambiguous_test.sh b/src/tools/nngcat/nngcat_ambiguous_test.sh index 414b6d191..944d5aedd 100755 --- a/src/tools/nngcat/nngcat_ambiguous_test.sh +++ b/src/tools/nngcat/nngcat_ambiguous_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_async_test.sh b/src/tools/nngcat/nngcat_async_test.sh index 2b03e5221..aeec3de23 100755 --- a/src/tools/nngcat/nngcat_async_test.sh +++ b/src/tools/nngcat/nngcat_async_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_dup_proto_test.sh b/src/tools/nngcat/nngcat_dup_proto_test.sh index 1513d01cf..a55b7f3ba 100755 --- a/src/tools/nngcat/nngcat_dup_proto_test.sh +++ b/src/tools/nngcat/nngcat_dup_proto_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_help_test.sh b/src/tools/nngcat/nngcat_help_test.sh index 95ed9e3e0..77b75034a 100755 --- a/src/tools/nngcat/nngcat_help_test.sh +++ b/src/tools/nngcat/nngcat_help_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_incompat_test.sh b/src/tools/nngcat/nngcat_incompat_test.sh index 128b57baa..93b754883 100755 --- a/src/tools/nngcat/nngcat_incompat_test.sh +++ b/src/tools/nngcat/nngcat_incompat_test.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_pubsub_test.sh b/src/tools/nngcat/nngcat_pubsub_test.sh index b9ba90edd..52d35a926 100755 --- a/src/tools/nngcat/nngcat_pubsub_test.sh +++ b/src/tools/nngcat/nngcat_pubsub_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_recvmaxsz_test.sh b/src/tools/nngcat/nngcat_recvmaxsz_test.sh index b5d4ff4a1..a41a02c07 100755 --- a/src/tools/nngcat/nngcat_recvmaxsz_test.sh +++ b/src/tools/nngcat/nngcat_recvmaxsz_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_stdin_pipe_test.sh b/src/tools/nngcat/nngcat_stdin_pipe_test.sh index 5fec0ab7b..824107e47 100755 --- a/src/tools/nngcat/nngcat_stdin_pipe_test.sh +++ b/src/tools/nngcat/nngcat_stdin_pipe_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_unlimited_test.sh b/src/tools/nngcat/nngcat_unlimited_test.sh index 0486b9b18..88a1e3095 100755 --- a/src/tools/nngcat/nngcat_unlimited_test.sh +++ b/src/tools/nngcat/nngcat_unlimited_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. From 8ef204270bd1df556e2b7f07054882d617fbf0bd Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Wed, 27 Oct 2021 22:34:41 -0700 Subject: [PATCH 133/180] fixes #1346 windows ipc winsec fails frequently in CI/CD --- .clang-format | 2 +- src/core/id_test.c | 22 +-- src/platform/posix/CMakeLists.txt | 3 + src/platform/posix/posix_ipcwinsec_test.c | 31 ++++ src/platform/windows/CMakeLists.txt | 5 +- src/platform/windows/win_ipc_sec_test.c | 190 +++++++++++++++++++ src/platform/windows/win_thread.c | 3 +- src/sp/protocol/pair0/pair.c | 70 +++---- src/sp/protocol/pair1/pair.c | 28 +-- src/sp/protocol/pipeline0/push.c | 16 +- src/supplemental/websocket/websocket_test.c | 70 +++---- tests/CMakeLists.txt | 1 - tests/ipcwinsec.c | 192 -------------------- 13 files changed, 334 insertions(+), 299 deletions(-) create mode 100644 src/platform/posix/posix_ipcwinsec_test.c create mode 100644 src/platform/windows/win_ipc_sec_test.c delete mode 100644 tests/ipcwinsec.c diff --git a/.clang-format b/.clang-format index ff7c2f088..02137561b 100644 --- a/.clang-format +++ b/.clang-format @@ -5,7 +5,7 @@ ColumnLimit: 79 AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: true AlignTrailingComments: true -AlignEscapedNewlinesLeft: true +AlignEscapedNewlines: Left PointerAlignment: Right ForEachMacros: ['NNI_LIST_FOREACH'] AlwaysBreakAfterReturnType: TopLevelDefinitions diff --git a/src/core/id_test.c b/src/core/id_test.c index 51872e690..b948cc132 100644 --- a/src/core/id_test.c +++ b/src/core/id_test.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -15,8 +15,8 @@ void test_basic(void) { nni_id_map m; - char * five = "five"; - char * four = "four"; + char *five = "five"; + char *four = "four"; nni_id_map_init(&m, 0, 0, false); @@ -60,8 +60,8 @@ void test_collision(void) { nni_id_map m; - char * five = "five"; - char * four = "four"; + char *five = "five"; + char *four = "four"; nni_id_map_init(&m, 0, 0, false); @@ -141,7 +141,7 @@ test_dynamic(void) nni_id_map_init(&m, 10, 13, false); - // We can fill the table. + // We can fill the table. NUTS_PASS(nni_id_alloc(&m, &id, &expect[0])); NUTS_TRUE(id == 10); NUTS_PASS(nni_id_alloc(&m, &id, &expect[1])); @@ -186,11 +186,11 @@ test_set_out_of_range(void) void test_stress(void) { - void * values[NUM_VALUES]; + void *values[NUM_VALUES]; nni_id_map m; size_t i; int rv; - void * x; + void *x; int v; nni_id_map_init(&m, 0, 0, false); @@ -240,15 +240,15 @@ test_stress(void) // Post stress check. for (i = 0; i < NUM_VALUES; i++) { - x = nni_id_get(&m, i); + x = nni_id_get(&m, (uint32_t) i); if (x != values[i]) { NUTS_TRUE(x == values[i]); break; } // We only use the test macros if we know they are going - // to fail. Otherwise there will be too many errors reported. - rv = nni_id_remove(&m, i); + // to fail. Otherwise, there will be too many errors reported. + rv = nni_id_remove(&m, (uint32_t) i); if ((x == NULL) && (rv != NNG_ENOENT)) { NUTS_FAIL(rv, NNG_ENOENT); } else if ((x != NULL) && (rv != 0)) { diff --git a/src/platform/posix/CMakeLists.txt b/src/platform/posix/CMakeLists.txt index 02a8cb53a..7b619fa22 100644 --- a/src/platform/posix/CMakeLists.txt +++ b/src/platform/posix/CMakeLists.txt @@ -105,4 +105,7 @@ if (NNG_PLATFORM_POSIX) else () nng_sources(posix_rand_urandom.c) endif () + + nng_test(posix_ipcwinsec_test) + endif () \ No newline at end of file diff --git a/src/platform/posix/posix_ipcwinsec_test.c b/src/platform/posix/posix_ipcwinsec_test.c new file mode 100644 index 000000000..934eeea91 --- /dev/null +++ b/src/platform/posix/posix_ipcwinsec_test.c @@ -0,0 +1,31 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// +#include +#include + +void +test_ipc_win_sec(void) +{ + char address[64]; + nng_stream_listener *l; + int x; + + nuts_scratch_addr("ipc", sizeof(address), address); + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + NUTS_FAIL(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, &x), + NNG_ENOTSUP); + nng_stream_listener_free(l); +} + +NUTS_TESTS = { + { "ipc security descriptor", test_ipc_win_sec }, + { NULL, NULL }, +}; diff --git a/src/platform/windows/CMakeLists.txt b/src/platform/windows/CMakeLists.txt index 174e77f86..d1d158e09 100644 --- a/src/platform/windows/CMakeLists.txt +++ b/src/platform/windows/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2020 Staysail Systems, Inc. +# Copyright 2021 Staysail Systems, Inc. # # This software is supplied under the terms of the MIT License, a # copy of which should be located in the distribution where this @@ -46,4 +46,7 @@ if (NNG_PLATFORM_WINDOWS) win_thread.c win_udp.c ) + + nng_test(win_ipc_sec_test) + endif () \ No newline at end of file diff --git a/src/platform/windows/win_ipc_sec_test.c b/src/platform/windows/win_ipc_sec_test.c new file mode 100644 index 000000000..ab65533bd --- /dev/null +++ b/src/platform/windows/win_ipc_sec_test.c @@ -0,0 +1,190 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include + +// Microsoft prefers CamelCase header names, but relies on case-insensitive +// file systems to make that work. The rest of the world (min-gw64 included) +// uses case-sensitive names and lowercase. + +#include +#include + +SECURITY_DESCRIPTOR * +sdescAuthUsers(PSID sid, PACL *aclp) +{ + SECURITY_DESCRIPTOR *sdesc; + EXPLICIT_ACCESS xa; + ACL *acl; + + sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); + NUTS_ASSERT(sdesc != NULL); + + InitializeSecurityDescriptor(sdesc, SECURITY_DESCRIPTOR_REVISION); + + xa.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; + xa.grfAccessMode = SET_ACCESS; + xa.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; + xa.Trustee.TrusteeForm = TRUSTEE_IS_SID; + xa.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + xa.Trustee.ptstrName = (LPSTR) sid; + + SetEntriesInAcl(1, &xa, NULL, &acl); + *aclp = acl; + + SetSecurityDescriptorDacl(sdesc, TRUE, acl, FALSE); + return (sdesc); +} + +void +test_ipc_security_descriptor(void) +{ + nng_stream_listener *l; + char address[64]; + char pipe[64]; + SECURITY_DESCRIPTOR *sd; + SID users; + DWORD size; + PACL acl = NULL; + PACL dacl; + PSECURITY_DESCRIPTOR psd; + PACE_HEADER ace; + PSID psid; + PACCESS_ALLOWED_ACE allowed; + nng_aio *aio; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + size = sizeof(users); + CreateWellKnownSid(WinAuthenticatedUserSid, NULL, &users, &size); + sd = sdescAuthUsers(&users, &acl); + + NUTS_ASSERT(sd != NULL); + NUTS_ASSERT(acl != NULL); + NUTS_PASS(nng_aio_alloc(&aio, NULL, NULL)); + + NUTS_PASS(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sd)); + NUTS_PASS(nng_stream_listener_listen(l)); + nng_stream_listener_accept(l, aio); + + (void) snprintf(pipe, sizeof(pipe), "\\\\.\\pipe\\%s", address+strlen("ipc://")); + HANDLE ph = CreateFileA(pipe, READ_CONTROL, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, NULL); + + nng_aio_wait(aio); + NUTS_PASS(nng_aio_result(aio)); + HANDLE pd = (HANDLE) nng_aio_get_output(aio, 0); + + NUTS_ASSERT(ph != INVALID_HANDLE_VALUE); + NUTS_ASSERT(pd != INVALID_HANDLE_VALUE); + + NUTS_ASSERT( + GetSecurityInfo(ph, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, + NULL, NULL, &dacl, NULL, &psd) == ERROR_SUCCESS); + + NUTS_ASSERT(dacl->AceCount == 1); + NUTS_ASSERT(GetAce(dacl, 0, (void **) &ace) == TRUE); + allowed = (PACCESS_ALLOWED_ACE) ace; + psid = (PSID) &allowed->SidStart; + NUTS_ASSERT(IsValidSid(psid)); + NUTS_ASSERT(EqualSid(psid, &users) == TRUE); + + CloseHandle(pd); + CloseHandle(ph); + free(sd); + LocalFree(acl); + LocalFree(psd); + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_busy(void) +{ + // This test ensures that the descriptor can only be set before + // the listener is started. + nng_stream_listener *l; + char address[64]; + SECURITY_DESCRIPTOR *sd; + SID users; + DWORD size; + PACL acl = NULL; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + size = sizeof(users); + CreateWellKnownSid(WinAuthenticatedUserSid, NULL, &users, &size); + sd = sdescAuthUsers(&users, &acl); + + NUTS_ASSERT(sd != NULL); + NUTS_ASSERT(acl != NULL); + + NUTS_PASS(nng_stream_listener_listen(l)); + + NUTS_FAIL(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sd), + NNG_EBUSY); + + free(sd); + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_bogus(void) +{ + nng_stream_listener *l; + char address[64]; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + + NUTS_FAIL(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, NULL), + NNG_EINVAL); + + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_dialer(void) +{ + nng_stream_dialer *d; + char address[64]; + SECURITY_DESCRIPTOR *sdesc; + + nuts_scratch_addr("ipc", sizeof(address), address); + NUTS_PASS(nng_stream_dialer_alloc(&d, address)); + + sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); + NUTS_ASSERT(sdesc != NULL); + InitializeSecurityDescriptor(sdesc, SECURITY_DESCRIPTOR_REVISION); + NUTS_FAIL(nng_stream_dialer_set_ptr( + d, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sdesc), + NNG_ENOTSUP); + free(sdesc); + nng_stream_dialer_free(d); +} + +NUTS_TESTS = { + { "ipc security descriptor", test_ipc_security_descriptor }, + { "ipc security descriptor busy", test_ipc_security_descriptor_busy }, + { "ipc security descriptor bogus", + test_ipc_security_descriptor_bogus }, + { "ipc security descriptor dialer", + test_ipc_security_descriptor_dialer }, + { NULL, NULL }, +}; diff --git a/src/platform/windows/win_thread.c b/src/platform/windows/win_thread.c index dc9ed12af..9c7c09d3e 100644 --- a/src/platform/windows/win_thread.c +++ b/src/platform/windows/win_thread.c @@ -381,7 +381,8 @@ nni_plat_thr_set_name(nni_plat_thr *thr, const char *name) if ((wcs = nni_alloc(len * 2)) == NULL) { return; } - (void) MultiByteToWideChar(CP_UTF8, 0, name, len, wcs, len); + (void) MultiByteToWideChar( + CP_UTF8, 0, name, (int) len, wcs, (int) len); set_thread_desc(h, wcs); nni_free(wcs, len * 2); } diff --git a/src/sp/protocol/pair0/pair.c b/src/sp/protocol/pair0/pair.c index c2407d817..c6470b7bb 100644 --- a/src/sp/protocol/pair0/pair.c +++ b/src/sp/protocol/pair0/pair.c @@ -32,7 +32,7 @@ static void pair0_pipe_send(pair0_pipe *, nni_msg *); // pair0_sock is our per-socket protocol private structure. struct pair0_sock { - pair0_pipe * p; + pair0_pipe *p; nni_mtx mtx; nni_lmq wmq; nni_list waq; @@ -44,12 +44,12 @@ struct pair0_sock { bool wr_ready; // pipe ready for write }; -// An pair0_pipe is our per-pipe protocol private structure. We keep +// A pair0_pipe is our per-pipe protocol private structure. We keep // one of these even though in theory we'd only have a single underlying // pipe. The separate data structure is more like other protocols that do // manage multiple pipes. struct pair0_pipe { - nni_pipe * pipe; + nni_pipe *pipe; pair0_sock *pair; nni_aio aio_send; nni_aio aio_recv; @@ -190,8 +190,8 @@ pair0_pipe_recv_cb(void *arg) { pair0_pipe *p = arg; pair0_sock *s = p->pair; - nni_msg * msg; - nni_aio * a; + nni_msg *msg; + nni_aio *a; if (nni_aio_result(&p->aio_recv) != 0) { nni_pipe_close(p->pipe); @@ -231,8 +231,8 @@ static void pair0_send_sched(pair0_sock *s) { pair0_pipe *p; - nni_msg * m; - nni_aio * a = NULL; + nni_msg *m; + nni_aio *a = NULL; size_t l = 0; nni_mtx_lock(&s->mtx); @@ -303,8 +303,8 @@ static void pair0_sock_close(void *arg) { pair0_sock *s = arg; - nni_aio * a; - nni_msg * m; + nni_aio *a; + nni_msg *m; nni_mtx_lock(&s->mtx); while (((a = nni_list_first(&s->raq)) != NULL) || ((a = nni_list_first(&s->waq)) != NULL)) { @@ -334,7 +334,7 @@ static void pair0_sock_send(void *arg, nni_aio *aio) { pair0_sock *s = arg; - nni_msg * m; + nni_msg *m; size_t len; int rv; @@ -384,7 +384,7 @@ pair0_sock_recv(void *arg, nni_aio *aio) { pair0_sock *s = arg; pair0_pipe *p; - nni_msg * m; + nni_msg *m; int rv; if (nni_aio_begin(aio) != 0) { @@ -463,7 +463,7 @@ pair0_get_send_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->mtx); - val = nni_lmq_cap(&s->wmq); + val = (int) nni_lmq_cap(&s->wmq); nni_mtx_unlock(&s->mtx); return (nni_copyout_int(val, buf, szp, t)); @@ -498,7 +498,7 @@ pair0_get_recv_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->mtx); - val = nni_lmq_cap(&s->rmq); + val = (int) nni_lmq_cap(&s->rmq); nni_mtx_unlock(&s->mtx); return (nni_copyout_int(val, buf, szp, t)); @@ -531,28 +531,28 @@ pair0_sock_get_send_fd(void *arg, void *buf, size_t *szp, nni_opt_type t) } static nni_option pair0_sock_options[] = { - { - .o_name = NNG_OPT_RECVFD, - .o_get = pair0_sock_get_recv_fd, - }, - { - .o_name = NNG_OPT_SENDFD, - .o_get = pair0_sock_get_send_fd, - }, - { - .o_name = NNG_OPT_SENDBUF, - .o_get = pair0_get_send_buf_len, - .o_set = pair0_set_send_buf_len, - }, - { - .o_name = NNG_OPT_RECVBUF, - .o_get = pair0_get_recv_buf_len, - .o_set = pair0_set_recv_buf_len, - }, - // terminate list - { - .o_name = NULL, - }, + { + .o_name = NNG_OPT_RECVFD, + .o_get = pair0_sock_get_recv_fd, + }, + { + .o_name = NNG_OPT_SENDFD, + .o_get = pair0_sock_get_send_fd, + }, + { + .o_name = NNG_OPT_SENDBUF, + .o_get = pair0_get_send_buf_len, + .o_set = pair0_set_send_buf_len, + }, + { + .o_name = NNG_OPT_RECVBUF, + .o_get = pair0_get_recv_buf_len, + .o_set = pair0_set_recv_buf_len, + }, + // terminate list + { + .o_name = NULL, + }, }; static nni_proto_pipe_ops pair0_pipe_ops = { diff --git a/src/sp/protocol/pair1/pair.c b/src/sp/protocol/pair1/pair.c index 4a909888c..e6be4628c 100644 --- a/src/sp/protocol/pair1/pair.c +++ b/src/sp/protocol/pair1/pair.c @@ -32,9 +32,9 @@ static void pair1_pipe_send(pair1_pipe *, nni_msg *); // pair1_sock is our per-socket protocol private structure. struct pair1_sock { - nni_sock * sock; + nni_sock *sock; bool raw; - pair1_pipe * p; + pair1_pipe *p; nni_atomic_int ttl; nni_mtx mtx; nni_lmq wmq; @@ -63,7 +63,7 @@ struct pair1_sock { // pair1_pipe is our per-pipe protocol private structure. struct pair1_pipe { - nni_pipe * pipe; + nni_pipe *pipe; pair1_sock *pair; nni_aio aio_send; nni_aio aio_recv; @@ -302,11 +302,11 @@ pair1_pipe_recv_cb(void *arg) { pair1_pipe *p = arg; pair1_sock *s = p->pair; - nni_msg * msg; + nni_msg *msg; uint32_t hdr; - nni_pipe * pipe = p->pipe; + nni_pipe *pipe = p->pipe; size_t len; - nni_aio * a; + nni_aio *a; if (nni_aio_result(&p->aio_recv) != 0) { nni_pipe_close(p->pipe); @@ -372,8 +372,8 @@ static void pair1_send_sched(pair1_sock *s) { pair1_pipe *p; - nni_msg * m; - nni_aio * a = NULL; + nni_msg *m; + nni_aio *a = NULL; size_t l = 0; nni_mtx_lock(&s->mtx); @@ -444,8 +444,8 @@ static void pair1_sock_close(void *arg) { pair1_sock *s = arg; - nni_aio * a; - nni_msg * m; + nni_aio *a; + nni_msg *m; nni_mtx_lock(&s->mtx); while (((a = nni_list_first(&s->raq)) != NULL) || ((a = nni_list_first(&s->waq)) != NULL)) { @@ -521,7 +521,7 @@ static void pair1_sock_send(void *arg, nni_aio *aio) { pair1_sock *s = arg; - nni_msg * m; + nni_msg *m; size_t len; int rv; @@ -599,7 +599,7 @@ pair1_sock_recv(void *arg, nni_aio *aio) { pair1_sock *s = arg; pair1_pipe *p; - nni_msg * m; + nni_msg *m; int rv; if (nni_aio_begin(aio) != 0) { @@ -678,7 +678,7 @@ pair1_get_send_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->mtx); - val = nni_lmq_cap(&s->wmq); + val = (int) nni_lmq_cap(&s->wmq); nni_mtx_unlock(&s->mtx); return (nni_copyout_int(val, buf, szp, t)); @@ -713,7 +713,7 @@ pair1_get_recv_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->mtx); - val = nni_lmq_cap(&s->rmq); + val = (int) nni_lmq_cap(&s->rmq); nni_mtx_unlock(&s->mtx); return (nni_copyout_int(val, buf, szp, t)); diff --git a/src/sp/protocol/pipeline0/push.c b/src/sp/protocol/pipeline0/push.c index ad43d967d..028104cdb 100644 --- a/src/sp/protocol/pipeline0/push.c +++ b/src/sp/protocol/pipeline0/push.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -43,8 +43,8 @@ struct push0_sock { // push0_pipe is our per-pipe protocol private structure. struct push0_pipe { - nni_pipe * pipe; - push0_sock * push; + nni_pipe *pipe; + push0_sock *push; nni_list_node node; nni_aio aio_recv; @@ -85,7 +85,7 @@ static void push0_sock_close(void *arg) { push0_sock *s = arg; - nni_aio * a; + nni_aio *a; nni_mtx_lock(&s->m); while ((a = nni_list_first(&s->aq)) != NULL) { nni_aio_list_remove(a); @@ -182,8 +182,8 @@ static void push0_pipe_ready(push0_pipe *p) { push0_sock *s = p->push; - nni_msg * m; - nni_aio * a = NULL; + nni_msg *m; + nni_aio *a = NULL; size_t l; bool blocked; @@ -266,7 +266,7 @@ push0_sock_send(void *arg, nni_aio *aio) { push0_sock *s = arg; push0_pipe *p; - nni_msg * m; + nni_msg *m; size_t l; int rv; @@ -356,7 +356,7 @@ push0_get_send_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->m); - val = nni_lmq_cap(&s->wq); + val = (int) nni_lmq_cap(&s->wq); nni_mtx_unlock(&s->m); return (nni_copyout_int(val, buf, szp, t)); diff --git a/src/supplemental/websocket/websocket_test.c b/src/supplemental/websocket/websocket_test.c index 9ea680173..be4e1b302 100644 --- a/src/supplemental/websocket/websocket_test.c +++ b/src/supplemental/websocket/websocket_test.c @@ -17,17 +17,17 @@ void test_websocket_wildcard(void) { - nng_stream_dialer * d = NULL; + nng_stream_dialer *d = NULL; nng_stream_listener *l = NULL; nng_sockaddr sa1; nng_sockaddr sa2; size_t sz; - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_aio * aio1 = NULL; - nng_aio * aio2 = NULL; - nng_stream * c1 = NULL; - nng_stream * c2 = NULL; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_aio *aio1 = NULL; + nng_aio *aio2 = NULL; + nng_stream *c1 = NULL; + nng_stream *c2 = NULL; nng_iov iov; char buf1[8]; char buf2[8]; @@ -125,18 +125,18 @@ test_websocket_wildcard(void) void test_websocket_conn_props(void) { - nng_stream_dialer * d = NULL; + nng_stream_dialer *d = NULL; nng_stream_listener *l = NULL; nng_sockaddr sa1; nng_sockaddr sa2; size_t sz; - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_stream * c1 = NULL; - nng_stream * c2 = NULL; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_stream *c1 = NULL; + nng_stream *c2 = NULL; char uri[64]; bool on; - char * str; + char *str; uint16_t port = nuts_next_port(); (void) snprintf(uri, sizeof(uri), "ws://127.0.0.1:%d/test", port); @@ -219,14 +219,14 @@ test_websocket_conn_props(void) void test_websocket_text_mode(void) { - nng_stream_dialer * d = NULL; + nng_stream_dialer *d = NULL; nng_stream_listener *l = NULL; - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_aio * aio1 = NULL; - nng_aio * aio2 = NULL; - nng_stream * c1 = NULL; - nng_stream * c2 = NULL; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_aio *aio1 = NULL; + nng_aio *aio2 = NULL; + nng_stream *c1 = NULL; + nng_stream *c2 = NULL; char uri[64]; char txb[5]; char rxb[5]; @@ -342,16 +342,16 @@ test_websocket_text_mode(void) } typedef struct recv_state { - nng_stream * c; + nng_stream *c; int total; int xfr; - nng_mtx * lock; - nng_cv * cv; - nng_aio * aio; + nng_mtx *lock; + nng_cv *cv; + nng_aio *aio; int err; bool done; - uint8_t * send_buf; - uint8_t * buf; + uint8_t *send_buf; + uint8_t *buf; nni_sha1_ctx sum; } recv_state; @@ -393,20 +393,20 @@ void test_websocket_fragmentation(void) { nng_stream_listener *l = NULL; - nng_stream_dialer * d = NULL; - nng_stream * c = NULL; + nng_stream_dialer *d = NULL; + nng_stream *c = NULL; uint16_t port; char url[64]; - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_aio * caio = NULL; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_aio *caio = NULL; int resid; recv_state state; uint8_t sum1[20]; uint8_t sum2[20]; - uint8_t * recv_buf; - uint8_t * send_buf; - uint8_t * buf; + uint8_t *recv_buf; + uint8_t *send_buf; + uint8_t *buf; nng_iov iov; memset(&state, 0, sizeof(state)); @@ -475,7 +475,7 @@ test_websocket_fragmentation(void) nng_aio_wait(caio); NUTS_PASS(nng_aio_result(caio)); NUTS_TRUE(nng_aio_count(caio) > 0); - len = nng_aio_count(caio); + len = (int) nng_aio_count(caio); resid -= len; buf += len; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 856ce387a..f9f9ee6ec 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -131,7 +131,6 @@ add_nng_test1(httpserver 30 NNG_SUPP_HTTP) add_nng_test(inproc 5) add_nng_test(ipc 5) add_nng_test(ipcsupp 10) -add_nng_test(ipcwinsec 5) add_nng_test(multistress 60) add_nng_test(nonblock 60) add_nng_test(options 5) diff --git a/tests/ipcwinsec.c b/tests/ipcwinsec.c deleted file mode 100644 index 533dfe379..000000000 --- a/tests/ipcwinsec.c +++ /dev/null @@ -1,192 +0,0 @@ -// -// Copyright 2021 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This software is supplied under the terms of the MIT License, a -// copy of which should be located in the distribution where this -// file was obtained (LICENSE.txt). A copy of the license may also be -// found online at https://opensource.org/licenses/MIT. -// - -#include -#include -#include -#include - -#include "convey.h" -#include "stubs.h" -#include "trantest.h" - -#define ADDR "/tmp/ipc_winsec_test" - -// Inproc tests. - -#ifndef _WIN32 -TestMain("IPC Security Descriptor", { - Convey("Given a socket and an IPC listener", { - nng_socket s; - nng_listener l; - int x; - - So(nng_rep0_open(&s) == 0); - Reset({ nng_close(s); }); - So(nng_listener_create(&l, s, "ipc://" ADDR) == 0); - Convey("We cannot set Windows SECURITY_DESCRIPTOR on POSIX", { - So(nng_listener_setopt_ptr(l, - NNG_OPT_IPC_SECURITY_DESCRIPTOR, - &x) == NNG_ENOTSUP); - }); - }); -}) -#else - -#include - -// Microsoft prefers CamelCase header names, but relies on case insensitive -// file systems to make that work. The rest of the world (min-gw64 included) -// uses case sensitive names and lowercase. - -#include - -#include - -#include - -SECURITY_DESCRIPTOR * -sdescAuthUsers(PSID sid, PACL *aclp) -{ - SECURITY_DESCRIPTOR *sdesc; - EXPLICIT_ACCESS xa; - ACL * acl; - - sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); - assert(sdesc != NULL); - - InitializeSecurityDescriptor(sdesc, SECURITY_DESCRIPTOR_REVISION); - - xa.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; - xa.grfAccessMode = SET_ACCESS; - xa.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - xa.Trustee.TrusteeForm = TRUSTEE_IS_SID; - xa.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - xa.Trustee.ptstrName = (LPSTR) sid; - - SetEntriesInAcl(1, &xa, NULL, &acl); - *aclp = acl; - - SetSecurityDescriptorDacl(sdesc, TRUE, acl, FALSE); - return (sdesc); -} - -TestMain("IPC Security Descriptor", { - Convey("Given a socket and an IPC listener", { - nng_socket s; - nng_listener l; - - So(nng_rep0_open(&s) == 0); - Reset({ nng_close(s); }); - - So(nng_listener_create(&l, s, "ipc://" ADDR) == 0); - Convey("We can set security descriptor on Windows", { - SECURITY_DESCRIPTOR *sdesc; - SID users; - DWORD size; - PACL acl = NULL; - - size = sizeof(users); - CreateWellKnownSid( - WinAuthenticatedUserSid, NULL, &users, &size); - - sdesc = sdescAuthUsers(&users, &acl); - assert(sdesc != NULL); - assert(acl != NULL); - Reset({ - free(sdesc); - LocalFree(acl); - }); - - So(nng_listener_setopt_ptr(l, - NNG_OPT_IPC_SECURITY_DESCRIPTOR, sdesc) == 0); - So(nng_listener_start(l, 0) == 0); - - Convey("And they are effective", { - PACL dacl; - PSECURITY_DESCRIPTOR sd; - PACE_HEADER ace; - PSID asid; - PACCESS_ALLOWED_ACE allowed; - - HANDLE ph = CreateFileA("\\\\.\\\\pipe\\" ADDR, - READ_CONTROL, 0, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); - - So(ph != INVALID_HANDLE_VALUE); - Reset({ CloseHandle(ph); }); - - So(GetSecurityInfo(ph, SE_KERNEL_OBJECT, - DACL_SECURITY_INFORMATION, NULL, NULL, - &dacl, NULL, &sd) == ERROR_SUCCESS); - Reset({ LocalFree(sd); }); - - So(dacl->AceCount == 1); - So(GetAce(dacl, 0, (void **) &ace) == TRUE); - allowed = (PACCESS_ALLOWED_ACE) ace; - asid = (PSID) &allowed->SidStart; - So(IsValidSid(asid)); - So(EqualSid(asid, &users) == TRUE); - }); - }); - - Convey("We cannot set security descriptor after started", { - SECURITY_DESCRIPTOR *sdesc; - SID users; - DWORD size; - PACL acl = NULL; - - size = sizeof(users); - CreateWellKnownSid( - WinAuthenticatedUserSid, NULL, &users, &size); - - sdesc = sdescAuthUsers(&users, &acl); - assert(sdesc != NULL); - assert(acl != NULL); - Reset({ - free(sdesc); - LocalFree(acl); - }); - - So(nng_listener_start(l, 0) == 0); - So(nng_listener_setopt_ptr(l, - NNG_OPT_IPC_SECURITY_DESCRIPTOR, - sdesc) == NNG_EBUSY); - }); - - Convey("We cannot set bogus security", { - So(nng_listener_setopt_ptr(l, - NNG_OPT_IPC_SECURITY_DESCRIPTOR, - NULL) == NNG_EINVAL); - }); - }); - - Convey("We cannot set security descriptor on an IPC dialer", { - nng_socket s; - nng_dialer d; - SECURITY_DESCRIPTOR *sdesc; - - sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); - assert(sdesc != NULL); - InitializeSecurityDescriptor( - sdesc, SECURITY_DESCRIPTOR_REVISION); - - So(nng_rep0_open(&s) == 0); - Reset({ - nng_close(s); - free(sdesc); - }); - - So(nng_dialer_create(&d, s, "ipc://" ADDR) == 0); - So(nng_dialer_setopt_ptr(d, NNG_OPT_IPC_SECURITY_DESCRIPTOR, - sdesc) == NNG_ENOTSUP); - }); -}) -#endif From 3543d5ab828af865bbe872e28827b1b3435c0a33 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Fri, 12 Nov 2021 16:32:13 +0800 Subject: [PATCH 134/180] * FIX [mqtt_test] 'SEGV on unknown address' --- src/mqtt/mqtt_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 1ac171e04..55bba85a1 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -491,4 +491,5 @@ TEST_LIST = { { "decode publish", test_decode_publish }, { "decode puback", test_decode_puback }, { "decode suback", test_decode_suback }, + { NULL, NULL }, }; From bec460552848466925dbf8b78b2bfa328eb530c3 Mon Sep 17 00:00:00 2001 From: eeff Date: Fri, 12 Nov 2021 11:26:56 +0800 Subject: [PATCH 135/180] Fix mqtt client protocol state machine The nng concurrency model may call the pipe sending and receiving callback in any order, which compromises the correctness of the protocol state machine. This fix introduces a new `acked` state to solve the problem. --- src/sp/protocol/mqtt/mqtt_client.c | 101 ++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 9bccf5333..5a935cb92 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -51,19 +51,22 @@ static void mqtt_ctx_fini(void *arg); static void mqtt_ctx_send(void *arg, nni_aio *aio); static void mqtt_ctx_recv(void *arg, nni_aio *aio); +typedef nni_mqtt_packet_type packet_type_t; + // Work state indicating what MQTT packet we *expect* to send/recv. // // bits: 7 6 5 4 3 2 1 0 -// error <_/ | | | -// final <___/ | | -// init <_____/ |________> lower nib encoding packet type -// +// error <_/ | | | | +// final <___/ | | \________> lower nib encoding packet type +// init <_____/ \__________> ack received typedef uint8_t work_state_t; +#define WORK_STATE_ACKED 0x10 // state we had received expected ack packet #define WORK_STATE_INIT 0x20 // start state #define WORK_STATE_FINAL 0x40 // final state #define WORK_STATE_ERROR 0x80 // error state +#define work_is_acked(work) ((work)->state & WORK_STATE_ACKED) #define work_is_error(work) ((work)->state & WORK_STATE_ERROR) #define work_is_final(work) ((work)->state & WORK_STATE_FINAL) #define work_packet_type(work) ((work)->state & 0xEF) @@ -71,6 +74,7 @@ typedef uint8_t work_state_t; #define work_set_init(work) ((work)->state = WORK_STATE_INIT) #define work_set_send(work, packet) ((work)->state = (packet)) #define work_set_recv(work, packet) ((work)->state = (packet)) +#define work_set_acked(work) ((work)->state |= WORK_STATE_ACKED) #define work_set_error(work) ((work)->state = WORK_STATE_ERROR) #define work_set_final(work) ((work)->state = WORK_STATE_FINAL) @@ -556,7 +560,6 @@ mqtt_send_cb(void *arg) return; case NNG_MQTT_PUBLISH: - // TODO: handle retry // we have sent a PUBLISH if (0 == work->qos) { // QoS 0, no further actions @@ -564,17 +567,23 @@ mqtt_send_cb(void *arg) } else { if (1 == work->qos) { // for QoS 1, expect receiving a PUBACK - work_set_recv(work, NNG_MQTT_PUBACK); + if (!work_is_acked(work)) { + work_set_recv(work, NNG_MQTT_PUBACK); + work_timer_schedule(work); + } else { + // scheduling disorder, PUBACK received + work_set_final(work); + } } else { // for QoS 2, expect receiving a PUBREC - work_set_recv(work, NNG_MQTT_PUBREC); - } - if (0 != - nni_id_set( - &p->send_unack, work->packet_id, work)) { - // FIXME + if (!work_is_acked(work)) { + work_set_recv(work, NNG_MQTT_PUBREC); + work_timer_schedule(work); + } else { + // scheduling disorder, PUBREC received + work_set_recv(work, NNG_MQTT_PUBCOMP); + } } - work_timer_schedule(work); } break; @@ -590,16 +599,24 @@ mqtt_send_cb(void *arg) case NNG_MQTT_SUBSCRIBE: // we have sent a SUBSCRIBE, expect receiving a SUBACK - work_set_recv(work, NNG_MQTT_SUBACK); - nni_id_set(&p->send_unack, work->packet_id, work); - work_timer_schedule(work); + if (!work_is_acked(work)) { + work_set_recv(work, NNG_MQTT_SUBACK); + work_timer_schedule(work); + } else { + // scheduling disorder, SUBACK received + work_set_final(work); + } break; case NNG_MQTT_UNSUBSCRIBE: // we have sent a UNSUBSCRIBE, expect receiving a UNSUBACK - work_set_recv(work, NNG_MQTT_UNSUBACK); - nni_id_set(&p->send_unack, work->packet_id, work); - work_timer_schedule(work); + if (!work_is_acked(work)) { + work_set_recv(work, NNG_MQTT_UNSUBACK); + work_timer_schedule(work); + } else { + // scheduling disorder, UNSUBACK received + work_set_final(work); + } break; default: @@ -660,9 +677,9 @@ mqtt_recv_cb(void *arg) nni_mqtt_msg_proto_data_alloc(msg); nni_mqtt_msg_decode(msg); - nni_mqtt_packet_type packet_type = nni_mqtt_msg_get_packet_type(msg); - int32_t packet_id; - uint8_t qos; + packet_type_t packet_type = nni_mqtt_msg_get_packet_type(msg); + int32_t packet_id; + uint8_t qos; // schedule another receive nni_pipe_recv(p->pipe, &p->recv_aio); @@ -686,28 +703,43 @@ mqtt_recv_cb(void *arg) // fall through case NNG_MQTT_SUBACK: - // we have received a SUBACK, successful subcription + // we have received a SUBACK, successful subscription // fall through case NNG_MQTT_UNSUBACK: - // we have received a UNSUBACK, successful unsubcription + // we have received a UNSUBACK, successful unsubscription packet_id = nni_mqtt_msg_get_packet_id(msg); nni_msg_free(msg); work = nni_id_get(&p->send_unack, packet_id); if (NULL == work) { // ignore this message nni_mtx_unlock(&s->mtx); - // nni_pipe_close(p->pipe); return; } nni_id_remove(&p->send_unack, packet_id); - if (work_packet_type(work) == packet_type) { + packet_type_t expect_packet_type = work_packet_type(work); + if (expect_packet_type == packet_type) { work_set_final(work); + work_timer_cancel(work); + } else if ( + // 1. we are sending QoS 1 and received PUBACK + (NNG_MQTT_PUBLISH == expect_packet_type && + 1 == work->qos && NNG_MQTT_PUBACK == packet_type) || + // 2. we are sending QoS 2 and received PUBCOMP + (NNG_MQTT_PUBLISH == expect_packet_type && + 2 == work->qos && NNG_MQTT_PUBCOMP == packet_type) || + // 3. we are sending SUBSCRIBE and received SUBACK + (NNG_MQTT_SUBSCRIBE == expect_packet_type && + NNG_MQTT_SUBACK == packet_type) || + // 4. we are sending UNSUBSCRIBE and received UNSUBACK + (NNG_MQTT_UNSUBSCRIBE == expect_packet_type && + NNG_MQTT_UNSUBACK == packet_type)) { + // scheduling disorder + work_set_acked(work); } else { work_set_error(work); } - work_timer_cancel(work); break; case NNG_MQTT_PINGRESP: @@ -730,10 +762,15 @@ mqtt_recv_cb(void *arg) // expect to receive a PUBCOMP if (work_packet_type(work) == packet_type) { work_set_recv(work, NNG_MQTT_PUBCOMP); + work_timer_cancel(work); + } else if (work_packet_type(work) == NNG_MQTT_PUBLISH && + 2 == work->qos) { + // scheduling disorder + work_set_acked(work); } else { work_set_error(work); + work_timer_cancel(work); } - work_timer_cancel(work); break; case NNG_MQTT_PUBREL: @@ -872,7 +909,6 @@ mqtt_send_start(mqtt_sock_t *s) return; } - // TODO: handle retry if (NULL != (work = nni_list_first(&s->send_queue))) { packet_type = nni_mqtt_msg_get_packet_type(work->msg); @@ -901,6 +937,13 @@ mqtt_send_start(mqtt_sock_t *s) nni_mqtt_msg_set_packet_id( work->msg, work->packet_id); nni_mqtt_msg_encode(work->msg); + NNI_ASSERT(nni_id_get(&p->send_unack, + work->packet_id) == NULL); + if (0 != + nni_id_set(&p->send_unack, work->packet_id, + work)) { + // FIXME + } break; default: From 868e895e584b942ff77e664a94c4608a5c5720fe Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Tue, 16 Nov 2021 18:42:56 +0800 Subject: [PATCH 136/180] * FIX [mqtt_tcp] move process of encoding msg to mqtt_tcp from demo. --- demo/mqtt_async/mqtt_async.c | 10 +++------- src/sp/transport/mqtt/mqtt_tcp.c | 17 +++++------------ 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index 46d9d36ec..cffd0f8d0 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -158,8 +158,8 @@ static void connect_cb(void *arg, nng_msg *msg) { (void) arg; - printf( - "connack status: %d\n", nng_mqtt_msg_get_connack_return_code(msg)); + printf("Connack status: %d\n", + nng_mqtt_msg_get_connack_return_code(msg)); nng_msg_free(msg); } @@ -191,10 +191,6 @@ client(const char *url) nng_mqtt_msg_set_connect_keep_alive(msg, 60); nng_mqtt_msg_set_connect_clean_session(msg, true); - if ((rv = nng_mqtt_msg_encode(msg)) != 0) { - fprintf(stderr, "nng_mqtt_msg_encode failed: %d\n", rv); - } - nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); nng_dialer_set_cb(dialer, connect_cb, NULL); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); @@ -224,4 +220,4 @@ main(int argc, const char **argv) client(argv[1]); return 0; -} \ No newline at end of file +} diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index e745eaa64..6574d13be 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -279,9 +279,6 @@ mqtt_tcptran_pipe_nego_cb(void *arg) } else if (p->gotrxhead < p->wantrxhead) { p->gotrxhead += nni_aio_count(aio); } - printf("mqtt_tcptran_pipe_nego_cb gotrx %ld wantrx %ld gottx %ld " - "wanttx %ld.\n", - p->gotrxhead, p->wantrxhead, p->gottxhead, p->wanttxhead); if (p->gottxhead < p->wanttxhead) { nni_iov iov; @@ -310,12 +307,10 @@ mqtt_tcptran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); return; } + // finish recevied fixed header - // TODO only deal with CONNACK, so just use rxlen at all time if (p->rxmsg == NULL) { if ((p->rxlen[0] & 0x20) != 0x20) { - fprintf( - stderr, "not recv connack [%x].\n", p->rxlen[0]); rv = NNG_EPROTO; goto error; } @@ -335,7 +330,6 @@ mqtt_tcptran_pipe_nego_cb(void *arg) p->wantrxhead = var_int + 1 + pos; if ((rv = (p->wantrxhead <= 4) ? 0 : NNG_EPROTO) != 0) { - fprintf(stderr, "wantrxhead error rv[%d].\n", rv); // TODO BUG here goto error; } @@ -352,7 +346,6 @@ mqtt_tcptran_pipe_nego_cb(void *arg) return; } if (p->gotrxhead >= p->wantrxhead) { - fprintf(stderr, "finish recv connack. [%ld]\n", p->gotrxhead); nni_mqtt_msg_decode(p->rxmsg); p->rxmsg = NULL; } @@ -400,7 +393,6 @@ mqtt_tcptran_pipe_send_cb(void *arg) nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->sendq); - // fprintf(stderr, "mqtt_tcptran_pipe_send_cb.\n"); if ((rv = nni_aio_result(txaio)) != 0) { nni_pipe_bump_error(p->npipe, rv); @@ -448,7 +440,6 @@ mqtt_tcptran_pipe_recv_cb(void *arg) mqtt_tcptran_pipe *p = arg; nni_aio * rxaio = p->rxaio; - // printf("mqtt_tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->recvq); @@ -792,9 +783,12 @@ mqtt_tcptran_pipe_start( rv = nni_dialer_getopt( ep->ndialer, NNG_OPT_MQTT_CONNMSG, &connmsg, NULL, NNI_TYPE_POINTER); if (!connmsg) { - fprintf(stderr, "Connmsg get error [%d] \n", rv); nni_list_append(&ep->waitpipes, p); mqtt_tcptran_ep_match(ep); + return; + } + if ((rv = nng_mqtt_msg_encode(connmsg)) != 0) { + nni_list_append(&ep->waitpipes, p); mqtt_tcptran_ep_match(ep); return; } @@ -1176,7 +1170,6 @@ mqtt_tcptran_ep_connect(void *arg, nni_aio *aio) { mqtt_tcptran_ep *ep = arg; int rv; - // fprintf(stderr, "mqtt_tcptran_ep_connect\n"); if (nni_aio_begin(aio) != 0) { return; From e4e49c63a361c14d79e2ac4dadf28ec0333f833e Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Wed, 17 Nov 2021 18:30:14 +0800 Subject: [PATCH 137/180] * FIX [demo/mqtt] fix some error in the sync client demo. --- demo/mqtt/mqtt_client.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index 1388f1dd0..015de345e 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -72,7 +72,7 @@ static void connect_cb(void *arg, nng_msg *ackmsg) { char * userarg = (char *) arg; - uint8_t status = nng_mqtt_msg_get_conack_return_code(ackmsg); + uint8_t status = nng_mqtt_msg_get_connack_return_code(ackmsg); printf("Connected cb. \n" " -> Status [%d]\n" " -> Userarg [%s].\n", @@ -104,19 +104,13 @@ client_connect(nng_socket *sock, const char *url, bool verbose) nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); nng_mqtt_msg_set_connect_proto_version(connmsg, 4); nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); - nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); - nng_mqtt_msg_set_connect_password(connmsg, "secrets"); - nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); - nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); - nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); +// nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); +// nng_mqtt_msg_set_connect_password(connmsg, "secrets"); +// nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); +// nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); +// nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); nng_mqtt_msg_set_connect_clean_session(connmsg, true); - rv = nng_mqtt_msg_encode(connmsg); - - if (rv != 0) { - printf("Problem on building CONNECT message: %d\n", rv); - } - uint8_t buff[1024] = { 0 }; if (verbose) { @@ -132,9 +126,6 @@ client_connect(nng_socket *sock, const char *url, bool verbose) printf("connected\n"); // TODO Connmsg would be free when client disconnected - // nng_msg_free(connmsg); - nng_mqtt_msg_proto_data_free(connmsg); - return (0); } From 1eac1139938bdf76f0779096df169c53dd287e83 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Thu, 18 Nov 2021 15:05:57 +0800 Subject: [PATCH 138/180] * FIX [mqtt.c] fix the error of utf8-string setting in connect package. --- demo/mqtt/mqtt_client.c | 10 +++++----- src/mqtt/mqtt.c | 10 +++++----- src/mqtt/mqtt_test.c | 5 +++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index 015de345e..d0ea12295 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -104,11 +104,11 @@ client_connect(nng_socket *sock, const char *url, bool verbose) nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT); nng_mqtt_msg_set_connect_proto_version(connmsg, 4); nng_mqtt_msg_set_connect_keep_alive(connmsg, 60); -// nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); -// nng_mqtt_msg_set_connect_password(connmsg, "secrets"); -// nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); -// nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); -// nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); + nng_mqtt_msg_set_connect_user_name(connmsg, "nng_mqtt_client"); + nng_mqtt_msg_set_connect_password(connmsg, "secrets"); + nng_mqtt_msg_set_connect_will_msg(connmsg, "bye-bye"); + nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic"); + nng_mqtt_msg_set_connect_client_id(connmsg, "nng_mqtt_client"); nng_mqtt_msg_set_connect_clean_session(connmsg, true); uint8_t buff[1024] = { 0 }; diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index 195f82889..03c2322a3 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -453,7 +453,7 @@ nni_mqtt_msg_set_connect_client_id(nni_msg *msg, const char *client_id) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.client_id, - (const uint8_t *) client_id, strlen(client_id) + 1); + (const uint8_t *) client_id, strlen(client_id)); } void @@ -461,7 +461,7 @@ nni_mqtt_msg_set_connect_will_topic(nni_msg *msg, const char *will_topic) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.will_topic, - (const uint8_t *) will_topic, strlen(will_topic) + 1); + (const uint8_t *) will_topic, strlen(will_topic)); } void @@ -469,7 +469,7 @@ nni_mqtt_msg_set_connect_will_msg(nni_msg *msg, const char *will_msg) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.will_msg, - (const uint8_t *) will_msg, strlen(will_msg) + 1); + (const uint8_t *) will_msg, strlen(will_msg)); } void @@ -477,7 +477,7 @@ nni_mqtt_msg_set_connect_user_name(nni_msg *msg, const char *user_name) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.user_name, - (const uint8_t *) user_name, strlen(user_name) + 1); + (const uint8_t *) user_name, strlen(user_name)); } void @@ -485,7 +485,7 @@ nni_mqtt_msg_set_connect_password(nni_msg *msg, const char *password) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.password, - (const uint8_t *) password, strlen(password) + 1); + (const uint8_t *) password, strlen(password)); } const char * diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index 55bba85a1..d97560f2f 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -76,16 +76,17 @@ void test_encode_connect(void) { nng_msg *msg; + char client_id[] = "nanomq-mqtt"; NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); - nng_mqtt_msg_set_connect_client_id(msg, "nanomq-mqtt"); + nng_mqtt_msg_set_connect_client_id(msg, client_id); NUTS_ASSERT(strncmp(nng_mqtt_msg_get_connect_client_id(msg), - "nanomq-mqtt", 12) == 0); + client_id, strlen(client_id)) == 0); char will_topic[] = "/nanomq/will_msg"; nng_mqtt_msg_set_connect_will_topic(msg, will_topic); From 0c40cbd3c27553991a678d6790275077663e07d2 Mon Sep 17 00:00:00 2001 From: eeff Date: Tue, 16 Nov 2021 18:12:06 +0800 Subject: [PATCH 139/180] Remove mqtt protocol pre-allocated work list --- src/sp/protocol/mqtt/mqtt_client.c | 91 +++++++++++++++++++----------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 5a935cb92..3f8241027 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -21,8 +21,6 @@ #define NNG_MQTT_PEER 0 #define NNG_MQTT_PEER_NAME "mqtt-server" -#define MQTT_WORK_NUM 64 - typedef struct mqtt_sock_s mqtt_sock_t; typedef struct mqtt_pipe_s mqtt_pipe_t; typedef struct mqtt_ctx_s mqtt_ctx_t; @@ -119,10 +117,9 @@ struct mqtt_sock_s { nni_mtx mtx; // TODO: more fine grained mutual exclusion mqtt_ctx_t master; // to which we delegate send/recv calls mqtt_pipe_t * mqtt_pipe; - nni_list send_queue; // work pending to send - nni_list recv_queue; // work pending to receive - nni_list free_list; // free list of work - work_t works[MQTT_WORK_NUM]; // pre allocated work + nni_list send_queue; // work pending to send + nni_list recv_queue; // work pending to receive + nni_list free_list; // free list of work }; /****************************************************************************** @@ -248,10 +245,6 @@ mqtt_sock_init(void *arg, nni_sock *sock) NNI_LIST_INIT(&s->send_queue, work_t, node); NNI_LIST_INIT(&s->recv_queue, work_t, node); NNI_LIST_INIT(&s->free_list, work_t, node); - for (int i = 0; i < MQTT_WORK_NUM; ++i) { - work_init(&s->works[i], s, s->retry, mqtt_timer_cb); - nni_list_append(&s->free_list, &s->works[i]); - } return (0); } @@ -260,15 +253,18 @@ static void mqtt_sock_fini(void *arg) { mqtt_sock_t *s = arg; + work_t * work; nni_mtx_lock(&s->mtx); NNI_ASSERT(nni_list_empty(&s->send_queue)); NNI_ASSERT(nni_list_empty(&s->recv_queue)); - nni_mtx_unlock(&s->mtx); - for (int i = 0; i < MQTT_WORK_NUM; ++i) { - work_fini(&s->works[i]); + while (NULL != (work = nni_list_first(&s->free_list))) { + nni_list_remove(&s->free_list, work); + work_fini(work); + nni_free(work, sizeof(work_t)); } + nni_mtx_unlock(&s->mtx); mqtt_ctx_fini(&s->master); nni_mtx_fini(&s->mtx); @@ -302,6 +298,33 @@ mqtt_sock_recv(void *arg, nni_aio *aio) mqtt_ctx_recv(&s->master, aio); } +// Note: This routine should be called with the sock lock held. +static inline work_t * +mqtt_sock_get_work(mqtt_sock_t *s) +{ + // TODO: reduce number of allocation + // TODO: shrink when low load + work_t *work = nni_list_first(&s->free_list); + if (NULL != work) { + nni_list_remove(&s->free_list, work); + } else { + work = nni_zalloc(sizeof(work_t)); + if (NULL == work) { + return NULL; // oom + } + work_init(work, s, s->retry, mqtt_timer_cb); + } + return work; +} + +// Note: This routine should be called with the sock lock held. +static inline void +mqtt_sock_free_work(mqtt_sock_t *s, work_t *work) +{ + work_reset(work); + nni_list_append(&s->free_list, work); +} + /****************************************************************************** * Pipe Implementation * ******************************************************************************/ @@ -481,8 +504,7 @@ mqtt_timer_cb(void *arg) // reach max retransmitting, quit nni_aio_finish_error(work->user_aio, NNG_EAGAIN); nni_id_remove(&p->send_unack, work->packet_id); - work_reset(work); - nni_list_append(&s->free_list, work); + mqtt_sock_free_work(s, work); } nni_mtx_unlock(&s->mtx); @@ -544,11 +566,11 @@ mqtt_send_cb(void *arg) // indicating a successful receipt of a QoS 2 message work_set_final(work); nni_id_remove(&p->recv_unack, work->packet_id); + // ownership of work->msg to the lmq mqtt_pipe_recv_msgq_putq(p, work->msg); + work->msg = NULL; + mqtt_sock_free_work(s, work); mqtt_run_recv_queue(s); - work->msg = NULL; // ownership to the lmq - work_reset(work); - nni_list_append(&s->free_list, work); mqtt_send_start(s); nni_mtx_unlock(&s->mtx); return; @@ -633,8 +655,7 @@ mqtt_send_cb(void *arg) } else if (work_is_final(work)) { // good news, protocol state machine run to the end nni_aio *aio = work->user_aio; - work_reset(work); - nni_list_append(&s->free_list, work); + mqtt_sock_free_work(s, work); mqtt_send_start(s); nni_mtx_unlock(&s->mtx); if (NULL != aio) { @@ -786,11 +807,11 @@ mqtt_recv_cb(void *arg) // the transport handled sending the PUBCOMP for us work_set_final(work); nni_id_remove(&p->recv_unack, work->packet_id); + // ownership of work->msg to the lmq mqtt_pipe_recv_msgq_putq(p, work->msg); mqtt_run_recv_queue(s); - work->msg = msg; // ownership of work->msg to the lmq - work_reset(work); // will release msg - nni_list_append(&s->free_list, work); + work->msg = msg; + mqtt_sock_free_work(s, work); // will release msg nni_mtx_unlock(&s->mtx); return; @@ -805,8 +826,12 @@ mqtt_recv_cb(void *arg) nni_mtx_unlock(&s->mtx); return; } else { - work = nni_list_first(&s->free_list); - nni_list_remove(&s->free_list, work); + work = mqtt_sock_get_work(s); + if (work == NULL) { + nni_mtx_unlock(&s->mtx); + nni_pipe_close(p->pipe); + return; + } work->qos = qos; work->msg = msg; // keep the message work->packet_id = @@ -834,8 +859,7 @@ mqtt_recv_cb(void *arg) } else if (work_is_final(work)) { // good news, protocol state machine run to the end nni_aio *aio = work->user_aio; - work_reset(work); - nni_list_append(&s->free_list, work); + mqtt_sock_free_work(s, work); nni_mtx_unlock(&s->mtx); nni_aio_finish(aio, 0, 0); return; @@ -857,17 +881,16 @@ mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) return; } - work = nni_list_first(&s->free_list); + work = mqtt_sock_get_work(s); if (NULL == work) { nni_mtx_unlock(&s->mtx); - nni_aio_finish_error(aio, NNG_EBUSY); + nni_aio_finish_error(aio, NNG_ENOMEM); return; } work->user_aio = aio; work_set_recv(work, NNG_MQTT_PUBLISH); - nni_list_remove(&s->free_list, work); nni_list_append(&s->recv_queue, work); // enqueue to recv mqtt_run_recv_queue(s); } @@ -889,7 +912,7 @@ mqtt_run_recv_queue(mqtt_sock_t *s) nni_aio_set_msg(work->user_aio, msg); nni_aio_finish(work->user_aio, 0, nni_msg_header_len(msg) + nni_msg_len(msg)); - nni_list_append(&s->free_list, work); + mqtt_sock_free_work(s, work); work = nni_list_first(&s->recv_queue); } @@ -1005,10 +1028,11 @@ mqtt_ctx_send(void *arg, nni_aio *aio) return; } - work = nni_list_first(&s->free_list); + work = mqtt_sock_get_work(s); + if (NULL == work) { nni_mtx_unlock(&s->mtx); - nni_aio_finish_error(aio, NNG_EBUSY); + nni_aio_finish_error(aio, NNG_ENOMEM); return; } @@ -1016,7 +1040,6 @@ mqtt_ctx_send(void *arg, nni_aio *aio) work->msg = nni_aio_get_msg(aio); nni_aio_bump_count( aio, nni_msg_header_len(work->msg) + nni_msg_len(work->msg)); - nni_list_remove(&s->free_list, work); nni_list_append(&s->send_queue, work); // enqueue to send if (nni_list_first(&s->send_queue) == work) { From fd8da8f3f8736c8972cfe255e847f050fa877335 Mon Sep 17 00:00:00 2001 From: eeff Date: Wed, 17 Nov 2021 19:00:20 +0800 Subject: [PATCH 140/180] Fix mqtt protocol to release resources correctly When closing the pipe: 1. Aborts any pending send/recv work in the queue 2. Aborts any unacknowledged send/recv work --- src/core/idhash.c | 12 +++++ src/core/idhash.h | 1 + src/sp/protocol/mqtt/mqtt_client.c | 75 ++++++++++++------------------ 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/core/idhash.c b/src/core/idhash.c index c61850d29..1defc704c 100644 --- a/src/core/idhash.c +++ b/src/core/idhash.c @@ -56,6 +56,18 @@ nni_id_map_fini(nni_id_map *m) } } +void +nni_id_map_foreach(nni_id_map *m, nni_cb cb) +{ + if (m->id_entries != NULL) { + for (size_t i = 0; i < m->id_cap; ++i) { + if (m->id_entries[i].val != NULL) { + cb(m->id_entries[i].val); + } + } + } +} + // Inspired by Python dict implementation. This probe will visit every // cell. We always hash consecutively assigned IDs. This requires that // the capacity is always a power of two. diff --git a/src/core/idhash.h b/src/core/idhash.h index 0c9043cec..7dbd78cf9 100644 --- a/src/core/idhash.h +++ b/src/core/idhash.h @@ -42,6 +42,7 @@ struct nni_id_map { extern void nni_id_map_init(nni_id_map *, uint32_t, uint32_t, bool); extern void nni_id_map_fini(nni_id_map *); +extern void nni_id_map_foreach(nni_id_map *, nni_cb); extern void *nni_id_get(nni_id_map *, uint32_t); extern int nni_id_set(nni_id_map *, uint32_t, void *); extern int nni_id_alloc(nni_id_map *, uint32_t *, void *); diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 3f8241027..862cf7eb1 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -164,46 +164,6 @@ work_reset(work_t *work) nni_list_node_remove(&work->node); } -// cancels any outstanding operation, -// and waits for the work to complete, if still running. -static inline void -work_stop(work_t *work) -{ - nni_list_node_remove(&work->node); -} - -// closes the aio for further activity. -// It aborts any in-progress transaction (if it can). -static inline void -work_close(work_t *work) -{ - if (NULL != work->user_aio) { - nni_aio_finish_error(work->user_aio, NNG_ECONNRESET); - nni_msg_free(work->msg); - work->msg = NULL; - work->user_aio = NULL; - } - nni_list_node_remove(&work->node); -} - -static inline void -work_stop_queue(nni_list *queue) -{ - work_t *work; - NNI_LIST_FOREACH (queue, work) { - work_stop(work); - } -} - -static inline void -work_close_queue(nni_list *queue) -{ - work_t *work; - NNI_LIST_FOREACH (queue, work) { - work_close(work); - } -} - static inline void work_timer_schedule(work_t *work) { @@ -325,6 +285,26 @@ mqtt_sock_free_work(mqtt_sock_t *s, work_t *work) nni_list_append(&s->free_list, work); } +// Note: This routine should be called with the sock lock held. +static inline void +mqtt_sock_close_work(mqtt_sock_t *s, work_t *work) +{ + if (NULL != work->user_aio) { + nni_aio_finish_error(work->user_aio, NNG_ECONNRESET); + } + mqtt_sock_free_work(s, work); +} + +// Note: This routine should be called with the sock lock held. +static inline void +mqtt_sock_close_work_queue(mqtt_sock_t *s, nni_list *queue) +{ + work_t *work; + while (NULL != (work = nni_list_first(queue))) { + mqtt_sock_close_work(s, work); // remove from the list + } +} + /****************************************************************************** * Pipe Implementation * ******************************************************************************/ @@ -402,11 +382,16 @@ mqtt_pipe_stop(void *arg) nni_mtx_lock(&s->mtx); nni_aio_stop(&p->send_aio); nni_aio_stop(&p->recv_aio); - work_stop_queue(&s->send_queue); - work_stop_queue(&s->recv_queue); nni_mtx_unlock(&s->mtx); } +void +mqtt_close_unack_work_cb(void *arg) +{ + work_t *work = arg; + mqtt_sock_close_work(work->mqtt_sock, work); +} + static void mqtt_pipe_close(void *arg) { @@ -418,8 +403,10 @@ mqtt_pipe_close(void *arg) s->mqtt_pipe = NULL; nni_aio_close(&p->send_aio); nni_aio_close(&p->recv_aio); - work_close_queue(&s->send_queue); - work_close_queue(&s->recv_queue); + mqtt_sock_close_work_queue(s, &s->send_queue); + mqtt_sock_close_work_queue(s, &s->recv_queue); + nni_id_map_foreach(&p->send_unack, mqtt_close_unack_work_cb); + nni_id_map_foreach(&p->recv_unack, mqtt_close_unack_work_cb); nni_mtx_unlock(&s->mtx); nni_atomic_set_bool(&p->closed, true); From 5469d5d072208b4ee774e9afa83457d9635785f2 Mon Sep 17 00:00:00 2001 From: eeff Date: Wed, 17 Nov 2021 23:57:50 +0800 Subject: [PATCH 141/180] Fix mqtt protocol context receive operation --- src/sp/protocol/mqtt/mqtt_client.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 862cf7eb1..2848b9a90 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -864,10 +864,6 @@ mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) mqtt_pipe_t *p = s->mqtt_pipe; work_t * work; - if (NULL == p || nni_atomic_get_bool(&p->closed)) { - return; - } - work = mqtt_sock_get_work(s); if (NULL == work) { @@ -879,6 +875,12 @@ mqtt_recv_start(mqtt_sock_t *s, nni_aio *aio) work->user_aio = aio; work_set_recv(work, NNG_MQTT_PUBLISH); nni_list_append(&s->recv_queue, work); // enqueue to recv + + // no open pipe + if (NULL == p || nni_atomic_get_bool(&p->closed)) { + return; + } + mqtt_run_recv_queue(s); } From 16112c1038b27e3ed2cb4e5224eb74c4a73f4fb6 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 19 Nov 2021 15:25:57 +0800 Subject: [PATCH 142/180] * FIX [mqtt_parser] fix #200 (error reintroduced by commit 0452cf0) --- include/nng/protocol/mqtt/mqtt_parser.h | 4 ++-- src/sp/protocol/reqrep0/nano_tcp.c | 15 +-------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index 0b3e99fa3..d00cdeaec 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -9,11 +9,11 @@ #define DISCONNECT_MSG \ "{\"username\":\"%s\"," \ - "\"ts\":%lu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" + "\"ts\":%llu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" #define CONNECT_MSG \ "{\"username\":\"%s\", " \ - "\"ts\":%lu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":" \ + "\"ts\":%llu,\"proto_name\":\"%s\",\"keepalive\":%d,\"return_code\":" \ "\"%x\",\"proto_ver\":%d,\"client_id\":\"%s\", \"clean_start\":%d}" #define DISCONNECT_TOPIC "$SYS/brokers/disconnected" diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c index 37a8a4e06..14629a991 100644 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ b/src/sp/protocol/reqrep0/nano_tcp.c @@ -80,7 +80,6 @@ struct nano_pipe { nni_aio aio_recv; nni_aio aio_timer; nni_list_node rnode; // receivable list linkage - nni_list sendq; // contexts waiting to send bool busy; bool closed; bool kicked; @@ -479,7 +478,7 @@ nano_pipe_fini(void *arg) nni_id_map * nano_qos_db = p->pipe->nano_qos_db; //TODO safely free the msgs in qos_db -// nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); + // nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); nni_id_map_fini(nano_qos_db); nng_free(nano_qos_db, sizeof(struct nni_id_map)); @@ -596,18 +595,6 @@ close_pipe(nano_pipe *p) } nano_nni_lmq_flush(&p->rlmq); - // TODO delete - while ((ctx = nni_list_first(&p->sendq)) != NULL) { - nni_aio *aio; - nni_msg *msg; - nni_list_remove(&p->sendq, ctx); - aio = ctx->saio; - ctx->saio = NULL; - msg = nni_aio_get_msg(aio); - nni_aio_set_msg(aio, NULL); - nni_aio_finish(aio, 0, nni_msg_len(msg)); - nni_msg_free(msg); - } nni_id_remove(&s->pipes, nni_pipe_id(p->pipe)); } From 40dc505fb404dd4f22bb9b7dafeafd4ad5cf8317 Mon Sep 17 00:00:00 2001 From: eeff Date: Fri, 19 Nov 2021 14:16:01 +0800 Subject: [PATCH 143/180] Fix mqtt codec CONNECT encode handler dangling pointer --- src/mqtt/mqtt_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index f522dd070..699119095 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -423,8 +423,8 @@ nni_mqtt_msg_encode_connect(nni_msg *msg) if (mqtt->payload.connect.client_id.length == 0) { snprintf(client_id, 20, "nanomq-%04x", nni_random()); - mqtt->payload.connect.client_id.buf = (uint8_t *) client_id; - mqtt->payload.connect.client_id.length = strlen(client_id); + mqtt_buf_create(&mqtt->payload.connect.client_id, client_id, + strlen(client_id)); } /* length of protocol-name (consider "MQTT" by default */ From 9221c03a441886fbf9df3653057b3a9ae4d66d36 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 22 Nov 2021 10:33:28 +0800 Subject: [PATCH 144/180] * MDF [demo/mqtt_async, demo/mqtt] remove encode/decode from mqtt client demos --- demo/mqtt/mqtt_client.c | 13 ------------- demo/mqtt_async/mqtt_async.c | 14 ++++---------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/demo/mqtt/mqtt_client.c b/demo/mqtt/mqtt_client.c index d0ea12295..7e30e2ca0 100644 --- a/demo/mqtt/mqtt_client.c +++ b/demo/mqtt/mqtt_client.c @@ -143,12 +143,6 @@ client_subscribe(nng_socket sock, nng_mqtt_topic_qos *subscriptions, int count, nng_mqtt_msg_set_subscribe_topics(submsg, subscriptions, count); - rv = nng_mqtt_msg_encode(submsg); - - if (rv != 0) { - fatal("Problem on building SUBSCRIBE message: %d\n", rv); - } - uint8_t buff[1024] = { 0 }; if (verbose) { @@ -182,7 +176,6 @@ client_subscribe(nng_socket sock, nng_mqtt_topic_qos *subscriptions, int count, print80("Received: ", (char *) payload, payload_len, true); if (verbose) { - nng_mqtt_msg_decode(msg); memset(buff, 0, sizeof(buff)); nng_mqtt_msg_dump(msg, buff, sizeof(buff), true); printf("%s\n", buff); @@ -212,12 +205,6 @@ client_publish(nng_socket sock, const char *topic, const char *payload, pubmsg, (uint8_t *) payload, strlen(payload)); nng_mqtt_msg_set_publish_topic(pubmsg, topic); - rv = nng_mqtt_msg_encode(pubmsg); - - if (rv != 0) { - fatal("Problem on building PUBLISH message: %d\n", rv); - } - uint8_t print[1024] = { 0 }; if (verbose) { diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index cffd0f8d0..5e2ac1877 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -66,7 +66,7 @@ client_cb(void *arg) nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); nng_mqtt_msg_set_subscribe_topics( msg, topic_qos, topic_qos_count); - nng_mqtt_msg_encode(msg); + work->msg = msg; nng_aio_set_msg(work->aio, work->msg); work->msg = NULL; @@ -82,12 +82,7 @@ client_cb(void *arg) fatal("nng_recv_aio", rv); } msg = nng_aio_get_msg(work->aio); - if (nng_mqtt_msg_decode(msg) != 0) { - printf("nng_mqtt_msg_decode failed"); - nng_msg_free(msg); - nng_ctx_recv(work->ctx, work->aio); - return; - } + uint32_t payload_len; uint8_t *payload = nng_mqtt_msg_get_publish_payload(msg, &payload_len); @@ -112,7 +107,6 @@ client_cb(void *arg) nng_mqtt_msg_set_publish_topic(work->msg, topic); nng_mqtt_msg_set_publish_payload( work->msg, (uint8_t *) topic, strlen(topic)); - nng_mqtt_msg_encode(work->msg); nng_aio_set_msg(work->aio, work->msg); work->msg = NULL; @@ -158,8 +152,8 @@ static void connect_cb(void *arg, nng_msg *msg) { (void) arg; - printf("Connack status: %d\n", - nng_mqtt_msg_get_connack_return_code(msg)); + printf( + "Connack status: %d\n", nng_mqtt_msg_get_connack_return_code(msg)); nng_msg_free(msg); } From ecbb9bbb2e5f6a89f68b56e9088b2cb53de5dfee Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Tue, 23 Nov 2021 17:28:20 +0800 Subject: [PATCH 145/180] * FIX [mqtt] compile warning & error on Windows --- src/mqtt/mqtt.c | 20 ++++++++++---------- src/mqtt/mqtt_codec.c | 44 +++++++++++++++++++++---------------------- src/nng.c | 6 +++--- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index 03c2322a3..5c9879a0a 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -9,7 +9,6 @@ static nni_proto_msg_ops proto_msg_ops = { .msg_dup = nni_mqtt_msg_dup }; - int nni_mqtt_msg_proto_data_alloc(nni_msg *msg) { @@ -170,7 +169,7 @@ nni_mqtt_msg_set_publish_topic(nni_msg *msg, const char *topic) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->var_header.publish.topic_name, - (uint8_t *) topic, strlen(topic)); + (uint8_t *) topic, (uint32_t) strlen(topic)); } const char * @@ -185,7 +184,8 @@ void nni_mqtt_msg_set_publish_payload(nni_msg *msg, uint8_t *payload, uint32_t len) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); - mqtt_buf_create(&proto_data->payload.publish.payload, payload, len); + mqtt_buf_create( + &proto_data->payload.publish.payload, payload, (uint32_t) len); } uint8_t * @@ -453,7 +453,7 @@ nni_mqtt_msg_set_connect_client_id(nni_msg *msg, const char *client_id) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.client_id, - (const uint8_t *) client_id, strlen(client_id)); + (const uint8_t *) client_id, (uint32_t) strlen(client_id)); } void @@ -461,7 +461,7 @@ nni_mqtt_msg_set_connect_will_topic(nni_msg *msg, const char *will_topic) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.will_topic, - (const uint8_t *) will_topic, strlen(will_topic)); + (const uint8_t *) will_topic, (uint32_t) strlen(will_topic)); } void @@ -469,7 +469,7 @@ nni_mqtt_msg_set_connect_will_msg(nni_msg *msg, const char *will_msg) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.will_msg, - (const uint8_t *) will_msg, strlen(will_msg)); + (const uint8_t *) will_msg, (uint32_t) strlen(will_msg)); } void @@ -477,7 +477,7 @@ nni_mqtt_msg_set_connect_user_name(nni_msg *msg, const char *user_name) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.user_name, - (const uint8_t *) user_name, strlen(user_name)); + (const uint8_t *) user_name, (uint32_t) strlen(user_name)); } void @@ -485,7 +485,7 @@ nni_mqtt_msg_set_connect_password(nni_msg *msg, const char *password) { nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.password, - (const uint8_t *) password, strlen(password)); + (const uint8_t *) password, (uint32_t) strlen(password)); } const char * @@ -586,7 +586,7 @@ nni_mqtt_topic_array_set( nni_mqtt_topic *topic, size_t index, const char *topic_name) { topic[index].buf = (uint8_t *) nni_strdup(topic_name); - topic[index].length = strlen(topic_name); + topic[index].length = (uint32_t) strlen(topic_name); } void @@ -612,7 +612,7 @@ nni_mqtt_topic_qos_array_set(nni_mqtt_topic_qos *topic_qos, size_t index, const char *topic_name, uint8_t qos) { topic_qos[index].topic.buf = (uint8_t *) nni_strdup(topic_name); - topic_qos[index].topic.length = strlen(topic_name); + topic_qos[index].topic.length = (uint32_t) strlen(topic_name); topic_qos[index].qos = qos; } diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index 699119095..f7d128419 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -423,8 +423,8 @@ nni_mqtt_msg_encode_connect(nni_msg *msg) if (mqtt->payload.connect.client_id.length == 0) { snprintf(client_id, 20, "nanomq-%04x", nni_random()); - mqtt_buf_create(&mqtt->payload.connect.client_id, client_id, - strlen(client_id)); + mqtt_buf_create(&mqtt->payload.connect.client_id, + (const uint8_t *) client_id, (uint32_t) strlen(client_id)); } /* length of protocol-name (consider "MQTT" by default */ @@ -458,7 +458,7 @@ nni_mqtt_msg_encode_connect(nni_msg *msg) var_header->conn_flags.password_flag = 1; } - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; if (mqtt->fixed_header.remaining_length > MQTT_MAX_MSG_LEN) { return MQTT_ERR_PAYLOAD_SIZE; } @@ -541,7 +541,7 @@ nni_mqtt_msg_encode_connack(nni_msg *msg) mqtt_connack_vhdr *var_header = &mqtt->var_header.connack; - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; nni_mqtt_msg_encode_fixed_header(msg, mqtt); /* Connect Acknowledge Flags */ @@ -575,7 +575,7 @@ nni_mqtt_msg_encode_subscribe(nni_msg *msg) // encoded as UTF-8 encoded strings */ } - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; mqtt->fixed_header.common.bit_1 = 1; nni_mqtt_msg_encode_fixed_header(msg, mqtt); @@ -606,7 +606,7 @@ nni_mqtt_msg_encode_suback(nni_msg *msg) poslength += spld->ret_code_count; - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; nni_mqtt_msg_encode_fixed_header(msg, mqtt); /* Packet Identifier */ @@ -633,7 +633,7 @@ nni_mqtt_msg_encode_publish(nni_msg *msg) poslength += 2; /* for Packet Identifier */ } poslength += mqtt->payload.publish.payload.length; - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; nni_mqtt_msg_encode_fixed_header(msg, mqtt); @@ -666,7 +666,7 @@ nni_mqtt_msg_encode_puback(nni_msg *msg) mqtt_puback_vhdr *var_header = &mqtt->var_header.puback; - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; /* Packet Identifier */ nni_mqtt_msg_append_u16(msg, var_header->packet_id); @@ -683,7 +683,7 @@ nni_mqtt_msg_encode_pubrec(nni_msg *msg) nni_msg_clear(msg); int poslength = 2; /* for Packet Identifier */ - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; nni_mqtt_msg_encode_fixed_header(msg, mqtt); mqtt_pubrec_vhdr *var_header = &mqtt->var_header.pubrec; @@ -705,7 +705,7 @@ nni_mqtt_msg_encode_pubrel(nni_msg *msg) mqtt_pubrec_vhdr *var_header = &mqtt->var_header.pubrec; mqtt->fixed_header.common.bit_1 = 1; - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; nni_mqtt_msg_encode_fixed_header(msg, mqtt); /* Packet Identifier */ @@ -724,7 +724,7 @@ nni_mqtt_msg_encode_pubcomp(nni_msg *msg) mqtt_pubcomp_vhdr *var_header = &mqtt->var_header.pubcomp; - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; nni_mqtt_msg_encode_fixed_header(msg, mqtt); /* Packet Identifier */ @@ -753,7 +753,7 @@ nni_mqtt_msg_encode_unsubscribe(nni_msg *msg) // encoded as UTF-8 encoded strings */ } - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; mqtt->fixed_header.common.bit_1 = 1; nni_mqtt_msg_encode_fixed_header(msg, mqtt); @@ -780,7 +780,7 @@ nni_mqtt_msg_encode_unsuback(nni_msg *msg) mqtt_unsuback_vhdr *var_header = &mqtt->var_header.unsuback; - mqtt->fixed_header.remaining_length = poslength; + mqtt->fixed_header.remaining_length = (uint32_t) poslength; nni_mqtt_msg_encode_fixed_header(msg, mqtt); /* Packet Identifier */ @@ -822,8 +822,8 @@ nni_mqtt_msg_decode_fixed_header(nni_msg *msg) uint32_t remain_len = 0; int ret; - if ((ret = mqtt_get_remaining_length( - header, len, &remain_len, &used_bytes)) != MQTT_SUCCESS) { + if ((ret = mqtt_get_remaining_length(header, (uint32_t) len, + &remain_len, &used_bytes)) != MQTT_SUCCESS) { return ret; } @@ -979,19 +979,19 @@ nni_mqtt_msg_decode_subscribe(nni_msg *msg) &buf, &spld->topic_arr[spld->topic_count].topic); if (ret != MQTT_SUCCESS) { ret = MQTT_ERR_PROTOCOL; - goto ERROR; + goto err; } /* QoS */ ret = read_byte(&buf, &spld->topic_arr[spld->topic_count].qos); if (ret != MQTT_SUCCESS) { ret = MQTT_ERR_PROTOCOL; - goto ERROR; + goto err; } spld->topic_count++; } return MQTT_SUCCESS; -ERROR: +err: nni_free(spld->topic_arr, sizeof(mqtt_topic_qos) * topic_count); return ret; } @@ -1025,14 +1025,14 @@ nni_mqtt_msg_decode_suback(nni_msg *msg) ret = read_byte(&buf, ptr); if (ret != MQTT_SUCCESS) { ret = MQTT_ERR_PROTOCOL; - goto ERROR; + goto err; } ptr++; } return MQTT_SUCCESS; -ERROR: +err: nni_free(mqtt->payload.suback.ret_code_arr, mqtt->payload.suback.ret_code_count); return ret; @@ -1193,13 +1193,13 @@ nni_mqtt_msg_decode_unsubscribe(nni_msg *msg) read_utf8_str(&buf, &uspld->topic_arr[uspld->topic_count]); if (ret != MQTT_SUCCESS) { ret = MQTT_ERR_PROTOCOL; - goto ERROR; + goto err; } uspld->topic_count++; } return MQTT_SUCCESS; -ERROR: +err: nni_free(uspld->topic_arr, topic_count * sizeof(mqtt_buf)); return ret; diff --git a/src/nng.c b/src/nng.c index 91c55afb2..f1878cef5 100644 --- a/src/nng.c +++ b/src/nng.c @@ -2310,7 +2310,7 @@ nng_mqtt_topic_array_set( void nng_mqtt_topic_array_free(nng_mqtt_topic *topic, size_t n) { - return nni_mqtt_topic_array_free(topic, n); + nni_mqtt_topic_array_free(topic, n); } nng_mqtt_topic_qos * @@ -2323,13 +2323,13 @@ void nng_mqtt_topic_qos_array_set(nng_mqtt_topic_qos *topic_qos, size_t index, const char *topic_name, uint8_t qos) { - return nni_mqtt_topic_qos_array_set(topic_qos, index, topic_name, qos); + nni_mqtt_topic_qos_array_set(topic_qos, index, topic_name, qos); } void nng_mqtt_topic_qos_array_free(nng_mqtt_topic_qos *topic_qos, size_t n) { - return nni_mqtt_topic_qos_array_free(topic_qos, n); + nni_mqtt_topic_qos_array_free(topic_qos, n); } void From 2f5d8b83573179afffd3575fbcf06aa2d67533bc Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Tue, 23 Nov 2021 17:28:20 +0800 Subject: [PATCH 146/180] * FIX [mqtt_test] run failed on Windows --- include/nng/nng.h | 18 ++++++++++++++---- src/mqtt/mqtt_codec.c | 6 ++---- src/mqtt/mqtt_test.c | 28 ++++++++++++++-------------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index 1bd9d0063..07c6a916b 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1283,8 +1283,15 @@ NNG_DECL int nng_pipe_getopt_string(nng_pipe, const char *, char **); // a library; it will affect all sockets. NNG_DECL void nng_closeall(void); -typedef enum { - NNG_MQTT_CONNECT = 0x01, + +#ifdef __MSC_VER +#pragma pack(push, 1) +#endif +typedef enum +#if defined(__MINGW32__) || defined(__MINGW64__) + __attribute__((__packed__)) +#endif +{ NNG_MQTT_CONNECT = 0x01, NNG_MQTT_CONNACK = 0x02, NNG_MQTT_PUBLISH = 0x03, NNG_MQTT_PUBACK = 0x04, @@ -1298,8 +1305,11 @@ typedef enum { NNG_MQTT_PINGREQ = 0x0C, NNG_MQTT_PINGRESP = 0x0D, NNG_MQTT_DISCONNECT = 0x0E, - NNG_MQTT_AUTH = 0x0F -} nng_mqtt_packet_type; + NNG_MQTT_AUTH = 0x0F } + nng_mqtt_packet_type; +#ifdef __MSC_VER +#pragma pack(pop) +#endif struct mqtt_buf_t { uint32_t length; diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index f7d128419..3395aba10 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -114,7 +114,7 @@ nni_mqtt_msg_decode(nni_msg *msg) { int ret; if ((ret = nni_mqtt_msg_decode_fixed_header(msg)) != MQTT_SUCCESS) { - nni_plat_printf("decode_fixed_header failed %d\n", ret); + // nni_plat_printf("decode_fixed_header failed %d\n", ret); return ret; } nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); @@ -814,9 +814,7 @@ nni_mqtt_msg_decode_fixed_header(nni_msg *msg) return MQTT_ERR_PROTOCOL; } - uint8_t first = (uint8_t)(*header); - - memcpy(&mqtt->fixed_header.common, &first, 1); + memcpy(&mqtt->fixed_header.common, header, 1); uint8_t used_bytes; uint32_t remain_len = 0; diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index d97560f2f..e3be0f198 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -41,7 +41,7 @@ test_dup(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); nng_mqtt_topic_qos topic_qos[] = { { .qos = 0, @@ -62,10 +62,10 @@ test_dup(void) print_mqtt_msg(msg); print_mqtt_msg(msg2); - NUTS_ASSERT(memcmp(nng_msg_header(msg), nng_msg_header(msg2), + NUTS_TRUE(memcmp(nng_msg_header(msg), nng_msg_header(msg2), nng_msg_header_len(msg)) == 0); - NUTS_ASSERT(memcmp(nng_msg_body(msg), nng_msg_body(msg2), + NUTS_TRUE(memcmp(nng_msg_body(msg), nng_msg_body(msg2), nng_msg_len(msg)) == 0); nng_msg_free(msg); @@ -81,11 +81,11 @@ test_encode_connect(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNECT); nng_mqtt_msg_set_connect_client_id(msg, client_id); - NUTS_ASSERT(strncmp(nng_mqtt_msg_get_connect_client_id(msg), + NUTS_TRUE(strncmp(nng_mqtt_msg_get_connect_client_id(msg), client_id, strlen(client_id)) == 0); char will_topic[] = "/nanomq/will_msg"; @@ -112,7 +112,7 @@ test_encode_connect(void) NUTS_PASS(nng_mqtt_msg_decode(decode_msg)); print_mqtt_msg(decode_msg); - // NUTS_ASSERT(memcmp(nng_msg_body(msg), nng_msg_body(decode_msg), + // NUTS_TRUE(memcmp(nng_msg_body(msg), nng_msg_body(decode_msg), // nng_msg_len(msg)) == 0); nng_msg_free(decode_msg); @@ -126,7 +126,7 @@ test_encode_connack(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNACK); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNACK); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_CONNACK); nng_mqtt_msg_set_connack_flags(msg, 1); @@ -146,7 +146,7 @@ test_encode_publish(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBLISH); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBLISH); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBLISH); nng_mqtt_msg_set_publish_qos(msg, 2); nng_mqtt_msg_set_publish_retain(msg, true); @@ -173,7 +173,7 @@ test_encode_puback(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBACK); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBACK); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBACK); NUTS_PASS(nng_mqtt_msg_encode(msg)); @@ -189,7 +189,7 @@ test_encode_subscribe(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBSCRIBE); nng_mqtt_topic_qos topic_qos[] = { { .qos = 0, @@ -217,7 +217,7 @@ test_encode_suback(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBACK); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBACK); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_SUBACK); uint8_t ret_codes[] = { 0, 1, 2, 3 }; @@ -238,7 +238,7 @@ test_encode_unsubscribe(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); nng_mqtt_topic topic_qos[] = { { .buf = (uint8_t *) "/nanomq/mqtt/1", @@ -262,8 +262,8 @@ test_encode_disconnect(void) NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); - nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_UNSUBSCRIBE); - NUTS_ASSERT(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_UNSUBSCRIBE); + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_DISCONNECT); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_DISCONNECT); NUTS_PASS(nng_mqtt_msg_encode(msg)); print_mqtt_msg(msg); From 9ed169a1c444fac0c5c843a0f2b61a8a4e1d0c69 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Tue, 23 Nov 2021 17:28:20 +0800 Subject: [PATCH 147/180] * FIX [mqtt] dup invalid content before encoding. --- include/nng/nng.h | 18 ++++-------------- src/mqtt/mqtt.c | 10 ++++++++++ src/mqtt/mqtt.h | 18 +++++++++--------- src/mqtt/mqtt_test.c | 43 ++++++++++++++++++++++++++++++++++++++----- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index 07c6a916b..1bd9d0063 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -1283,15 +1283,8 @@ NNG_DECL int nng_pipe_getopt_string(nng_pipe, const char *, char **); // a library; it will affect all sockets. NNG_DECL void nng_closeall(void); - -#ifdef __MSC_VER -#pragma pack(push, 1) -#endif -typedef enum -#if defined(__MINGW32__) || defined(__MINGW64__) - __attribute__((__packed__)) -#endif -{ NNG_MQTT_CONNECT = 0x01, +typedef enum { + NNG_MQTT_CONNECT = 0x01, NNG_MQTT_CONNACK = 0x02, NNG_MQTT_PUBLISH = 0x03, NNG_MQTT_PUBACK = 0x04, @@ -1305,11 +1298,8 @@ typedef enum NNG_MQTT_PINGREQ = 0x0C, NNG_MQTT_PINGRESP = 0x0D, NNG_MQTT_DISCONNECT = 0x0E, - NNG_MQTT_AUTH = 0x0F } - nng_mqtt_packet_type; -#ifdef __MSC_VER -#pragma pack(pop) -#endif + NNG_MQTT_AUTH = 0x0F +} nng_mqtt_packet_type; struct mqtt_buf_t { uint32_t length; diff --git a/src/mqtt/mqtt.c b/src/mqtt/mqtt.c index 5c9879a0a..030328901 100644 --- a/src/mqtt/mqtt.c +++ b/src/mqtt/mqtt.c @@ -170,6 +170,7 @@ nni_mqtt_msg_set_publish_topic(nni_msg *msg, const char *topic) nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->var_header.publish.topic_name, (uint8_t *) topic, (uint32_t) strlen(topic)); + proto_data->is_copied = true; } const char * @@ -186,6 +187,7 @@ nni_mqtt_msg_set_publish_payload(nni_msg *msg, uint8_t *payload, uint32_t len) nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create( &proto_data->payload.publish.payload, payload, (uint32_t) len); + proto_data->is_copied = true; } uint8_t * @@ -295,6 +297,7 @@ nni_mqtt_msg_set_subscribe_topics( proto_data->payload.subscribe.topic_arr, i, (const char *) topics[i].topic.buf, topics[i].qos); } + proto_data->is_copied = true; } nni_mqtt_topic_qos * @@ -328,6 +331,7 @@ nni_mqtt_msg_set_suback_return_codes( memcpy(proto_data->payload.suback.ret_code_arr, ret_codes, ret_codes_count); proto_data->payload.suback.ret_code_count = ret_codes_count; + proto_data->is_copied = true; } uint8_t * @@ -367,6 +371,7 @@ nni_mqtt_msg_set_unsubscribe_topics( proto_data->payload.unsubscribe.topic_arr, i, (const char *) topics[i].buf); } + proto_data->is_copied = true; } nni_mqtt_topic * @@ -454,6 +459,7 @@ nni_mqtt_msg_set_connect_client_id(nni_msg *msg, const char *client_id) nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.client_id, (const uint8_t *) client_id, (uint32_t) strlen(client_id)); + proto_data->is_copied = true; } void @@ -462,6 +468,7 @@ nni_mqtt_msg_set_connect_will_topic(nni_msg *msg, const char *will_topic) nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.will_topic, (const uint8_t *) will_topic, (uint32_t) strlen(will_topic)); + proto_data->is_copied = true; } void @@ -470,6 +477,7 @@ nni_mqtt_msg_set_connect_will_msg(nni_msg *msg, const char *will_msg) nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.will_msg, (const uint8_t *) will_msg, (uint32_t) strlen(will_msg)); + proto_data->is_copied = true; } void @@ -478,6 +486,7 @@ nni_mqtt_msg_set_connect_user_name(nni_msg *msg, const char *user_name) nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.user_name, (const uint8_t *) user_name, (uint32_t) strlen(user_name)); + proto_data->is_copied = true; } void @@ -486,6 +495,7 @@ nni_mqtt_msg_set_connect_password(nni_msg *msg, const char *password) nni_mqtt_proto_data *proto_data = nni_msg_get_proto_data(msg); mqtt_buf_create(&proto_data->payload.connect.password, (const uint8_t *) password, (uint32_t) strlen(password)); + proto_data->is_copied = true; } const char * diff --git a/src/mqtt/mqtt.h b/src/mqtt/mqtt.h index 92738ea62..b6354b4dd 100644 --- a/src/mqtt/mqtt.h +++ b/src/mqtt/mqtt.h @@ -187,18 +187,18 @@ union mqtt_payload { }; typedef struct { - uint8_t bit_0 : 1; - uint8_t bit_1 : 1; - uint8_t bit_2 : 1; - uint8_t bit_3 : 1; - nni_mqtt_packet_type packet_type : 4; + uint8_t bit_0 : 1; + uint8_t bit_1 : 1; + uint8_t bit_2 : 1; + uint8_t bit_3 : 1; + uint8_t packet_type : 4; } mqtt_common_hdr; typedef struct { - uint8_t retain : 1; - uint8_t qos : 2; - uint8_t dup : 1; - nni_mqtt_packet_type packet_type : 4; + uint8_t retain : 1; + uint8_t qos : 2; + uint8_t dup : 1; + uint8_t packet_type : 4; } mqtt_pub_hdr; typedef struct mqtt_fixed_hdr_t { diff --git a/src/mqtt/mqtt_test.c b/src/mqtt/mqtt_test.c index e3be0f198..a686e8fe5 100644 --- a/src/mqtt/mqtt_test.c +++ b/src/mqtt/mqtt_test.c @@ -63,10 +63,42 @@ test_dup(void) print_mqtt_msg(msg2); NUTS_TRUE(memcmp(nng_msg_header(msg), nng_msg_header(msg2), - nng_msg_header_len(msg)) == 0); + nng_msg_header_len(msg)) == 0); NUTS_TRUE(memcmp(nng_msg_body(msg), nng_msg_body(msg2), - nng_msg_len(msg)) == 0); + nng_msg_len(msg)) == 0); + + nng_msg_free(msg2); + nng_msg_free(msg); +} + +void +test_dup_publish(void) +{ + nng_msg *msg; + + NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); + + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_PUBLISH); + NUTS_TRUE(nng_mqtt_msg_get_packet_type(msg) == NNG_MQTT_PUBLISH); + + nng_mqtt_msg_set_publish_qos(msg, 0); + nng_mqtt_msg_set_publish_topic(msg, "/nanomq/msg"); + nng_mqtt_msg_set_publish_payload(msg, (uint8_t *) "aaaaaaaa", 8); + + // NUTS_PASS(nng_mqtt_msg_encode(msg)); + + nng_msg *msg2; + NUTS_PASS(nng_msg_dup(&msg2, msg)); + + print_mqtt_msg(msg); + print_mqtt_msg(msg2); + + NUTS_TRUE(memcmp(nng_msg_header(msg), nng_msg_header(msg2), + nng_msg_header_len(msg)) == 0); + + NUTS_TRUE(memcmp(nng_msg_body(msg), nng_msg_body(msg2), + nng_msg_len(msg)) == 0); nng_msg_free(msg); nng_msg_free(msg2); @@ -76,7 +108,7 @@ void test_encode_connect(void) { nng_msg *msg; - char client_id[] = "nanomq-mqtt"; + char client_id[] = "nanomq-mqtt"; NUTS_PASS(nng_mqtt_msg_alloc(&msg, 0)); @@ -85,8 +117,8 @@ test_encode_connect(void) nng_mqtt_msg_set_connect_client_id(msg, client_id); - NUTS_TRUE(strncmp(nng_mqtt_msg_get_connect_client_id(msg), - client_id, strlen(client_id)) == 0); + NUTS_TRUE(strncmp(nng_mqtt_msg_get_connect_client_id(msg), client_id, + strlen(client_id)) == 0); char will_topic[] = "/nanomq/will_msg"; nng_mqtt_msg_set_connect_will_topic(msg, will_topic); @@ -477,6 +509,7 @@ test_decode_suback(void) TEST_LIST = { { "alloc message", test_alloc }, { "dup message", test_dup }, + { "dup publish message", test_dup_publish }, { "encode connect", test_encode_connect }, { "encode conack", test_encode_connack }, { "encode publish", test_encode_publish }, From dd5b1541a5ecb06051fc15fadd9b203814616919 Mon Sep 17 00:00:00 2001 From: eeff Date: Tue, 23 Nov 2021 10:59:14 +0800 Subject: [PATCH 148/180] Fix mqtt protocol to encode all messages according to codec --- src/sp/protocol/mqtt/mqtt_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 2848b9a90..88b131bce 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -948,7 +948,6 @@ mqtt_send_start(mqtt_sock_t *s) mqtt_pipe_get_next_packet_id(p); nni_mqtt_msg_set_packet_id( work->msg, work->packet_id); - nni_mqtt_msg_encode(work->msg); NNI_ASSERT(nni_id_get(&p->send_unack, work->packet_id) == NULL); if (0 != @@ -964,6 +963,8 @@ mqtt_send_start(mqtt_sock_t *s) work->user_aio, NNG_EPROTO); return; } + + nni_mqtt_msg_encode(work->msg); } work_set_send(work, packet_type); From 7a7a8d267a6c63451b3768babf66a11b6107d4ef Mon Sep 17 00:00:00 2001 From: eeff Date: Tue, 23 Nov 2021 14:35:28 +0800 Subject: [PATCH 149/180] Fix mqtt protocol pipe start --- src/sp/protocol/mqtt/mqtt_client.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 88b131bce..3d9793660 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -315,10 +315,6 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) mqtt_pipe_t *p = arg; mqtt_sock_t *sock = s; - nni_mtx_lock(&sock->mtx); - sock->mqtt_pipe = p; - nni_mtx_unlock(&sock->mtx); - nni_atomic_init_bool(&p->closed); nni_atomic_set_bool(&p->closed, false); nni_atomic_set(&p->next_packet_id, 0); @@ -338,6 +334,7 @@ mqtt_pipe_init(void *arg, nni_pipe *pipe, void *s) nni_id_map_init(&p->send_unack, 0x0000u, 0xffffu, true); nni_id_map_init(&p->recv_unack, 0x0000u, 0xffffu, true); nni_lmq_init(&p->recv_messages, 128); // FIXME: remove hard code value + return (0); } @@ -365,6 +362,7 @@ mqtt_pipe_start(void *arg) // } nni_mtx_lock(&s->mtx); + s->mqtt_pipe = p; mqtt_send_start(s); nni_mtx_unlock(&s->mtx); From 3186d06d971c8b63db46324b985d610f5be30759 Mon Sep 17 00:00:00 2001 From: eeff Date: Tue, 23 Nov 2021 16:33:59 +0800 Subject: [PATCH 150/180] Fix mqtt protocol keep alive timer performance Previously we schedule a keep alive timer when the send queue is empty, and this may cause the timer to be scheduled many times in certain work load condition. This fix solves the problem by always scheduling the timer periodically. --- src/sp/protocol/mqtt/mqtt_client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index 3d9793660..fa85d4493 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -364,6 +364,7 @@ mqtt_pipe_start(void *arg) nni_mtx_lock(&s->mtx); s->mqtt_pipe = p; mqtt_send_start(s); + work_timer_schedule(&p->ping_work); nni_mtx_unlock(&s->mtx); nni_pipe_recv(p->pipe, &p->recv_aio); @@ -461,6 +462,8 @@ mqtt_keep_alive_cb(void *arg) mqtt_send_start(s); } + work_timer_schedule(&p->ping_work); + nni_mtx_unlock(&s->mtx); } @@ -969,9 +972,6 @@ mqtt_send_start(mqtt_sock_t *s) nni_msg_clone(work->msg); nni_aio_set_msg(&p->send_aio, work->msg); nni_pipe_send(p->pipe, &p->send_aio); - } else { - // no packet to send, start the ping request timer - work_timer_schedule(&p->ping_work); } return; From 0db3d5822923babb1abf6b36cbb45f33a6d89454 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 26 Nov 2021 15:43:27 +0800 Subject: [PATCH 151/180] * MDF [protocol/mqtt] move protocol layer of nanomq to independent dir. --- cmake/NNGOptions.cmake | 16 + include/nng/protocol/mqtt/mqtt_parser.h | 1 + .../protocol/mqtt/{nano_tcp.h => nmq_mqtt.h} | 6 +- src/sp/protocol/mqtt/CMakeLists.txt | 17 +- src/sp/protocol/mqtt/nmq_mqtt.c | 1035 +++++++++++++++++ src/sp/protocol/reqrep0/CMakeLists.txt | 4 +- 6 files changed, 1064 insertions(+), 15 deletions(-) rename include/nng/protocol/mqtt/{nano_tcp.h => nmq_mqtt.h} (82%) create mode 100644 src/sp/protocol/mqtt/nmq_mqtt.c diff --git a/cmake/NNGOptions.cmake b/cmake/NNGOptions.cmake index b8067bca0..458072572 100644 --- a/cmake/NNGOptions.cmake +++ b/cmake/NNGOptions.cmake @@ -76,6 +76,12 @@ mark_as_advanced(NNG_PROTO_RESPONDENT0) option (NNG_PROTO_SURVEYOR0 "Enable SURVEYORv0 protocol." ON) mark_as_advanced(NNG_PROTO_SURVEYOR0) +option (NNG_PROTO_MQTT_CLIENT "Enable MQTT Client protocol." ON) +mark_as_advanced(NNG_PROTO_MQTT_CLIENT) + +option (NNG_PROTO_MQTT_BROKER "Enable MQTT Broker protocol." ON) +mark_as_advanced(NNG_PROTO_MQTT_BROKER) + # TLS support. # Enabling TLS is required to enable support for the TLS transport @@ -123,6 +129,16 @@ mark_as_advanced(NNG_TRANSPORT_TLS) option (NNG_TRANSPORT_WS "Enable WebSocket transport." ON) mark_as_advanced(NNG_TRANSPORT_WS) +# MQTT Client +option (NNG_TRANSPORT_MQTT_TCP "Enable MQTT TCP transport." ON) +mark_as_advanced(NNG_TRANSPORT_MQTT_TCP) + +#MQTT Broker +option (NNG_TRANSPORT_MQTT_BROKER_TCP "Enable MQTT BROKER TCP transport." ON) +mark_as_advanced(NNG_TRANSPORT_MQTT_BROKER_TCP) + + + CMAKE_DEPENDENT_OPTION(NNG_TRANSPORT_WSS "Enable WSS transport." ON "NNG_ENABLE_TLS" OFF) mark_as_advanced(NNG_TRANSPORT_WSS) diff --git a/include/nng/protocol/mqtt/mqtt_parser.h b/include/nng/protocol/mqtt/mqtt_parser.h index d00cdeaec..94515da72 100644 --- a/include/nng/protocol/mqtt/mqtt_parser.h +++ b/include/nng/protocol/mqtt/mqtt_parser.h @@ -7,6 +7,7 @@ #include #include +// Do not change to %lu! just supress the warning of compiler! #define DISCONNECT_MSG \ "{\"username\":\"%s\"," \ "\"ts\":%llu,\"reason_code\":\"%x\",\"client_id\":\"%s\"}" diff --git a/include/nng/protocol/mqtt/nano_tcp.h b/include/nng/protocol/mqtt/nmq_mqtt.h similarity index 82% rename from include/nng/protocol/mqtt/nano_tcp.h rename to include/nng/protocol/mqtt/nmq_mqtt.h index d03fe13c5..a93ab1894 100755 --- a/include/nng/protocol/mqtt/nano_tcp.h +++ b/include/nng/protocol/mqtt/nmq_mqtt.h @@ -14,7 +14,7 @@ extern "C" { #endif -NNG_DECL int nng_nano_tcp0_open(nng_socket *); +NNG_DECL int nng_nmq_tcp0_open(nng_socket *); #ifndef nng_nano_tcp_open #define nng_nano_tcp_open nng_nano_tcp0_open @@ -22,8 +22,8 @@ NNG_DECL int nng_nano_tcp0_open(nng_socket *); #define NNG_NANO_TCP_SELF 0x31 #define NNG_NANO_TCP_PEER 0x30 -#define NNG_NANO_TCP_SELF_NAME "nano_rep" -#define NNG_NANO_TCP_PEER_NAME "nano_req" +#define NNG_NANO_TCP_SELF_NAME "nmq_broker" +#define NNG_NANO_TCP_PEER_NAME "nmq_client" #ifdef __cplusplus } diff --git a/src/sp/protocol/mqtt/CMakeLists.txt b/src/sp/protocol/mqtt/CMakeLists.txt index 778315732..3af54eada 100755 --- a/src/sp/protocol/mqtt/CMakeLists.txt +++ b/src/sp/protocol/mqtt/CMakeLists.txt @@ -2,16 +2,13 @@ # Jaylin EMQ # https://opensource.org/licenses/MIT. # +nng_directory(mqtt) -# static mqtt parser +nng_sources_if(NNG_PROTO_BROKER mqtt_parser.c nmq_mqtt.c) +nng_headers_if(NNG_PROTO_BROKER nng/protocol/mqtt/mqtt_parser.h nng/protocol/mqtt/nmq_mqtt.h) +nng_defines_if(NNG_PROTO_BROKER NNG_HAVE_MQTT_BROKER) -option(NNG_PROTO_REQ0 "Enable REQv0 protocol." ON) -mark_as_advanced(NNG_PROTO_REQ0) - -option(NNG_PROTO_REP0 "Enable REPv0 protocol." ON) -mark_as_advanced(NNG_PROTO_REP0) - -nng_sources_if(NNG_PROTO_REQ0 mqtt_parser.c) -nng_headers_if(NNG_PROTO_REQ0 nng/protocol/mqtt/mqtt_parser.h) -nng_defines_if(NNG_PROTO_REQ0 NNG_HAVE_MQTT) +#nng_sources_if(NNG_PROTO_MQTT_CLIENT mqtt_client.c) +#nng_headers_if(NNG_PROTO_MQTT_CLIENT nng/protocol/mqtt/mqtt_parser.h nng/mqtt/mqtt_client.h) +#nng_defines_if(NNG_PROTO_MQTT_CLIENT NNG_HAVE_MQTT_CLIENT) diff --git a/src/sp/protocol/mqtt/nmq_mqtt.c b/src/sp/protocol/mqtt/nmq_mqtt.c new file mode 100644 index 000000000..ece530986 --- /dev/null +++ b/src/sp/protocol/mqtt/nmq_mqtt.c @@ -0,0 +1,1035 @@ +// +// Copyright 2020 NanoMQ Team, Inc. +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include +#include +#include +#include + +#include "core/nng_impl.h" +#include "core/sockimpl.h" +#include "nng/nng.h" +#include "nng/protocol/mqtt/mqtt.h" +#include "nng/protocol/mqtt/mqtt_parser.h" +#include "nng/protocol/mqtt/nano_tcp.h" + +#include + +// TODO rewrite as nano_mq protocol with RPC support + +typedef struct nano_pipe nano_pipe; +typedef struct nano_sock nano_sock; +typedef struct nano_ctx nano_ctx; +typedef struct cs_msg_list cs_msg_list; + +static void nano_pipe_send_cb(void *); +static void nano_pipe_recv_cb(void *); +static void nano_pipe_fini(void *); +static void nano_pipe_close(void *); +static inline void close_pipe(nano_pipe *p); +// static void nano_period_check(nano_sock *s, nni_list *sent_list, void *arg); +// static void nano_keepalive(nano_pipe *p, void *arg); + +// huge context/ dynamic context? +struct nano_ctx { + nano_sock *sock; + uint32_t pipe_id; + // uint32_t resend_count; + // uint32_t pipe_len; //record total length of pipe_id queue + // when resending + nano_pipe *spipe, *qos_pipe; // send pipe + nni_aio * saio; // send aio + nni_aio * raio; // recv aio + // uint32_t* rspipes;// pub resend pipe queue Qos 1/2 + // nni_list send_queue; // contexts waiting to send. + nni_list_node sqnode; + nni_list_node rqnode; + // nni_timer_node qos_timer; +}; + +// nano_sock is our per-socket protocol private structure. +struct nano_sock { + nni_mtx lk; + nni_atomic_int ttl; + nni_id_map pipes; + nni_lmq waitlmq; + nni_list recvpipes; // list of pipes with data to receive + nni_list recvq; + nano_ctx ctx; // base socket + nni_pollable readable; + nni_pollable writable; + conf * conf; + void * db; +}; + +// nano_pipe is our per-pipe protocol private structure. +struct nano_pipe { + nni_mtx lk; + nni_pipe * pipe; + nano_sock * rep; + uint32_t id; + void * tree; // root node of db tree + nni_aio aio_send; + nni_aio aio_recv; + nni_aio aio_timer; + nni_list_node rnode; // receivable list linkage + bool busy; + bool closed; + bool kicked; + uint8_t reason_code; + uint8_t ka_refresh; + nano_conn_param *conn_param; + nni_lmq rlmq; +}; + +static inline int +nano_nni_lmq_getq(nni_lmq *lmq, nng_msg **msg, uint8_t *qos) +{ + int rv = nni_lmq_getq(lmq, msg); + if (rv == 0) { + if (qos) { + *qos = NANO_NNI_LMQ_GET_QOS_BITS(*msg); + } + *msg = NANO_NNI_LMQ_GET_MSG_POINTER(*msg); + } + return rv; +} + +void +nano_nni_lmq_flush(nni_lmq *lmq) +{ + while (lmq->lmq_len > 0) { + nng_msg *msg = lmq->lmq_msgs[lmq->lmq_get++]; + lmq->lmq_get &= lmq->lmq_mask; + lmq->lmq_len--; + nni_msg_free(NANO_NNI_LMQ_GET_MSG_POINTER(msg)); + } +} + +int +nano_nni_lmq_resize(nni_lmq *lmq, size_t cap) +{ + nng_msg * msg; + nng_msg **newq; + size_t alloc; + size_t len; + + alloc = 2; + while (alloc < cap) { + alloc *= 2; + } + + newq = nni_alloc(sizeof(nng_msg *) * alloc); + if (newq == NULL) { + return (NNG_ENOMEM); + } + + len = 0; + while ((len < cap) && (nni_lmq_getq(lmq, &msg) == 0)) { + newq[len++] = msg; + } + + // Flush anything left over. + nano_nni_lmq_flush(lmq); + + nni_free(lmq->lmq_msgs, lmq->lmq_alloc * sizeof(nng_msg *)); + lmq->lmq_msgs = newq; + lmq->lmq_cap = cap; + lmq->lmq_alloc = alloc; + lmq->lmq_mask = alloc - 1; + lmq->lmq_len = len; + lmq->lmq_put = len; + lmq->lmq_get = 0; + + return (0); +} + +void +nano_nni_lmq_fini(nni_lmq *lmq) +{ + if (lmq == NULL) { + return; + } + + /* Free any orphaned messages. */ + while (lmq->lmq_len > 0) { + nng_msg *msg = lmq->lmq_msgs[lmq->lmq_get++]; + lmq->lmq_get &= lmq->lmq_mask; + lmq->lmq_len--; + nni_msg_free(NANO_NNI_LMQ_GET_MSG_POINTER(msg)); + } + + nni_free(lmq->lmq_msgs, lmq->lmq_alloc * sizeof(nng_msg *)); +} + +static void +nano_pipe_timer_cb(void *arg) +{ + nano_pipe *p = arg; + int qos_duration = p->rep->conf->qos_duration; + nni_msg * msg, *rmsg; + nni_time time; + nni_pipe * npipe = p->pipe; + uint16_t pid; + + if (nng_aio_result(&p->aio_timer) != 0) { + return; + } + nni_mtx_lock(&p->lk); + if (p->ka_refresh * (qos_duration) > p->conn_param->keepalive_mqtt) { + nni_println("Warning: close pipe & kick client due to KeepAlive " + "timeout!"); + // TODO check keepalived timer interval + p->reason_code = 0x8D; + nni_aio_finish_error(&p->aio_recv, NNG_ECONNREFUSED); + nni_mtx_unlock(&p->lk); + return; + } + p->ka_refresh++; + if (!p->busy) { + msg = nni_id_get_any(npipe->nano_qos_db, &pid); + if (msg != NULL) { + uint8_t qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); + rmsg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); + time = nni_msg_get_timestamp(msg); + if ((nni_clock() - time) >= + (long unsigned) qos_duration * 1250) { + p->busy = true; + // TODO set max retrying times in nanomq.conf + nni_msg_clone(rmsg); + nano_msg_set_dup(rmsg); + nni_aio_set_packetid(&p->aio_send, pid); + nni_aio_set_msg(&p->aio_send, rmsg); + debug_msg( + "resending qos msg packetid: %d", pid); + nni_pipe_send(p->pipe, &p->aio_send); + nni_id_remove(npipe->nano_qos_db, pid); + } + } + } + + nni_mtx_unlock(&p->lk); + nni_sleep_aio(qos_duration * 1000, &p->aio_timer); + return; +} + +/* +static void +nano_keepalive(nano_pipe *p, void *arg) +{ + uint16_t interval; + + interval = conn_param_get_keepalive(p->conn_param); + debug_msg("KeepAlive: %d", interval); + //20% KeepAlive as buffer time for multi-threading + nni_timer_schedule(&p->ka_timer, nni_clock() + NNI_SECOND * interval * +0.8); +} +*/ + +static void +nano_ctx_close(void *arg) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + nni_aio * aio; + + debug_msg("nano_ctx_close"); + nni_mtx_lock(&s->lk); + if ((aio = ctx->saio) != NULL) { + // nano_pipe *pipe = ctx->spipe; + ctx->saio = NULL; + ctx->spipe = NULL; + ctx->qos_pipe = NULL; + nni_aio_finish_error(aio, NNG_ECLOSED); + } + if ((aio = ctx->raio) != NULL) { + nni_list_remove(&s->recvq, ctx); + ctx->raio = NULL; + nni_aio_finish_error(aio, NNG_ECLOSED); + } + nni_mtx_unlock(&s->lk); +} + +static void +nano_ctx_fini(void *arg) +{ + nano_ctx *ctx = arg; + + nano_ctx_close(ctx); + + // timer + debug_msg("========= nano_ctx_fini ========="); + // nni_timer_cancel(&ctx->qos_timer); + // nni_timer_fini(&ctx->qos_timer); +} + +static int +nano_ctx_init(void *carg, void *sarg) +{ + nano_sock *s = sarg; + nano_ctx * ctx = carg; + + debug_msg("&&&&&&&& nano_ctx_init %p &&&&&&&&&", ctx); + NNI_LIST_NODE_INIT(&ctx->sqnode); + NNI_LIST_NODE_INIT(&ctx->rqnode); + + ctx->sock = s; + ctx->pipe_id = 0; + + return (0); +} + +static void +nano_ctx_cancel_send(nni_aio *aio, void *arg, int rv) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + + debug_msg("*********** nano_ctx_cancel_send ***********"); + nni_mtx_lock(&s->lk); + if (ctx->saio != aio) { + nni_mtx_unlock(&s->lk); + return; + } + nni_list_node_remove(&ctx->sqnode); + ctx->saio = NULL; + nni_mtx_unlock(&s->lk); + + nni_msg_header_clear(nni_aio_get_msg(aio)); // reset the headers + nni_aio_finish_error(aio, rv); +} + +static void +nano_ctx_send(void *arg, nni_aio *aio) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + nano_pipe *p; + nni_msg * msg; + int rv; + uint32_t pipe; + size_t qos = 0; + + msg = nni_aio_get_msg(aio); + + if (nni_aio_begin(aio) != 0) { + return; + } + + debug_msg("#### nano_ctx_send with ctx %p msg type %x ####", + ctx, nni_msg_cmd_type(msg)); + + if ((pipe = nni_msg_get_pipe(msg)) != 0) { + nni_msg_set_pipe(msg, 0); + } else { + pipe = ctx->pipe_id; // reply to self + } + ctx->pipe_id = 0; // ensure connack/PING/DISCONNECT/PUBACK only sends once + + if (ctx == &s->ctx) { + nni_pollable_clear(&s->writable); + } + + nni_mtx_lock(&s->lk); + debug_msg(" ******** working with pipe id : %d ctx ********", pipe); + if ((p = nni_id_get(&s->pipes, pipe)) == NULL) { + // Pipe is gone. Make this look like a good send to avoid + // disrupting the state machine. We don't care if the peer + // lost interest in our reply. + nni_mtx_unlock(&s->lk); + nni_aio_set_msg(aio, NULL); + // TODO lastwill/SYS topic will trigger this (sub to the topic + // that publish to by itself) + debug_syslog("ERROR: pipe is gone, pub failed"); + nni_msg_free(msg); + return; + } + nni_mtx_unlock(&s->lk); + nni_mtx_lock(&p->lk); + qos = (size_t) nni_aio_get_prov_extra(aio, 0); + msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); + if (!p->busy) { + p->busy = true; + nni_aio_set_msg(&p->aio_send, msg); + nni_pipe_send(p->pipe, &p->aio_send); + nni_mtx_unlock(&p->lk); + nni_aio_set_msg(aio, NULL); + return; + } + + if ((rv = nni_aio_schedule(aio, nano_ctx_cancel_send, ctx)) != 0) { + nni_msg_free(msg); + nni_mtx_unlock(&p->lk); + return; + } + debug_msg("WARNING: pipe %d occupied! resending in cb!", pipe); + if (nni_lmq_full(&p->rlmq)) { + // Make space for the new message. TODO add max limit of msgq + // len in conf + if ((rv = nano_nni_lmq_resize( + &p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { + debug_syslog("warning msg dropped!"); + nni_msg *old; + (void) nano_nni_lmq_getq(&p->rlmq, &old, NULL); + nni_msg_free(old); + } + } + + nni_lmq_putq(&p->rlmq, msg); + + nni_mtx_unlock(&p->lk); + nni_aio_set_msg(aio, NULL); + return; +} + +static void +nano_sock_fini(void *arg) +{ + nano_sock *s = arg; + + nni_id_map_fini(&s->pipes); + nni_lmq_fini(&s->waitlmq); + nano_ctx_fini(&s->ctx); + nni_pollable_fini(&s->writable); + nni_pollable_fini(&s->readable); + nni_mtx_fini(&s->lk); + + conf_fini(s->conf); +} + +static int +nano_sock_init(void *arg, nni_sock *sock) +{ + nano_sock *s = arg; + + NNI_ARG_UNUSED(sock); + + nni_mtx_init(&s->lk); + + nni_id_map_init(&s->pipes, 0, 0, false); + nni_lmq_init(&s->waitlmq, 256); + NNI_LIST_INIT(&s->recvq, nano_ctx, rqnode); + NNI_LIST_INIT(&s->recvpipes, nano_pipe, rnode); + + nni_atomic_init(&s->ttl); + nni_atomic_set(&s->ttl, 8); + + (void) nano_ctx_init(&s->ctx, s); + + debug_msg("************* nano_sock_init %p *************", s); + // We start off without being either readable or writable. + // Readability comes when there is something on the socket. + nni_pollable_init(&s->writable); + nni_pollable_init(&s->readable); + + return (0); +} + +static void +nano_sock_open(void *arg) +{ + NNI_ARG_UNUSED(arg); +} + +static void +nano_sock_close(void *arg) +{ + nano_sock *s = arg; + + nano_ctx_close(&s->ctx); +} + +static void +nano_pipe_stop(void *arg) +{ + nano_pipe *p = arg; + + debug_msg("##########nano_pipe_stop###############"); + nni_aio_stop(&p->aio_send); + nni_aio_stop(&p->aio_timer); + nni_aio_stop(&p->aio_recv); +} + +static void +nano_pipe_fini(void *arg) +{ + nano_pipe * p = arg; + nng_msg * msg; + + debug_msg("########## nano_pipe_fini ###############"); + if ((msg = nni_aio_get_msg(&p->aio_recv)) != NULL) { + nni_aio_set_msg(&p->aio_recv, NULL); + nni_msg_free(msg); + } + + if ((msg = nni_aio_get_msg(&p->aio_send)) != NULL) { + nni_aio_set_msg(&p->aio_recv, NULL); + nni_msg_free(msg); + } + + nni_id_map * nano_qos_db = p->pipe->nano_qos_db; + + //TODO safely free the msgs in qos_db + // nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); + nni_id_map_fini(nano_qos_db); + nng_free(nano_qos_db, sizeof(struct nni_id_map)); + + nni_mtx_fini(&p->lk); + nni_aio_fini(&p->aio_send); + nni_aio_fini(&p->aio_recv); + nni_aio_fini(&p->aio_timer); + nano_nni_lmq_fini(&p->rlmq); +} + +static int +nano_pipe_init(void *arg, nni_pipe *pipe, void *s) +{ + nano_pipe *p = arg; + nano_sock *sock = s; + + debug_msg("##########nano_pipe_init###############"); + + nni_mtx_init(&p->lk); + nni_lmq_init(&p->rlmq, sock->conf->msq_len); + nni_aio_init(&p->aio_send, nano_pipe_send_cb, p); + nni_aio_init(&p->aio_timer, nano_pipe_timer_cb, p); + nni_aio_init(&p->aio_recv, nano_pipe_recv_cb, p); + + p->reason_code = 0x00; + p->id = nni_pipe_id(pipe); + p->pipe = pipe; + p->rep = s; + p->ka_refresh = 0; + p->kicked = false; + p->conn_param = nni_pipe_get_conn_param(pipe); + p->tree = sock->db; + p->conn_param->nano_qos_db = p->pipe->nano_qos_db; + + return (0); +} + +static int +nano_pipe_start(void *arg) +{ + nano_pipe *p = arg; + nano_sock *s = p->rep; + nni_msg * msg; + uint8_t rv, *reason; // reason code of CONNACK + uint8_t buf[4] = { 0x20, 0x02, 0x00, 0x00 }; + nni_pipe * npipe = p->pipe; + char * clientid = NULL; + uint32_t clientid_key = 0; + nni_msg ** msgq = NULL; + uint16_t pid = 0; + + debug_msg("##########nano_pipe_start################"); + /* + // TODO check peer protocol ver (websocket or tcp or quic??) + if (nni_pipe_peer(p->pipe) != NNG_NANO_TCP_PEER) { + // Peer protocol mismatch. + return (NNG_EPROTO); + } + */ + nni_msg_alloc(&msg, 0); + nni_msg_header_append(msg, buf, 4); + reason = nni_msg_header(msg) + 2; + nni_mtx_lock(&s->lk); + // TODO replace pipe_id with hash key of client_id + // pipe_id is just random value of id_dyn_val with self-increment. + nni_id_set(&s->pipes, nni_pipe_id(p->pipe), p); + rv = verify_connect(p->conn_param, s->conf); + if (rv != 0) { + // TODO disconnect client && send connack with reason code 0x05 + debug_syslog("Invalid auth info."); + *(reason + 1) = rv; // set return code + } + nni_mtx_unlock(&s->lk); + + // restore cached qos msg + clientid = (char *) conn_param_get_clientid(p->conn_param); + clientid_key = DJBHashn(clientid, strlen(clientid)); + if (cached_check_id(clientid_key)) { + msgq = (nni_msg **)dbtree_restore_session_msg(p->tree, clientid_key); + for(int i=0; i< (int) cvector_size(msgq); i++) { + pid = nni_pipe_inc_packetid(npipe); + nni_id_set(npipe->nano_qos_db, pid, msgq[i]); + } + cvector_free(msgq); + } + + // TODO MQTT V5 check return code + if (*(reason + 1) == 0) { + nni_sleep_aio(s->conf->qos_duration * 1500, &p->aio_timer); + } + nni_msg_set_cmd_type(msg, CMD_CONNACK); + nni_msg_set_conn_param(msg, p->conn_param); + // There is no need to check the state of aio_recv + // Since pipe_start is definetly the first cb to be excuted of pipe. + nni_aio_set_msg(&p->aio_recv, msg); + nni_aio_finish(&p->aio_recv, 0, nni_msg_len(msg)); + return (rv); +} + +static inline void +close_pipe(nano_pipe *p) +{ + nano_sock *s = p->rep; + + nni_aio_close(&p->aio_send); + nni_aio_close(&p->aio_recv); + nni_aio_close(&p->aio_timer); + + // nni_mtx_lock(&s->lk); + p->closed = true; + if (nni_list_active(&s->recvpipes, p)) { + nni_list_remove(&s->recvpipes, p); + } + nano_nni_lmq_flush(&p->rlmq); + + nni_id_remove(&s->pipes, nni_pipe_id(p->pipe)); +} + +static void +nano_pipe_close(void *arg) +{ + nano_pipe *p = arg; + nano_sock *s = p->rep; + nano_ctx * ctx; + nni_aio * aio = NULL; + nni_msg * msg; + nni_pipe * npipe = p->pipe; + uint16_t packetid = 0; + char * clientid = NULL; + uint32_t clientid_key = 0; + + debug_msg("################# nano_pipe_close ##############"); + nni_mtx_lock(&s->lk); + close_pipe(p); + + // cache qos msg TODO optimization in processing + if (p->conn_param->clean_start == 0) { + clientid = (char *)conn_param_get_clientid(p->conn_param); + clientid_key = DJBHashn(clientid, strlen(clientid)); + while((msg = nni_id_get_any(npipe->nano_qos_db, &packetid)) != NULL) { + while(nni_msg_shared(msg)) + nni_msg_free(msg); + dbtree_cache_session_msg(p->tree, msg, clientid_key); + nni_id_remove(npipe->nano_qos_db, packetid); + } + } + + // create disconnect event msg + msg = nano_msg_notify_disconnect(p->conn_param, p->reason_code); + if (msg == NULL) { + nni_mtx_unlock(&s->lk); + return; + } + nni_msg_set_conn_param(msg, p->conn_param); + nni_msg_set_cmd_type(msg, CMD_DISCONNECT_EV); + nni_msg_set_pipe(msg, p->id); + + // expose disconnect event + if ((ctx = nni_list_first(&s->recvq)) != NULL) { + aio = ctx->raio; + ctx->raio = NULL; + nni_list_remove(&s->recvq, ctx); + nni_mtx_unlock(&s->lk); + nni_aio_set_msg(aio, msg); + nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); + return; + } else { + // no enough ctx, so cache to waitlmq + if (nni_lmq_full(&s->waitlmq)) { + if (nni_lmq_resize(&s->waitlmq, nni_lmq_cap(&s->waitlmq) * 2) != 0) { + debug_msg("wait lmq resize failed."); + } + } + nni_lmq_putq(&s->waitlmq, msg); + } + nni_mtx_unlock(&s->lk); +} + +static void +nano_pipe_send_cb(void *arg) +{ + nano_pipe *p = arg; + nni_msg * msg; + + debug_msg("******** nano_pipe_send_cb %d ****", p->id); + // retry here + if (nni_aio_result(&p->aio_send) != 0) { + nni_msg_free(nni_aio_get_msg(&p->aio_send)); + nni_aio_set_msg(&p->aio_send, NULL); + nni_pipe_close(p->pipe); + return; + } + nni_mtx_lock(&p->lk); + + nni_aio_set_packetid(&p->aio_send, 0); + if (nni_lmq_getq(&p->rlmq, &msg) == 0) { + // msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); + nni_aio_set_msg(&p->aio_send, msg); + debug_msg("rlmq msg resending! %ld msgs left\n", nni_lmq_len(&p->rlmq)); + nni_pipe_send(p->pipe, &p->aio_send); + nni_mtx_unlock(&p->lk); + return; + } + + p->busy = false; + nni_mtx_unlock(&p->lk); + return; +} + +static void +nano_cancel_recv(nni_aio *aio, void *arg, int rv) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + + debug_msg("*********** nano_cancel_recv ***********"); + nni_mtx_lock(&s->lk); + if (ctx->raio == aio) { + nni_list_remove(&s->recvq, ctx); + ctx->raio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&s->lk); +} + +static void +nano_ctx_recv(void *arg, nni_aio *aio) +{ + nano_ctx * ctx = arg; + nano_sock *s = ctx->sock; + nano_pipe *p; + // size_t len; + nni_msg *msg = NULL; + + if (nni_aio_begin(aio) != 0) { + return; + } + + debug_msg("nano_ctx_recv start %p", ctx); + nni_mtx_lock(&s->lk); + + if (nni_lmq_getq(&s->waitlmq, &msg) == 0) { + nni_mtx_unlock(&s->lk); + debug_msg("handle msg in waitlmq."); + nni_aio_set_msg(aio, msg); + nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); + return; + } + + if ((p = nni_list_first(&s->recvpipes)) == NULL) { + int rv; + if ((rv = nni_aio_schedule(aio, nano_cancel_recv, ctx)) != 0) { + nni_mtx_unlock(&s->lk); + nni_aio_finish_error(aio, rv); + return; + } + if (ctx->raio != NULL) { + // Cannot have a second receive operation pending. + // This could be ESTATE, or we could cancel the first + // with ECANCELED. We elect the former. + debug_msg("ERROR: former aio not finish yet"); + nni_mtx_unlock(&s->lk); + nni_aio_finish_error(aio, NNG_ESTATE); + return; + } + ctx->raio = aio; + nni_list_append(&s->recvq, ctx); + nni_mtx_unlock(&s->lk); + return; + } + msg = nni_aio_get_msg(&p->aio_recv); + nni_aio_set_msg(&p->aio_recv, NULL); + nni_list_remove(&s->recvpipes, p); + if (nni_list_empty(&s->recvpipes)) { + nni_pollable_clear(&s->readable); + } + nni_pipe_recv(p->pipe, &p->aio_recv); + if ((ctx == &s->ctx) && !p->busy) { + nni_pollable_raise(&s->writable); + } + + // TODO MQTT 5 property + + ctx->pipe_id = nni_pipe_id(p->pipe); + debug_msg("nano_ctx_recv ends %p pipe: %p pipe_id: %d", ctx, p, + ctx->pipe_id); + nni_mtx_unlock(&s->lk); + + nni_aio_set_msg(aio, msg); + nni_aio_finish(aio, 0, nni_msg_len(msg)); +} + +static void +nano_pipe_recv_cb(void *arg) +{ + nano_pipe * p = arg; + nano_sock * s = p->rep; + nano_conn_param *cparam = NULL; + uint32_t len, len_of_varint = 0; + nano_ctx * ctx; + nni_msg * msg, *qos_msg = NULL; + nni_aio * aio; + nni_pipe * npipe = p->pipe; + uint8_t * ptr; + uint16_t ackid; + + if (nni_aio_result(&p->aio_recv) != 0) { + // unexpected disconnect + nni_pipe_close(p->pipe); + return; + } + debug_msg("######### nano_pipe_recv_cb ############"); + p->ka_refresh = 0; + msg = nni_aio_get_msg(&p->aio_recv); + if (msg == NULL) { + goto end; + } + + // ttl = nni_atomic_get(&s->ttl); + nni_msg_set_pipe(msg, p->id); + ptr = nni_msg_body(msg); + + // TODO HOOK + switch (nng_msg_cmd_type(msg)) { + case CMD_UNSUBSCRIBE: + case CMD_SUBSCRIBE: + cparam = p->conn_param; + if (cparam->pro_ver == PROTOCOL_VERSION_v5) { + len = get_var_integer(ptr + 2, &len_of_varint); + nni_msg_set_payload_ptr( + msg, ptr + 2 + len + len_of_varint); + } else { + nni_msg_set_payload_ptr(msg, ptr + 2); + } + break; + case CMD_DISCONNECT: + nni_pipe_close(p->pipe); + case CMD_CONNACK: + case CMD_PUBLISH: + case CMD_PINGREQ: + // Websocket need to reply PINGREQ in application layer + break; + case CMD_PUBACK: + case CMD_PUBCOMP: + nni_mtx_lock(&p->lk); + NNI_GET16(ptr, ackid); + if ((qos_msg = nni_id_get(npipe->nano_qos_db, ackid)) != + NULL) { + qos_msg = NANO_NNI_LMQ_GET_MSG_POINTER(qos_msg); + nni_msg_free(qos_msg); + nni_id_remove(npipe->nano_qos_db, ackid); + } else { + // shouldn't get here BUG TODO + debug_syslog("qos msg not found!"); + } + nni_mtx_unlock(&p->lk); + case CMD_CONNECT: + case CMD_PUBREC: + case CMD_PUBREL: + goto drop; + default: + goto drop; + } + + if (p->closed) { + // If we are closed, then we can't return data. + nni_aio_set_msg(&p->aio_recv, NULL); + nni_msg_free(msg); + debug_msg("ERROR: pipe is closed abruptly!!"); + return; + } + + nni_mtx_lock(&s->lk); + if ((ctx = nni_list_first(&s->recvq)) == NULL) { + // No one waiting to receive yet, holding pattern. + nni_list_append(&s->recvpipes, p); + nni_pollable_raise(&s->readable); + nni_mtx_unlock(&s->lk); + debug_msg("ERROR: no ctx found!! create more ctxs!"); + // nni_println("ERROR: no ctx found!! create more ctxs!"); + return; + } + + nni_list_remove(&s->recvq, ctx); + aio = ctx->raio; + ctx->raio = NULL; + nni_aio_set_msg(&p->aio_recv, NULL); + if ((ctx == &s->ctx) && !p->busy) { + nni_pollable_raise(&s->writable); + } + + // schedule another receive + nni_pipe_recv(p->pipe, &p->aio_recv); + + ctx->pipe_id = p->id; + debug_msg("currently processing pipe_id: %d", p->id); + + nni_mtx_unlock(&s->lk); + nni_aio_set_msg(aio, msg); + + nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); + debug_msg("end of nano_pipe_recv_cb %p", ctx); + return; + +drop: + nni_msg_free(msg); +end: + nni_aio_set_msg(&p->aio_recv, NULL); + nni_pipe_recv(p->pipe, &p->aio_recv); + debug_msg("Warning:dropping msg"); + return; +} + +static int +nano_sock_set_max_ttl(void *arg, const void *buf, size_t sz, nni_opt_type t) +{ + nano_sock *s = arg; + int ttl; + int rv; + + if ((rv = nni_copyin_int(&ttl, buf, sz, 1, NNI_MAX_MAX_TTL, t)) == 0) { + nni_atomic_set(&s->ttl, ttl); + } + return (rv); +} + +static int +nano_sock_get_max_ttl(void *arg, void *buf, size_t *szp, nni_opt_type t) +{ + nano_sock *s = arg; + + return (nni_copyout_int(nni_atomic_get(&s->ttl), buf, szp, t)); +} + +static int +nano_sock_get_sendfd(void *arg, void *buf, size_t *szp, nni_opt_type t) +{ + nano_sock *s = arg; + int rv; + int fd; + + if ((rv = nni_pollable_getfd(&s->writable, &fd)) != 0) { + return (rv); + } + return (nni_copyout_int(fd, buf, szp, t)); +} + +static int +nano_sock_get_recvfd(void *arg, void *buf, size_t *szp, nni_opt_type t) +{ + nano_sock *s = arg; + int rv; + int fd; + + if ((rv = nni_pollable_getfd(&s->readable, &fd)) != 0) { + return (rv); + } + + return (nni_copyout_int(fd, buf, szp, t)); +} + +static void +nano_sock_send(void *arg, nni_aio *aio) +{ + nano_sock *s = arg; + + nano_ctx_send(&s->ctx, aio); +} + +static void +nano_sock_recv(void *arg, nni_aio *aio) +{ + nano_sock *s = arg; + + nano_ctx_recv(&s->ctx, aio); +} + +static void +nano_sock_setdb(void *arg, void *data) +{ + nano_sock *s = arg; + conf * nano_conf = data; + + s->conf = nano_conf; + s->db = nano_conf->db_root; + + conf_auth_parser(s->conf); +} + +// This is the global protocol structure -- our linkage to the core. +// This should be the only global non-static symbol in this file. +static nni_proto_pipe_ops nano_pipe_ops = { + .pipe_size = sizeof(nano_pipe), + .pipe_init = nano_pipe_init, + .pipe_fini = nano_pipe_fini, + .pipe_start = nano_pipe_start, + .pipe_close = nano_pipe_close, + .pipe_stop = nano_pipe_stop, +}; + +static nni_proto_ctx_ops nano_ctx_ops = { + .ctx_size = sizeof(nano_ctx), + .ctx_init = nano_ctx_init, + .ctx_fini = nano_ctx_fini, + .ctx_send = nano_ctx_send, + .ctx_recv = nano_ctx_recv, +}; + +static nni_option nano_sock_options[] = { + { + .o_name = NNG_OPT_MAXTTL, + .o_get = nano_sock_get_max_ttl, + .o_set = nano_sock_set_max_ttl, + }, + { + .o_name = NNG_OPT_RECVFD, + .o_get = nano_sock_get_recvfd, + }, + { + .o_name = NNG_OPT_SENDFD, + .o_get = nano_sock_get_sendfd, + }, + { + .o_name = NULL, + }, +}; + +static nni_proto_sock_ops nano_sock_ops = { + .sock_size = sizeof(nano_sock), + .sock_init = nano_sock_init, + .sock_fini = nano_sock_fini, + .sock_open = nano_sock_open, + .sock_close = nano_sock_close, + .sock_options = nano_sock_options, + .sock_send = nano_sock_send, + .sock_recv = nano_sock_recv, +}; + +static nni_proto nano_tcp_proto = { + .proto_version = NNI_PROTOCOL_VERSION, + .proto_self = { NNG_NANO_TCP_SELF, NNG_NANO_TCP_SELF_NAME }, + .proto_peer = { NNG_NANO_TCP_PEER, NNG_NANO_TCP_PEER_NAME }, + .proto_flags = NNI_PROTO_FLAG_SNDRCV, + .proto_sock_ops = &nano_sock_ops, + .proto_pipe_ops = &nano_pipe_ops, + .proto_ctx_ops = &nano_ctx_ops, +}; + +int +nng_nmq_tcp0_open(nng_socket *sidp) +{ + // TODO Global binary tree init here + return (nni_proto_mqtt_open(sidp, &nano_tcp_proto, nano_sock_setdb)); +} diff --git a/src/sp/protocol/reqrep0/CMakeLists.txt b/src/sp/protocol/reqrep0/CMakeLists.txt index d588034fe..a3cecfd03 100644 --- a/src/sp/protocol/reqrep0/CMakeLists.txt +++ b/src/sp/protocol/reqrep0/CMakeLists.txt @@ -15,8 +15,8 @@ nng_sources_if(NNG_PROTO_REQ0 req.c xreq.c) nng_headers_if(NNG_PROTO_REQ0 nng/protocol/reqrep0/req.h) nng_defines_if(NNG_PROTO_REQ0 NNG_HAVE_REQ0) -nng_sources_if(NNG_PROTO_REP0 rep.c xrep.c nano_tcp.c) -nng_headers_if(NNG_PROTO_REP0 nng/protocol/reqrep0/rep.h nng/protocol/mqtt/nano_tcp.h) +nng_sources_if(NNG_PROTO_REP0 rep.c xrep.c) +nng_headers_if(NNG_PROTO_REP0 nng/protocol/reqrep0/rep.h) nng_defines_if(NNG_PROTO_REP0 NNG_HAVE_REP0) nng_test(req_test) From 6c73e3071869ae53778e97caf6a2f7ee3c90454c Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 26 Nov 2021 15:47:28 +0800 Subject: [PATCH 152/180] * MDF [transport/mqtt] add independet dir & url for mqtt's transport layer. First step to be compatible with SP of nanomsg. --- include/nng/transport/mqtt/broker_tcp.h | 30 + include/nng/transport/mqtt/mqtt_tcp.h | 30 + src/core/stream.c | 15 + src/sp/transport.c | 9 + src/sp/transport/CMakeLists.txt | 1 + src/sp/transport/mqtt/CMakeLists.txt | 20 + src/sp/transport/mqtt/broker_tcp.c | 1424 +++++++++++++++++++++ src/sp/transport/mqtt/mqtt_tcp.c | 1502 +++++++++++++++++++++++ src/sp/transport/tcp/tcp.c | 813 +++++------- 9 files changed, 3360 insertions(+), 484 deletions(-) create mode 100644 include/nng/transport/mqtt/broker_tcp.h create mode 100644 include/nng/transport/mqtt/mqtt_tcp.h create mode 100644 src/sp/transport/mqtt/CMakeLists.txt create mode 100644 src/sp/transport/mqtt/broker_tcp.c create mode 100644 src/sp/transport/mqtt/mqtt_tcp.c diff --git a/include/nng/transport/mqtt/broker_tcp.h b/include/nng/transport/mqtt/broker_tcp.h new file mode 100644 index 000000000..7b59126bc --- /dev/null +++ b/include/nng/transport/mqtt/broker_tcp.h @@ -0,0 +1,30 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2017 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef NNG_TRANSPORT_MQTT_BROKER_TCP_TCP_H +#define NNG_TRANSPORT_MQTT_BROKER_TCP_TCP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// TCP transport. This is used for communication over TCP/IP. + +#ifndef NNG_ELIDE_DEPRECATED +NNG_DECL int nmq_mqtt_tcp_register(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // NNG_TRANSPORT_MQTT_TCP_TCP_H diff --git a/include/nng/transport/mqtt/mqtt_tcp.h b/include/nng/transport/mqtt/mqtt_tcp.h new file mode 100644 index 000000000..31a3c61a0 --- /dev/null +++ b/include/nng/transport/mqtt/mqtt_tcp.h @@ -0,0 +1,30 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2017 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef NNG_TRANSPORT_MQTT_TCP_TCP_H +#define NNG_TRANSPORT_MQTT_TCP_TCP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// TCP transport. This is used for communication over TCP/IP. + +#ifndef NNG_ELIDE_DEPRECATED +NNG_DECL int nng_mqtt_tcp_register(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // NNG_TRANSPORT_MQTT_TCP_TCP_H diff --git a/src/core/stream.c b/src/core/stream.c index 418bfb159..5779d37ee 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -59,6 +59,21 @@ static struct { .dialer_alloc = nni_tcp_dialer_alloc, .listener_alloc = nni_tcp_listener_alloc, }, +{ + .scheme = "broker+tcp", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, + { + .scheme = "broker+tcp4", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, + { + .scheme = "broker+tcp6", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, { .scheme = "tls+tcp", .dialer_alloc = nni_tls_dialer_alloc, diff --git a/src/sp/transport.c b/src/sp/transport.c index ed27ebeb1..af819735c 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -57,6 +57,12 @@ extern void nni_sp_ipc_register(void); #ifdef NNG_TRANSPORT_TCP extern void nni_sp_tcp_register(void); #endif +#ifdef NNG_TRANSPORT_MQTT_TCP +// extern void nni_mqtt_tcp_register(); +#endif +#ifdef NNG_TRANSPORT_MQTT_BROKER_TCP +extern void nni_nmq_broker_tcp_register(); +#endif #ifdef NNG_TRANSPORT_TLS extern void nni_sp_tls_register(void); #endif @@ -85,6 +91,9 @@ nni_sp_tran_sys_init(void) #ifdef NNG_TRANSPORT_TCP nni_sp_tcp_register(); #endif +#ifdef NNG_TRANSPORT_MQTT_BROKER_TCP + nni_nmq_broker_tcp_register(); +#endif #ifdef NNG_TRANSPORT_TLS nni_sp_tls_register(); #endif diff --git a/src/sp/transport/CMakeLists.txt b/src/sp/transport/CMakeLists.txt index add8a9c95..0007ebbf6 100644 --- a/src/sp/transport/CMakeLists.txt +++ b/src/sp/transport/CMakeLists.txt @@ -13,6 +13,7 @@ nng_directory(transport) add_subdirectory(inproc) add_subdirectory(ipc) add_subdirectory(tcp) +add_subdirectory(mqtt) add_subdirectory(tls) add_subdirectory(ws) add_subdirectory(zerotier) diff --git a/src/sp/transport/mqtt/CMakeLists.txt b/src/sp/transport/mqtt/CMakeLists.txt new file mode 100644 index 000000000..5609f5813 --- /dev/null +++ b/src/sp/transport/mqtt/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# Copyright 2020 Staysail Systems, Inc. +# Copyright 2018 Capitar IT Group BV +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. +# + +# TCP protocol +nng_directory(mqtt) + +#nng_sources_if(NNG_TRANSPORT_MQTT_TCP mqtt_tcp.c) +#nng_headers_if(NNG_TRANSPORT_MQTT_TCP nng/transport/mqtt/mqtt_tcp.h) +#nng_defines_if(NNG_TRANSPORT_MQTT_TCP NNG_TRANSPORT_MQTT_TCP) + +nng_sources_if(NNG_TRANSPORT_MQTT_BROKER_TCP broker_tcp.c) +nng_headers_if(NNG_TRANSPORT_MQTT_BROKER_TCP nng/transport/mqtt/broker_tcp.h) +nng_defines_if(NNG_TRANSPORT_MQTT_BROKER_TCP NNG_TRANSPORT_MQTT_BROKER_TCP) diff --git a/src/sp/transport/mqtt/broker_tcp.c b/src/sp/transport/mqtt/broker_tcp.c new file mode 100644 index 000000000..b11f193f8 --- /dev/null +++ b/src/sp/transport/mqtt/broker_tcp.c @@ -0,0 +1,1424 @@ +// rewrite by Jaylin EMQ X for MQTT usage + +#include +#include +#include +#include +#include +#include + +#include "core/nng_impl.h" +#include "core/sockimpl.h" +#include "nng/nng_debug.h" + +#include "nng/protocol/mqtt/mqtt.h" +#include "nng/protocol/mqtt/mqtt_parser.h" + +// TCP transport. Platform specific TCP operations must be +// supplied as well. + +typedef struct tcptran_pipe tcptran_pipe; +typedef struct tcptran_ep tcptran_ep; + +// tcp_pipe is one end of a TCP connection. +struct tcptran_pipe { + nng_stream *conn; + nni_pipe * npipe; // for statitical + // uint16_t peer; //reserved for MQTT sdk version + // uint16_t proto; + size_t rcvmax; + size_t gotrxhead; + size_t wantrxhead; + size_t qlength; // length of qos_buf + bool closed; + uint8_t txlen[NANO_MIN_PACKET_LEN]; + uint8_t rxlen[NNI_NANO_MAX_HEADER_SIZE]; + uint8_t * conn_buf; + uint8_t * qos_buf; + nni_aio * txaio; + nni_aio * rxaio; + nni_aio * qsaio; + nni_aio * rsaio; + nni_aio * rpaio; + nni_aio * negoaio; + nni_msg * rxmsg, *cnmsg; + nni_mtx mtx; + conn_param * tcp_cparam; + nni_list recvq; + nni_list sendq; + nni_list_node node; + tcptran_ep * ep; + nni_atomic_flag reaped; + nni_reap_node reap; + // uint8_t sli_win[5]; //use aio multiple times instead of + // seperating 2 packets manually +}; + +struct tcptran_ep { + nni_mtx mtx; + // uint16_t proto; + size_t rcvmax; + bool fini; + bool started; + bool closed; + nng_url * url; + nng_sockaddr src; + int refcnt; // active pipes + nni_aio * useraio; + nni_aio * connaio; + nni_aio * timeaio; + nni_list busypipes; // busy pipes -- ones passed to socket + nni_list waitpipes; // pipes waiting to match to socket + nni_list negopipes; // pipes busy negotiating + nni_reap_node reap; + nng_stream_listener *listener; +#ifdef NNG_ENABLE_STATS + nni_stat_item st_rcv_max; +#endif +}; + +static void tcptran_pipe_send_start(tcptran_pipe *); +static void tcptran_pipe_recv_start(tcptran_pipe *); +static void tcptran_pipe_send_cb(void *); +static void tcptran_pipe_recv_cb(void *); +static void tcptran_pipe_nego_cb(void *); +static void tcptran_ep_fini(void *); +static void tcptran_pipe_fini(void *); + +static nni_reap_list tcptran_ep_reap_list = { + .rl_offset = offsetof(tcptran_ep, reap), + .rl_func = tcptran_ep_fini, +}; + +static nni_reap_list tcptran_pipe_reap_list = { + .rl_offset = offsetof(tcptran_pipe, reap), + .rl_func = tcptran_pipe_fini, +}; + +static void +tcptran_init(void) +{ +} + +static void +tcptran_fini(void) +{ +} + +static void +tcptran_pipe_close(void *arg) +{ + tcptran_pipe *p = arg; + // nni_pipe * npipe = p->npipe; + + nni_mtx_lock(&p->mtx); + p->closed = true; + nni_mtx_unlock(&p->mtx); + + nni_aio_close(p->rxaio); + nni_aio_close(p->rpaio); + nni_aio_close(p->txaio); + nni_aio_close(p->rsaio); + nni_aio_close(p->qsaio); + nni_aio_close(p->negoaio); + + nng_stream_close(p->conn); + debug_syslog("tcptran_pipe_close\n"); +} + +static void +tcptran_pipe_stop(void *arg) +{ + tcptran_pipe *p = arg; + + nni_aio_stop(p->qsaio); + nni_aio_stop(p->rsaio); + nni_aio_stop(p->rpaio); + nni_aio_stop(p->rxaio); + nni_aio_stop(p->txaio); + nni_aio_stop(p->negoaio); +} + +static int +tcptran_pipe_init(void *arg, nni_pipe *npipe) +{ + debug_msg("************tcptran_pipe_init************"); + tcptran_pipe *p = arg; + + nni_pipe_set_conn_param(npipe, p->tcp_cparam); + p->npipe = npipe; + p->conn_buf = NULL; + p->qos_buf = nng_alloc(16 + NNI_NANO_MAX_PACKET_SIZE); + return (0); +} + +static void +tcptran_pipe_fini(void *arg) +{ + tcptran_pipe *p = arg; + tcptran_ep * ep; + + tcptran_pipe_stop(p); + if ((ep = p->ep) != NULL) { + nni_mtx_lock(&ep->mtx); + nni_list_node_remove(&p->node); + ep->refcnt--; + if (ep->fini && (ep->refcnt == 0)) { + nni_reap(&tcptran_ep_reap_list, ep); + } + nni_mtx_unlock(&ep->mtx); + } + + nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); + nni_aio_free(p->qsaio); + nni_aio_free(p->rpaio); + nni_aio_free(p->rsaio); + nni_aio_free(p->rxaio); + nni_aio_free(p->txaio); + nni_aio_free(p->negoaio); + nng_stream_free(p->conn); + nni_msg_free(p->rxmsg); + nni_mtx_fini(&p->mtx); + NNI_FREE_STRUCT(p); +} + +static void +tcptran_pipe_reap(tcptran_pipe *p) +{ + if (!nni_atomic_flag_test_and_set(&p->reaped)) { + if (p->conn != NULL) { + nng_stream_close(p->conn); + } + nni_reap(&tcptran_pipe_reap_list, p); + } +} + +static int +tcptran_pipe_alloc(tcptran_pipe **pipep) +{ + tcptran_pipe *p; + int rv; + + if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&p->mtx); + if (((rv = nni_aio_alloc(&p->txaio, tcptran_pipe_send_cb, p)) != 0) || + ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rpaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rxaio, tcptran_pipe_recv_cb, p)) != 0) || + ((rv = nni_aio_alloc(&p->negoaio, tcptran_pipe_nego_cb, p)) != + 0)) { + tcptran_pipe_fini(p); + return (rv); + } + nni_aio_list_init(&p->recvq); + nni_aio_list_init(&p->sendq); + nni_atomic_flag_reset(&p->reaped); + + *pipep = p; + + return (0); +} + +static void +tcptran_ep_match(tcptran_ep *ep) +{ + nni_aio * aio; + tcptran_pipe *p; + + if (((aio = ep->useraio) == NULL) || + ((p = nni_list_first(&ep->waitpipes)) == NULL)) { + return; + } + nni_list_remove(&ep->waitpipes, p); + nni_list_append(&ep->busypipes, p); + ep->useraio = NULL; + p->rcvmax = ep->rcvmax; + nni_aio_set_output(aio, 0, p); + nni_aio_finish(aio, 0, 0); +} + +/** + * MQTT protocal negotiate + * deal with CONNECT packet + * Fixed header to variable header + * receive multiple times for complete data packet then reply ACK in protocol + * layer iov_len limits the length readv reads + * TODO independent with nng SP + */ +static void +tcptran_pipe_nego_cb(void *arg) +{ + tcptran_pipe *p = arg; + tcptran_ep * ep = p->ep; + nni_aio * aio = p->negoaio; + nni_aio * uaio; + uint32_t len; + int rv, len_of_varint = 0; + + debug_msg("start tcptran_pipe_nego_cb max len %ld pipe_addr %p\n", + NANO_CONNECT_PACKET_LEN, p); + nni_mtx_lock(&ep->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + // calculate number of bytes received + if (p->gotrxhead < p->wantrxhead) { + p->gotrxhead += nni_aio_count(aio); + } + + // recv fixed header + if (p->gotrxhead < NNI_NANO_MAX_HEADER_SIZE) { + nni_iov iov; + iov.iov_len = NNI_NANO_MAX_HEADER_SIZE - p->gotrxhead; + iov.iov_buf = &p->rxlen[p->gotrxhead]; + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { + if (p->rxlen[0] != CMD_CONNECT) { + debug_msg("CMD TYPE %x", p->rxlen[0]); + rv = NNG_EPROTO; + goto error; + } + len = + get_var_integer(p->rxlen + 1, (uint32_t *) &len_of_varint); + p->wantrxhead = len + 1 + len_of_varint; + rv = (p->wantrxhead >= NANO_CONNECT_PACKET_LEN) ? 0 + : NNG_EPROTO; + if (rv != 0) { + goto error; + } + } + + if (p->gotrxhead < p->wantrxhead) { + nni_iov iov; + iov.iov_len = p->wantrxhead - p->gotrxhead; + if (p->conn_buf == NULL) { + p->conn_buf = nng_alloc(p->wantrxhead); + memcpy(p->conn_buf, p->rxlen, p->gotrxhead); + } + iov.iov_buf = &p->conn_buf[p->gotrxhead]; + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + + // We have both sent and received the CONNECT headers. + // CONNECT packet serialization + + if (p->gotrxhead >= p->wantrxhead) { + if (p->tcp_cparam == NULL) { + conn_param_alloc(&p->tcp_cparam); + } + if (conn_handler(p->conn_buf, p->tcp_cparam) == 0) { + nng_free(p->conn_buf, p->wantrxhead); + p->conn_buf = NULL; + // we don't need to alloc a new msg, just use pipe. + // We are all ready now. We put this in the wait list, + // and then try to run the matcher. + nni_list_remove(&ep->negopipes, p); + nni_list_append(&ep->waitpipes, p); + tcptran_ep_match(ep); + nni_mtx_unlock(&ep->mtx); + return; + } else { + rv = NNG_EPROTO; + nng_free(p->conn_buf, p->wantrxhead); + conn_param_free(p->tcp_cparam); + goto error; + } + } + + nni_mtx_unlock(&ep->mtx); + debug_msg("^^^^^^^^^^end of tcptran_pipe_nego_cb^^^^^^^^^^\n"); + return; + +error: + nng_stream_close(p->conn); + + if ((uaio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(uaio, rv); + } + nni_mtx_unlock(&ep->mtx); + tcptran_pipe_reap(p); + debug_msg("connect nego error rv: %d!", rv); + return; +} + +static void +tcptran_pipe_send_cb(void *arg) +{ + tcptran_pipe *p = arg; + int rv; + nni_aio * aio; + uint8_t * header; + uint8_t flag, cmd; + size_t n; + nni_msg * msg; + nni_aio * txaio = p->txaio; + + nni_mtx_lock(&p->mtx); + aio = nni_list_first(&p->sendq); + + debug_msg("############### tcptran_pipe_send_cb ################"); + + if ((rv = nni_aio_result(txaio)) != 0) { + nni_pipe_bump_error(p->npipe, rv); + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + + n = nni_aio_count(txaio); + nni_aio_iov_advance(txaio, n); + debug_msg( + "tcp socket sent %ld bytes iov %ld", n, nni_aio_iov_count(txaio)); + + if (nni_aio_iov_count(txaio) > 0) { + nng_stream_send(p->conn, txaio); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + tcptran_pipe_send_start(p); + + msg = nni_aio_get_msg(aio); + n = nni_msg_len(msg); + cmd = nni_msg_cmd_type(msg); + if (cmd == CMD_CONNACK) { + header = nni_msg_header(msg); + // parse result code TODO verify bug + flag = header[3]; + } + // nni_pipe_bump_tx(p->npipe, n); + // free qos buffer + if (p->qlength > 16 + NNI_NANO_MAX_PACKET_SIZE) { + nng_free(p->qos_buf, p->qlength); + p->qos_buf = nng_alloc(16 + NNI_NANO_MAX_PACKET_SIZE); + } + nni_mtx_unlock(&p->mtx); + + nni_aio_set_msg(aio, NULL); + nni_msg_free(msg); + if (cmd == CMD_CONNACK && flag != 0x00) { + nni_aio_finish_error(aio, NNG_ECLOSED); + } else { + nni_aio_finish_sync(aio, 0, n); + } +} + +/* + * deal with MQTT protocol + * insure read complete MQTT packet from socket + */ +static void +tcptran_pipe_recv_cb(void *arg) +{ + nni_aio * aio; + nni_iov iov; + uint8_t type; + uint32_t len = 0, rv, pos = 1; + size_t n; + nni_msg * msg; + tcptran_pipe *p = arg; + nni_aio * rxaio = p->rxaio; + conn_param * cparam; + + debug_msg("tcptran_pipe_recv_cb %p\n", p); + nni_mtx_lock(&p->mtx); + + aio = nni_list_first(&p->recvq); + + if ((rv = nni_aio_result(rxaio)) != 0) { + debug_msg("nni aio error!! %d\n", rv); + goto recv_error; + } + + n = nni_aio_count(rxaio); + p->gotrxhead += n; + + nni_aio_iov_advance(rxaio, n); + // not receive enough bytes, deal with remaining length + len = get_var_integer(p->rxlen, &pos); + debug_msg("new %ld recevied %ld header %x %d pos: %d len : %d", n, + p->gotrxhead, p->rxlen[0], p->rxlen[1], pos, len); + debug_msg("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); + + if (nni_aio_iov_count(rxaio) > 0) { + debug_msg("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], + strlen((char *) p->rxlen)); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } else if (p->gotrxhead <= NNI_NANO_MAX_HEADER_SIZE && + p->rxlen[p->gotrxhead - 1] > 0x7f) { + // length error + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { + rv = NNG_EMSGSIZE; + goto recv_error; + } + // same packet, continue receving next byte of remaining length + iov.iov_buf = &p->rxlen[p->gotrxhead]; + iov.iov_len = 1; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } else if (len == 0 && n == 2) { + if ((p->rxlen[0] & 0XFF) == CMD_PINGREQ) { + nng_aio_wait(p->qsaio); + p->txlen[0] = CMD_PINGRESP; + p->txlen[1] = 0x00; + iov.iov_len = 2; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->qsaio, 1, &iov); + nng_stream_send(p->conn, p->qsaio); + goto notify; + } + } + + // finish fixed header + p->wantrxhead = len + p->gotrxhead; + cparam = p->tcp_cparam; + + if (p->rxmsg == NULL) { + // We should have gotten a message header. len -> remaining + // length to define how many bytes left + debug_msg("pipe %p header got: %x %x %x %x %x, %ld!!\n", p, + p->rxlen[0], p->rxlen[1], p->rxlen[2], p->rxlen[3], + p->rxlen[4], p->wantrxhead); + // Make sure the message payload is not too big. If it is + // the caller will shut down the pipe. + if ((len > p->rcvmax) && (p->rcvmax > 0)) { + debug_msg("size error\n"); + rv = NNG_EMSGSIZE; + goto recv_error; + } + + if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + debug_syslog("mem error %ld\n", (size_t) len); + goto recv_error; + } + + // Submit the rest of the data for a read -- seperate Fixed + // header with variable header and so on + // we want to read the entire message now. + if (len != 0) { + iov.iov_buf = nni_msg_body(p->rxmsg); + iov.iov_len = (size_t) len; + + nni_aio_set_iov(rxaio, 1, &iov); + // second recv action + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + } + + // We read a message completely. Let the user know the good news. use + // as application message callback of users + nni_aio_list_remove(aio); + msg = p->rxmsg; + p->rxmsg = NULL; + n = nni_msg_len(msg); + type = p->rxlen[0] & 0xf0; + + fixed_header_adaptor(p->rxlen, msg); + nni_msg_set_conn_param(msg, cparam); + // duplicated with fixed_header_adaptor + nni_msg_set_remaining_len(msg, len); + nni_msg_set_cmd_type(msg, type); + debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", + len, cparam, cparam->clientid.body, cparam->username.body, + cparam->pro_ver); + + // set the payload pointer of msg according to packet_type + debug_msg("The type of msg is %x", type); + if (type == CMD_PUBLISH) { + uint8_t qos_pac; + uint16_t pid; + + qos_pac = nni_msg_get_pub_qos(msg); + if (qos_pac > 0) { + nng_aio_wait(p->rsaio); + if (qos_pac == 1) { + p->txlen[0] = CMD_PUBACK; + } else if (qos_pac == 2) { + p->txlen[0] = CMD_PUBREC; + } + p->txlen[1] = 0x02; + pid = nni_msg_get_pub_pid(msg); + NNI_PUT16(p->txlen + 2, pid); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->rsaio, 1, &iov); + nng_stream_send(p->conn, p->rsaio); + } + } else if (type == CMD_PUBREC) { + nng_aio_wait(p->rpaio); + p->txlen[0] = 0X62; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(msg), 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->rpaio, 1, &iov); + nng_stream_send(p->conn, p->rpaio); + } else if (type == CMD_PUBREL) { + nng_aio_wait(p->qsaio); + p->txlen[0] = CMD_PUBCOMP; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(msg), 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->qsaio, 1, &iov); + nng_stream_send(p->conn, p->qsaio); + } + + // keep connection & Schedule next receive + // nni_pipe_bump_rx(p->npipe, n); + tcptran_pipe_recv_start(p); + nni_mtx_unlock(&p->mtx); + + nni_aio_set_msg(aio, msg); + nni_aio_finish_sync(aio, 0, n); + debug_msg("end of tcptran_pipe_recv_cb: synch! %p\n", p); + return; + +recv_error: + nni_aio_list_remove(aio); + msg = p->rxmsg; + p->rxmsg = NULL; + nni_pipe_bump_error(p->npipe, rv); + nni_mtx_unlock(&p->mtx); + + nni_msg_free(msg); + nni_aio_finish_error(aio, rv); + debug_msg("tcptran_pipe_recv_cb: recv error rv: %d\n", rv); + return; +notify: + // nni_pipe_bump_rx(p->npipe, n); + nni_aio_list_remove(aio); + tcptran_pipe_recv_start(p); + nni_mtx_unlock(&p->mtx); + nni_aio_set_msg(aio, NULL); + nni_aio_finish(aio, 0, 0); + return; +} + +static void +tcptran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) +{ + tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (!nni_aio_list_active(aio)) { + nni_mtx_unlock(&p->mtx); + return; + } + // If this is being sent, then cancel the pending transfer. + // The callback on the txaio will cause the user aio to + // be canceled too. + if (nni_list_first(&p->sendq) == aio) { + nni_aio_abort(p->txaio, rv); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + + nni_aio_finish_error(aio, rv); +} + +static void +tcptran_pipe_send_start(tcptran_pipe *p) +{ + nni_aio *aio; + nni_aio *txaio; + nni_msg *msg; + int niov; + nni_iov iov[4]; + uint8_t qos; + + debug_msg("########### tcptran_pipe_send_start ###########"); + if (p->closed) { + while ((aio = nni_list_first(&p->sendq)) != NULL) { + nni_list_remove(&p->sendq, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + return; + } + + if ((aio = nni_list_first(&p->sendq)) == NULL) { + debug_msg("aio not functioning"); + return; + } + + // This runs to send the message. + msg = nni_aio_get_msg(aio); + if (msg == NULL) { + // TODO error handler + nni_println("ERROR: sending NULL msg!"); + return; + } + qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); + //qos default to 0 if the msg is not PUBLISH + msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); + nni_aio_set_msg(aio, msg); + // never modify msg + if (nni_msg_header_len(msg) > 0 && + nni_msg_cmd_type(msg) == CMD_PUBLISH) { + uint8_t *body, *header, qos_pac; + uint8_t varheader[2], + fixheader[NNI_NANO_MAX_HEADER_SIZE] = { 0 }, + tmp[4] = { 0 }; + nni_pipe *pipe; + uint16_t pid; + size_t tlen, rlen; + + pipe = p->npipe; + body = nni_msg_body(msg); + header = nni_msg_header(msg); + p->qlength = 0; + NNI_GET16(body, tlen); + + qos_pac = nni_msg_get_pub_qos(msg); + if (qos_pac == 0) { + // save time & space for QoS 0 publish + goto send; + } + + debug_msg("qos_pac %d sub %d\n", qos_pac, qos); + memcpy(fixheader, header, nni_msg_header_len(msg)); + qos = qos_pac > qos ? qos : qos_pac; + + if (qos_pac > qos) { + if (qos == 1) { + // set qos to 1 + fixheader[0] = fixheader[0] & 0xF9; + fixheader[0] = fixheader[0] | 0x02; + rlen = nni_msg_header_len(msg) - 1; + } else { + // set qos to 0 + fixheader[0] = fixheader[0] & 0xF9; + uint32_t pos = 1; + rlen = put_var_integer( + tmp, get_var_integer(header, &pos) - 2); + memcpy(fixheader + 1, tmp, rlen); + } + } else { + rlen = nni_msg_header_len(msg) - 1; + } + + txaio = p->txaio; + niov = 0; + // fixed header + p->qlength += rlen + 1; // strlen(fixheader) + // 1st part of variable header: topic + + p->qlength += tlen + 2; // get topic length + // packet id + if (qos > 0) { + // set pid + nni_msg *old; + pid = nni_aio_get_packetid(aio); + if (pid == 0) { + //first time send this msg + pid = nni_pipe_inc_packetid(pipe); + // store msg for qos retrying + debug_msg("* processing QoS pubmsg with pipe: %p *", p); + nni_msg_clone(msg); + if ((old = nni_id_get( + pipe->nano_qos_db, pid)) != NULL) { + // TODO packetid already exists. + // do we need to replace old with new one ? + // print warning to users + nni_println( + "ERROR: packet id duplicates in " + "nano_qos_db"); + old = NANO_NNI_LMQ_GET_MSG_POINTER(old); + nni_msg_free(old); + // nni_id_remove(&pipe->nano_qos_db, + // pid); + } + old = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); + nni_id_set(pipe->nano_qos_db, pid, old); + } + NNI_PUT16(varheader, pid); + p->qlength += 2; + } + if (p->qlength > 16 + NNI_NANO_MAX_PACKET_SIZE) { + nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); + p->qos_buf = nng_alloc(sizeof(uint8_t) * (p->qlength)); + } + memcpy(p->qos_buf, fixheader, rlen + 1); + memcpy(p->qos_buf + rlen + 1, body, tlen + 2); + if (qos > 0) { + memcpy(p->qos_buf + rlen + tlen + 3, varheader, 2); + } + iov[niov].iov_buf = p->qos_buf; + iov[niov].iov_len = p->qlength; + niov++; + + // payload + if (nni_msg_len(msg) > 0 && + qos_pac > + 0) { // determine if it needs to skip packet id field + iov[niov].iov_buf = body + 2 + tlen + 2; + iov[niov].iov_len = nni_msg_len(msg) - 4 - tlen; + niov++; + } else if (nni_msg_len(msg) > 0) { + iov[niov].iov_buf = body + 2 + tlen; + iov[niov].iov_len = nni_msg_len(msg) - 2 - tlen; + niov++; + } + + nni_aio_set_iov(txaio, niov, iov); + nng_stream_send(p->conn, txaio); + return; + } +send: + txaio = p->txaio; + niov = 0; + + if (nni_msg_header_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_header(msg); + iov[niov].iov_len = nni_msg_header_len(msg); + niov++; + } + if (nni_msg_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_body(msg); + iov[niov].iov_len = nni_msg_len(msg); + niov++; + } + nni_aio_set_iov(txaio, niov, iov); + nng_stream_send(p->conn, txaio); +} + +static void +tcptran_pipe_send(void *arg, nni_aio *aio) +{ + tcptran_pipe *p = arg; + int rv; + + debug_msg("####################tcptran_pipe_send###########"); + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, tcptran_pipe_send_cancel, p)) != 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + nni_list_append(&p->sendq, aio); + if (nni_list_first(&p->sendq) == aio) { + //send publish msg or send others + tcptran_pipe_send_start(p); + } + nni_mtx_unlock(&p->mtx); +} + +static void +tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) +{ + tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (!nni_aio_list_active(aio)) { + nni_mtx_unlock(&p->mtx); + return; + } + // If receive in progress, then cancel the pending transfer. + // The callback on the rxaio will cause the user aio to + // be canceled too. + if (nni_list_first(&p->recvq) == aio) { + nni_aio_abort(p->rxaio, rv); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); +} + +static void +tcptran_pipe_recv(void *arg, nni_aio *aio) +{ + tcptran_pipe *p = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, tcptran_pipe_recv_cancel, p)) != 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + + if (nni_aio_list_active(aio) == 0) { + nni_list_append(&p->recvq, aio); + } + + if (nni_list_first(&p->recvq) == aio) { + tcptran_pipe_recv_start(p); + } + nni_mtx_unlock(&p->mtx); +} + +/* +static uint16_t +tcptran_pipe_peer(void *arg) +{ + tcptran_pipe *p = arg; + + return (p->peer); +} +*/ + +static int +tcptran_pipe_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + tcptran_pipe *p = arg; + return (nni_stream_get(p->conn, name, buf, szp, t)); +} + +static void +tcptran_pipe_recv_start(tcptran_pipe *p) +{ + nni_aio *rxaio; + nni_iov iov; + debug_msg("*** tcptran_pipe_recv_start ***\n"); + NNI_ASSERT(p->rxmsg == NULL); + + if (p->closed) { + nni_aio *aio; + while ((aio = nni_list_first(&p->recvq)) != NULL) { + nni_list_remove(&p->recvq, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + return; + } + if (nni_list_empty(&p->recvq)) { + return; + } + + // Schedule a read of the fixed header. + rxaio = p->rxaio; + p->gotrxhead = 0; + p->wantrxhead = NANO_MIN_FIXED_HEADER_LEN; + iov.iov_buf = p->rxlen; + iov.iov_len = NANO_MIN_FIXED_HEADER_LEN; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); +} + +// DEAL WITH CONNECT when PIPE INIT +static void +tcptran_pipe_start(tcptran_pipe *p, nng_stream *conn, tcptran_ep *ep) +{ + nni_iov iov; + // nni_tcp_conn *c; + + ep->refcnt++; + + p->conn = conn; + p->ep = ep; + // p->proto = ep->proto; + + debug_msg("tcptran_pipe_start!"); + p->gotrxhead = 0; + p->wantrxhead = NANO_CONNECT_PACKET_LEN; // packet type 1 + remaining + // length 1 + protocal name 7 + // + flag 1 + keepalive 2 = 12 + iov.iov_len = NNI_NANO_MAX_HEADER_SIZE; // dynamic + iov.iov_buf = p->rxlen; + + nni_aio_set_iov(p->negoaio, 1, &iov); + nni_list_append(&ep->negopipes, p); + + nni_aio_set_timeout(p->negoaio, + 15 * 1000); // 15 sec timeout to negotiate abide with emqx + nng_stream_recv(p->conn, p->negoaio); +} + +static void +tcptran_ep_fini(void *arg) +{ + tcptran_ep *ep = arg; + + nni_mtx_lock(&ep->mtx); + ep->fini = true; + if (ep->refcnt != 0) { + nni_mtx_unlock(&ep->mtx); + return; + } + nni_mtx_unlock(&ep->mtx); + nni_aio_stop(ep->timeaio); + nni_aio_stop(ep->connaio); + nng_stream_listener_free(ep->listener); + nni_aio_free(ep->timeaio); + nni_aio_free(ep->connaio); + + nni_mtx_fini(&ep->mtx); + NNI_FREE_STRUCT(ep); +} + +static void +tcptran_ep_close(void *arg) +{ + tcptran_ep * ep = arg; + tcptran_pipe *p; + + nni_mtx_lock(&ep->mtx); + + debug_syslog("tcptran_ep_close"); + ep->closed = true; + nni_aio_close(ep->timeaio); + if (ep->listener != NULL) { + nng_stream_listener_close(ep->listener); + } + NNI_LIST_FOREACH (&ep->negopipes, p) { + tcptran_pipe_close(p); + } + NNI_LIST_FOREACH (&ep->waitpipes, p) { + tcptran_pipe_close(p); + } + NNI_LIST_FOREACH (&ep->busypipes, p) { + tcptran_pipe_close(p); + } + if (ep->useraio != NULL) { + nni_aio_finish_error(ep->useraio, NNG_ECLOSED); + ep->useraio = NULL; + } + + nni_mtx_unlock(&ep->mtx); +} + +// This parses off the optional source address that this transport uses. +// The special handling of this URL format is quite honestly an historical +// mistake, which we would remove if we could.static int +int +tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl) +{ + int af; + char * semi; + char * src; + size_t len; + int rv; + nni_aio *aio; + + // We modify the URL. This relies on the fact that the underlying + // transport does not free this, so we can just use references. + + url->u_scheme = surl->u_scheme; + url->u_port = surl->u_port; + url->u_hostname = surl->u_hostname; + + if ((semi = strchr(url->u_hostname, ';')) == NULL) { + memset(sa, 0, sizeof(*sa)); + return (0); + } + + len = (size_t) (semi - url->u_hostname); + url->u_hostname = semi + 1; + + if (strcmp(surl->u_scheme, "tcp") == 0) { + af = NNG_AF_UNSPEC; + } else if (strcmp(surl->u_scheme, "tcp4") == 0) { + af = NNG_AF_INET; + } else if (strcmp(surl->u_scheme, "tcp6") == 0) { + af = NNG_AF_INET6; + } else { + return (NNG_EADDRINVAL); + } + + if ((src = nni_alloc(len + 1)) == NULL) { + return (NNG_ENOMEM); + } + memcpy(src, surl->u_hostname, len); + src[len] = '\0'; + + if ((rv = nni_aio_alloc(&aio, NULL, NULL)) != 0) { + nni_free(src, len + 1); + return (rv); + } + + nni_resolv_ip(src, "0", af, true, sa, aio); + nni_aio_wait(aio); + rv = nni_aio_result(aio); + nni_aio_free(aio); + nni_free(src, len + 1); + return (rv); +} + +static void +tcptran_timer_cb(void *arg) +{ + tcptran_ep *ep = arg; + if (nni_aio_result(ep->timeaio) == 0) { + nng_stream_listener_accept(ep->listener, ep->connaio); + } +} + +// TCP accpet trigger +static void +tcptran_accept_cb(void *arg) +{ + tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + tcptran_pipe *p; + int rv; + nng_stream * conn; + + nni_mtx_lock(&ep->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + conn = nni_aio_get_output(aio, 0); + if ((rv = tcptran_pipe_alloc(&p)) != 0) { + nng_stream_free(conn); + goto error; + } + + if (ep->closed) { + tcptran_pipe_fini(p); + nng_stream_free(conn); + rv = NNG_ECLOSED; + goto error; + } + tcptran_pipe_start(p, conn, ep); + nng_stream_listener_accept(ep->listener, ep->connaio); + nni_mtx_unlock(&ep->mtx); + return; + +error: + // When an error here occurs, let's send a notice up to the consumer. + // That way it can be reported properly. + if ((aio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + switch (rv) { + + case NNG_ENOMEM: + case NNG_ENOFILES: + nng_sleep_aio(10, ep->timeaio); + break; + + default: + if (!ep->closed) { + nng_stream_listener_accept(ep->listener, ep->connaio); + } + break; + } + nni_mtx_unlock(&ep->mtx); +} + +static int +tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) +{ + tcptran_ep *ep; + NNI_ARG_UNUSED(sock); + + if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&ep->mtx); + NNI_LIST_INIT(&ep->busypipes, tcptran_pipe, node); + NNI_LIST_INIT(&ep->waitpipes, tcptran_pipe, node); + NNI_LIST_INIT(&ep->negopipes, tcptran_pipe, node); + + // ep->proto = nni_sock_proto_id(sock); + ep->url = url; +#ifdef NNG_ENABLE_STATS + static const nni_stat_info rcv_max_info = { + .si_name = "rcv_max", + .si_desc = "maximum receive size", + .si_type = NNG_STAT_LEVEL, + .si_unit = NNG_UNIT_BYTES, + .si_atomic = true, + }; + nni_stat_init(&ep->st_rcv_max, &rcv_max_info); +#endif + + *epp = ep; + return (0); +} + +static int +tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) +{ + tcptran_ep *ep; + int rv; + nni_sock * sock = nni_listener_sock(nlistener); + + // Check for invalid URL components. + if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { + return (NNG_EADDRINVAL); + } + if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || + (url->u_query != NULL)) { + return (NNG_EADDRINVAL); + } + + if ((rv = tcptran_ep_init(&ep, url, sock)) != 0) { + return (rv); + } + + if (((rv = nni_aio_alloc(&ep->connaio, tcptran_accept_cb, ep)) != 0) || + ((rv = nni_aio_alloc(&ep->timeaio, tcptran_timer_cb, ep)) != 0) || + ((rv = nng_stream_listener_alloc_url(&ep->listener, url)) != 0)) { + tcptran_ep_fini(ep); + return (rv); + } + +#ifdef NNG_ENABLE_STATS + nni_listener_add_stat(nlistener, &ep->st_rcv_max); +#endif + *lp = ep; + return (0); +} + +static void +tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) +{ + tcptran_ep *ep = arg; + nni_mtx_lock(&ep->mtx); + if (ep->useraio == aio) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + +// TODO network interface bind +static int +tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + tcptran_ep *ep = arg; + char * s; + int rv; + int port = 0; + + if (ep->listener != NULL) { + (void) nng_stream_listener_get_int( + ep->listener, NNG_OPT_TCP_BOUND_PORT, &port); + } + + if ((rv = nni_url_asprintf_port(&s, ep->url, port)) == 0) { + rv = nni_copyout_str(s, v, szp, t); + nni_strfree(s); + } + return (rv); +} + +static int +tcptran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + rv = nni_copyout_size(ep->rcvmax, v, szp, t); + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static int +tcptran_ep_set_recvmaxsz(void *arg, const void *v, size_t sz, nni_opt_type t) +{ + tcptran_ep *ep = arg; + size_t val; + int rv; + if ((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) { + tcptran_pipe *p; + nni_mtx_lock(&ep->mtx); + ep->rcvmax = val; + NNI_LIST_FOREACH (&ep->waitpipes, p) { + p->rcvmax = val; + } + NNI_LIST_FOREACH (&ep->negopipes, p) { + p->rcvmax = val; + } + NNI_LIST_FOREACH (&ep->busypipes, p) { + p->rcvmax = val; + } + nni_mtx_unlock(&ep->mtx); +#ifdef NNG_ENABLE_STATS + nni_stat_set_value(&ep->st_rcv_max, val); +#endif + } + return (rv); +} + +static int +tcptran_ep_bind(void *arg) +{ + tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + rv = nng_stream_listener_listen(ep->listener); + nni_mtx_unlock(&ep->mtx); + + return (rv); +} + +static void +tcptran_ep_accept(void *arg, nni_aio *aio) +{ + tcptran_ep *ep = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + if (ep->useraio != NULL) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + if ((rv = nni_aio_schedule(aio, tcptran_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, rv); + return; + } + ep->useraio = aio; + if (!ep->started) { + ep->started = true; + nng_stream_listener_accept(ep->listener, ep->connaio); + } else { + tcptran_ep_match(ep); + } + nni_mtx_unlock(&ep->mtx); +} + +static nni_sp_pipe_ops tcptran_pipe_ops = { + .p_init = tcptran_pipe_init, + .p_fini = tcptran_pipe_fini, + .p_stop = tcptran_pipe_stop, + .p_send = tcptran_pipe_send, + .p_recv = tcptran_pipe_recv, + .p_close = tcptran_pipe_close, + //.p_peer = tcptran_pipe_peer, + .p_getopt = tcptran_pipe_getopt, +}; + +static const nni_option tcptran_ep_opts[] = { + { + .o_name = NNG_OPT_RECVMAXSZ, + .o_get = tcptran_ep_get_recvmaxsz, + .o_set = tcptran_ep_set_recvmaxsz, + }, + { + .o_name = NNG_OPT_URL, + .o_get = tcptran_ep_get_url, + }, + // terminate list + { + .o_name = NULL, + }, +}; + +static int +tcptran_listener_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_listener_get(ep->listener, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t); + } + return (rv); +} + +static int +tcptran_listener_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_listener_set(ep->listener, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t); + } + return (rv); +} + +static nni_sp_listener_ops tcptran_listener_ops = { + .l_init = tcptran_listener_init, + .l_fini = tcptran_ep_fini, + .l_bind = tcptran_ep_bind, + .l_accept = tcptran_ep_accept, + .l_close = tcptran_ep_close, + .l_getopt = tcptran_listener_getopt, + .l_setopt = tcptran_listener_setopt, +}; + +static nni_sp_tran tcp_tran_mqtt = { + .tran_scheme = "broker+tcp", + .tran_listener = &tcptran_listener_ops, + .tran_pipe = &tcptran_pipe_ops, + .tran_init = tcptran_init, + .tran_fini = tcptran_fini, +}; + +static nni_sp_tran tcp4_tran_mqtt = { + .tran_scheme = "broker+tcp4", + .tran_listener = &tcptran_listener_ops, + .tran_pipe = &tcptran_pipe_ops, + .tran_init = tcptran_init, + .tran_fini = tcptran_fini, +}; + +static nni_sp_tran tcp6_tran_mqtt = { + .tran_scheme = "broker+tcp6", + .tran_listener = &tcptran_listener_ops, + .tran_pipe = &tcptran_pipe_ops, + .tran_init = tcptran_init, + .tran_fini = tcptran_fini, +}; + +#ifndef NNG_ELIDE_DEPRECATED +int +nmq_mqtt_tcp_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_nmq_broker_tcp_register(void) +{ + nni_sp_tran_register(&tcp_tran_mqtt); + nni_sp_tran_register(&tcp4_tran_mqtt); + nni_sp_tran_register(&tcp6_tran_mqtt); +} diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c new file mode 100644 index 000000000..6574d13be --- /dev/null +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -0,0 +1,1502 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// Copyright 2019 Devolutions +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include +#include + +#include "core/nng_impl.h" +#include "mqtt/mqtt.h" + +// TCP transport. Platform specific TCP operations must be +// supplied as well. + +typedef struct mqtt_tcptran_pipe mqtt_tcptran_pipe; +typedef struct mqtt_tcptran_ep mqtt_tcptran_ep; + +#define NNI_NANO_MAX_HEADER_SIZE 5 + +// tcp_pipe is one end of a TCP connection. +struct mqtt_tcptran_pipe { + nng_stream * conn; + nni_pipe * npipe; + uint16_t peer; + uint16_t proto; + size_t rcvmax; + bool closed; + nni_list_node node; + mqtt_tcptran_ep *ep; + nni_atomic_flag reaped; + nni_reap_node reap; + uint8_t txlen[sizeof(uint64_t)]; + uint8_t rxlen[sizeof(uint64_t)]; // fixed header + size_t gottxhead; + size_t gotrxhead; + size_t wanttxhead; + size_t wantrxhead; + nni_list recvq; + nni_list sendq; + nni_aio * txaio; + nni_aio * rxaio; + nni_aio * rsaio; + nni_aio * qsaio; + nni_aio * rpaio; + nni_aio * negoaio; + nni_msg * rxmsg; + nni_msg * smsg; + nni_mtx mtx; +}; + +struct mqtt_tcptran_ep { + nni_mtx mtx; + uint16_t proto; + size_t rcvmax; + bool fini; + bool started; + bool closed; + nng_url * url; + const char * host; // for dialers + nng_sockaddr src; + int refcnt; // active pipes + nni_aio * useraio; + nni_aio * connaio; + nni_aio * timeaio; + nni_list busypipes; // busy pipes -- ones passed to socket + nni_list waitpipes; // pipes waiting to match to socket + nni_list negopipes; // pipes busy negotiating + nni_reap_node reap; + nng_stream_dialer * dialer; + nng_stream_listener *listener; + nni_dialer * ndialer; + void * connmsg; + void (*conncb)(void *, nng_msg *); + void *arg; + +#ifdef NNG_ENABLE_STATS + nni_stat_item st_rcv_max; +#endif +}; + +static void mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *); +static void mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *); +static void mqtt_tcptran_pipe_send_cb(void *); +static void mqtt_tcptran_pipe_recv_cb(void *); +static void mqtt_tcptran_pipe_nego_cb(void *); +static void mqtt_tcptran_ep_fini(void *); +static void mqtt_tcptran_pipe_fini(void *); +uint16_t nni_msg_get_pub_pid(nni_msg *m); + +static nni_reap_list tcptran_ep_reap_list = { + .rl_offset = offsetof(mqtt_tcptran_ep, reap), + .rl_func = mqtt_tcptran_ep_fini, +}; + +static nni_reap_list tcptran_pipe_reap_list = { + .rl_offset = offsetof(mqtt_tcptran_pipe, reap), + .rl_func = mqtt_tcptran_pipe_fini, +}; + +static void +mqtt_tcptran_init(void) +{ +} + +static void +mqtt_tcptran_fini(void) +{ +} + +uint16_t +nni_msg_get_pub_pid(nni_msg *m) +{ + uint16_t pid; + uint8_t *pos, len; + + pos = nni_msg_body(m); + NNI_GET16(pos, len); + NNI_GET16(pos + len + 2, pid); + return pid; +} + +static void +mqtt_tcptran_pipe_close(void *arg) +{ + mqtt_tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + p->closed = true; + nni_mtx_unlock(&p->mtx); + + nni_aio_close(p->rxaio); + nni_aio_close(p->rsaio); + nni_aio_close(p->qsaio); + nni_aio_close(p->txaio); + nni_aio_close(p->rpaio); + nni_aio_close(p->negoaio); + + nng_stream_close(p->conn); +} + +static void +mqtt_tcptran_pipe_stop(void *arg) +{ + mqtt_tcptran_pipe *p = arg; + + nni_aio_stop(p->rxaio); + nni_aio_stop(p->rsaio); + nni_aio_stop(p->qsaio); + nni_aio_stop(p->rpaio); + nni_aio_stop(p->txaio); + nni_aio_stop(p->negoaio); +} + +static int +mqtt_tcptran_pipe_init(void *arg, nni_pipe *npipe) +{ + mqtt_tcptran_pipe *p = arg; + p->npipe = npipe; + + return (0); +} + +static void +mqtt_tcptran_pipe_fini(void *arg) +{ + mqtt_tcptran_pipe *p = arg; + mqtt_tcptran_ep * ep; + + mqtt_tcptran_pipe_stop(p); + if ((ep = p->ep) != NULL) { + nni_mtx_lock(&ep->mtx); + nni_list_node_remove(&p->node); + ep->refcnt--; + if (ep->fini && (ep->refcnt == 0)) { + nni_reap(&tcptran_ep_reap_list, ep); + } + nni_mtx_unlock(&ep->mtx); + } + + nni_aio_free(p->rxaio); + nni_aio_free(p->txaio); + nni_aio_free(p->rsaio); + nni_aio_free(p->qsaio); + nni_aio_free(p->rpaio); + nni_aio_free(p->negoaio); + nng_stream_free(p->conn); + nni_msg_free(p->rxmsg); + nni_mtx_fini(&p->mtx); + NNI_FREE_STRUCT(p); +} + +static void +mqtt_tcptran_pipe_reap(mqtt_tcptran_pipe *p) +{ + if (!nni_atomic_flag_test_and_set(&p->reaped)) { + if (p->conn != NULL) { + nng_stream_close(p->conn); + } + nni_reap(&tcptran_pipe_reap_list, p); + } +} + +static int +mqtt_tcptran_pipe_alloc(mqtt_tcptran_pipe **pipep) +{ + mqtt_tcptran_pipe *p; + int rv; + + if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&p->mtx); + if (((rv = nni_aio_alloc(&p->txaio, mqtt_tcptran_pipe_send_cb, p)) != + 0) || + ((rv = nni_aio_alloc(&p->rxaio, mqtt_tcptran_pipe_recv_cb, p)) != + 0) || + ((rv = nni_aio_alloc(&p->rsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rpaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->negoaio, mqtt_tcptran_pipe_nego_cb, p)) != + 0)) { + mqtt_tcptran_pipe_fini(p); + return (rv); + } + nni_aio_list_init(&p->recvq); + nni_aio_list_init(&p->sendq); + nni_atomic_flag_reset(&p->reaped); + + *pipep = p; + + return (0); +} + +static void +mqtt_tcptran_ep_match(mqtt_tcptran_ep *ep) +{ + nni_aio * aio; + mqtt_tcptran_pipe *p; + + if (((aio = ep->useraio) == NULL) || + ((p = nni_list_first(&ep->waitpipes)) == NULL)) { + return; + } + nni_list_remove(&ep->waitpipes, p); + nni_list_append(&ep->busypipes, p); + ep->useraio = NULL; + p->rcvmax = ep->rcvmax; + nni_aio_set_output(aio, 0, p); + nni_aio_finish(aio, 0, 0); +} + +static void +mqtt_tcptran_pipe_nego_cb(void *arg) +{ + mqtt_tcptran_pipe *p = arg; + mqtt_tcptran_ep * ep = p->ep; + nni_aio * aio = p->negoaio; + nni_aio * uaio; + int rv; + uint8_t pos = 0; + int var_int; + nni_msg * rmsg = p->rxmsg; + + nni_mtx_lock(&ep->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + // We start transmitting before we receive. + if (p->gottxhead < p->wanttxhead) { + p->gottxhead += nni_aio_count(aio); + } else if (p->gotrxhead < p->wantrxhead) { + p->gotrxhead += nni_aio_count(aio); + } + + if (p->gottxhead < p->wanttxhead) { + nni_iov iov; + iov.iov_len = p->wanttxhead - p->gottxhead; + iov.iov_buf = &p->txlen[p->gottxhead]; + // send it down... + nni_aio_set_iov(aio, 1, &iov); + nng_stream_send(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + + // receving fixed header + if (p->gotrxhead == 0 || + (p->gotrxhead <= 5 && p->rxlen[p->gotrxhead - 1] > 0x7f && + p->rxmsg == NULL)) { + nni_iov iov; + iov.iov_buf = &p->rxlen[p->gotrxhead]; + if (p->gotrxhead == 0) { + iov.iov_len = p->wantrxhead - p->gotrxhead; + } else { + iov.iov_len = 1; + } + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + + // finish recevied fixed header + if (p->rxmsg == NULL) { + if ((p->rxlen[0] & 0x20) != 0x20) { + rv = NNG_EPROTO; + goto error; + } + + pos = 0; + if ((rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, + (uint32_t *) &var_int, &pos)) != 0) { + goto error; + } + + if ((rv = nni_mqtt_msg_alloc(&p->rxmsg, var_int)) != 0) { + rv = NNG_ENOMEM; + goto error; + } + + nni_msg_header_append(p->rxmsg, p->rxlen, pos + 1); + + p->wantrxhead = var_int + 1 + pos; + if ((rv = (p->wantrxhead <= 4) ? 0 : NNG_EPROTO) != 0) { + // TODO BUG here + goto error; + } + } + // remaining length + // TODO CPU Waste + if (p->gotrxhead < p->wantrxhead) { + nni_iov iov; + iov.iov_len = p->wantrxhead - p->gotrxhead; + iov.iov_buf = nni_msg_body(p->rxmsg); + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + if (p->gotrxhead >= p->wantrxhead) { + nni_mqtt_msg_decode(p->rxmsg); + p->rxmsg = NULL; + } + + // We are all ready now. We put this in the wait list, and + // then try to run the matcher. + nni_list_remove(&ep->negopipes, p); + nni_list_append(&ep->waitpipes, p); + + mqtt_tcptran_ep_match(ep); + nni_mtx_unlock(&ep->mtx); + + // Run user callback + if (ep->conncb != NULL) { + ep->conncb(ep->arg, rmsg); + } + + return; + +error: + nng_stream_close(p->conn); + + if (p->rxmsg != NULL) { + nni_msg_free(p->rxmsg); + p->rxmsg = NULL; + } + + if ((uaio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(uaio, rv); + } + nni_mtx_unlock(&ep->mtx); + mqtt_tcptran_pipe_reap(p); +} + +static void +mqtt_tcptran_pipe_send_cb(void *arg) +{ + mqtt_tcptran_pipe *p = arg; + int rv; + nni_aio * aio; + size_t n; + nni_msg * msg; + nni_aio * txaio = p->txaio; + + nni_mtx_lock(&p->mtx); + aio = nni_list_first(&p->sendq); + + if ((rv = nni_aio_result(txaio)) != 0) { + nni_pipe_bump_error(p->npipe, rv); + // Intentionally we do not queue up another transfer. + // There's an excellent chance that the pipe is no longer + // usable, with a partial transfer. + // The protocol should see this error, and close the + // pipe itself, we hope. + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + + n = nni_aio_count(txaio); + nni_aio_iov_advance(txaio, n); + if (nni_aio_iov_count(txaio) > 0) { + nng_stream_send(p->conn, txaio); + nni_mtx_unlock(&p->mtx); + return; + } + + nni_aio_list_remove(aio); + mqtt_tcptran_pipe_send_start(p); + + msg = nni_aio_get_msg(aio); + n = nni_msg_len(msg); + nni_pipe_bump_tx(p->npipe, n); + nni_mtx_unlock(&p->mtx); + + nni_aio_set_msg(aio, NULL); + nni_msg_free(msg); + nni_aio_finish_sync(aio, 0, n); +} + +static void +mqtt_tcptran_pipe_recv_cb(void *arg) +{ + nni_aio * aio; + nni_iov iov; + uint8_t type, pos, flags; + uint32_t len = 0, rv; + size_t n; + nni_msg * msg; + mqtt_tcptran_pipe *p = arg; + nni_aio * rxaio = p->rxaio; + + nni_mtx_lock(&p->mtx); + + aio = nni_list_first(&p->recvq); + + if ((rv = nni_aio_result(rxaio)) != 0) { + goto recv_error; + } + + n = nni_aio_count(rxaio); + p->gotrxhead += n; + + nni_aio_iov_advance(rxaio, n); + + rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, &len, &pos); + p->wantrxhead = len + 1 + pos; + if (p->gotrxhead <= 5 && p->rxlen[p->gotrxhead - 1] > 0x7f) { + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { + rv = NNG_EMSGSIZE; + goto recv_error; + } + // same packet, continue receving next byte of remaining length + iov.iov_buf = &p->rxlen[p->gotrxhead]; + iov.iov_len = 1; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + + // fixed header finished + if (NULL == p->rxmsg) { + // Make sure the message payload is not too big. If it is + // the caller will shut down the pipe. + // if ((len > p->rcvmax) && (p->rcvmax > 0)) { + // rv = NNG_EMSGSIZE; + // goto recv_error; + // } + + if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + goto recv_error; + } + + // Submit the rest of the data for a read -- seperate Fixed + // header with variable header and so on + // we want to read the entire message now. + if (len != 0) { + iov.iov_buf = nni_msg_body(p->rxmsg); + iov.iov_len = (size_t) len; + + nni_aio_set_iov(rxaio, 1, &iov); + // second recv action + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + } + + // We read a message completely. Let the user know the good news. use + // as application message callback of users + nni_aio_list_remove(aio); + nni_msg_header_append(p->rxmsg, p->rxlen, pos + 1); + msg = p->rxmsg; + p->rxmsg = NULL; + n = nni_msg_len(msg); + type = p->rxlen[0] & 0xf0; + flags = p->rxlen[0] & 0x0f; + // set the payload pointer of msg according to packet_type + if (type == 0x30) { + uint8_t qos_pac; + uint16_t pid; + + qos_pac = nni_msg_get_pub_qos(msg); + if (qos_pac > 0) { + nng_aio_wait(p->rsaio); + if (qos_pac == 1) { + p->txlen[0] = 0X40; + } else if (qos_pac == 2) { + p->txlen[0] = 0X50; + } + p->txlen[1] = 0x02; + pid = nni_msg_get_pub_pid(msg); + NNI_PUT16(p->txlen + 2, pid); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + printf("PUBRECV\n"); + nni_aio_set_iov(p->rsaio, 1, &iov); + nng_stream_send(p->conn, p->rsaio); + } + } else if (type == 0x50) { + nng_aio_wait(p->qsaio); + p->txlen[0] = 0X62; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(msg), 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->qsaio, 1, &iov); + nng_stream_send(p->conn, p->qsaio); + } else if (type == 0x60 && flags == 0x02) { + nng_aio_wait(p->rpaio); + p->txlen[0] = 0x70; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(msg), 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + printf("PUBCOMP\n"); + nni_aio_set_iov(p->rpaio, 1, &iov); + nng_stream_send(p->conn, p->rpaio); + } + + // keep connection & Schedule next receive + // nni_pipe_bump_rx(p->npipe, n); + mqtt_tcptran_pipe_recv_start(p); + + nni_aio_set_msg(aio, msg); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_sync(aio, 0, n); + return; + +recv_error: + nni_aio_list_remove(aio); + msg = p->rxmsg; + p->rxmsg = NULL; + nni_pipe_bump_error(p->npipe, rv); + nni_mtx_unlock(&p->mtx); + + nni_msg_free(msg); + nni_aio_finish_error(aio, rv); + printf("mqtt_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); + return; +notify: + // nni_pipe_bump_rx(p->npipe, n); + nni_aio_list_remove(aio); + mqtt_tcptran_pipe_recv_start(p); + nni_mtx_unlock(&p->mtx); + nni_aio_set_msg(aio, NULL); + nni_aio_finish(aio, 0, 0); + return; +} + +static void +mqtt_tcptran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) +{ + mqtt_tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (!nni_aio_list_active(aio)) { + nni_mtx_unlock(&p->mtx); + return; + } + // If this is being sent, then cancel the pending transfer. + // The callback on the txaio will cause the user aio to + // be canceled too. + if (nni_list_first(&p->sendq) == aio) { + nni_aio_abort(p->txaio, rv); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + + nni_aio_finish_error(aio, rv); +} + +static void +mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *p) +{ + nni_aio *aio; + nni_aio *txaio; + nni_msg *msg; + int niov; + nni_iov iov[3]; + // uint64_t len; + + if (p->closed) { + while ((aio = nni_list_first(&p->sendq)) != NULL) { + nni_list_remove(&p->sendq, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + return; + } + + if ((aio = nni_list_first(&p->sendq)) == NULL) { + return; + } + + // This runs to send the message. + msg = nni_aio_get_msg(aio); + + // len = nni_msg_len(msg) + nni_msg_header_len(msg); + // NNI_PUT64(p->txlen, len); + + txaio = p->txaio; + niov = 0; + + if (nni_msg_header_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_header(msg); + iov[niov].iov_len = nni_msg_header_len(msg); + niov++; + } + if (nni_msg_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_body(msg); + iov[niov].iov_len = nni_msg_len(msg); + niov++; + } + nni_aio_set_iov(txaio, niov, iov); + nng_stream_send(p->conn, txaio); +} + +static void +mqtt_tcptran_pipe_send(void *arg, nni_aio *aio) +{ + mqtt_tcptran_pipe *p = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, mqtt_tcptran_pipe_send_cancel, p)) != + 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + nni_list_append(&p->sendq, aio); + if (nni_list_first(&p->sendq) == aio) { + mqtt_tcptran_pipe_send_start(p); + } + nni_mtx_unlock(&p->mtx); +} + +static void +mqtt_tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) +{ + mqtt_tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (!nni_aio_list_active(aio)) { + nni_mtx_unlock(&p->mtx); + return; + } + // If receive in progress, then cancel the pending transfer. + // The callback on the rxaio will cause the user aio to + // be canceled too. + if (nni_list_first(&p->recvq) == aio) { + nni_aio_abort(p->rxaio, rv); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); +} + +static void +mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *p) +{ + nni_aio *rxaio; + nni_iov iov; + NNI_ASSERT(p->rxmsg == NULL); + + if (p->closed) { + nni_aio *aio; + while ((aio = nni_list_first(&p->recvq)) != NULL) { + nni_list_remove(&p->recvq, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + return; + } + if (nni_list_empty(&p->recvq)) { + return; + } + + // Schedule a read of the header. + rxaio = p->rxaio; + p->gotrxhead = 0; + p->wantrxhead = 2; + iov.iov_buf = p->rxlen; + iov.iov_len = 2; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); +} + +static void +mqtt_tcptran_pipe_recv(void *arg, nni_aio *aio) +{ + mqtt_tcptran_pipe *p = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, mqtt_tcptran_pipe_recv_cancel, p)) != + 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + + nni_list_append(&p->recvq, aio); + if (nni_list_first(&p->recvq) == aio) { + mqtt_tcptran_pipe_recv_start(p); + } + nni_mtx_unlock(&p->mtx); +} + +static uint16_t +mqtt_tcptran_pipe_peer(void *arg) +{ + mqtt_tcptran_pipe *p = arg; + + return (p->peer); +} + +static int +mqtt_tcptran_pipe_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + mqtt_tcptran_pipe *p = arg; + return (nni_stream_get(p->conn, name, buf, szp, t)); +} + +static void +mqtt_tcptran_pipe_start( + mqtt_tcptran_pipe *p, nng_stream *conn, mqtt_tcptran_ep *ep) +{ + nni_iov iov[2]; + nni_msg *connmsg; + int rv, niov = 0; + + ep->refcnt++; + + p->conn = conn; + p->ep = ep; + p->proto = ep->proto; + + rv = nni_dialer_getopt( + ep->ndialer, NNG_OPT_MQTT_CONNMSG, &connmsg, NULL, NNI_TYPE_POINTER); + if (!connmsg) { + nni_list_append(&ep->waitpipes, p); + mqtt_tcptran_ep_match(ep); + return; + } + if ((rv = nng_mqtt_msg_encode(connmsg)) != 0) { + nni_list_append(&ep->waitpipes, p); + mqtt_tcptran_ep_match(ep); + return; + } + + p->gotrxhead = 0; + p->gottxhead = 0; + // TODO TX length for MQTT 5 + p->wantrxhead = 2; + p->wanttxhead = nni_msg_header_len(connmsg) + nni_msg_len(connmsg); + p->rxmsg = NULL; + + if (nni_msg_header_len(connmsg) > 0) { + iov[niov].iov_buf = nni_msg_header(connmsg); + iov[niov].iov_len = nni_msg_header_len(connmsg); + niov++; + } + if (nni_msg_len(connmsg) > 0) { + iov[niov].iov_buf = nni_msg_body(connmsg); + iov[niov].iov_len = nni_msg_len(connmsg); + niov++; + } + nni_aio_set_iov(p->negoaio, niov, iov); + nni_list_append(&ep->negopipes, p); + + nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate + nng_stream_send(p->conn, p->negoaio); +} + +static void +mqtt_tcptran_ep_fini(void *arg) +{ + mqtt_tcptran_ep *ep = arg; + + nni_mtx_lock(&ep->mtx); + ep->fini = true; + if (ep->refcnt != 0) { + nni_mtx_unlock(&ep->mtx); + return; + } + nni_mtx_unlock(&ep->mtx); + nni_aio_stop(ep->timeaio); + nni_aio_stop(ep->connaio); + nng_stream_dialer_free(ep->dialer); + nng_stream_listener_free(ep->listener); + nni_aio_free(ep->timeaio); + nni_aio_free(ep->connaio); + + nni_mtx_fini(&ep->mtx); + NNI_FREE_STRUCT(ep); +} + +static void +mqtt_tcptran_ep_close(void *arg) +{ + mqtt_tcptran_ep * ep = arg; + mqtt_tcptran_pipe *p; + + nni_mtx_lock(&ep->mtx); + + ep->closed = true; + nni_aio_close(ep->timeaio); + if (ep->dialer != NULL) { + nng_stream_dialer_close(ep->dialer); + } + if (ep->listener != NULL) { + nng_stream_listener_close(ep->listener); + } + NNI_LIST_FOREACH (&ep->negopipes, p) { + mqtt_tcptran_pipe_close(p); + } + NNI_LIST_FOREACH (&ep->waitpipes, p) { + mqtt_tcptran_pipe_close(p); + } + NNI_LIST_FOREACH (&ep->busypipes, p) { + mqtt_tcptran_pipe_close(p); + } + if (ep->useraio != NULL) { + nni_aio_finish_error(ep->useraio, NNG_ECLOSED); + ep->useraio = NULL; + } + + nni_mtx_unlock(&ep->mtx); +} + +// This parses off the optional source address that this transport uses. +// The special handling of this URL format is quite honestly an historical +// mistake, which we would remove if we could. +static int +mqtt_tcptran_url_parse_source( + nng_url *url, nng_sockaddr *sa, const nng_url *surl) +{ + int af; + char * semi; + char * src; + size_t len; + int rv; + nni_aio *aio; + + // We modify the URL. This relies on the fact that the underlying + // transport does not free this, so we can just use references. + + url->u_scheme = surl->u_scheme; + url->u_port = surl->u_port; + url->u_hostname = surl->u_hostname; + + if ((semi = strchr(url->u_hostname, ';')) == NULL) { + memset(sa, 0, sizeof(*sa)); + return (0); + } + + len = (size_t)(semi - url->u_hostname); + url->u_hostname = semi + 1; + + if (strcmp(surl->u_scheme, "tcp") == 0) { + af = NNG_AF_UNSPEC; + } else if (strcmp(surl->u_scheme, "tcp4") == 0) { + af = NNG_AF_INET; + } else if (strcmp(surl->u_scheme, "tcp6") == 0) { + af = NNG_AF_INET6; + } else { + return (NNG_EADDRINVAL); + } + + if ((src = nni_alloc(len + 1)) == NULL) { + return (NNG_ENOMEM); + } + memcpy(src, surl->u_hostname, len); + src[len] = '\0'; + + if ((rv = nni_aio_alloc(&aio, NULL, NULL)) != 0) { + nni_free(src, len + 1); + return (rv); + } + + nni_resolv_ip(src, "0", af, true, sa, aio); + nni_aio_wait(aio); + rv = nni_aio_result(aio); + nni_aio_free(aio); + nni_free(src, len + 1); + return (rv); +} + +static void +mqtt_tcptran_timer_cb(void *arg) +{ + mqtt_tcptran_ep *ep = arg; + if (nni_aio_result(ep->timeaio) == 0) { + nng_stream_listener_accept(ep->listener, ep->connaio); + } +} + +static void +mqtt_tcptran_accept_cb(void *arg) +{ + mqtt_tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + mqtt_tcptran_pipe *p; + int rv; + nng_stream * conn; + + nni_mtx_lock(&ep->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + conn = nni_aio_get_output(aio, 0); + if ((rv = mqtt_tcptran_pipe_alloc(&p)) != 0) { + nng_stream_free(conn); + goto error; + } + + if (ep->closed) { + mqtt_tcptran_pipe_fini(p); + nng_stream_free(conn); + rv = NNG_ECLOSED; + goto error; + } + mqtt_tcptran_pipe_start(p, conn, ep); + nng_stream_listener_accept(ep->listener, ep->connaio); + nni_mtx_unlock(&ep->mtx); + return; + +error: + // When an error here occurs, let's send a notice up to the consumer. + // That way it can be reported properly. + if ((aio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + switch (rv) { + + case NNG_ENOMEM: + case NNG_ENOFILES: + nng_sleep_aio(10, ep->timeaio); + break; + + default: + if (!ep->closed) { + nng_stream_listener_accept(ep->listener, ep->connaio); + } + break; + } + nni_mtx_unlock(&ep->mtx); +} + +static void +mqtt_tcptran_dial_cb(void *arg) +{ + mqtt_tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + mqtt_tcptran_pipe *p; + int rv; + nng_stream * conn; + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + conn = nni_aio_get_output(aio, 0); + if ((rv = mqtt_tcptran_pipe_alloc(&p)) != 0) { + nng_stream_free(conn); + goto error; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + mqtt_tcptran_pipe_fini(p); + nng_stream_free(conn); + rv = NNG_ECLOSED; + nni_mtx_unlock(&ep->mtx); + goto error; + } else { + mqtt_tcptran_pipe_start(p, conn, ep); + } + nni_mtx_unlock(&ep->mtx); + return; + +error: + // Error connecting. We need to pass this straight back + // to the user. + nni_mtx_lock(&ep->mtx); + if ((aio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + +static int +mqtt_tcptran_ep_init(mqtt_tcptran_ep **epp, nng_url *url, nni_sock *sock) +{ + mqtt_tcptran_ep *ep; + + if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&ep->mtx); + NNI_LIST_INIT(&ep->busypipes, mqtt_tcptran_pipe, node); + NNI_LIST_INIT(&ep->waitpipes, mqtt_tcptran_pipe, node); + NNI_LIST_INIT(&ep->negopipes, mqtt_tcptran_pipe, node); + + ep->proto = nni_sock_proto_id(sock); + ep->url = url; + ep->conncb = NULL; + ep->arg = NULL; + +#ifdef NNG_ENABLE_STATS + static const nni_stat_info rcv_max_info = { + .si_name = "rcv_max", + .si_desc = "maximum receive size", + .si_type = NNG_STAT_LEVEL, + .si_unit = NNG_UNIT_BYTES, + .si_atomic = true, + }; + nni_stat_init(&ep->st_rcv_max, &rcv_max_info); +#endif + + *epp = ep; + return (0); +} + +static int +mqtt_tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) +{ + mqtt_tcptran_ep *ep; + int rv; + nng_sockaddr srcsa; + nni_sock * sock = nni_dialer_sock(ndialer); + nng_url myurl; + + // Check for invalid URL components. only one dialer is allowed + if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { + return (NNG_EADDRINVAL); + } + if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || + (url->u_query != NULL) || (strlen(url->u_hostname) == 0) || + (strlen(url->u_port) == 0)) { + return (NNG_EADDRINVAL); + } + + if ((rv = mqtt_tcptran_url_parse_source(&myurl, &srcsa, url)) != 0) { + return (rv); + } + + if ((rv = mqtt_tcptran_ep_init(&ep, url, sock)) != 0) { + return (rv); + } + ep->ndialer = ndialer; + + if ((rv != 0) || + ((rv = nni_aio_alloc(&ep->connaio, mqtt_tcptran_dial_cb, ep)) != + 0) || + ((rv = nng_stream_dialer_alloc_url(&ep->dialer, &myurl)) != 0)) { + mqtt_tcptran_ep_fini(ep); + return (rv); + } + if ((srcsa.s_family != NNG_AF_UNSPEC) && + ((rv = nni_stream_dialer_set(ep->dialer, NNG_OPT_LOCADDR, &srcsa, + sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) { + mqtt_tcptran_ep_fini(ep); + return (rv); + } +#ifdef NNG_ENABLE_STATS +#endif + *dp = ep; + return (0); +} + +static int +mqtt_tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) +{ + mqtt_tcptran_ep *ep; + int rv; + nni_sock * sock = nni_listener_sock(nlistener); + + // Check for invalid URL components. + if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { + return (NNG_EADDRINVAL); + } + if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || + (url->u_query != NULL)) { + return (NNG_EADDRINVAL); + } + + if ((rv = mqtt_tcptran_ep_init(&ep, url, sock)) != 0) { + return (rv); + } + + if (((rv = nni_aio_alloc(&ep->connaio, mqtt_tcptran_accept_cb, ep)) != + 0) || + ((rv = nni_aio_alloc(&ep->timeaio, mqtt_tcptran_timer_cb, ep)) != + 0) || + ((rv = nng_stream_listener_alloc_url(&ep->listener, url)) != 0)) { + mqtt_tcptran_ep_fini(ep); + return (rv); + } +#ifdef NNG_ENABLE_STATS + nni_listener_add_stat(nlistener, &ep->st_rcv_max); +#endif + + *lp = ep; + return (0); +} + +static void +mqtt_tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) +{ + mqtt_tcptran_ep *ep = arg; + nni_mtx_lock(&ep->mtx); + if (ep->useraio == aio) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + +static void +mqtt_tcptran_ep_connect(void *arg, nni_aio *aio) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + if (ep->useraio != NULL) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + if ((rv = nni_aio_schedule(aio, mqtt_tcptran_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, rv); + return; + } + ep->useraio = aio; + + nng_stream_dialer_dial(ep->dialer, ep->connaio); + nni_mtx_unlock(&ep->mtx); +} + +static int +mqtt_tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + mqtt_tcptran_ep *ep = arg; + char * s; + int rv; + int port = 0; + + if (ep->listener != NULL) { + (void) nng_stream_listener_get_int( + ep->listener, NNG_OPT_TCP_BOUND_PORT, &port); + } + + if ((rv = nni_url_asprintf_port(&s, ep->url, port)) == 0) { + rv = nni_copyout_str(s, v, szp, t); + nni_strfree(s); + } + return (rv); +} + +static int +mqtt_tcptran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + rv = nni_copyout_size(ep->rcvmax, v, szp, t); + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static int +mqtt_tcptran_ep_set_recvmaxsz( + void *arg, const void *v, size_t sz, nni_opt_type t) +{ + mqtt_tcptran_ep *ep = arg; + size_t val; + int rv; + if ((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) { + mqtt_tcptran_pipe *p; + nni_mtx_lock(&ep->mtx); + ep->rcvmax = val; + NNI_LIST_FOREACH (&ep->waitpipes, p) { + p->rcvmax = val; + } + NNI_LIST_FOREACH (&ep->negopipes, p) { + p->rcvmax = val; + } + NNI_LIST_FOREACH (&ep->busypipes, p) { + p->rcvmax = val; + } + nni_mtx_unlock(&ep->mtx); +#ifdef NNG_ENABLE_STATS + nni_stat_set_value(&ep->st_rcv_max, val); +#endif + } + return (rv); +} + +static int +mqtt_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + // nni_mtx_lock(&ep->mtx); + nni_copyout_ptr(ep->connmsg, v, szp, t); + // ep->connmsg = NULL; + // nni_mtx_unlock(&ep->mtx); + rv = 0; + + return (rv); +} + +static int +mqtt_tcptran_dialer_setcb(void *arg, void (*cb)(void *, nng_msg *), void *args) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + ep->conncb = cb; + ep->arg = args; + nni_mtx_unlock(&ep->mtx); + + rv = 0; + return (rv); +} + +static int +mqtt_tcptran_ep_set_connmsg( + void *arg, const void *v, size_t sz, nni_opt_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + nni_copyin_ptr(&ep->connmsg, v, sz, t); + nni_mtx_unlock(&ep->mtx); + rv = 0; + + return (rv); +} + +static int +mqtt_tcptran_ep_bind(void *arg) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + rv = nng_stream_listener_listen(ep->listener); + nni_mtx_unlock(&ep->mtx); + + return (rv); +} + +static void +mqtt_tcptran_ep_accept(void *arg, nni_aio *aio) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + if (ep->useraio != NULL) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + if ((rv = nni_aio_schedule(aio, mqtt_tcptran_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, rv); + return; + } + ep->useraio = aio; + if (!ep->started) { + ep->started = true; + nng_stream_listener_accept(ep->listener, ep->connaio); + } else { + mqtt_tcptran_ep_match(ep); + } + nni_mtx_unlock(&ep->mtx); +} + +static nni_sp_pipe_ops mqtt_tcptran_pipe_ops = { + .p_init = mqtt_tcptran_pipe_init, + .p_fini = mqtt_tcptran_pipe_fini, + .p_stop = mqtt_tcptran_pipe_stop, + .p_send = mqtt_tcptran_pipe_send, + .p_recv = mqtt_tcptran_pipe_recv, + .p_close = mqtt_tcptran_pipe_close, + .p_peer = mqtt_tcptran_pipe_peer, + .p_getopt = mqtt_tcptran_pipe_getopt, +}; + +static const nni_option mqtt_tcptran_ep_opts[] = { + { + .o_name = NNG_OPT_RECVMAXSZ, + .o_get = mqtt_tcptran_ep_get_recvmaxsz, + .o_set = mqtt_tcptran_ep_set_recvmaxsz, + }, + { + .o_name = NNG_OPT_URL, + .o_get = mqtt_tcptran_ep_get_url, + }, + { + .o_name = NNG_OPT_MQTT_CONNMSG, + .o_get = mqtt_tcptran_ep_get_connmsg, + .o_set = mqtt_tcptran_ep_set_connmsg, + }, + // terminate list + { + .o_name = NULL, + }, +}; + +static int +mqtt_tcptran_dialer_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_dialer_get(ep->dialer, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(mqtt_tcptran_ep_opts, name, ep, buf, szp, t); + } + return (rv); +} + +static int +mqtt_tcptran_dialer_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + // TODO get mqtt dialer's option + rv = nni_stream_dialer_set(ep->dialer, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(mqtt_tcptran_ep_opts, name, ep, buf, sz, t); + } + return (rv); +} + +static int +mqtt_tcptran_listener_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_listener_get(ep->listener, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(mqtt_tcptran_ep_opts, name, ep, buf, szp, t); + } + return (rv); +} + +static int +mqtt_tcptran_listener_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + mqtt_tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_listener_set(ep->listener, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(mqtt_tcptran_ep_opts, name, ep, buf, sz, t); + } + return (rv); +} + +static nni_sp_dialer_ops mqtt_tcptran_dialer_ops = { + .d_init = mqtt_tcptran_dialer_init, + .d_fini = mqtt_tcptran_ep_fini, + .d_connect = mqtt_tcptran_ep_connect, + .d_close = mqtt_tcptran_ep_close, + .d_getopt = mqtt_tcptran_dialer_getopt, + .d_setopt = mqtt_tcptran_dialer_setopt, + .d_connsetcb = mqtt_tcptran_dialer_setcb, +}; + +static nni_sp_listener_ops mqtt_tcptran_listener_ops = { + .l_init = mqtt_tcptran_listener_init, + .l_fini = mqtt_tcptran_ep_fini, + .l_bind = mqtt_tcptran_ep_bind, + .l_accept = mqtt_tcptran_ep_accept, + .l_close = mqtt_tcptran_ep_close, + .l_getopt = mqtt_tcptran_listener_getopt, + .l_setopt = mqtt_tcptran_listener_setopt, +}; + +static nni_sp_tran mqtt_tcp_tran = { + .tran_scheme = "mqtt-tcp", + .tran_dialer = &mqtt_tcptran_dialer_ops, + .tran_listener = &mqtt_tcptran_listener_ops, + .tran_pipe = &mqtt_tcptran_pipe_ops, + .tran_init = mqtt_tcptran_init, + .tran_fini = mqtt_tcptran_fini, +}; + +static nni_sp_tran mqtt_tcp4_tran = { + .tran_scheme = "mqtt-tcp4", + .tran_dialer = &mqtt_tcptran_dialer_ops, + .tran_listener = &mqtt_tcptran_listener_ops, + .tran_pipe = &mqtt_tcptran_pipe_ops, + .tran_init = mqtt_tcptran_init, + .tran_fini = mqtt_tcptran_fini, +}; + +static nni_sp_tran mqtt_tcp6_tran = { + .tran_scheme = "mqtt-tcp6", + .tran_dialer = &mqtt_tcptran_dialer_ops, + .tran_listener = &mqtt_tcptran_listener_ops, + .tran_pipe = &mqtt_tcptran_pipe_ops, + .tran_init = mqtt_tcptran_init, + .tran_fini = mqtt_tcptran_fini, +}; + +#ifndef NNG_ELIDE_DEPRECATED +int +nng_mqtt_tcp_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_mqtt_tcp_register(void) +{ + nni_sp_tran_register(&mqtt_tcp_tran); + nni_sp_tran_register(&mqtt_tcp4_tran); + nni_sp_tran_register(&mqtt_tcp6_tran); +} diff --git a/src/sp/transport/tcp/tcp.c b/src/sp/transport/tcp/tcp.c index d6bd5e8f7..624403a75 100644 --- a/src/sp/transport/tcp/tcp.c +++ b/src/sp/transport/tcp/tcp.c @@ -1,19 +1,18 @@ -// rewrite by Jaylin EMQ X for MQTT usage -// TODO Independent tcptran protocol +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// Copyright 2019 Devolutions +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// -#include -#include -#include -#include #include #include #include "core/nng_impl.h" -#include "core/sockimpl.h" -#include "nng/nng_debug.h" - -#include "nng/protocol/mqtt/mqtt.h" -#include "nng/protocol/mqtt/mqtt_parser.h" // TCP transport. Platform specific TCP operations must be // supplied as well. @@ -23,46 +22,40 @@ typedef struct tcptran_ep tcptran_ep; // tcp_pipe is one end of a TCP connection. struct tcptran_pipe { - nng_stream *conn; - nni_pipe * npipe; // for statitical - // uint16_t peer; //reserved for MQTT sdk version - // uint16_t proto; + nng_stream * conn; + nni_pipe * npipe; + uint16_t peer; + uint16_t proto; size_t rcvmax; + bool closed; + nni_list_node node; + tcptran_ep * ep; + nni_atomic_flag reaped; + nni_reap_node reap; + uint8_t txlen[sizeof(uint64_t)]; + uint8_t rxlen[sizeof(uint64_t)]; + size_t gottxhead; size_t gotrxhead; + size_t wanttxhead; size_t wantrxhead; - size_t qlength; // length of qos_buf - bool closed; - uint8_t txlen[NANO_MIN_PACKET_LEN]; - uint8_t rxlen[NNI_NANO_MAX_HEADER_SIZE]; - uint8_t * conn_buf; - uint8_t * qos_buf; + nni_list recvq; + nni_list sendq; nni_aio * txaio; nni_aio * rxaio; - nni_aio * qsaio; - nni_aio * rsaio; - nni_aio * rpaio; nni_aio * negoaio; - nni_msg * rxmsg, *cnmsg; + nni_msg * rxmsg; nni_mtx mtx; - conn_param * tcp_cparam; - nni_list recvq; - nni_list sendq; - nni_list_node node; - tcptran_ep * ep; - nni_atomic_flag reaped; - nni_reap_node reap; - // uint8_t sli_win[5]; //use aio multiple times instead of - // seperating 2 packets manually }; struct tcptran_ep { - nni_mtx mtx; - // uint16_t proto; + nni_mtx mtx; + uint16_t proto; size_t rcvmax; bool fini; bool started; bool closed; nng_url * url; + const char * host; // for dialers nng_sockaddr src; int refcnt; // active pipes nni_aio * useraio; @@ -72,7 +65,9 @@ struct tcptran_ep { nni_list waitpipes; // pipes waiting to match to socket nni_list negopipes; // pipes busy negotiating nni_reap_node reap; + nng_stream_dialer * dialer; nng_stream_listener *listener; + #ifdef NNG_ENABLE_STATS nni_stat_item st_rcv_max; #endif @@ -110,21 +105,16 @@ static void tcptran_pipe_close(void *arg) { tcptran_pipe *p = arg; - // nni_pipe * npipe = p->npipe; nni_mtx_lock(&p->mtx); p->closed = true; nni_mtx_unlock(&p->mtx); nni_aio_close(p->rxaio); - nni_aio_close(p->rpaio); nni_aio_close(p->txaio); - nni_aio_close(p->rsaio); - nni_aio_close(p->qsaio); nni_aio_close(p->negoaio); nng_stream_close(p->conn); - debug_syslog("tcptran_pipe_close\n"); } static void @@ -132,9 +122,6 @@ tcptran_pipe_stop(void *arg) { tcptran_pipe *p = arg; - nni_aio_stop(p->qsaio); - nni_aio_stop(p->rsaio); - nni_aio_stop(p->rpaio); nni_aio_stop(p->rxaio); nni_aio_stop(p->txaio); nni_aio_stop(p->negoaio); @@ -143,13 +130,9 @@ tcptran_pipe_stop(void *arg) static int tcptran_pipe_init(void *arg, nni_pipe *npipe) { - debug_msg("************tcptran_pipe_init************"); tcptran_pipe *p = arg; + p->npipe = npipe; - nni_pipe_set_conn_param(npipe, p->tcp_cparam); - p->npipe = npipe; - p->conn_buf = NULL; - p->qos_buf = nng_alloc(16 + NNI_NANO_MAX_PACKET_SIZE); return (0); } @@ -170,10 +153,6 @@ tcptran_pipe_fini(void *arg) nni_mtx_unlock(&ep->mtx); } - nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); - nni_aio_free(p->qsaio); - nni_aio_free(p->rpaio); - nni_aio_free(p->rsaio); nni_aio_free(p->rxaio); nni_aio_free(p->txaio); nni_aio_free(p->negoaio); @@ -205,9 +184,6 @@ tcptran_pipe_alloc(tcptran_pipe **pipep) } nni_mtx_init(&p->mtx); if (((rv = nni_aio_alloc(&p->txaio, tcptran_pipe_send_cb, p)) != 0) || - ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || - ((rv = nni_aio_alloc(&p->rpaio, NULL, p)) != 0) || - ((rv = nni_aio_alloc(&p->rsaio, NULL, p)) != 0) || ((rv = nni_aio_alloc(&p->rxaio, tcptran_pipe_recv_cb, p)) != 0) || ((rv = nni_aio_alloc(&p->negoaio, tcptran_pipe_nego_cb, p)) != 0)) { @@ -241,14 +217,6 @@ tcptran_ep_match(tcptran_ep *ep) nni_aio_finish(aio, 0, 0); } -/** - * MQTT protocal negotiate - * deal with CONNECT packet - * Fixed header to variable header - * receive multiple times for complete data packet then reply ACK in protocol - * layer iov_len limits the length readv reads - * TODO independent with nng SP - */ static void tcptran_pipe_nego_cb(void *arg) { @@ -256,93 +224,69 @@ tcptran_pipe_nego_cb(void *arg) tcptran_ep * ep = p->ep; nni_aio * aio = p->negoaio; nni_aio * uaio; - uint32_t len; - int rv, len_of_varint = 0; + int rv; - debug_msg("start tcptran_pipe_nego_cb max len %ld pipe_addr %p\n", - NANO_CONNECT_PACKET_LEN, p); nni_mtx_lock(&ep->mtx); if ((rv = nni_aio_result(aio)) != 0) { goto error; } - // calculate number of bytes received - if (p->gotrxhead < p->wantrxhead) { + // We start transmitting before we receive. + if (p->gottxhead < p->wanttxhead) { + p->gottxhead += nni_aio_count(aio); + } else if (p->gotrxhead < p->wantrxhead) { p->gotrxhead += nni_aio_count(aio); } - // recv fixed header - if (p->gotrxhead < NNI_NANO_MAX_HEADER_SIZE) { + if (p->gottxhead < p->wanttxhead) { nni_iov iov; - iov.iov_len = NNI_NANO_MAX_HEADER_SIZE - p->gotrxhead; - iov.iov_buf = &p->rxlen[p->gotrxhead]; + iov.iov_len = p->wanttxhead - p->gottxhead; + iov.iov_buf = &p->txlen[p->gottxhead]; + // send it down... nni_aio_set_iov(aio, 1, &iov); - nng_stream_recv(p->conn, aio); + nng_stream_send(p->conn, aio); nni_mtx_unlock(&ep->mtx); return; } - if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { - if (p->rxlen[0] != CMD_CONNECT) { - debug_msg("CMD TYPE %x", p->rxlen[0]); - rv = NNG_EPROTO; - goto error; - } - len = - get_var_integer(p->rxlen + 1, (uint32_t *) &len_of_varint); - p->wantrxhead = len + 1 + len_of_varint; - rv = (p->wantrxhead >= NANO_CONNECT_PACKET_LEN) ? 0 - : NNG_EPROTO; - if (rv != 0) { - goto error; - } - } - if (p->gotrxhead < p->wantrxhead) { nni_iov iov; iov.iov_len = p->wantrxhead - p->gotrxhead; - if (p->conn_buf == NULL) { - p->conn_buf = nng_alloc(p->wantrxhead); - memcpy(p->conn_buf, p->rxlen, p->gotrxhead); - } - iov.iov_buf = &p->conn_buf[p->gotrxhead]; + iov.iov_buf = &p->rxlen[p->gotrxhead]; nni_aio_set_iov(aio, 1, &iov); nng_stream_recv(p->conn, aio); nni_mtx_unlock(&ep->mtx); return; } + // We have both sent and received the headers. Let's check the + // receiver. + if ((p->rxlen[0] != 0) || (p->rxlen[1] != 'S') || + (p->rxlen[2] != 'P') || (p->rxlen[3] != 0) || (p->rxlen[6] != 0) || + (p->rxlen[7] != 0)) { + rv = NNG_EPROTO; + goto error; + } - // We have both sent and received the CONNECT headers. - // CONNECT packet serialization + NNI_GET16(&p->rxlen[4], p->peer); - if (p->gotrxhead >= p->wantrxhead) { - if (p->tcp_cparam == NULL) { - conn_param_alloc(&p->tcp_cparam); - } - if (conn_handler(p->conn_buf, p->tcp_cparam) == 0) { - nng_free(p->conn_buf, p->wantrxhead); - p->conn_buf = NULL; - // we don't need to alloc a new msg, just use pipe. - // We are all ready now. We put this in the wait list, - // and then try to run the matcher. - nni_list_remove(&ep->negopipes, p); - nni_list_append(&ep->waitpipes, p); - tcptran_ep_match(ep); - nni_mtx_unlock(&ep->mtx); - return; - } else { - rv = NNG_EPROTO; - nng_free(p->conn_buf, p->wantrxhead); - conn_param_free(p->tcp_cparam); - goto error; - } - } + // We are ready now. We put this in the wait list, and + // then try to run the matcher. + nni_list_remove(&ep->negopipes, p); + nni_list_append(&ep->waitpipes, p); + tcptran_ep_match(ep); nni_mtx_unlock(&ep->mtx); - debug_msg("^^^^^^^^^^end of tcptran_pipe_nego_cb^^^^^^^^^^\n"); + return; error: + // If the connection is closed, we need to pass back a different + // error code. This is necessary to avoid a problem where the + // closed status is confused with the accept file descriptor + // being closed. + if (rv == NNG_ECLOSED) { + rv = NNG_ECONNSHUT; + } nng_stream_close(p->conn); if ((uaio = ep->useraio) != NULL) { @@ -351,8 +295,6 @@ tcptran_pipe_nego_cb(void *arg) } nni_mtx_unlock(&ep->mtx); tcptran_pipe_reap(p); - debug_msg("connect nego error rv: %d!", rv); - return; } static void @@ -361,8 +303,6 @@ tcptran_pipe_send_cb(void *arg) tcptran_pipe *p = arg; int rv; nni_aio * aio; - uint8_t * header; - uint8_t flag, cmd; size_t n; nni_msg * msg; nni_aio * txaio = p->txaio; @@ -370,10 +310,13 @@ tcptran_pipe_send_cb(void *arg) nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->sendq); - debug_msg("############### tcptran_pipe_send_cb ################"); - if ((rv = nni_aio_result(txaio)) != 0) { nni_pipe_bump_error(p->npipe, rv); + // Intentionally we do not queue up another transfer. + // There's an excellent chance that the pipe is no longer + // usable, with a partial transfer. + // The protocol should see this error, and close the + // pipe itself, we hope. nni_aio_list_remove(aio); nni_mtx_unlock(&p->mtx); nni_aio_finish_error(aio, rv); @@ -382,221 +325,95 @@ tcptran_pipe_send_cb(void *arg) n = nni_aio_count(txaio); nni_aio_iov_advance(txaio, n); - debug_msg( - "tcp socket sent %ld bytes iov %ld", n, nni_aio_iov_count(txaio)); - if (nni_aio_iov_count(txaio) > 0) { nng_stream_send(p->conn, txaio); nni_mtx_unlock(&p->mtx); return; } + nni_aio_list_remove(aio); tcptran_pipe_send_start(p); msg = nni_aio_get_msg(aio); n = nni_msg_len(msg); - cmd = nni_msg_cmd_type(msg); - if (cmd == CMD_CONNACK) { - header = nni_msg_header(msg); - // parse result code TODO verify bug - flag = header[3]; - } - // nni_pipe_bump_tx(p->npipe, n); - // free qos buffer - if (p->qlength > 16 + NNI_NANO_MAX_PACKET_SIZE) { - nng_free(p->qos_buf, p->qlength); - p->qos_buf = nng_alloc(16 + NNI_NANO_MAX_PACKET_SIZE); - } + nni_pipe_bump_tx(p->npipe, n); nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, NULL); nni_msg_free(msg); - if (cmd == CMD_CONNACK && flag != 0x00) { - nni_aio_finish_error(aio, NNG_ECLOSED); - } else { - nni_aio_finish_sync(aio, 0, n); - } + nni_aio_finish_sync(aio, 0, n); } -/* - * deal with MQTT protocol - * insure read complete MQTT packet from socket - */ static void tcptran_pipe_recv_cb(void *arg) { + tcptran_pipe *p = arg; nni_aio * aio; - nni_iov iov; - uint8_t type; - uint32_t len = 0, rv, pos = 1; + int rv; size_t n; nni_msg * msg; - tcptran_pipe *p = arg; nni_aio * rxaio = p->rxaio; - conn_param * cparam; - debug_msg("tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); - aio = nni_list_first(&p->recvq); if ((rv = nni_aio_result(rxaio)) != 0) { - debug_msg("nni aio error!! %d\n", rv); goto recv_error; } n = nni_aio_count(rxaio); - p->gotrxhead += n; - nni_aio_iov_advance(rxaio, n); - // not receive enough bytes, deal with remaining length - len = get_var_integer(p->rxlen, &pos); - debug_msg("new %ld recevied %ld header %x %d pos: %d len : %d", n, - p->gotrxhead, p->rxlen[0], p->rxlen[1], pos, len); - debug_msg("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); - if (nni_aio_iov_count(rxaio) > 0) { - debug_msg("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], - strlen((char *) p->rxlen)); - nng_stream_recv(p->conn, rxaio); - nni_mtx_unlock(&p->mtx); - return; - } else if (p->gotrxhead <= NNI_NANO_MAX_HEADER_SIZE && - p->rxlen[p->gotrxhead - 1] > 0x7f) { - // length error - if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { - rv = NNG_EMSGSIZE; - goto recv_error; - } - // same packet, continue receving next byte of remaining length - iov.iov_buf = &p->rxlen[p->gotrxhead]; - iov.iov_len = 1; - nni_aio_set_iov(rxaio, 1, &iov); nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; - } else if (len == 0 && n == 2) { - if ((p->rxlen[0] & 0XFF) == CMD_PINGREQ) { - nng_aio_wait(p->qsaio); - p->txlen[0] = CMD_PINGRESP; - p->txlen[1] = 0x00; - iov.iov_len = 2; - iov.iov_buf = &p->txlen; - // send it down... - nni_aio_set_iov(p->qsaio, 1, &iov); - nng_stream_send(p->conn, p->qsaio); - goto notify; - } } - // finish fixed header - p->wantrxhead = len + p->gotrxhead; - cparam = p->tcp_cparam; - + // If we don't have a message yet, we were reading the TCP message + // header, which is just the length. This tells us the size of the + // message to allocate and how much more to expect. if (p->rxmsg == NULL) { - // We should have gotten a message header. len -> remaining - // length to define how many bytes left - debug_msg("pipe %p header got: %x %x %x %x %x, %ld!!\n", p, - p->rxlen[0], p->rxlen[1], p->rxlen[2], p->rxlen[3], - p->rxlen[4], p->wantrxhead); + uint64_t len; + // We should have gotten a message header. + NNI_GET64(p->rxlen, len); + // Make sure the message payload is not too big. If it is // the caller will shut down the pipe. if ((len > p->rcvmax) && (p->rcvmax > 0)) { - debug_msg("size error\n"); rv = NNG_EMSGSIZE; goto recv_error; } if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { - debug_syslog("mem error %ld\n", (size_t) len); goto recv_error; } - // Submit the rest of the data for a read -- seperate Fixed - // header with variable header and so on - // we want to read the entire message now. + // Submit the rest of the data for a read -- we want to + // read the entire message now. if (len != 0) { + nni_iov iov; iov.iov_buf = nni_msg_body(p->rxmsg); iov.iov_len = (size_t) len; nni_aio_set_iov(rxaio, 1, &iov); - // second recv action nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); return; } } - // We read a message completely. Let the user know the good news. use - // as application message callback of users + // We read a message completely. Let the user know the good news. nni_aio_list_remove(aio); msg = p->rxmsg; p->rxmsg = NULL; n = nni_msg_len(msg); - type = p->rxlen[0] & 0xf0; - - fixed_header_adaptor(p->rxlen, msg); - nni_msg_set_conn_param(msg, cparam); - // duplicated with fixed_header_adaptor - nni_msg_set_remaining_len(msg, len); - nni_msg_set_cmd_type(msg, type); - debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", - len, cparam, cparam->clientid.body, cparam->username.body, - cparam->pro_ver); - - // set the payload pointer of msg according to packet_type - debug_msg("The type of msg is %x", type); - if (type == CMD_PUBLISH) { - uint8_t qos_pac; - uint16_t pid; - - qos_pac = nni_msg_get_pub_qos(msg); - if (qos_pac > 0) { - nng_aio_wait(p->rsaio); - if (qos_pac == 1) { - p->txlen[0] = CMD_PUBACK; - } else if (qos_pac == 2) { - p->txlen[0] = CMD_PUBREC; - } - p->txlen[1] = 0x02; - pid = nni_msg_get_pub_pid(msg); - NNI_PUT16(p->txlen + 2, pid); - iov.iov_len = 4; - iov.iov_buf = &p->txlen; - // send it down... - nni_aio_set_iov(p->rsaio, 1, &iov); - nng_stream_send(p->conn, p->rsaio); - } - } else if (type == CMD_PUBREC) { - nng_aio_wait(p->rpaio); - p->txlen[0] = 0X62; - p->txlen[1] = 0x02; - memcpy(p->txlen + 2, nni_msg_body(msg), 2); - iov.iov_len = 4; - iov.iov_buf = &p->txlen; - // send it down... - nni_aio_set_iov(p->rpaio, 1, &iov); - nng_stream_send(p->conn, p->rpaio); - } else if (type == CMD_PUBREL) { - nng_aio_wait(p->qsaio); - p->txlen[0] = CMD_PUBCOMP; - p->txlen[1] = 0x02; - memcpy(p->txlen + 2, nni_msg_body(msg), 2); - iov.iov_len = 4; - iov.iov_buf = &p->txlen; - // send it down... - nni_aio_set_iov(p->qsaio, 1, &iov); - nng_stream_send(p->conn, p->qsaio); - } - // keep connection & Schedule next receive - // nni_pipe_bump_rx(p->npipe, n); + nni_pipe_bump_rx(p->npipe, n); tcptran_pipe_recv_start(p); nni_mtx_unlock(&p->mtx); nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, n); - debug_msg("end of tcptran_pipe_recv_cb: synch! %p\n", p); return; recv_error: @@ -604,20 +421,12 @@ tcptran_pipe_recv_cb(void *arg) msg = p->rxmsg; p->rxmsg = NULL; nni_pipe_bump_error(p->npipe, rv); + // Intentionally, we do not queue up another receive. + // The protocol should notice this error and close the pipe. nni_mtx_unlock(&p->mtx); nni_msg_free(msg); nni_aio_finish_error(aio, rv); - debug_msg("tcptran_pipe_recv_cb: recv error rv: %d\n", rv); - return; -notify: - // nni_pipe_bump_rx(p->npipe, n); - nni_aio_list_remove(aio); - tcptran_pipe_recv_start(p); - nni_mtx_unlock(&p->mtx); - nni_aio_set_msg(aio, NULL); - nni_aio_finish(aio, 0, 0); - return; } static void @@ -651,10 +460,9 @@ tcptran_pipe_send_start(tcptran_pipe *p) nni_aio *txaio; nni_msg *msg; int niov; - nni_iov iov[4]; - uint8_t qos; + nni_iov iov[3]; + uint64_t len; - debug_msg("########### tcptran_pipe_send_start ###########"); if (p->closed) { while ((aio = nni_list_first(&p->sendq)) != NULL) { nni_list_remove(&p->sendq, aio); @@ -664,137 +472,20 @@ tcptran_pipe_send_start(tcptran_pipe *p) } if ((aio = nni_list_first(&p->sendq)) == NULL) { - debug_msg("aio not functioning"); return; } // This runs to send the message. msg = nni_aio_get_msg(aio); - if (msg == NULL) { - // TODO error handler - nni_println("ERROR: sending NULL msg!"); - return; - } - qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); - //qos default to 0 if the msg is not PUBLISH - msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); - nni_aio_set_msg(aio, msg); - // never modify msg - if (nni_msg_header_len(msg) > 0 && - nni_msg_cmd_type(msg) == CMD_PUBLISH) { - uint8_t *body, *header, qos_pac; - uint8_t varheader[2], - fixheader[NNI_NANO_MAX_HEADER_SIZE] = { 0 }, - tmp[4] = { 0 }; - nni_pipe *pipe; - uint16_t pid; - size_t tlen, rlen; - - pipe = p->npipe; - body = nni_msg_body(msg); - header = nni_msg_header(msg); - p->qlength = 0; - NNI_GET16(body, tlen); - - qos_pac = nni_msg_get_pub_qos(msg); - if (qos_pac == 0) { - // save time & space for QoS 0 publish - goto send; - } - - debug_msg("qos_pac %d sub %d\n", qos_pac, qos); - memcpy(fixheader, header, nni_msg_header_len(msg)); - qos = qos_pac > qos ? qos : qos_pac; - - if (qos_pac > qos) { - if (qos == 1) { - // set qos to 1 - fixheader[0] = fixheader[0] & 0xF9; - fixheader[0] = fixheader[0] | 0x02; - rlen = nni_msg_header_len(msg) - 1; - } else { - // set qos to 0 - fixheader[0] = fixheader[0] & 0xF9; - uint32_t pos = 1; - rlen = put_var_integer( - tmp, get_var_integer(header, &pos) - 2); - memcpy(fixheader + 1, tmp, rlen); - } - } else { - rlen = nni_msg_header_len(msg) - 1; - } + len = nni_msg_len(msg) + nni_msg_header_len(msg); - txaio = p->txaio; - niov = 0; - // fixed header - p->qlength += rlen + 1; // strlen(fixheader) - // 1st part of variable header: topic - - p->qlength += tlen + 2; // get topic length - // packet id - if (qos > 0) { - // set pid - nni_msg *old; - pid = nni_aio_get_packetid(aio); - if (pid == 0) { - //first time send this msg - pid = nni_pipe_inc_packetid(pipe); - // store msg for qos retrying - debug_msg("* processing QoS pubmsg with pipe: %p *", p); - nni_msg_clone(msg); - if ((old = nni_id_get( - pipe->nano_qos_db, pid)) != NULL) { - // TODO packetid already exists. - // do we need to replace old with new one ? - // print warning to users - nni_println( - "ERROR: packet id duplicates in " - "nano_qos_db"); - old = NANO_NNI_LMQ_GET_MSG_POINTER(old); - nni_msg_free(old); - // nni_id_remove(&pipe->nano_qos_db, - // pid); - } - old = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); - nni_id_set(pipe->nano_qos_db, pid, old); - } - NNI_PUT16(varheader, pid); - p->qlength += 2; - } - if (p->qlength > 16 + NNI_NANO_MAX_PACKET_SIZE) { - nng_free(p->qos_buf, 16 + NNI_NANO_MAX_PACKET_SIZE); - p->qos_buf = nng_alloc(sizeof(uint8_t) * (p->qlength)); - } - memcpy(p->qos_buf, fixheader, rlen + 1); - memcpy(p->qos_buf + rlen + 1, body, tlen + 2); - if (qos > 0) { - memcpy(p->qos_buf + rlen + tlen + 3, varheader, 2); - } - iov[niov].iov_buf = p->qos_buf; - iov[niov].iov_len = p->qlength; - niov++; - - // payload - if (nni_msg_len(msg) > 0 && - qos_pac > - 0) { // determine if it needs to skip packet id field - iov[niov].iov_buf = body + 2 + tlen + 2; - iov[niov].iov_len = nni_msg_len(msg) - 4 - tlen; - niov++; - } else if (nni_msg_len(msg) > 0) { - iov[niov].iov_buf = body + 2 + tlen; - iov[niov].iov_len = nni_msg_len(msg) - 2 - tlen; - niov++; - } - - nni_aio_set_iov(txaio, niov, iov); - nng_stream_send(p->conn, txaio); - return; - } -send: - txaio = p->txaio; - niov = 0; + NNI_PUT64(p->txlen, len); + txaio = p->txaio; + niov = 0; + iov[0].iov_buf = p->txlen; + iov[0].iov_len = sizeof(p->txlen); + niov++; if (nni_msg_header_len(msg) > 0) { iov[niov].iov_buf = nni_msg_header(msg); iov[niov].iov_len = nni_msg_header_len(msg); @@ -815,7 +506,6 @@ tcptran_pipe_send(void *arg, nni_aio *aio) tcptran_pipe *p = arg; int rv; - debug_msg("####################tcptran_pipe_send###########"); if (nni_aio_begin(aio) != 0) { return; } @@ -827,7 +517,6 @@ tcptran_pipe_send(void *arg, nni_aio *aio) } nni_list_append(&p->sendq, aio); if (nni_list_first(&p->sendq) == aio) { - //send publish msg or send others tcptran_pipe_send_start(p); } nni_mtx_unlock(&p->mtx); @@ -856,6 +545,34 @@ tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) nni_aio_finish_error(aio, rv); } +static void +tcptran_pipe_recv_start(tcptran_pipe *p) +{ + nni_aio *rxaio; + nni_iov iov; + NNI_ASSERT(p->rxmsg == NULL); + + if (p->closed) { + nni_aio *aio; + while ((aio = nni_list_first(&p->recvq)) != NULL) { + nni_list_remove(&p->recvq, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + return; + } + if (nni_list_empty(&p->recvq)) { + return; + } + + // Schedule a read of the header. + rxaio = p->rxaio; + iov.iov_buf = p->rxlen; + iov.iov_len = sizeof(p->rxlen); + nni_aio_set_iov(rxaio, 1, &iov); + + nng_stream_recv(p->conn, rxaio); +} + static void tcptran_pipe_recv(void *arg, nni_aio *aio) { @@ -872,25 +589,20 @@ tcptran_pipe_recv(void *arg, nni_aio *aio) return; } - if (nni_aio_list_active(aio) == 0) { - nni_list_append(&p->recvq, aio); - } - + nni_list_append(&p->recvq, aio); if (nni_list_first(&p->recvq) == aio) { tcptran_pipe_recv_start(p); } nni_mtx_unlock(&p->mtx); } -/* static uint16_t tcptran_pipe_peer(void *arg) { - tcptran_pipe *p = arg; + tcptran_pipe *p = arg; - return (p->peer); + return (p->peer); } -*/ static int tcptran_pipe_getopt( @@ -900,63 +612,35 @@ tcptran_pipe_getopt( return (nni_stream_get(p->conn, name, buf, szp, t)); } -static void -tcptran_pipe_recv_start(tcptran_pipe *p) -{ - nni_aio *rxaio; - nni_iov iov; - debug_msg("*** tcptran_pipe_recv_start ***\n"); - NNI_ASSERT(p->rxmsg == NULL); - - if (p->closed) { - nni_aio *aio; - while ((aio = nni_list_first(&p->recvq)) != NULL) { - nni_list_remove(&p->recvq, aio); - nni_aio_finish_error(aio, NNG_ECLOSED); - } - return; - } - if (nni_list_empty(&p->recvq)) { - return; - } - - // Schedule a read of the fixed header. - rxaio = p->rxaio; - p->gotrxhead = 0; - p->wantrxhead = NANO_MIN_FIXED_HEADER_LEN; - iov.iov_buf = p->rxlen; - iov.iov_len = NANO_MIN_FIXED_HEADER_LEN; - nni_aio_set_iov(rxaio, 1, &iov); - nng_stream_recv(p->conn, rxaio); -} - -// DEAL WITH CONNECT when PIPE INIT static void tcptran_pipe_start(tcptran_pipe *p, nng_stream *conn, tcptran_ep *ep) { nni_iov iov; - // nni_tcp_conn *c; ep->refcnt++; - p->conn = conn; - p->ep = ep; - // p->proto = ep->proto; + p->conn = conn; + p->ep = ep; + p->proto = ep->proto; - debug_msg("tcptran_pipe_start!"); - p->gotrxhead = 0; - p->wantrxhead = NANO_CONNECT_PACKET_LEN; // packet type 1 + remaining - // length 1 + protocal name 7 - // + flag 1 + keepalive 2 = 12 - iov.iov_len = NNI_NANO_MAX_HEADER_SIZE; // dynamic - iov.iov_buf = p->rxlen; + p->txlen[0] = 0; + p->txlen[1] = 'S'; + p->txlen[2] = 'P'; + p->txlen[3] = 0; + NNI_PUT16(&p->txlen[4], p->proto); + NNI_PUT16(&p->txlen[6], 0); + p->gotrxhead = 0; + p->gottxhead = 0; + p->wantrxhead = 8; + p->wanttxhead = 8; + iov.iov_len = 8; + iov.iov_buf = &p->txlen[0]; nni_aio_set_iov(p->negoaio, 1, &iov); nni_list_append(&ep->negopipes, p); - nni_aio_set_timeout(p->negoaio, - 15 * 1000); // 15 sec timeout to negotiate abide with emqx - nng_stream_recv(p->conn, p->negoaio); + nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate + nng_stream_send(p->conn, p->negoaio); } static void @@ -973,6 +657,7 @@ tcptran_ep_fini(void *arg) nni_mtx_unlock(&ep->mtx); nni_aio_stop(ep->timeaio); nni_aio_stop(ep->connaio); + nng_stream_dialer_free(ep->dialer); nng_stream_listener_free(ep->listener); nni_aio_free(ep->timeaio); nni_aio_free(ep->connaio); @@ -989,9 +674,11 @@ tcptran_ep_close(void *arg) nni_mtx_lock(&ep->mtx); - debug_syslog("tcptran_ep_close"); ep->closed = true; nni_aio_close(ep->timeaio); + if (ep->dialer != NULL) { + nng_stream_dialer_close(ep->dialer); + } if (ep->listener != NULL) { nng_stream_listener_close(ep->listener); } @@ -1014,8 +701,8 @@ tcptran_ep_close(void *arg) // This parses off the optional source address that this transport uses. // The special handling of this URL format is quite honestly an historical -// mistake, which we would remove if we could.static int -int +// mistake, which we would remove if we could. +static int tcptran_url_parse_source(nng_url *url, nng_sockaddr *sa, const nng_url *surl) { int af; @@ -1078,7 +765,6 @@ tcptran_timer_cb(void *arg) } } -// TCP accpet trigger static void tcptran_accept_cb(void *arg) { @@ -1134,11 +820,52 @@ tcptran_accept_cb(void *arg) nni_mtx_unlock(&ep->mtx); } +static void +tcptran_dial_cb(void *arg) +{ + tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + tcptran_pipe *p; + int rv; + nng_stream * conn; + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + conn = nni_aio_get_output(aio, 0); + if ((rv = tcptran_pipe_alloc(&p)) != 0) { + nng_stream_free(conn); + goto error; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + tcptran_pipe_fini(p); + nng_stream_free(conn); + rv = NNG_ECLOSED; + nni_mtx_unlock(&ep->mtx); + goto error; + } else { + tcptran_pipe_start(p, conn, ep); + } + nni_mtx_unlock(&ep->mtx); + return; + +error: + // Error connecting. We need to pass this straight back + // to the user. + nni_mtx_lock(&ep->mtx); + if ((aio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + static int tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) { tcptran_ep *ep; - NNI_ARG_UNUSED(sock); if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); @@ -1148,8 +875,9 @@ tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) NNI_LIST_INIT(&ep->waitpipes, tcptran_pipe, node); NNI_LIST_INIT(&ep->negopipes, tcptran_pipe, node); - // ep->proto = nni_sock_proto_id(sock); - ep->url = url; + ep->proto = nni_sock_proto_id(sock); + ep->url = url; + #ifdef NNG_ENABLE_STATS static const nni_stat_info rcv_max_info = { .si_name = "rcv_max", @@ -1165,6 +893,53 @@ tcptran_ep_init(tcptran_ep **epp, nng_url *url, nni_sock *sock) return (0); } +static int +tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) +{ + tcptran_ep * ep; + int rv; + nng_sockaddr srcsa; + nni_sock * sock = nni_dialer_sock(ndialer); + nng_url myurl; + + // Check for invalid URL components. + if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { + return (NNG_EADDRINVAL); + } + if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || + (url->u_query != NULL) || (strlen(url->u_hostname) == 0) || + (strlen(url->u_port) == 0)) { + return (NNG_EADDRINVAL); + } + + if ((rv = tcptran_url_parse_source(&myurl, &srcsa, url)) != 0) { + return (rv); + } + + if ((rv = tcptran_ep_init(&ep, url, sock)) != 0) { + return (rv); + } + + if ((rv != 0) || + ((rv = nni_aio_alloc(&ep->connaio, tcptran_dial_cb, ep)) != 0) || + ((rv = nng_stream_dialer_alloc_url(&ep->dialer, &myurl)) != 0)) { + tcptran_ep_fini(ep); + return (rv); + } + if ((srcsa.s_family != NNG_AF_UNSPEC) && + ((rv = nni_stream_dialer_set(ep->dialer, NNG_OPT_LOCADDR, &srcsa, + sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) { + tcptran_ep_fini(ep); + return (rv); + } + +#ifdef NNG_ENABLE_STATS + nni_dialer_add_stat(ndialer, &ep->st_rcv_max); +#endif + *dp = ep; + return (0); +} + static int tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) { @@ -1191,10 +966,10 @@ tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) tcptran_ep_fini(ep); return (rv); } - #ifdef NNG_ENABLE_STATS nni_listener_add_stat(nlistener, &ep->st_rcv_max); #endif + *lp = ep; return (0); } @@ -1211,7 +986,37 @@ tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) nni_mtx_unlock(&ep->mtx); } -// TODO network interface bind +static void +tcptran_ep_connect(void *arg, nni_aio *aio) +{ + tcptran_ep *ep = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + if (ep->useraio != NULL) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + if ((rv = nni_aio_schedule(aio, tcptran_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, rv); + return; + } + ep->useraio = aio; + + nng_stream_dialer_dial(ep->dialer, ep->connaio); + nni_mtx_unlock(&ep->mtx); +} + static int tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) { @@ -1320,13 +1125,13 @@ tcptran_ep_accept(void *arg, nni_aio *aio) } static nni_sp_pipe_ops tcptran_pipe_ops = { - .p_init = tcptran_pipe_init, - .p_fini = tcptran_pipe_fini, - .p_stop = tcptran_pipe_stop, - .p_send = tcptran_pipe_send, - .p_recv = tcptran_pipe_recv, - .p_close = tcptran_pipe_close, - //.p_peer = tcptran_pipe_peer, + .p_init = tcptran_pipe_init, + .p_fini = tcptran_pipe_fini, + .p_stop = tcptran_pipe_stop, + .p_send = tcptran_pipe_send, + .p_recv = tcptran_pipe_recv, + .p_close = tcptran_pipe_close, + .p_peer = tcptran_pipe_peer, .p_getopt = tcptran_pipe_getopt, }; @@ -1346,6 +1151,34 @@ static const nni_option tcptran_ep_opts[] = { }, }; +static int +tcptran_dialer_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_dialer_get(ep->dialer, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(tcptran_ep_opts, name, ep, buf, szp, t); + } + return (rv); +} + +static int +tcptran_dialer_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_dialer_set(ep->dialer, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(tcptran_ep_opts, name, ep, buf, sz, t); + } + return (rv); +} + static int tcptran_listener_getopt( void *arg, const char *name, void *buf, size_t *szp, nni_type t) @@ -1374,6 +1207,15 @@ tcptran_listener_setopt( return (rv); } +static nni_sp_dialer_ops tcptran_dialer_ops = { + .d_init = tcptran_dialer_init, + .d_fini = tcptran_ep_fini, + .d_connect = tcptran_ep_connect, + .d_close = tcptran_ep_close, + .d_getopt = tcptran_dialer_getopt, + .d_setopt = tcptran_dialer_setopt, +}; + static nni_sp_listener_ops tcptran_listener_ops = { .l_init = tcptran_listener_init, .l_fini = tcptran_ep_fini, @@ -1384,24 +1226,27 @@ static nni_sp_listener_ops tcptran_listener_ops = { .l_setopt = tcptran_listener_setopt, }; -static nni_sp_tran tcp_tran_mqtt = { +static nni_sp_tran tcp_tran = { .tran_scheme = "tcp", + .tran_dialer = &tcptran_dialer_ops, .tran_listener = &tcptran_listener_ops, .tran_pipe = &tcptran_pipe_ops, .tran_init = tcptran_init, .tran_fini = tcptran_fini, }; -static nni_sp_tran tcp4_tran_mqtt = { +static nni_sp_tran tcp4_tran = { .tran_scheme = "tcp4", + .tran_dialer = &tcptran_dialer_ops, .tran_listener = &tcptran_listener_ops, .tran_pipe = &tcptran_pipe_ops, .tran_init = tcptran_init, .tran_fini = tcptran_fini, }; -static nni_sp_tran tcp6_tran_mqtt = { +static nni_sp_tran tcp6_tran = { .tran_scheme = "tcp6", + .tran_dialer = &tcptran_dialer_ops, .tran_listener = &tcptran_listener_ops, .tran_pipe = &tcptran_pipe_ops, .tran_init = tcptran_init, @@ -1419,7 +1264,7 @@ nng_tcp_register(void) void nni_sp_tcp_register(void) { - nni_sp_tran_register(&tcp_tran_mqtt); - nni_sp_tran_register(&tcp4_tran_mqtt); - nni_sp_tran_register(&tcp6_tran_mqtt); + nni_sp_tran_register(&tcp_tran); + nni_sp_tran_register(&tcp4_tran); + nni_sp_tran_register(&tcp6_tran); } From f9b8a0428932ea0a4434c0e5c6ebe1250ecc52aa Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Fri, 26 Nov 2021 19:55:52 +0800 Subject: [PATCH 153/180] * MDF [transport/websocket] move mqtt over websocket to independent dir & layer. --- include/nng/transport/ws/nmq_websocket.h | 35 + src/core/stream.c | 20 + src/sp/transport.c | 4 + src/sp/transport/ws/CMakeLists.txt | 4 +- src/sp/transport/ws/nmq_websocket.c | 1007 ++++++++++++++++++++++ src/supplemental/http/http_schemes.c | 18 +- 6 files changed, 1085 insertions(+), 3 deletions(-) create mode 100644 include/nng/transport/ws/nmq_websocket.h create mode 100644 src/sp/transport/ws/nmq_websocket.c diff --git a/include/nng/transport/ws/nmq_websocket.h b/include/nng/transport/ws/nmq_websocket.h new file mode 100644 index 000000000..0661fc431 --- /dev/null +++ b/include/nng/transport/ws/nmq_websocket.h @@ -0,0 +1,35 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef NNG_TRANSPORT_WS_WEBSOCKET_H +#define NNG_TRANSPORT_WS_WEBSOCKET_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// WebSocket transport. This is used for communication via WebSocket. + +// These aliases are for WSS naming consistency. +#define NNG_OPT_WSS_REQUEST_HEADERS NNG_OPT_WS_REQUEST_HEADERS +#define NNG_OPT_WSS_RESPONSE_HEADERS NNG_OPT_WS_RESPONSE_HEADERS + +#ifndef NNG_ELIDE_DEPRECATED +NNG_DECL int nng_nmq_ws_register(void); +NNG_DECL int nng_nmq_wss_register(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // NNG_TRANSPORT_WS_WEBSOCKET_H diff --git a/src/core/stream.c b/src/core/stream.c index 5779d37ee..b469b1108 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -109,6 +109,26 @@ static struct { .dialer_alloc = nni_ws_dialer_alloc, .listener_alloc = nni_ws_listener_alloc, }, + { + .scheme = "nmq+ws", + .dialer_alloc = nni_ws_dialer_alloc, + .listener_alloc = nni_ws_listener_alloc, + }, + { + .scheme = "nmq+ws4", + .dialer_alloc = nni_ws_dialer_alloc, + .listener_alloc = nni_ws_listener_alloc, + }, + { + .scheme = "nmq+ws6", + .dialer_alloc = nni_ws_dialer_alloc, + .listener_alloc = nni_ws_listener_alloc, + }, + { + .scheme = "nmq+wss", + .dialer_alloc = nni_ws_dialer_alloc, + .listener_alloc = nni_ws_listener_alloc, + }, { .scheme = NULL, }, diff --git a/src/sp/transport.c b/src/sp/transport.c index af819735c..6eb584632 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -68,9 +68,11 @@ extern void nni_sp_tls_register(void); #endif #ifdef NNG_TRANSPORT_WS extern void nni_sp_ws_register(void); +extern void nni_nmq_ws_register(void); #endif #ifdef NNG_TRANSPORT_WSS extern void nni_sp_wss_register(void); +extern void nni_nmq_wss_register(void); #endif #ifdef NNG_TRANSPORT_ZEROTIER extern void nni_sp_zt_register(void); @@ -99,9 +101,11 @@ nni_sp_tran_sys_init(void) #endif #ifdef NNG_TRANSPORT_WS nni_sp_ws_register(); + nni_nmq_ws_register(); #endif #ifdef NNG_TRANSPORT_WSS nni_sp_wss_register(); + nni_nmq_wss_register(); #endif #ifdef NNG_TRANSPORT_ZEROTIER nni_sp_zt_register(); diff --git a/src/sp/transport/ws/CMakeLists.txt b/src/sp/transport/ws/CMakeLists.txt index 6e409b43a..8e3b821e1 100644 --- a/src/sp/transport/ws/CMakeLists.txt +++ b/src/sp/transport/ws/CMakeLists.txt @@ -17,8 +17,8 @@ endif() nng_defines_if(NNG_TRANSPORT_WS NNG_TRANSPORT_WS) nng_defines_if(NNG_TRANSPORT_WSS NNG_TRANSPORT_WSS) -nng_sources_if(WS_ON websocket.c) -nng_headers_if(WS_ON nng/transport/ws/websocket.h) +nng_sources_if(WS_ON websocket.c nmq_websocket.c) +nng_headers_if(WS_ON nng/transport/ws/websocket.h nng/transport/ws/nmq_websocket.h) nng_test_if(WS_ON ws_test) diff --git a/src/sp/transport/ws/nmq_websocket.c b/src/sp/transport/ws/nmq_websocket.c new file mode 100644 index 000000000..801b78857 --- /dev/null +++ b/src/sp/transport/ws/nmq_websocket.c @@ -0,0 +1,1007 @@ +// +// Copyright 2020 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// Copyright 2019 Devolutions +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include +#include + +#include "core/nng_impl.h" +#include "core/sockimpl.h" +#include "supplemental/websocket/websocket.h" + +#include +#include + +#include "nng/nng_debug.h" +#include "nng/protocol/mqtt/mqtt.h" +#include "nng/protocol/mqtt/mqtt_parser.h" + +typedef struct ws_dialer ws_dialer; +typedef struct ws_listener ws_listener; +typedef struct ws_pipe ws_pipe; + +struct ws_dialer { + uint16_t peer; // remote protocol + nni_list aios; + nni_mtx mtx; + nni_aio * connaio; + nng_stream_dialer *dialer; + bool started; +}; + +struct ws_listener { + uint16_t peer; // remote protocol + nni_list aios; + nni_mtx mtx; + nni_aio * accaio; + nng_stream_listener *listener; + bool started; +}; + +struct ws_pipe { + nni_mtx mtx; + bool closed; + uint8_t txlen[NANO_MIN_PACKET_LEN]; + uint16_t peer; + size_t gotrxhead; + size_t wantrxhead; + nni_msg * tmp_msg; + nni_aio * user_txaio; + nni_aio * user_rxaio; + nni_aio * ep_aio; + nni_aio * txaio; + nni_aio * rxaio; + nni_aio * qsaio; + nni_pipe * npipe; + conn_param *ws_param; + nng_stream *ws; +}; + +static void +wstran_pipe_send_cb(void *arg) +{ + ws_pipe *p = arg; + nni_aio *taio; + nni_aio *uaio; + + nni_mtx_lock(&p->mtx); + taio = p->txaio; + uaio = p->user_txaio; + p->user_txaio = NULL; + + if (uaio != NULL) { + int rv; + if ((rv = nni_aio_result(taio)) != 0) { + nni_aio_finish_error(uaio, rv); + } else { + nni_aio_finish(uaio, 0, 0); + } + } + nni_mtx_unlock(&p->mtx); +} + +static void +wstran_pipe_recv_cb(void *arg) +{ + ws_pipe *p = arg; + uint32_t len = 0, rv, pos = 1; + uint8_t *ptr; + nni_msg *smsg = NULL, *msg = NULL; + nni_aio *raio = p->rxaio; + nni_aio *uaio = NULL; + + nni_mtx_lock(&p->mtx); + // only sets uaio at first time + if (p->user_rxaio != NULL) { + uaio = p->user_rxaio; + } + // process scatterd msgs + if ((rv = nni_aio_result(raio)) != 0) { + goto reset; + } + msg = nni_aio_get_msg(raio); + ptr = nni_msg_body(msg); + p->gotrxhead += nni_msg_len(msg); + debug_msg("#### wstran_pipe_recv_cb got %ld msg: %p %x %ld", + p->gotrxhead, ptr, *ptr, nni_msg_len(msg)); + // first we collect complete Fixheader + if (p->tmp_msg == NULL && p->gotrxhead > 0) { + if ((rv = nni_msg_alloc(&p->tmp_msg, 0)) != 0) { + debug_syslog("mem error %ld\n", (size_t) len); + goto reset; + } + } + // TODO use IOV instead of appending msg + nni_msg_append(p->tmp_msg, ptr, nni_msg_len(msg)); + ptr = nni_msg_body(p->tmp_msg); // packet might be sticky? + + if (p->wantrxhead == 0) { + if (p->gotrxhead == 1) { + goto recv; + } + len = get_var_integer(ptr, &pos); + if (*(ptr + pos - 1) >0x7f) { + // continue to next byte of remaining length + if (p->gotrxhead >= NNI_NANO_MAX_HEADER_SIZE) { + // length error + rv = NNG_EMSGSIZE; + goto reset; + } + } else { + // Fixed header finished + p->wantrxhead = len + pos; + nni_msg_set_cmd_type(p->tmp_msg, *ptr & 0xf0); + } + } + if (p->gotrxhead >= p->wantrxhead) { + goto done; + } + +recv: + nni_msg_free(msg); + nng_stream_recv(p->ws, raio); + nni_mtx_unlock(&p->mtx); + return; +done: + if (uaio == NULL) { + uaio = p->ep_aio; + } + if (uaio != NULL) { + p->gotrxhead = 0; + p->wantrxhead = 0; + nni_msg_free(msg); + if (nni_msg_cmd_type(p->tmp_msg) == CMD_CONNECT) { + // end of nego + if (p->ws_param == NULL) { + conn_param_alloc(&p->ws_param); + } + if (conn_handler( + nni_msg_body(p->tmp_msg), p->ws_param) != 0) { + goto reset; + } + nni_msg_free(p->tmp_msg); + p->tmp_msg = NULL; + nni_aio_set_msg(uaio, smsg); + nni_aio_set_output(uaio, 0, p); + // let pipe_start_cb in protocol layer deal with CONNACK + nni_aio_finish(uaio, 0, 0); + nni_mtx_unlock(&p->mtx); + return; + } else { + if (nni_msg_alloc(&smsg, 0) != 0) { + goto reset; + } + //parse fixed header + ws_fixed_header_adaptor(ptr, smsg); + nni_msg_free(p->tmp_msg); + p->tmp_msg = NULL; + nni_msg_set_conn_param(smsg, p->ws_param); + } + + uint8_t qos_pac; + uint16_t pid; + nni_msg *qos_msg; + if (nni_msg_cmd_type(smsg) == CMD_PUBLISH) { + qos_pac = nni_msg_get_pub_qos(smsg); + if (qos_pac > 0) { + nng_aio_wait(p->qsaio); + if (qos_pac == 1) { + p->txlen[0] = CMD_PUBACK; + } else if (qos_pac == 2) { + p->txlen[0] = CMD_PUBREC; + } + p->txlen[1] = 0x02; + pid = nni_msg_get_pub_pid(smsg); + NNI_PUT16(p->txlen + 2, pid); + nni_msg_alloc(&qos_msg, 0); + nni_msg_header_append(qos_msg, p->txlen, 4); + nni_aio_set_msg(p->qsaio, qos_msg); + nng_stream_send(p->ws, p->qsaio); + } + } else if (nni_msg_cmd_type(smsg) == CMD_PUBREC) { + nng_aio_wait(p->qsaio); + p->txlen[0] = 0X62; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(smsg), 2); + nni_msg_alloc(&qos_msg, 0); + nni_msg_header_append(qos_msg, p->txlen, 4); + nni_aio_set_msg(p->qsaio, qos_msg); + nng_stream_send(p->ws, p->qsaio); + } else if (nni_msg_cmd_type(smsg) == CMD_PUBREL) { + nng_aio_wait(p->qsaio); + p->txlen[0] = CMD_PUBCOMP; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(smsg), 2); + nni_msg_alloc(&qos_msg, 0); + nni_msg_header_append(qos_msg, p->txlen, 4); + nni_aio_set_msg(p->qsaio, qos_msg); + nng_stream_send(p->ws, p->qsaio); + } + + nni_aio_set_msg(uaio, smsg); + nni_aio_set_output(uaio, 0, p); + nni_aio_finish(uaio, 0, nni_msg_len(smsg)); + p->tmp_msg = NULL; + } else { + goto reset; + } + nni_mtx_unlock(&p->mtx); + return; +reset: + p->gotrxhead = 0; + p->wantrxhead = 0; + nng_stream_close(p->ws); + if (uaio != NULL) { + nni_aio_finish_error(uaio, rv); + } else if (p->ep_aio != NULL) { + nni_aio_finish_error(p->ep_aio, rv); + } + if (p->tmp_msg != NULL) { + smsg = p->tmp_msg; + nni_msg_free(smsg); + p->tmp_msg = NULL; + } + if (p->ws_param != NULL) { + conn_param_free(p->ws_param); + } + nni_mtx_unlock(&p->mtx); + return; +} + +static void +wstran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) +{ + ws_pipe *p = arg; + nni_mtx_lock(&p->mtx); + if (p->user_rxaio != aio) { + nni_mtx_unlock(&p->mtx); + return; + } + p->user_rxaio = NULL; + nni_aio_abort(p->rxaio, rv); + nni_aio_finish_error(aio, rv); + nni_mtx_unlock(&p->mtx); +} + +static void +wstran_pipe_recv(void *arg, nni_aio *aio) +{ + ws_pipe *p = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, wstran_pipe_recv_cancel, p)) != 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + p->user_rxaio = aio; + nng_stream_recv(p->ws, p->rxaio); + nni_mtx_unlock(&p->mtx); +} + +static void +wstran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) +{ + ws_pipe *p = arg; + nni_mtx_lock(&p->mtx); + if (p->user_txaio != aio) { + nni_mtx_unlock(&p->mtx); + return; + } + p->user_txaio = NULL; + nni_aio_abort(p->txaio, rv); + nni_aio_finish_error(aio, rv); + nni_mtx_unlock(&p->mtx); +} + +static inline void +wstran_mqtt_publish(){ + +} + +static void +wstran_pipe_send(void *arg, nni_aio *aio) +{ + ws_pipe *p = arg; + nni_msg *msg, *smsg; + uint8_t qos; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, wstran_pipe_send_cancel, p)) != 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + p->user_txaio = aio; + msg = nni_aio_get_msg(aio); + qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); + //qos default to 0 if the msg is not PUBLISH + msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); + if (nni_msg_cmd_type(msg) == CMD_PUBLISH) { + uint8_t *body, *header, qos_pac; + uint8_t varheader[2], + fixheader[NNI_NANO_MAX_HEADER_SIZE] = { 0 }, + tmp[4] = { 0 }; + nni_pipe *pipe; + uint16_t pid; + size_t tlen, rlen; + + qos_pac = nni_msg_get_pub_qos(msg); + qos = qos_pac > qos ? qos : qos_pac; + if (qos_pac == 0) { + // save time & space for QoS 0 publish + goto send; + } + + pipe = p->npipe; + body = nni_msg_body(msg); + header = nni_msg_header(msg); + NNI_GET16(body, tlen); + memcpy(fixheader, header, nni_msg_header_len(msg)); + if (qos_pac > qos) { + // need to modify the packets + if (qos == 1) { + // set qos to 1 (send qos 2 to 1) + fixheader[0] = fixheader[0] & 0xF9; + fixheader[0] = fixheader[0] | 0x02; + rlen = nni_msg_header_len(msg) - 1; + } else { + // set qos to 0 (send qos 2/1 to 0) + fixheader[0] = fixheader[0] & 0xF9; + uint32_t pos = 1; + rlen = put_var_integer( + tmp, get_var_integer(header, &pos) - 2); + memcpy(fixheader + 1, tmp, rlen); + } + } else { + // send msg as it is (qos_pac) + rlen = nni_msg_header_len(msg) - 1; + } + if (qos > 0) { + nni_msg *old; + pid = nni_aio_get_packetid(aio); + if (pid == 0) { + // first time send this msg + pid = nni_pipe_inc_packetid(pipe); + // store msg for qos retrying + debug_msg( + "* processing QoS pubmsg with pipe: %p *", + p); + nni_msg_clone(msg); + if ((old = nni_id_get( + pipe->nano_qos_db, pid)) != NULL) { + // TODO packetid already exists. + // do we need to replace old with new + // one ? print warning to users + nni_println( + "ERROR: packet id duplicates in " + "nano_qos_db"); + old = + NANO_NNI_LMQ_GET_MSG_POINTER(old); + nni_msg_free(old); + // nni_id_remove(&pipe->nano_qos_db, + // pid); + } + old = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); + nni_id_set(pipe->nano_qos_db, pid, old); + } + NNI_PUT16(varheader, pid); + } + nni_msg_alloc(&smsg, 0); + nni_msg_header_append(smsg, fixheader, rlen + 1); + nni_msg_append(smsg, body, tlen + 2); + if (qos > 0) { + //packetid + nni_msg_append(smsg, varheader, 2); + } + //payload + nni_msg_append(smsg, body + 4 + tlen, nni_msg_len(msg) - 4 - tlen); + //duplicated msg is gonna be freed by http. so we free old one here + nni_msg_free(msg); + msg = smsg; + } +// normal sending if it is not PUBLISH +send: + nni_aio_set_msg(aio, msg); + nni_aio_set_msg(p->txaio, msg); + nni_aio_set_msg(aio, NULL); + // verify connect + if (nni_msg_cmd_type(msg) == CMD_CONNACK) { + uint8_t *header = nni_msg_header(msg); + if (*(header+3) != 0x00) { + nni_pipe_close(p->npipe); + } + } + nng_stream_send(p->ws, p->txaio); + nni_mtx_unlock(&p->mtx); +} + +static void +wstran_pipe_stop(void *arg) +{ + ws_pipe *p = arg; + + nni_aio_stop(p->rxaio); + nni_aio_stop(p->txaio); + nni_aio_stop(p->qsaio); +} + +static int +wstran_pipe_init(void *arg, nni_pipe *pipe) +{ + debug_msg("************wstran_pipe_init************"); + ws_pipe *p = arg; + + nni_pipe_set_conn_param(pipe, p->ws_param); + p->npipe = pipe; + p->gotrxhead = 0; + p->wantrxhead = 0; + p->ep_aio = NULL; + return (0); +} + +static void +wstran_pipe_fini(void *arg) +{ + ws_pipe *p = arg; + + nni_aio_free(p->rxaio); + nni_aio_free(p->txaio); + nni_aio_free(p->qsaio); + + nng_stream_free(p->ws); + nni_msg_free(p->tmp_msg); + nni_mtx_fini(&p->mtx); + NNI_FREE_STRUCT(p); +} + +static void +wstran_pipe_close(void *arg) +{ + ws_pipe *p = arg; + + nni_aio_close(p->rxaio); + nni_aio_close(p->qsaio); + nni_aio_close(p->txaio); + + nni_mtx_lock(&p->mtx); + nng_stream_close(p->ws); + nni_mtx_unlock(&p->mtx); +} + +static int +wstran_pipe_alloc(ws_pipe **pipep, void *ws) +{ + ws_pipe *p; + int rv; + + if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&p->mtx); + + // Initialize AIOs. + if (((rv = nni_aio_alloc(&p->txaio, wstran_pipe_send_cb, p)) != 0) || + ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rxaio, wstran_pipe_recv_cb, p)) != 0)) { + wstran_pipe_fini(p); + return (rv); + } + p->ws = ws; + + *pipep = p; + return (0); +} + +static uint16_t +wstran_pipe_peer(void *arg) +{ + ws_pipe *p = arg; + + return (p->peer); +} + +static int +ws_listener_bind(void *arg) +{ + ws_listener *l = arg; + int rv; + + if ((rv = nng_stream_listener_listen(l->listener)) == 0) { + l->started = true; + } + return (rv); +} + +static void +ws_listener_cancel(nni_aio *aio, void *arg, int rv) +{ + ws_listener *l = arg; + + nni_mtx_lock(&l->mtx); + if (nni_aio_list_active(aio)) { + nni_aio_list_remove(aio); + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&l->mtx); +} + +static void +wstran_listener_accept(void *arg, nni_aio *aio) +{ + ws_listener *l = arg; + int rv; + + // We already bound, so we just need to look for an available + // pipe (created by the handler), and match it. + // Otherwise we stick the AIO in the accept list. + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&l->mtx); + if ((rv = nni_aio_schedule(aio, ws_listener_cancel, l)) != 0) { + nni_mtx_unlock(&l->mtx); + nni_aio_finish_error(aio, rv); + return; + } + nni_list_append(&l->aios, aio); + if (aio == nni_list_first(&l->aios)) { + nng_stream_listener_accept(l->listener, l->accaio); + } + nni_mtx_unlock(&l->mtx); +} + +static void +wstran_dialer_cancel(nni_aio *aio, void *arg, int rv) +{ + ws_dialer *d = arg; + + nni_mtx_lock(&d->mtx); + if (nni_aio_list_active(aio)) { + nni_aio_list_remove(aio); + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&d->mtx); +} + +static void +wstran_dialer_connect(void *arg, nni_aio *aio) +{ + ws_dialer *d = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + + nni_mtx_lock(&d->mtx); + if ((rv = nni_aio_schedule(aio, wstran_dialer_cancel, d)) != 0) { + nni_mtx_unlock(&d->mtx); + nni_aio_finish_error(aio, rv); + return; + } + NNI_ASSERT(nni_list_empty(&d->aios)); + d->started = true; + nni_list_append(&d->aios, aio); + nng_stream_dialer_dial(d->dialer, d->connaio); + nni_mtx_unlock(&d->mtx); +} + +static const nni_option ws_pipe_options[] = { + // terminate list + { + .o_name = NULL, + } +}; + +static int +wstran_pipe_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + ws_pipe *p = arg; + int rv; + + if ((rv = nni_stream_get(p->ws, name, buf, szp, t)) == NNG_ENOTSUP) { + rv = nni_getopt(ws_pipe_options, name, p, buf, szp, t); + } + return (rv); +} + +static nni_sp_pipe_ops ws_pipe_ops = { + .p_init = wstran_pipe_init, + .p_fini = wstran_pipe_fini, + .p_stop = wstran_pipe_stop, + .p_send = wstran_pipe_send, + .p_recv = wstran_pipe_recv, + .p_close = wstran_pipe_close, + .p_peer = wstran_pipe_peer, + .p_getopt = wstran_pipe_getopt, +}; + +static void +wstran_dialer_fini(void *arg) +{ + ws_dialer *d = arg; + + nni_aio_stop(d->connaio); + nng_stream_dialer_free(d->dialer); + nni_aio_free(d->connaio); + nni_mtx_fini(&d->mtx); + NNI_FREE_STRUCT(d); +} + +static void +wstran_listener_fini(void *arg) +{ + ws_listener *l = arg; + + nni_aio_stop(l->accaio); + nng_stream_listener_free(l->listener); + nni_aio_free(l->accaio); + nni_mtx_fini(&l->mtx); + NNI_FREE_STRUCT(l); +} + +static void +wstran_connect_cb(void *arg) +{ + ws_dialer * d = arg; + ws_pipe * p; + nni_aio * caio = d->connaio; + nni_aio * uaio; + int rv; + nng_stream *ws = NULL; + + nni_mtx_lock(&d->mtx); + if (nni_aio_result(caio) == 0) { + ws = nni_aio_get_output(caio, 0); + } + if ((uaio = nni_list_first(&d->aios)) == NULL) { + // The client stopped caring about this! + nng_stream_free(ws); + nni_mtx_unlock(&d->mtx); + return; + } + nni_aio_list_remove(uaio); + NNI_ASSERT(nni_list_empty(&d->aios)); + if ((rv = nni_aio_result(caio)) != 0) { + nni_aio_finish_error(uaio, rv); + } else if ((rv = wstran_pipe_alloc(&p, ws)) != 0) { + nng_stream_free(ws); + nni_aio_finish_error(uaio, rv); + } else { + p->peer = d->peer; + + nni_aio_set_output(uaio, 0, p); + nni_aio_finish(uaio, 0, 0); + } + nni_mtx_unlock(&d->mtx); +} + +static void +wstran_dialer_close(void *arg) +{ + ws_dialer *d = arg; + + nni_aio_close(d->connaio); + nng_stream_dialer_close(d->dialer); +} + +static void +wstran_listener_close(void *arg) +{ + ws_listener *l = arg; + + nni_aio_close(l->accaio); + nng_stream_listener_close(l->listener); +} + +static void +ws_pipe_start(ws_pipe *pipe, nng_stream *conn) +{ + NNI_ARG_UNUSED(conn); + ws_pipe *p = pipe; + debug_msg("ws_pipe_start!"); + + nng_stream_recv(p->ws, p->rxaio); +} + +static void +wstran_accept_cb(void *arg) +{ + ws_listener *l = arg; + nni_aio * aaio = l->accaio; + nni_aio * uaio; + int rv; + + nni_mtx_lock(&l->mtx); + uaio = nni_list_first(&l->aios); + if ((rv = nni_aio_result(aaio)) != 0) { + if (uaio != NULL) { + nni_aio_list_remove(uaio); + nni_aio_finish_error(uaio, rv); + } + } else { + nng_stream *ws = nni_aio_get_output(aaio, 0); + if (uaio != NULL) { + ws_pipe *p; + // Make a pipe + nni_aio_list_remove(uaio); + if ((rv = wstran_pipe_alloc(&p, ws)) != 0) { + nng_stream_close(ws); + nni_aio_finish_error(uaio, rv); + } else { + p->peer = l->peer; + ws_pipe_start(p, p->ws); + p->ep_aio = uaio; + } + } + } + + if (!nni_list_empty(&l->aios)) { + nng_stream_listener_accept(l->listener, aaio); + } + nni_mtx_unlock(&l->mtx); +} + +static int +wstran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) +{ + ws_dialer *d; + nni_sock * s = nni_dialer_sock(ndialer); + int rv; + char name[64]; + + if ((d = NNI_ALLOC_STRUCT(d)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&d->mtx); + + nni_aio_list_init(&d->aios); + + d->peer = nni_sock_peer_id(s); + + snprintf(name, sizeof(name), "mqtt"); + + if (((rv = nni_ws_dialer_alloc(&d->dialer, url)) != 0) || + ((rv = nni_aio_alloc(&d->connaio, wstran_connect_cb, d)) != 0) || + ((rv = nng_stream_dialer_set_bool( + d->dialer, NNI_OPT_WS_MSGMODE, true)) != 0) || + ((rv = nng_stream_dialer_set_string( + d->dialer, NNG_OPT_WS_PROTOCOL, name)) != 0)) { + wstran_dialer_fini(d); + return (rv); + } + + *dp = d; + return (0); +} + +// TODO proto name modify +static int +wstran_listener_init(void **lp, nng_url *url, nni_listener *listener) +{ + ws_listener *l; + int rv; + nni_sock * s = nni_listener_sock(listener); + char name[64]; + + if ((l = NNI_ALLOC_STRUCT(l)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&l->mtx); + + nni_aio_list_init(&l->aios); + + l->peer = nni_sock_peer_id(s); + + snprintf(name, sizeof(name), "mqtt"); + + if (((rv = nni_ws_listener_alloc(&l->listener, url)) != 0) || + ((rv = nni_aio_alloc(&l->accaio, wstran_accept_cb, l)) != 0) || + ((rv = nng_stream_listener_set_bool( + l->listener, NNI_OPT_WS_MSGMODE, true)) != 0) || + ((rv = nng_stream_listener_set_string( + l->listener, NNG_OPT_WS_PROTOCOL, name)) != 0)) { + wstran_listener_fini(l); + return (rv); + } + *lp = l; + return (0); +} + +static void +wstran_init(void) +{ +} + +static void +wstran_fini(void) +{ +} + +static const nni_option wstran_ep_opts[] = { + // terminate list + { + .o_name = NULL, + }, +}; + +static int +wstran_dialer_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + ws_dialer *d = arg; + int rv; + + rv = nni_stream_dialer_get(d->dialer, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(wstran_ep_opts, name, d, buf, szp, t); + } + return (rv); +} + +static int +wstran_dialer_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + ws_dialer *d = arg; + int rv; + + rv = nni_stream_dialer_set(d->dialer, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(wstran_ep_opts, name, d, buf, sz, t); + } + return (rv); +} + +static int +wstran_listener_get( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + ws_listener *l = arg; + int rv; + + rv = nni_stream_listener_get(l->listener, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(wstran_ep_opts, name, l, buf, szp, t); + } + return (rv); +} + +static int +wstran_listener_set( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + ws_listener *l = arg; + int rv; + + rv = nni_stream_listener_set(l->listener, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(wstran_ep_opts, name, l, buf, sz, t); + } + return (rv); +} + +static nni_sp_dialer_ops ws_dialer_ops = { + .d_init = wstran_dialer_init, + .d_fini = wstran_dialer_fini, + .d_connect = wstran_dialer_connect, + .d_close = wstran_dialer_close, + .d_setopt = wstran_dialer_setopt, + .d_getopt = wstran_dialer_getopt, +}; + +static nni_sp_listener_ops ws_listener_ops = { + .l_init = wstran_listener_init, + .l_fini = wstran_listener_fini, + .l_bind = ws_listener_bind, + .l_accept = wstran_listener_accept, + .l_close = wstran_listener_close, + .l_setopt = wstran_listener_set, + .l_getopt = wstran_listener_get, +}; + +static nni_sp_tran ws_tran = { + .tran_scheme = "nmq+ws", + .tran_dialer = &ws_dialer_ops, + .tran_listener = &ws_listener_ops, + .tran_pipe = &ws_pipe_ops, + .tran_init = wstran_init, + .tran_fini = wstran_fini, +}; + +static nni_sp_tran ws4_tran = { + .tran_scheme = "nmq+ws4", + .tran_dialer = &ws_dialer_ops, + .tran_listener = &ws_listener_ops, + .tran_pipe = &ws_pipe_ops, + .tran_init = wstran_init, + .tran_fini = wstran_fini, +}; + +static nni_sp_tran ws6_tran = { + .tran_scheme = "nmq+ws6", + .tran_dialer = &ws_dialer_ops, + .tran_listener = &ws_listener_ops, + .tran_pipe = &ws_pipe_ops, + .tran_init = wstran_init, + .tran_fini = wstran_fini, +}; + +#ifndef NNG_ELIDE_DEPRECATED +int +nng_nmq_ws_register(void) +{ + return (nni_init()); +} + +int +nng_nmq_wss_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_nmq_ws_register(void) +{ + nni_sp_tran_register(&ws_tran); + nni_sp_tran_register(&ws4_tran); + nni_sp_tran_register(&ws6_tran); +} + +#ifdef NNG_TRANSPORT_WSS + +static nni_sp_tran wss_tran = { + .tran_scheme = "nmq+wss", + .tran_dialer = &ws_dialer_ops, + .tran_listener = &ws_listener_ops, + .tran_pipe = &ws_pipe_ops, + .tran_init = wstran_init, + .tran_fini = wstran_fini, +}; + +static nni_sp_tran wss4_tran = { + .tran_scheme = "nmq+wss4", + .tran_dialer = &ws_dialer_ops, + .tran_listener = &ws_listener_ops, + .tran_pipe = &ws_pipe_ops, + .tran_init = wstran_init, + .tran_fini = wstran_fini, +}; + +static nni_sp_tran wss6_tran = { + .tran_scheme = "nmq+wss6", + .tran_dialer = &ws_dialer_ops, + .tran_listener = &ws_listener_ops, + .tran_pipe = &ws_pipe_ops, + .tran_init = wstran_init, + .tran_fini = wstran_fini, +}; + +void +nni_nmq_wss_register(void) +{ + nni_sp_tran_register(&wss_tran); + nni_sp_tran_register(&wss4_tran); + nni_sp_tran_register(&wss6_tran); +} + +#endif // NNG_TRANSPORT_WSS diff --git a/src/supplemental/http/http_schemes.c b/src/supplemental/http/http_schemes.c index df8b92081..7e984a042 100644 --- a/src/supplemental/http/http_schemes.c +++ b/src/supplemental/http/http_schemes.c @@ -27,6 +27,10 @@ static struct { .upper = "ws", .lower = "tcp", }, + { + .upper = "nmq+ws", + .lower = "tcp", + }, { .upper = "https", .lower = "tls+tcp", @@ -35,6 +39,10 @@ static struct { .upper = "wss", .lower = "tls+tcp", }, + { + .upper = "nmq+wss", + .lower = "tls+tcp", + }, { .upper = "http4", .lower = "tcp4", @@ -43,6 +51,10 @@ static struct { .upper = "ws4", .lower = "tcp4", }, + { + .upper = "nmq+ws4", + .lower = "tcp4", + }, { .upper = "http6", .lower = "tcp6", @@ -51,6 +63,10 @@ static struct { .upper = "ws6", .lower = "tcp6", }, + { + .upper = "nmq+ws6", + .lower = "tcp6", + }, { .upper = "https4", .lower = "tls+tcp4", @@ -82,4 +98,4 @@ nni_http_stream_scheme(const char *upper) } } return (NULL); -} \ No newline at end of file +} From be30b4e5a06860b378c5e48b13674027535b980e Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 29 Nov 2021 14:16:28 +0800 Subject: [PATCH 154/180] * MDF [transport/websocket] restore SP's websocket support. Add independent MQTT's websocket implementation --- src/sp/protocol/CMakeLists.txt | 1 - src/sp/transport/ws/websocket.c | 324 +++----------------------------- 2 files changed, 23 insertions(+), 302 deletions(-) diff --git a/src/sp/protocol/CMakeLists.txt b/src/sp/protocol/CMakeLists.txt index f74f459ab..a9d4c92fb 100644 --- a/src/sp/protocol/CMakeLists.txt +++ b/src/sp/protocol/CMakeLists.txt @@ -20,5 +20,4 @@ add_subdirectory(survey0) #NANOMQ MQTT library add_subdirectory(mqtt) -#more industrial protols comming soon! diff --git a/src/sp/transport/ws/websocket.c b/src/sp/transport/ws/websocket.c index d92264305..7cf9949f1 100644 --- a/src/sp/transport/ws/websocket.c +++ b/src/sp/transport/ws/websocket.c @@ -14,16 +14,11 @@ #include #include "core/nng_impl.h" -#include "core/sockimpl.h" #include "supplemental/websocket/websocket.h" #include #include -#include "nng/nng_debug.h" -#include "nng/protocol/mqtt/mqtt.h" -#include "nng/protocol/mqtt/mqtt_parser.h" - typedef struct ws_dialer ws_dialer; typedef struct ws_listener ws_listener; typedef struct ws_pipe ws_pipe; @@ -49,19 +44,11 @@ struct ws_listener { struct ws_pipe { nni_mtx mtx; bool closed; - uint8_t txlen[NANO_MIN_PACKET_LEN]; uint16_t peer; - size_t gotrxhead; - size_t wantrxhead; - nni_msg * tmp_msg; nni_aio * user_txaio; nni_aio * user_rxaio; - nni_aio * ep_aio; nni_aio * txaio; nni_aio * rxaio; - nni_aio * qsaio; - nni_pipe * npipe; - conn_param *ws_param; nng_stream *ws; }; @@ -91,169 +78,27 @@ wstran_pipe_send_cb(void *arg) static void wstran_pipe_recv_cb(void *arg) { - ws_pipe *p = arg; - uint32_t len = 0, rv, pos = 1; - uint8_t *ptr; - nni_msg *smsg = NULL, *msg = NULL; + ws_pipe *p = arg; nni_aio *raio = p->rxaio; - nni_aio *uaio = NULL; + nni_aio *uaio; + int rv; nni_mtx_lock(&p->mtx); - // only sets uaio at first time - if (p->user_rxaio != NULL) { - uaio = p->user_rxaio; - } - // process scatterd msgs + uaio = p->user_rxaio; + p->user_rxaio = NULL; if ((rv = nni_aio_result(raio)) != 0) { - goto reset; - } - msg = nni_aio_get_msg(raio); - ptr = nni_msg_body(msg); - p->gotrxhead += nni_msg_len(msg); - debug_msg("#### wstran_pipe_recv_cb got %ld msg: %p %x %ld", - p->gotrxhead, ptr, *ptr, nni_msg_len(msg)); - // first we collect complete Fixheader - if (p->tmp_msg == NULL && p->gotrxhead > 0) { - if ((rv = nni_msg_alloc(&p->tmp_msg, 0)) != 0) { - debug_syslog("mem error %ld\n", (size_t) len); - goto reset; - } - } - // TODO use IOV instead of appending msg - nni_msg_append(p->tmp_msg, ptr, nni_msg_len(msg)); - ptr = nni_msg_body(p->tmp_msg); // packet might be sticky? - - if (p->wantrxhead == 0) { - if (p->gotrxhead == 1) { - goto recv; - } - len = get_var_integer(ptr, &pos); - if (*(ptr + pos - 1) >0x7f) { - // continue to next byte of remaining length - if (p->gotrxhead >= NNI_NANO_MAX_HEADER_SIZE) { - // length error - rv = NNG_EMSGSIZE; - goto reset; - } - } else { - // Fixed header finished - p->wantrxhead = len + pos; - nni_msg_set_cmd_type(p->tmp_msg, *ptr & 0xf0); + if (uaio != NULL) { + nni_aio_finish_error(uaio, rv); } - } - if (p->gotrxhead >= p->wantrxhead) { - goto done; - } - -recv: - nni_msg_free(msg); - nng_stream_recv(p->ws, raio); - nni_mtx_unlock(&p->mtx); - return; -done: - if (uaio == NULL) { - uaio = p->ep_aio; - } - if (uaio != NULL) { - p->gotrxhead = 0; - p->wantrxhead = 0; - nni_msg_free(msg); - if (nni_msg_cmd_type(p->tmp_msg) == CMD_CONNECT) { - // end of nego - if (p->ws_param == NULL) { - conn_param_alloc(&p->ws_param); - } - if (conn_handler( - nni_msg_body(p->tmp_msg), p->ws_param) != 0) { - goto reset; - } - nni_msg_free(p->tmp_msg); - p->tmp_msg = NULL; - nni_aio_set_msg(uaio, smsg); - nni_aio_set_output(uaio, 0, p); - // let pipe_start_cb in protocol layer deal with CONNACK - nni_aio_finish(uaio, 0, 0); - nni_mtx_unlock(&p->mtx); - return; + } else { + nni_msg *msg = nni_aio_get_msg(raio); + if (uaio != NULL) { + nni_aio_finish_msg(uaio, msg); } else { - if (nni_msg_alloc(&smsg, 0) != 0) { - goto reset; - } - //parse fixed header - ws_fixed_header_adaptor(ptr, smsg); - nni_msg_free(p->tmp_msg); - p->tmp_msg = NULL; - nni_msg_set_conn_param(smsg, p->ws_param); - } - - uint8_t qos_pac; - uint16_t pid; - nni_msg *qos_msg; - if (nni_msg_cmd_type(smsg) == CMD_PUBLISH) { - qos_pac = nni_msg_get_pub_qos(smsg); - if (qos_pac > 0) { - nng_aio_wait(p->qsaio); - if (qos_pac == 1) { - p->txlen[0] = CMD_PUBACK; - } else if (qos_pac == 2) { - p->txlen[0] = CMD_PUBREC; - } - p->txlen[1] = 0x02; - pid = nni_msg_get_pub_pid(smsg); - NNI_PUT16(p->txlen + 2, pid); - nni_msg_alloc(&qos_msg, 0); - nni_msg_header_append(qos_msg, p->txlen, 4); - nni_aio_set_msg(p->qsaio, qos_msg); - nng_stream_send(p->ws, p->qsaio); - } - } else if (nni_msg_cmd_type(smsg) == CMD_PUBREC) { - nng_aio_wait(p->qsaio); - p->txlen[0] = 0X62; - p->txlen[1] = 0x02; - memcpy(p->txlen + 2, nni_msg_body(smsg), 2); - nni_msg_alloc(&qos_msg, 0); - nni_msg_header_append(qos_msg, p->txlen, 4); - nni_aio_set_msg(p->qsaio, qos_msg); - nng_stream_send(p->ws, p->qsaio); - } else if (nni_msg_cmd_type(smsg) == CMD_PUBREL) { - nng_aio_wait(p->qsaio); - p->txlen[0] = CMD_PUBCOMP; - p->txlen[1] = 0x02; - memcpy(p->txlen + 2, nni_msg_body(smsg), 2); - nni_msg_alloc(&qos_msg, 0); - nni_msg_header_append(qos_msg, p->txlen, 4); - nni_aio_set_msg(p->qsaio, qos_msg); - nng_stream_send(p->ws, p->qsaio); + nni_msg_free(msg); } - - nni_aio_set_msg(uaio, smsg); - nni_aio_set_output(uaio, 0, p); - nni_aio_finish(uaio, 0, nni_msg_len(smsg)); - p->tmp_msg = NULL; - } else { - goto reset; } nni_mtx_unlock(&p->mtx); - return; -reset: - p->gotrxhead = 0; - p->wantrxhead = 0; - nng_stream_close(p->ws); - if (uaio != NULL) { - nni_aio_finish_error(uaio, rv); - } else if (p->ep_aio != NULL) { - nni_aio_finish_error(p->ep_aio, rv); - } - if (p->tmp_msg != NULL) { - smsg = p->tmp_msg; - nni_msg_free(smsg); - p->tmp_msg = NULL; - } - if (p->ws_param != NULL) { - conn_param_free(p->ws_param); - } - nni_mtx_unlock(&p->mtx); - return; } static void @@ -306,17 +151,10 @@ wstran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) nni_mtx_unlock(&p->mtx); } -static inline void -wstran_mqtt_publish(){ - -} - static void wstran_pipe_send(void *arg, nni_aio *aio) { ws_pipe *p = arg; - nni_msg *msg, *smsg; - uint8_t qos; int rv; if (nni_aio_begin(aio) != 0) { @@ -329,105 +167,9 @@ wstran_pipe_send(void *arg, nni_aio *aio) return; } p->user_txaio = aio; - msg = nni_aio_get_msg(aio); - qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); - //qos default to 0 if the msg is not PUBLISH - msg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); - if (nni_msg_cmd_type(msg) == CMD_PUBLISH) { - uint8_t *body, *header, qos_pac; - uint8_t varheader[2], - fixheader[NNI_NANO_MAX_HEADER_SIZE] = { 0 }, - tmp[4] = { 0 }; - nni_pipe *pipe; - uint16_t pid; - size_t tlen, rlen; - - qos_pac = nni_msg_get_pub_qos(msg); - qos = qos_pac > qos ? qos : qos_pac; - if (qos_pac == 0) { - // save time & space for QoS 0 publish - goto send; - } - - pipe = p->npipe; - body = nni_msg_body(msg); - header = nni_msg_header(msg); - NNI_GET16(body, tlen); - memcpy(fixheader, header, nni_msg_header_len(msg)); - if (qos_pac > qos) { - // need to modify the packets - if (qos == 1) { - // set qos to 1 (send qos 2 to 1) - fixheader[0] = fixheader[0] & 0xF9; - fixheader[0] = fixheader[0] | 0x02; - rlen = nni_msg_header_len(msg) - 1; - } else { - // set qos to 0 (send qos 2/1 to 0) - fixheader[0] = fixheader[0] & 0xF9; - uint32_t pos = 1; - rlen = put_var_integer( - tmp, get_var_integer(header, &pos) - 2); - memcpy(fixheader + 1, tmp, rlen); - } - } else { - // send msg as it is (qos_pac) - rlen = nni_msg_header_len(msg) - 1; - } - if (qos > 0) { - nni_msg *old; - pid = nni_aio_get_packetid(aio); - if (pid == 0) { - // first time send this msg - pid = nni_pipe_inc_packetid(pipe); - // store msg for qos retrying - debug_msg( - "* processing QoS pubmsg with pipe: %p *", - p); - nni_msg_clone(msg); - if ((old = nni_id_get( - pipe->nano_qos_db, pid)) != NULL) { - // TODO packetid already exists. - // do we need to replace old with new - // one ? print warning to users - nni_println( - "ERROR: packet id duplicates in " - "nano_qos_db"); - old = - NANO_NNI_LMQ_GET_MSG_POINTER(old); - nni_msg_free(old); - // nni_id_remove(&pipe->nano_qos_db, - // pid); - } - old = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); - nni_id_set(pipe->nano_qos_db, pid, old); - } - NNI_PUT16(varheader, pid); - } - nni_msg_alloc(&smsg, 0); - nni_msg_header_append(smsg, fixheader, rlen + 1); - nni_msg_append(smsg, body, tlen + 2); - if (qos > 0) { - //packetid - nni_msg_append(smsg, varheader, 2); - } - //payload - nni_msg_append(smsg, body + 4 + tlen, nni_msg_len(msg) - 4 - tlen); - //duplicated msg is gonna be freed by http. so we free old one here - nni_msg_free(msg); - msg = smsg; - } -// normal sending if it is not PUBLISH -send: - nni_aio_set_msg(aio, msg); - nni_aio_set_msg(p->txaio, msg); + nni_aio_set_msg(p->txaio, nni_aio_get_msg(aio)); nni_aio_set_msg(aio, NULL); - // verify connect - if (nni_msg_cmd_type(msg) == CMD_CONNACK) { - uint8_t *header = nni_msg_header(msg); - if (*(header+3) != 0x00) { - nni_pipe_close(p->npipe); - } - } + nng_stream_send(p->ws, p->txaio); nni_mtx_unlock(&p->mtx); } @@ -439,20 +181,13 @@ wstran_pipe_stop(void *arg) nni_aio_stop(p->rxaio); nni_aio_stop(p->txaio); - nni_aio_stop(p->qsaio); } static int wstran_pipe_init(void *arg, nni_pipe *pipe) { - debug_msg("************wstran_pipe_init************"); - ws_pipe *p = arg; - - nni_pipe_set_conn_param(pipe, p->ws_param); - p->npipe = pipe; - p->gotrxhead = 0; - p->wantrxhead = 0; - p->ep_aio = NULL; + NNI_ARG_UNUSED(arg); + NNI_ARG_UNUSED(pipe); return (0); } @@ -463,10 +198,8 @@ wstran_pipe_fini(void *arg) nni_aio_free(p->rxaio); nni_aio_free(p->txaio); - nni_aio_free(p->qsaio); nng_stream_free(p->ws); - nni_msg_free(p->tmp_msg); nni_mtx_fini(&p->mtx); NNI_FREE_STRUCT(p); } @@ -477,7 +210,6 @@ wstran_pipe_close(void *arg) ws_pipe *p = arg; nni_aio_close(p->rxaio); - nni_aio_close(p->qsaio); nni_aio_close(p->txaio); nni_mtx_lock(&p->mtx); @@ -498,7 +230,6 @@ wstran_pipe_alloc(ws_pipe **pipep, void *ws) // Initialize AIOs. if (((rv = nni_aio_alloc(&p->txaio, wstran_pipe_send_cb, p)) != 0) || - ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || ((rv = nni_aio_alloc(&p->rxaio, wstran_pipe_recv_cb, p)) != 0)) { wstran_pipe_fini(p); return (rv); @@ -712,16 +443,6 @@ wstran_listener_close(void *arg) nng_stream_listener_close(l->listener); } -static void -ws_pipe_start(ws_pipe *pipe, nng_stream *conn) -{ - NNI_ARG_UNUSED(conn); - ws_pipe *p = pipe; - debug_msg("ws_pipe_start!"); - - nng_stream_recv(p->ws, p->rxaio); -} - static void wstran_accept_cb(void *arg) { @@ -748,12 +469,12 @@ wstran_accept_cb(void *arg) nni_aio_finish_error(uaio, rv); } else { p->peer = l->peer; - ws_pipe_start(p, p->ws); - p->ep_aio = uaio; + + nni_aio_set_output(uaio, 0, p); + nni_aio_finish(uaio, 0, 0); } } } - if (!nni_list_empty(&l->aios)) { nng_stream_listener_accept(l->listener, aaio); } @@ -777,7 +498,8 @@ wstran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) d->peer = nni_sock_peer_id(s); - snprintf(name, sizeof(name), "mqtt"); + snprintf( + name, sizeof(name), "%s.sp.nanomsg.org", nni_sock_peer_name(s)); if (((rv = nni_ws_dialer_alloc(&d->dialer, url)) != 0) || ((rv = nni_aio_alloc(&d->connaio, wstran_connect_cb, d)) != 0) || @@ -793,7 +515,6 @@ wstran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) return (0); } -// TODO proto name modify static int wstran_listener_init(void **lp, nng_url *url, nni_listener *listener) { @@ -811,7 +532,8 @@ wstran_listener_init(void **lp, nng_url *url, nni_listener *listener) l->peer = nni_sock_peer_id(s); - snprintf(name, sizeof(name), "mqtt"); + snprintf( + name, sizeof(name), "%s.sp.nanomsg.org", nni_sock_proto_name(s)); if (((rv = nni_ws_listener_alloc(&l->listener, url)) != 0) || ((rv = nni_aio_alloc(&l->accaio, wstran_accept_cb, l)) != 0) || From 4b9867fb2dd39824be52860e90bdc94e5d37b905 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Mon, 11 Oct 2021 08:51:42 -0700 Subject: [PATCH 155/180] Remove unused eq_len member. --- src/core/aio.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/core/aio.c b/src/core/aio.c index bc4816d6b..2f96f89f3 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -16,7 +16,6 @@ struct nni_aio_expire_q { nni_mtx eq_mtx; nni_cv eq_cv; nni_list eq_list; - uint32_t eq_len; nni_thr eq_thr; nni_time eq_next; // next expiration bool eq_exit; @@ -39,8 +38,8 @@ static int nni_aio_expire_q_cnt; // free to examine the aio for list membership, etc. The provider must // not call finish more than once though. // -// We use an array of expiration queues, each with it's own lock and -// condition variable, and expiration thread. By default this is one +// We use an array of expiration queues, each with its own lock and +// condition variable, and expiration thread. By default, this is one // per CPU core present -- the goal being to reduce overall pressure // caused by a single lock. The number of queues (and threads) can // be tuned using the NNG_EXPIRE_THREADS tunable. @@ -90,8 +89,8 @@ static int nni_aio_expire_q_cnt; #define aio_safe_lock(l) nni_mtx_lock(l) #define aio_safe_unlock(l) nni_mtx_unlock(l) #else -#define aio_safe_lock(l) -#define aio_safe_unlock(l) +#define aio_safe_lock(l) ((void) 1) +#define aio_safe_unlock(l) ((void) 1) #endif static nni_reap_list aio_reap_list = { @@ -333,7 +332,7 @@ nni_aio_begin(nni_aio *aio) //NNI_ASSERT(aio->a_cancel_fn == NULL); NNI_ASSERT(!nni_list_node_active(&aio->a_expire_node)); - // Some initialization can be done outside of the lock, because + // Some initialization can be done outside the lock, because // we must have exclusive access to the aio. for (unsigned i = 0; i < NNI_NUM_ELEMENTS(aio->a_outputs); i++) { aio->a_outputs[i] = NULL; @@ -556,8 +555,8 @@ nni_aio_expire_loop(void *arg) int rv; nni_time next; - next = q->eq_next; - now = nni_clock(); + next = q->eq_next; + now = nni_clock(); // Each time we wake up, we scan the entire list of elements. // We scan forward, moving up to NNI_EXPIRE_Q_SIZE elements @@ -576,7 +575,7 @@ nni_aio_expire_loop(void *arg) continue; } q->eq_next = NNI_TIME_NEVER; - exp_idx = 0; + exp_idx = 0; while (aio != NULL) { if ((aio->a_expire < now) && (exp_idx < NNI_EXPIRE_BATCH)) { @@ -601,7 +600,7 @@ nni_aio_expire_loop(void *arg) for (uint32_t i = 0; i < exp_idx; i++) { aio = expires[i]; - rv = aio->a_expire_ok ? 0 : NNG_ETIMEDOUT; + rv = aio->a_expire_ok ? 0 : NNG_ETIMEDOUT; nni_aio_cancel_fn cancel_fn = aio->a_cancel_fn; void *cancel_arg = aio->a_cancel_arg; From 6d93083caf7d659f0c1e546038a7c1c8b8d3f034 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 16 Oct 2021 23:27:35 -0700 Subject: [PATCH 156/180] fixes #1518 Disconnect during negotiation breaks listener --- src/sp/transport/ipc/ipc.c | 21 +++++++++++++-------- src/sp/transport/tls/tls.c | 13 ++++++++++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/sp/transport/ipc/ipc.c b/src/sp/transport/ipc/ipc.c index 8ed4ac942..df27ad238 100644 --- a/src/sp/transport/ipc/ipc.c +++ b/src/sp/transport/ipc/ipc.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // Copyright 2019 Devolutions // @@ -10,7 +10,6 @@ // #include -#include #include "core/nng_impl.h" @@ -251,8 +250,8 @@ ipc_pipe_neg_cb(void *arg) nni_mtx_unlock(&p->ep->mtx); return; } - // We have both sent and received the headers. Lets check the - // receive side header. + // We have both sent and received the headers. Let's check the + // receiver. if ((p->rx_head[0] != 0) || (p->rx_head[1] != 'S') || (p->rx_head[2] != 'P') || (p->rx_head[3] != 0) || (p->rx_head[6] != 0) || (p->rx_head[7] != 0)) { @@ -262,7 +261,7 @@ ipc_pipe_neg_cb(void *arg) NNI_GET16(&p->rx_head[4], p->peer); - // We are all ready now. We put this in the wait list, and + // We are ready now. We put this in the wait list, and // then try to run the matcher. nni_list_remove(&ep->neg_pipes, p); nni_list_append(&ep->wait_pipes, p); @@ -272,7 +271,13 @@ ipc_pipe_neg_cb(void *arg) return; error: - + // If the connection is closed, we need to pass back a different + // error code. This is necessary to avoid a problem where the + // closed status is confused with the accept file descriptor + // being closed. + if (rv == NNG_ECLOSED) { + rv = NNG_ECONNSHUT; + } nng_stream_close(p->conn); // If we are waiting to negotiate on a client side, then a failure // here has to be passed to the user app. @@ -347,7 +352,7 @@ ipc_pipe_recv_cb(void *arg) if ((rv = nni_aio_result(rx_aio)) != 0) { // Error on receive. This has to cause an error back - // to the user. Also, if we had allocated an rx_msg, lets + // to the user. Also, if we had an allocated rx_msg, lets // toss it. goto error; } @@ -406,7 +411,7 @@ ipc_pipe_recv_cb(void *arg) } } - // Otherwise we got a message read completely. Let the user know the + // Otherwise, we got a message read completely. Let the user know the // good news. aio = nni_list_first(&p->recv_q); diff --git a/src/sp/transport/tls/tls.c b/src/sp/transport/tls/tls.c index 75858839f..4db9170d1 100644 --- a/src/sp/transport/tls/tls.c +++ b/src/sp/transport/tls/tls.c @@ -258,8 +258,8 @@ tlstran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); return; } - // We have both sent and received the headers. Lets check the - // receive side header. + // We have both sent and received the headers. Let's check the + // receiver. if ((p->rxlen[0] != 0) || (p->rxlen[1] != 'S') || (p->rxlen[2] != 'P') || (p->rxlen[3] != 0) || (p->rxlen[6] != 0) || (p->rxlen[7] != 0)) { @@ -269,7 +269,7 @@ tlstran_pipe_nego_cb(void *arg) NNI_GET16(&p->rxlen[4], p->peer); - // We are all ready now. We put this in the wait list, and + // We are ready now. We put this in the wait list, and // then try to run the matcher. nni_list_remove(&ep->negopipes, p); nni_list_append(&ep->waitpipes, p); @@ -280,6 +280,13 @@ tlstran_pipe_nego_cb(void *arg) return; error: + // If the connection is closed, we need to pass back a different + // error code. This is necessary to avoid a problem where the + // closed status is confused with the accept file descriptor + // being closed. + if (rv == NNG_ECLOSED) { + rv = NNG_ECONNSHUT; + } nng_stream_close(p->tls); if ((uaio = ep->useraio) != NULL) { From e6a2e6859f6d257978e1abb4efd7cd2f29259a7d Mon Sep 17 00:00:00 2001 From: Leonard Pollak Date: Wed, 27 Oct 2021 07:53:02 +0200 Subject: [PATCH 157/180] Use env shebangs everywhere (#1515) Change all shebangs to use '#!/usr/bin/env bash'. This increases portability to platforms which do not cohere to the FHS. --- demo/async/run.sh | 2 +- etc/codecov.sh | 2 +- etc/coverage.sh | 2 +- etc/format-check.sh | 2 +- src/tools/nngcat/nngcat_ambiguous_test.sh | 2 +- src/tools/nngcat/nngcat_async_test.sh | 2 +- src/tools/nngcat/nngcat_dup_proto_test.sh | 2 +- src/tools/nngcat/nngcat_help_test.sh | 2 +- src/tools/nngcat/nngcat_incompat_test.sh | 2 +- src/tools/nngcat/nngcat_pubsub_test.sh | 2 +- src/tools/nngcat/nngcat_recvmaxsz_test.sh | 2 +- src/tools/nngcat/nngcat_stdin_pipe_test.sh | 2 +- src/tools/nngcat/nngcat_unlimited_test.sh | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/demo/async/run.sh b/demo/async/run.sh index 856fea9f4..b5128eb02 100755 --- a/demo/async/run.sh +++ b/demo/async/run.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ADDR=ipc:///tmp/async_demo COUNT=10 diff --git a/etc/codecov.sh b/etc/codecov.sh index 5ecdc55f3..7bddcd502 100755 --- a/etc/codecov.sh +++ b/etc/codecov.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright 2017 Garrett D'Amore # Copyright 2017 Capitar IT Group BV diff --git a/etc/coverage.sh b/etc/coverage.sh index 6f7355dca..73e71098e 100755 --- a/etc/coverage.sh +++ b/etc/coverage.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright 2017 Garrett D'Amore # Copyright 2017 Capitar IT Group BV diff --git a/etc/format-check.sh b/etc/format-check.sh index 68b3d8eb1..aca847c93 100755 --- a/etc/format-check.sh +++ b/etc/format-check.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # # Copyright 2016 Garrett D'Amore # diff --git a/src/tools/nngcat/nngcat_ambiguous_test.sh b/src/tools/nngcat/nngcat_ambiguous_test.sh index 414b6d191..944d5aedd 100755 --- a/src/tools/nngcat/nngcat_ambiguous_test.sh +++ b/src/tools/nngcat/nngcat_ambiguous_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_async_test.sh b/src/tools/nngcat/nngcat_async_test.sh index 2b03e5221..aeec3de23 100755 --- a/src/tools/nngcat/nngcat_async_test.sh +++ b/src/tools/nngcat/nngcat_async_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_dup_proto_test.sh b/src/tools/nngcat/nngcat_dup_proto_test.sh index 1513d01cf..a55b7f3ba 100755 --- a/src/tools/nngcat/nngcat_dup_proto_test.sh +++ b/src/tools/nngcat/nngcat_dup_proto_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_help_test.sh b/src/tools/nngcat/nngcat_help_test.sh index 95ed9e3e0..77b75034a 100755 --- a/src/tools/nngcat/nngcat_help_test.sh +++ b/src/tools/nngcat/nngcat_help_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_incompat_test.sh b/src/tools/nngcat/nngcat_incompat_test.sh index 128b57baa..93b754883 100755 --- a/src/tools/nngcat/nngcat_incompat_test.sh +++ b/src/tools/nngcat/nngcat_incompat_test.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_pubsub_test.sh b/src/tools/nngcat/nngcat_pubsub_test.sh index b9ba90edd..52d35a926 100755 --- a/src/tools/nngcat/nngcat_pubsub_test.sh +++ b/src/tools/nngcat/nngcat_pubsub_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_recvmaxsz_test.sh b/src/tools/nngcat/nngcat_recvmaxsz_test.sh index b5d4ff4a1..a41a02c07 100755 --- a/src/tools/nngcat/nngcat_recvmaxsz_test.sh +++ b/src/tools/nngcat/nngcat_recvmaxsz_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_stdin_pipe_test.sh b/src/tools/nngcat/nngcat_stdin_pipe_test.sh index 5fec0ab7b..824107e47 100755 --- a/src/tools/nngcat/nngcat_stdin_pipe_test.sh +++ b/src/tools/nngcat/nngcat_stdin_pipe_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. diff --git a/src/tools/nngcat/nngcat_unlimited_test.sh b/src/tools/nngcat/nngcat_unlimited_test.sh index 0486b9b18..88a1e3095 100755 --- a/src/tools/nngcat/nngcat_unlimited_test.sh +++ b/src/tools/nngcat/nngcat_unlimited_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2018 Staysail Systems, Inc. From d3fe0b86aabce7106c9684255ccae490fc7cabe9 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Wed, 27 Oct 2021 22:34:41 -0700 Subject: [PATCH 158/180] fixes #1346 windows ipc winsec fails frequently in CI/CD --- .clang-format | 2 +- src/core/id_test.c | 22 +-- src/platform/posix/CMakeLists.txt | 3 + src/platform/posix/posix_ipcwinsec_test.c | 31 ++++ src/platform/windows/CMakeLists.txt | 5 +- src/platform/windows/win_ipc_sec_test.c | 190 +++++++++++++++++++ src/platform/windows/win_thread.c | 3 +- src/sp/protocol/pair0/pair.c | 70 +++---- src/sp/protocol/pair1/pair.c | 28 +-- src/sp/protocol/pipeline0/push.c | 16 +- src/supplemental/websocket/websocket_test.c | 70 +++---- tests/CMakeLists.txt | 1 - tests/ipcwinsec.c | 192 -------------------- 13 files changed, 334 insertions(+), 299 deletions(-) create mode 100644 src/platform/posix/posix_ipcwinsec_test.c create mode 100644 src/platform/windows/win_ipc_sec_test.c delete mode 100644 tests/ipcwinsec.c diff --git a/.clang-format b/.clang-format index ff7c2f088..02137561b 100644 --- a/.clang-format +++ b/.clang-format @@ -5,7 +5,7 @@ ColumnLimit: 79 AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: true AlignTrailingComments: true -AlignEscapedNewlinesLeft: true +AlignEscapedNewlines: Left PointerAlignment: Right ForEachMacros: ['NNI_LIST_FOREACH'] AlwaysBreakAfterReturnType: TopLevelDefinitions diff --git a/src/core/id_test.c b/src/core/id_test.c index 51872e690..b948cc132 100644 --- a/src/core/id_test.c +++ b/src/core/id_test.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -15,8 +15,8 @@ void test_basic(void) { nni_id_map m; - char * five = "five"; - char * four = "four"; + char *five = "five"; + char *four = "four"; nni_id_map_init(&m, 0, 0, false); @@ -60,8 +60,8 @@ void test_collision(void) { nni_id_map m; - char * five = "five"; - char * four = "four"; + char *five = "five"; + char *four = "four"; nni_id_map_init(&m, 0, 0, false); @@ -141,7 +141,7 @@ test_dynamic(void) nni_id_map_init(&m, 10, 13, false); - // We can fill the table. + // We can fill the table. NUTS_PASS(nni_id_alloc(&m, &id, &expect[0])); NUTS_TRUE(id == 10); NUTS_PASS(nni_id_alloc(&m, &id, &expect[1])); @@ -186,11 +186,11 @@ test_set_out_of_range(void) void test_stress(void) { - void * values[NUM_VALUES]; + void *values[NUM_VALUES]; nni_id_map m; size_t i; int rv; - void * x; + void *x; int v; nni_id_map_init(&m, 0, 0, false); @@ -240,15 +240,15 @@ test_stress(void) // Post stress check. for (i = 0; i < NUM_VALUES; i++) { - x = nni_id_get(&m, i); + x = nni_id_get(&m, (uint32_t) i); if (x != values[i]) { NUTS_TRUE(x == values[i]); break; } // We only use the test macros if we know they are going - // to fail. Otherwise there will be too many errors reported. - rv = nni_id_remove(&m, i); + // to fail. Otherwise, there will be too many errors reported. + rv = nni_id_remove(&m, (uint32_t) i); if ((x == NULL) && (rv != NNG_ENOENT)) { NUTS_FAIL(rv, NNG_ENOENT); } else if ((x != NULL) && (rv != 0)) { diff --git a/src/platform/posix/CMakeLists.txt b/src/platform/posix/CMakeLists.txt index 02a8cb53a..7b619fa22 100644 --- a/src/platform/posix/CMakeLists.txt +++ b/src/platform/posix/CMakeLists.txt @@ -105,4 +105,7 @@ if (NNG_PLATFORM_POSIX) else () nng_sources(posix_rand_urandom.c) endif () + + nng_test(posix_ipcwinsec_test) + endif () \ No newline at end of file diff --git a/src/platform/posix/posix_ipcwinsec_test.c b/src/platform/posix/posix_ipcwinsec_test.c new file mode 100644 index 000000000..934eeea91 --- /dev/null +++ b/src/platform/posix/posix_ipcwinsec_test.c @@ -0,0 +1,31 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// +#include +#include + +void +test_ipc_win_sec(void) +{ + char address[64]; + nng_stream_listener *l; + int x; + + nuts_scratch_addr("ipc", sizeof(address), address); + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + NUTS_FAIL(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, &x), + NNG_ENOTSUP); + nng_stream_listener_free(l); +} + +NUTS_TESTS = { + { "ipc security descriptor", test_ipc_win_sec }, + { NULL, NULL }, +}; diff --git a/src/platform/windows/CMakeLists.txt b/src/platform/windows/CMakeLists.txt index 174e77f86..d1d158e09 100644 --- a/src/platform/windows/CMakeLists.txt +++ b/src/platform/windows/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2020 Staysail Systems, Inc. +# Copyright 2021 Staysail Systems, Inc. # # This software is supplied under the terms of the MIT License, a # copy of which should be located in the distribution where this @@ -46,4 +46,7 @@ if (NNG_PLATFORM_WINDOWS) win_thread.c win_udp.c ) + + nng_test(win_ipc_sec_test) + endif () \ No newline at end of file diff --git a/src/platform/windows/win_ipc_sec_test.c b/src/platform/windows/win_ipc_sec_test.c new file mode 100644 index 000000000..ab65533bd --- /dev/null +++ b/src/platform/windows/win_ipc_sec_test.c @@ -0,0 +1,190 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include + +// Microsoft prefers CamelCase header names, but relies on case-insensitive +// file systems to make that work. The rest of the world (min-gw64 included) +// uses case-sensitive names and lowercase. + +#include +#include + +SECURITY_DESCRIPTOR * +sdescAuthUsers(PSID sid, PACL *aclp) +{ + SECURITY_DESCRIPTOR *sdesc; + EXPLICIT_ACCESS xa; + ACL *acl; + + sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); + NUTS_ASSERT(sdesc != NULL); + + InitializeSecurityDescriptor(sdesc, SECURITY_DESCRIPTOR_REVISION); + + xa.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; + xa.grfAccessMode = SET_ACCESS; + xa.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; + xa.Trustee.TrusteeForm = TRUSTEE_IS_SID; + xa.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + xa.Trustee.ptstrName = (LPSTR) sid; + + SetEntriesInAcl(1, &xa, NULL, &acl); + *aclp = acl; + + SetSecurityDescriptorDacl(sdesc, TRUE, acl, FALSE); + return (sdesc); +} + +void +test_ipc_security_descriptor(void) +{ + nng_stream_listener *l; + char address[64]; + char pipe[64]; + SECURITY_DESCRIPTOR *sd; + SID users; + DWORD size; + PACL acl = NULL; + PACL dacl; + PSECURITY_DESCRIPTOR psd; + PACE_HEADER ace; + PSID psid; + PACCESS_ALLOWED_ACE allowed; + nng_aio *aio; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + size = sizeof(users); + CreateWellKnownSid(WinAuthenticatedUserSid, NULL, &users, &size); + sd = sdescAuthUsers(&users, &acl); + + NUTS_ASSERT(sd != NULL); + NUTS_ASSERT(acl != NULL); + NUTS_PASS(nng_aio_alloc(&aio, NULL, NULL)); + + NUTS_PASS(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sd)); + NUTS_PASS(nng_stream_listener_listen(l)); + nng_stream_listener_accept(l, aio); + + (void) snprintf(pipe, sizeof(pipe), "\\\\.\\pipe\\%s", address+strlen("ipc://")); + HANDLE ph = CreateFileA(pipe, READ_CONTROL, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, NULL); + + nng_aio_wait(aio); + NUTS_PASS(nng_aio_result(aio)); + HANDLE pd = (HANDLE) nng_aio_get_output(aio, 0); + + NUTS_ASSERT(ph != INVALID_HANDLE_VALUE); + NUTS_ASSERT(pd != INVALID_HANDLE_VALUE); + + NUTS_ASSERT( + GetSecurityInfo(ph, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, + NULL, NULL, &dacl, NULL, &psd) == ERROR_SUCCESS); + + NUTS_ASSERT(dacl->AceCount == 1); + NUTS_ASSERT(GetAce(dacl, 0, (void **) &ace) == TRUE); + allowed = (PACCESS_ALLOWED_ACE) ace; + psid = (PSID) &allowed->SidStart; + NUTS_ASSERT(IsValidSid(psid)); + NUTS_ASSERT(EqualSid(psid, &users) == TRUE); + + CloseHandle(pd); + CloseHandle(ph); + free(sd); + LocalFree(acl); + LocalFree(psd); + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_busy(void) +{ + // This test ensures that the descriptor can only be set before + // the listener is started. + nng_stream_listener *l; + char address[64]; + SECURITY_DESCRIPTOR *sd; + SID users; + DWORD size; + PACL acl = NULL; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + size = sizeof(users); + CreateWellKnownSid(WinAuthenticatedUserSid, NULL, &users, &size); + sd = sdescAuthUsers(&users, &acl); + + NUTS_ASSERT(sd != NULL); + NUTS_ASSERT(acl != NULL); + + NUTS_PASS(nng_stream_listener_listen(l)); + + NUTS_FAIL(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sd), + NNG_EBUSY); + + free(sd); + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_bogus(void) +{ + nng_stream_listener *l; + char address[64]; + + nuts_scratch_addr("ipc", sizeof(address), address); + + NUTS_PASS(nng_stream_listener_alloc(&l, address)); + + NUTS_FAIL(nng_stream_listener_set_ptr( + l, NNG_OPT_IPC_SECURITY_DESCRIPTOR, NULL), + NNG_EINVAL); + + nng_stream_listener_close(l); + nng_stream_listener_free(l); +} + +void +test_ipc_security_descriptor_dialer(void) +{ + nng_stream_dialer *d; + char address[64]; + SECURITY_DESCRIPTOR *sdesc; + + nuts_scratch_addr("ipc", sizeof(address), address); + NUTS_PASS(nng_stream_dialer_alloc(&d, address)); + + sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); + NUTS_ASSERT(sdesc != NULL); + InitializeSecurityDescriptor(sdesc, SECURITY_DESCRIPTOR_REVISION); + NUTS_FAIL(nng_stream_dialer_set_ptr( + d, NNG_OPT_IPC_SECURITY_DESCRIPTOR, sdesc), + NNG_ENOTSUP); + free(sdesc); + nng_stream_dialer_free(d); +} + +NUTS_TESTS = { + { "ipc security descriptor", test_ipc_security_descriptor }, + { "ipc security descriptor busy", test_ipc_security_descriptor_busy }, + { "ipc security descriptor bogus", + test_ipc_security_descriptor_bogus }, + { "ipc security descriptor dialer", + test_ipc_security_descriptor_dialer }, + { NULL, NULL }, +}; diff --git a/src/platform/windows/win_thread.c b/src/platform/windows/win_thread.c index dc9ed12af..9c7c09d3e 100644 --- a/src/platform/windows/win_thread.c +++ b/src/platform/windows/win_thread.c @@ -381,7 +381,8 @@ nni_plat_thr_set_name(nni_plat_thr *thr, const char *name) if ((wcs = nni_alloc(len * 2)) == NULL) { return; } - (void) MultiByteToWideChar(CP_UTF8, 0, name, len, wcs, len); + (void) MultiByteToWideChar( + CP_UTF8, 0, name, (int) len, wcs, (int) len); set_thread_desc(h, wcs); nni_free(wcs, len * 2); } diff --git a/src/sp/protocol/pair0/pair.c b/src/sp/protocol/pair0/pair.c index c2407d817..c6470b7bb 100644 --- a/src/sp/protocol/pair0/pair.c +++ b/src/sp/protocol/pair0/pair.c @@ -32,7 +32,7 @@ static void pair0_pipe_send(pair0_pipe *, nni_msg *); // pair0_sock is our per-socket protocol private structure. struct pair0_sock { - pair0_pipe * p; + pair0_pipe *p; nni_mtx mtx; nni_lmq wmq; nni_list waq; @@ -44,12 +44,12 @@ struct pair0_sock { bool wr_ready; // pipe ready for write }; -// An pair0_pipe is our per-pipe protocol private structure. We keep +// A pair0_pipe is our per-pipe protocol private structure. We keep // one of these even though in theory we'd only have a single underlying // pipe. The separate data structure is more like other protocols that do // manage multiple pipes. struct pair0_pipe { - nni_pipe * pipe; + nni_pipe *pipe; pair0_sock *pair; nni_aio aio_send; nni_aio aio_recv; @@ -190,8 +190,8 @@ pair0_pipe_recv_cb(void *arg) { pair0_pipe *p = arg; pair0_sock *s = p->pair; - nni_msg * msg; - nni_aio * a; + nni_msg *msg; + nni_aio *a; if (nni_aio_result(&p->aio_recv) != 0) { nni_pipe_close(p->pipe); @@ -231,8 +231,8 @@ static void pair0_send_sched(pair0_sock *s) { pair0_pipe *p; - nni_msg * m; - nni_aio * a = NULL; + nni_msg *m; + nni_aio *a = NULL; size_t l = 0; nni_mtx_lock(&s->mtx); @@ -303,8 +303,8 @@ static void pair0_sock_close(void *arg) { pair0_sock *s = arg; - nni_aio * a; - nni_msg * m; + nni_aio *a; + nni_msg *m; nni_mtx_lock(&s->mtx); while (((a = nni_list_first(&s->raq)) != NULL) || ((a = nni_list_first(&s->waq)) != NULL)) { @@ -334,7 +334,7 @@ static void pair0_sock_send(void *arg, nni_aio *aio) { pair0_sock *s = arg; - nni_msg * m; + nni_msg *m; size_t len; int rv; @@ -384,7 +384,7 @@ pair0_sock_recv(void *arg, nni_aio *aio) { pair0_sock *s = arg; pair0_pipe *p; - nni_msg * m; + nni_msg *m; int rv; if (nni_aio_begin(aio) != 0) { @@ -463,7 +463,7 @@ pair0_get_send_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->mtx); - val = nni_lmq_cap(&s->wmq); + val = (int) nni_lmq_cap(&s->wmq); nni_mtx_unlock(&s->mtx); return (nni_copyout_int(val, buf, szp, t)); @@ -498,7 +498,7 @@ pair0_get_recv_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->mtx); - val = nni_lmq_cap(&s->rmq); + val = (int) nni_lmq_cap(&s->rmq); nni_mtx_unlock(&s->mtx); return (nni_copyout_int(val, buf, szp, t)); @@ -531,28 +531,28 @@ pair0_sock_get_send_fd(void *arg, void *buf, size_t *szp, nni_opt_type t) } static nni_option pair0_sock_options[] = { - { - .o_name = NNG_OPT_RECVFD, - .o_get = pair0_sock_get_recv_fd, - }, - { - .o_name = NNG_OPT_SENDFD, - .o_get = pair0_sock_get_send_fd, - }, - { - .o_name = NNG_OPT_SENDBUF, - .o_get = pair0_get_send_buf_len, - .o_set = pair0_set_send_buf_len, - }, - { - .o_name = NNG_OPT_RECVBUF, - .o_get = pair0_get_recv_buf_len, - .o_set = pair0_set_recv_buf_len, - }, - // terminate list - { - .o_name = NULL, - }, + { + .o_name = NNG_OPT_RECVFD, + .o_get = pair0_sock_get_recv_fd, + }, + { + .o_name = NNG_OPT_SENDFD, + .o_get = pair0_sock_get_send_fd, + }, + { + .o_name = NNG_OPT_SENDBUF, + .o_get = pair0_get_send_buf_len, + .o_set = pair0_set_send_buf_len, + }, + { + .o_name = NNG_OPT_RECVBUF, + .o_get = pair0_get_recv_buf_len, + .o_set = pair0_set_recv_buf_len, + }, + // terminate list + { + .o_name = NULL, + }, }; static nni_proto_pipe_ops pair0_pipe_ops = { diff --git a/src/sp/protocol/pair1/pair.c b/src/sp/protocol/pair1/pair.c index 4a909888c..e6be4628c 100644 --- a/src/sp/protocol/pair1/pair.c +++ b/src/sp/protocol/pair1/pair.c @@ -32,9 +32,9 @@ static void pair1_pipe_send(pair1_pipe *, nni_msg *); // pair1_sock is our per-socket protocol private structure. struct pair1_sock { - nni_sock * sock; + nni_sock *sock; bool raw; - pair1_pipe * p; + pair1_pipe *p; nni_atomic_int ttl; nni_mtx mtx; nni_lmq wmq; @@ -63,7 +63,7 @@ struct pair1_sock { // pair1_pipe is our per-pipe protocol private structure. struct pair1_pipe { - nni_pipe * pipe; + nni_pipe *pipe; pair1_sock *pair; nni_aio aio_send; nni_aio aio_recv; @@ -302,11 +302,11 @@ pair1_pipe_recv_cb(void *arg) { pair1_pipe *p = arg; pair1_sock *s = p->pair; - nni_msg * msg; + nni_msg *msg; uint32_t hdr; - nni_pipe * pipe = p->pipe; + nni_pipe *pipe = p->pipe; size_t len; - nni_aio * a; + nni_aio *a; if (nni_aio_result(&p->aio_recv) != 0) { nni_pipe_close(p->pipe); @@ -372,8 +372,8 @@ static void pair1_send_sched(pair1_sock *s) { pair1_pipe *p; - nni_msg * m; - nni_aio * a = NULL; + nni_msg *m; + nni_aio *a = NULL; size_t l = 0; nni_mtx_lock(&s->mtx); @@ -444,8 +444,8 @@ static void pair1_sock_close(void *arg) { pair1_sock *s = arg; - nni_aio * a; - nni_msg * m; + nni_aio *a; + nni_msg *m; nni_mtx_lock(&s->mtx); while (((a = nni_list_first(&s->raq)) != NULL) || ((a = nni_list_first(&s->waq)) != NULL)) { @@ -521,7 +521,7 @@ static void pair1_sock_send(void *arg, nni_aio *aio) { pair1_sock *s = arg; - nni_msg * m; + nni_msg *m; size_t len; int rv; @@ -599,7 +599,7 @@ pair1_sock_recv(void *arg, nni_aio *aio) { pair1_sock *s = arg; pair1_pipe *p; - nni_msg * m; + nni_msg *m; int rv; if (nni_aio_begin(aio) != 0) { @@ -678,7 +678,7 @@ pair1_get_send_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->mtx); - val = nni_lmq_cap(&s->wmq); + val = (int) nni_lmq_cap(&s->wmq); nni_mtx_unlock(&s->mtx); return (nni_copyout_int(val, buf, szp, t)); @@ -713,7 +713,7 @@ pair1_get_recv_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->mtx); - val = nni_lmq_cap(&s->rmq); + val = (int) nni_lmq_cap(&s->rmq); nni_mtx_unlock(&s->mtx); return (nni_copyout_int(val, buf, szp, t)); diff --git a/src/sp/protocol/pipeline0/push.c b/src/sp/protocol/pipeline0/push.c index ad43d967d..028104cdb 100644 --- a/src/sp/protocol/pipeline0/push.c +++ b/src/sp/protocol/pipeline0/push.c @@ -1,5 +1,5 @@ // -// Copyright 2020 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a @@ -43,8 +43,8 @@ struct push0_sock { // push0_pipe is our per-pipe protocol private structure. struct push0_pipe { - nni_pipe * pipe; - push0_sock * push; + nni_pipe *pipe; + push0_sock *push; nni_list_node node; nni_aio aio_recv; @@ -85,7 +85,7 @@ static void push0_sock_close(void *arg) { push0_sock *s = arg; - nni_aio * a; + nni_aio *a; nni_mtx_lock(&s->m); while ((a = nni_list_first(&s->aq)) != NULL) { nni_aio_list_remove(a); @@ -182,8 +182,8 @@ static void push0_pipe_ready(push0_pipe *p) { push0_sock *s = p->push; - nni_msg * m; - nni_aio * a = NULL; + nni_msg *m; + nni_aio *a = NULL; size_t l; bool blocked; @@ -266,7 +266,7 @@ push0_sock_send(void *arg, nni_aio *aio) { push0_sock *s = arg; push0_pipe *p; - nni_msg * m; + nni_msg *m; size_t l; int rv; @@ -356,7 +356,7 @@ push0_get_send_buf_len(void *arg, void *buf, size_t *szp, nni_opt_type t) int val; nni_mtx_lock(&s->m); - val = nni_lmq_cap(&s->wq); + val = (int) nni_lmq_cap(&s->wq); nni_mtx_unlock(&s->m); return (nni_copyout_int(val, buf, szp, t)); diff --git a/src/supplemental/websocket/websocket_test.c b/src/supplemental/websocket/websocket_test.c index 9ea680173..be4e1b302 100644 --- a/src/supplemental/websocket/websocket_test.c +++ b/src/supplemental/websocket/websocket_test.c @@ -17,17 +17,17 @@ void test_websocket_wildcard(void) { - nng_stream_dialer * d = NULL; + nng_stream_dialer *d = NULL; nng_stream_listener *l = NULL; nng_sockaddr sa1; nng_sockaddr sa2; size_t sz; - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_aio * aio1 = NULL; - nng_aio * aio2 = NULL; - nng_stream * c1 = NULL; - nng_stream * c2 = NULL; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_aio *aio1 = NULL; + nng_aio *aio2 = NULL; + nng_stream *c1 = NULL; + nng_stream *c2 = NULL; nng_iov iov; char buf1[8]; char buf2[8]; @@ -125,18 +125,18 @@ test_websocket_wildcard(void) void test_websocket_conn_props(void) { - nng_stream_dialer * d = NULL; + nng_stream_dialer *d = NULL; nng_stream_listener *l = NULL; nng_sockaddr sa1; nng_sockaddr sa2; size_t sz; - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_stream * c1 = NULL; - nng_stream * c2 = NULL; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_stream *c1 = NULL; + nng_stream *c2 = NULL; char uri[64]; bool on; - char * str; + char *str; uint16_t port = nuts_next_port(); (void) snprintf(uri, sizeof(uri), "ws://127.0.0.1:%d/test", port); @@ -219,14 +219,14 @@ test_websocket_conn_props(void) void test_websocket_text_mode(void) { - nng_stream_dialer * d = NULL; + nng_stream_dialer *d = NULL; nng_stream_listener *l = NULL; - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_aio * aio1 = NULL; - nng_aio * aio2 = NULL; - nng_stream * c1 = NULL; - nng_stream * c2 = NULL; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_aio *aio1 = NULL; + nng_aio *aio2 = NULL; + nng_stream *c1 = NULL; + nng_stream *c2 = NULL; char uri[64]; char txb[5]; char rxb[5]; @@ -342,16 +342,16 @@ test_websocket_text_mode(void) } typedef struct recv_state { - nng_stream * c; + nng_stream *c; int total; int xfr; - nng_mtx * lock; - nng_cv * cv; - nng_aio * aio; + nng_mtx *lock; + nng_cv *cv; + nng_aio *aio; int err; bool done; - uint8_t * send_buf; - uint8_t * buf; + uint8_t *send_buf; + uint8_t *buf; nni_sha1_ctx sum; } recv_state; @@ -393,20 +393,20 @@ void test_websocket_fragmentation(void) { nng_stream_listener *l = NULL; - nng_stream_dialer * d = NULL; - nng_stream * c = NULL; + nng_stream_dialer *d = NULL; + nng_stream *c = NULL; uint16_t port; char url[64]; - nng_aio * daio = NULL; - nng_aio * laio = NULL; - nng_aio * caio = NULL; + nng_aio *daio = NULL; + nng_aio *laio = NULL; + nng_aio *caio = NULL; int resid; recv_state state; uint8_t sum1[20]; uint8_t sum2[20]; - uint8_t * recv_buf; - uint8_t * send_buf; - uint8_t * buf; + uint8_t *recv_buf; + uint8_t *send_buf; + uint8_t *buf; nng_iov iov; memset(&state, 0, sizeof(state)); @@ -475,7 +475,7 @@ test_websocket_fragmentation(void) nng_aio_wait(caio); NUTS_PASS(nng_aio_result(caio)); NUTS_TRUE(nng_aio_count(caio) > 0); - len = nng_aio_count(caio); + len = (int) nng_aio_count(caio); resid -= len; buf += len; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 856ce387a..f9f9ee6ec 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -131,7 +131,6 @@ add_nng_test1(httpserver 30 NNG_SUPP_HTTP) add_nng_test(inproc 5) add_nng_test(ipc 5) add_nng_test(ipcsupp 10) -add_nng_test(ipcwinsec 5) add_nng_test(multistress 60) add_nng_test(nonblock 60) add_nng_test(options 5) diff --git a/tests/ipcwinsec.c b/tests/ipcwinsec.c deleted file mode 100644 index 533dfe379..000000000 --- a/tests/ipcwinsec.c +++ /dev/null @@ -1,192 +0,0 @@ -// -// Copyright 2021 Staysail Systems, Inc. -// Copyright 2018 Capitar IT Group BV -// -// This software is supplied under the terms of the MIT License, a -// copy of which should be located in the distribution where this -// file was obtained (LICENSE.txt). A copy of the license may also be -// found online at https://opensource.org/licenses/MIT. -// - -#include -#include -#include -#include - -#include "convey.h" -#include "stubs.h" -#include "trantest.h" - -#define ADDR "/tmp/ipc_winsec_test" - -// Inproc tests. - -#ifndef _WIN32 -TestMain("IPC Security Descriptor", { - Convey("Given a socket and an IPC listener", { - nng_socket s; - nng_listener l; - int x; - - So(nng_rep0_open(&s) == 0); - Reset({ nng_close(s); }); - So(nng_listener_create(&l, s, "ipc://" ADDR) == 0); - Convey("We cannot set Windows SECURITY_DESCRIPTOR on POSIX", { - So(nng_listener_setopt_ptr(l, - NNG_OPT_IPC_SECURITY_DESCRIPTOR, - &x) == NNG_ENOTSUP); - }); - }); -}) -#else - -#include - -// Microsoft prefers CamelCase header names, but relies on case insensitive -// file systems to make that work. The rest of the world (min-gw64 included) -// uses case sensitive names and lowercase. - -#include - -#include - -#include - -SECURITY_DESCRIPTOR * -sdescAuthUsers(PSID sid, PACL *aclp) -{ - SECURITY_DESCRIPTOR *sdesc; - EXPLICIT_ACCESS xa; - ACL * acl; - - sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); - assert(sdesc != NULL); - - InitializeSecurityDescriptor(sdesc, SECURITY_DESCRIPTOR_REVISION); - - xa.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; - xa.grfAccessMode = SET_ACCESS; - xa.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - xa.Trustee.TrusteeForm = TRUSTEE_IS_SID; - xa.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - xa.Trustee.ptstrName = (LPSTR) sid; - - SetEntriesInAcl(1, &xa, NULL, &acl); - *aclp = acl; - - SetSecurityDescriptorDacl(sdesc, TRUE, acl, FALSE); - return (sdesc); -} - -TestMain("IPC Security Descriptor", { - Convey("Given a socket and an IPC listener", { - nng_socket s; - nng_listener l; - - So(nng_rep0_open(&s) == 0); - Reset({ nng_close(s); }); - - So(nng_listener_create(&l, s, "ipc://" ADDR) == 0); - Convey("We can set security descriptor on Windows", { - SECURITY_DESCRIPTOR *sdesc; - SID users; - DWORD size; - PACL acl = NULL; - - size = sizeof(users); - CreateWellKnownSid( - WinAuthenticatedUserSid, NULL, &users, &size); - - sdesc = sdescAuthUsers(&users, &acl); - assert(sdesc != NULL); - assert(acl != NULL); - Reset({ - free(sdesc); - LocalFree(acl); - }); - - So(nng_listener_setopt_ptr(l, - NNG_OPT_IPC_SECURITY_DESCRIPTOR, sdesc) == 0); - So(nng_listener_start(l, 0) == 0); - - Convey("And they are effective", { - PACL dacl; - PSECURITY_DESCRIPTOR sd; - PACE_HEADER ace; - PSID asid; - PACCESS_ALLOWED_ACE allowed; - - HANDLE ph = CreateFileA("\\\\.\\\\pipe\\" ADDR, - READ_CONTROL, 0, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); - - So(ph != INVALID_HANDLE_VALUE); - Reset({ CloseHandle(ph); }); - - So(GetSecurityInfo(ph, SE_KERNEL_OBJECT, - DACL_SECURITY_INFORMATION, NULL, NULL, - &dacl, NULL, &sd) == ERROR_SUCCESS); - Reset({ LocalFree(sd); }); - - So(dacl->AceCount == 1); - So(GetAce(dacl, 0, (void **) &ace) == TRUE); - allowed = (PACCESS_ALLOWED_ACE) ace; - asid = (PSID) &allowed->SidStart; - So(IsValidSid(asid)); - So(EqualSid(asid, &users) == TRUE); - }); - }); - - Convey("We cannot set security descriptor after started", { - SECURITY_DESCRIPTOR *sdesc; - SID users; - DWORD size; - PACL acl = NULL; - - size = sizeof(users); - CreateWellKnownSid( - WinAuthenticatedUserSid, NULL, &users, &size); - - sdesc = sdescAuthUsers(&users, &acl); - assert(sdesc != NULL); - assert(acl != NULL); - Reset({ - free(sdesc); - LocalFree(acl); - }); - - So(nng_listener_start(l, 0) == 0); - So(nng_listener_setopt_ptr(l, - NNG_OPT_IPC_SECURITY_DESCRIPTOR, - sdesc) == NNG_EBUSY); - }); - - Convey("We cannot set bogus security", { - So(nng_listener_setopt_ptr(l, - NNG_OPT_IPC_SECURITY_DESCRIPTOR, - NULL) == NNG_EINVAL); - }); - }); - - Convey("We cannot set security descriptor on an IPC dialer", { - nng_socket s; - nng_dialer d; - SECURITY_DESCRIPTOR *sdesc; - - sdesc = calloc(SECURITY_DESCRIPTOR_MIN_LENGTH, 1); - assert(sdesc != NULL); - InitializeSecurityDescriptor( - sdesc, SECURITY_DESCRIPTOR_REVISION); - - So(nng_rep0_open(&s) == 0); - Reset({ - nng_close(s); - free(sdesc); - }); - - So(nng_dialer_create(&d, s, "ipc://" ADDR) == 0); - So(nng_dialer_setopt_ptr(d, NNG_OPT_IPC_SECURITY_DESCRIPTOR, - sdesc) == NNG_ENOTSUP); - }); -}) -#endif From 6b3b17a563fcb31f9e3015c973f07d94609cc780 Mon Sep 17 00:00:00 2001 From: Edward Rudd Date: Fri, 26 Nov 2021 12:54:58 -0500 Subject: [PATCH 159/180] fix building with PAIR and PUBSUB disabled (#1530) When building with PAIR and PUBSUB protocols disabled, the perf tools fail to compile. This makes some minor tweaks to correct that --- src/tools/perf/perf.c | 4 ++++ src/tools/perf/pubdrop.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/tools/perf/perf.c b/src/tools/perf/perf.c index accac6213..46d91cd84 100644 --- a/src/tools/perf/perf.c +++ b/src/tools/perf/perf.c @@ -45,6 +45,10 @@ static open_func open_client = no_open; #define nng_pair0_open no_open #endif +#if !defined(NNG_HAVE_PAIR0) && !defined(NNG_HAVE_PAIR1) +#define nng_pair_open no_open +#endif + #if defined(NNG_HAVE_REQ0) #include #else diff --git a/src/tools/perf/pubdrop.c b/src/tools/perf/pubdrop.c index 41ac5ba07..f7e1dbfd3 100644 --- a/src/tools/perf/pubdrop.c +++ b/src/tools/perf/pubdrop.c @@ -27,6 +27,8 @@ #else +#define NNG_OPT_SUB_SUBSCRIBE "sub:subscribe" + static void die(const char *, ...); static int From 96e513835c7424f1913f23cb2615bda587232707 Mon Sep 17 00:00:00 2001 From: Edward Rudd Date: Sat, 27 Nov 2021 20:55:35 -0500 Subject: [PATCH 160/180] update demos to not use deprecated functions (#1531) --- demo/async/CMakeLists.txt | 7 +++++-- demo/http_client/CMakeLists.txt | 5 ++++- demo/raw/CMakeLists.txt | 6 ++++-- demo/reqrep/CMakeLists.txt | 3 ++- demo/reqrep/reqrep.c | 32 ++++++++++++++++---------------- demo/rest/CMakeLists.txt | 5 ++++- 6 files changed, 35 insertions(+), 23 deletions(-) diff --git a/demo/async/CMakeLists.txt b/demo/async/CMakeLists.txt index 614bcfc3b..ef9311bf1 100644 --- a/demo/async/CMakeLists.txt +++ b/demo/async/CMakeLists.txt @@ -7,7 +7,7 @@ # file was obtained (LICENSE.txt). A copy of the license may also be # found online at https://opensource.org/licenses/MIT. -cmake_minimum_required (VERSION 2.8.7) +cmake_minimum_required (VERSION 2.8.12) project(nng-asyncdemo) @@ -16,9 +16,12 @@ set(PARALLEL 128 CACHE STRING "Parallelism (min 4, max 1000)") # Call this from your own project's makefile. find_package(nng CONFIG REQUIRED) +find_package(Threads) + add_executable(server server.c) target_link_libraries(server nng::nng) -target_compile_definitions(server PRIVATE -DPARALLEL=${PARALLEL}) +target_compile_definitions(server PRIVATE NNG_ELIDE_DEPRECATED PARALLEL=${PARALLEL}) add_executable(client client.c) target_link_libraries(client nng::nng) +target_compile_definitions(client PRIVATE NNG_ELIDE_DEPRECATED) diff --git a/demo/http_client/CMakeLists.txt b/demo/http_client/CMakeLists.txt index 3fe126f94..8f4b62f4a 100644 --- a/demo/http_client/CMakeLists.txt +++ b/demo/http_client/CMakeLists.txt @@ -7,12 +7,15 @@ # file was obtained (LICENSE.txt). A copy of the license may also be # found online at https://opensource.org/licenses/MIT. -cmake_minimum_required (VERSION 2.8.7) +cmake_minimum_required (VERSION 2.8.12) project(http_client) # Call this from your own project's makefile. find_package(nng CONFIG REQUIRED) +find_package(Threads) + add_executable(http_client http_client.c) target_link_libraries(http_client nng::nng) +target_compile_definitions(http_client PRIVATE NNG_ELIDE_DEPRECATED) diff --git a/demo/raw/CMakeLists.txt b/demo/raw/CMakeLists.txt index 15e481d57..2df8d3946 100644 --- a/demo/raw/CMakeLists.txt +++ b/demo/raw/CMakeLists.txt @@ -7,7 +7,7 @@ # file was obtained (LICENSE.txt). A copy of the license may also be # found online at https://opensource.org/licenses/MIT. -cmake_minimum_required (VERSION 2.8.7) +cmake_minimum_required (VERSION 2.8.12) project(raw) @@ -15,6 +15,8 @@ set(PARALLEL 128 CACHE STRING "Parallelism (min 4, max 1000)") find_package(nng CONFIG REQUIRED) +find_package(Threads) + add_executable(raw raw.c) target_link_libraries(raw nng::nng) -target_compile_definitions(raw PRIVATE -DPARALLEL=${PARALLEL}) +target_compile_definitions(raw PRIVATE NNG_ELIDE_DEPRECATED PARALLEL=${PARALLEL}) diff --git a/demo/reqrep/CMakeLists.txt b/demo/reqrep/CMakeLists.txt index c7a258b0c..092346466 100644 --- a/demo/reqrep/CMakeLists.txt +++ b/demo/reqrep/CMakeLists.txt @@ -7,7 +7,7 @@ # file was obtained (LICENSE.txt). A copy of the license may also be # found online at https://opensource.org/licenses/MIT. -cmake_minimum_required (VERSION 2.8.7) +cmake_minimum_required (VERSION 2.8.12) project(reqrep) @@ -20,3 +20,4 @@ find_package(Threads) add_executable(reqrep reqrep.c) target_link_libraries(reqrep nng::nng) +target_compile_definitions(reqrep PRIVATE NNG_ELIDE_DEPRECATED) diff --git a/demo/reqrep/reqrep.c b/demo/reqrep/reqrep.c index 3fccf6886..62ff29a48 100644 --- a/demo/reqrep/reqrep.c +++ b/demo/reqrep/reqrep.c @@ -88,15 +88,15 @@ server(const char *url) if (strncmp(url, "zt://", 5) == 0) { printf("ZeroTier transport will store its keys in current working directory.\n"); printf("The server and client instances must run in separate directories.\n"); - nng_listener_setopt_string(listener, NNG_OPT_ZT_HOME, "."); - nng_listener_setopt_ms(listener, NNG_OPT_RECONNMINT, 1); - nng_listener_setopt_ms(listener, NNG_OPT_RECONNMAXT, 1000); - nng_setopt_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000); - nng_setopt_ms(sock, NNG_OPT_RECVMAXSZ, 0); - nng_listener_setopt_ms(listener, NNG_OPT_ZT_PING_TIME, 10000); - nng_listener_setopt_ms(listener, NNG_OPT_ZT_CONN_TIME, 1000); + nng_listener_set_string(listener, NNG_OPT_ZT_HOME, "."); + nng_listener_set_ms(listener, NNG_OPT_RECONNMINT, 1); + nng_listener_set_ms(listener, NNG_OPT_RECONNMAXT, 1000); + nng_socket_set_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000); + nng_socket_set_ms(sock, NNG_OPT_RECVMAXSZ, 0); + nng_listener_set_ms(listener, NNG_OPT_ZT_PING_TIME, 10000); + nng_listener_set_ms(listener, NNG_OPT_ZT_CONN_TIME, 1000); } else { - nng_setopt_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000); + nng_socket_set_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000); } nng_listener_start(listener, 0); @@ -158,15 +158,15 @@ client(const char *url) if (strncmp(url, "zt://", 5) == 0) { printf("ZeroTier transport will store its keys in current working directory\n"); printf("The server and client instances must run in separate directories.\n"); - nng_dialer_setopt_string(dialer, NNG_OPT_ZT_HOME, "."); - nng_dialer_setopt_ms(dialer, NNG_OPT_RECONNMINT, 1); - nng_dialer_setopt_ms(dialer, NNG_OPT_RECONNMAXT, 1000); - nng_setopt_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000); - nng_setopt_ms(sock, NNG_OPT_RECVMAXSZ, 0); - nng_dialer_setopt_ms(dialer, NNG_OPT_ZT_PING_TIME, 10000); - nng_dialer_setopt_ms(dialer, NNG_OPT_ZT_CONN_TIME, 1000); + nng_dialer_set_string(dialer, NNG_OPT_ZT_HOME, "."); + nng_dialer_set_ms(dialer, NNG_OPT_RECONNMINT, 1); + nng_dialer_set_ms(dialer, NNG_OPT_RECONNMAXT, 1000); + nng_socket_set_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000); + nng_socket_set_ms(sock, NNG_OPT_RECVMAXSZ, 0); + nng_dialer_set_ms(dialer, NNG_OPT_ZT_PING_TIME, 10000); + nng_dialer_set_ms(dialer, NNG_OPT_ZT_CONN_TIME, 1000); } else { - nng_setopt_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000); + nng_socket_set_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000); } nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); diff --git a/demo/rest/CMakeLists.txt b/demo/rest/CMakeLists.txt index 5466e3c7f..d5dd4fe4a 100644 --- a/demo/rest/CMakeLists.txt +++ b/demo/rest/CMakeLists.txt @@ -7,11 +7,14 @@ # file was obtained (LICENSE.txt). A copy of the license may also be # found online at https://opensource.org/licenses/MIT. -cmake_minimum_required (VERSION 2.8.7) +cmake_minimum_required (VERSION 2.8.12) project(rest) find_package(nng CONFIG REQUIRED) +find_package(Threads) + add_executable(rest-server server.c) target_link_libraries(rest-server nng::nng) +target_compile_definitions(rest-server PRIVATE NNG_ELIDE_DEPRECATED) From dffbb463d0fb9dc8d799e59d2cb83a8c54d12747 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 27 Nov 2021 18:42:54 -0800 Subject: [PATCH 161/180] fixes #1526 NNG_USE_CLOCKID Bug? This makes CLOCK_MONOTONIC the default (as it should have been) for platforms that have it defined, except for Apple platforms which lack support for using anything other than the real time clock with condition variables. (And unfortunately silently ignore attempts to do otherwise.) --- src/platform/posix/posix_config.h | 30 +++++++++++++++--------------- src/testing/marry.c | 4 ++++ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/platform/posix/posix_config.h b/src/platform/posix/posix_config.h index 2abe51b4f..f9d13d7e6 100644 --- a/src/platform/posix/posix_config.h +++ b/src/platform/posix/posix_config.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Staysail Systems, Inc. +// Copyright 2021 Staysail Systems, Inc. // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -20,11 +20,14 @@ // the system lacks clock_gettime, then it will choose this automatically. // This value may be ignored on platforms that don't use POSIX clocks. // -// #define NNG_USE_CLOCKID +// #define NNG_USE_CLOCKID CLOCK_MONOTONIC // This macro may be defined to a different clock id (see -// clock_gettime()). By default we use CLOCK_MONOTONIC if it exists, -// or CLOCK_REALTIME otherwise. This is ignored if NNG_USE_GETTIMEOFDAY -// is defined. Platforms that don't use POSIX clocks will probably +// clock_gettime()). By default, we use CLOCK_MONOTONIC if it exists, +// or CLOCK_REALTIME otherwise. (Except for macOS, which does not have +// a functional pthread_condattr_setclock().) +// +// This is ignored if NNG_USE_GETTIMEOFDAY is defined. +// Platforms that don't use POSIX clocks will probably // ignore any setting here. // // #define NNG_HAVE_BACKTRACE @@ -61,21 +64,18 @@ #endif #endif +#ifndef NNG_USE_CLOCKID +#if defined(__APPLE__) #define NNG_USE_CLOCKID CLOCK_REALTIME -#ifndef CLOCK_REALTIME -#define NNG_USE_GETTIMEOFDAY -#elif !defined(NNG_USE_CLOCKID) +#elif defined(CLOCK_MONOTONIC) #define NNG_USE_CLOCKID CLOCK_MONOTONIC -#else +#elif defined(CLOCK_REALTIME) #define NNG_USE_CLOCKID CLOCK_REALTIME -#endif // CLOCK_REALTIME - -#if defined(NNG_HAVE_KQUEUE) -// pass #else -// fallback to poll(2) -#define NNG_USE_POSIX_POLLQ_POLL 1 +#define NNG_USE_GETTIMEOFDAY +#endif #endif + #define NNG_USE_POSIX_RESOLV_GAI 1 #endif // NNG_PLATFORM_POSIX diff --git a/src/testing/marry.c b/src/testing/marry.c index be109b7d2..2fc0e9acb 100644 --- a/src/testing/marry.c +++ b/src/testing/marry.c @@ -281,6 +281,10 @@ nuts_marry_ex( replace_port_zero(url, addr, port); url = addr; } + if (((rv = nng_setopt_ms(s2, NNG_OPT_RECONNMINT, 10)) != 0) || + ((rv = nng_setopt_ms(s2, NNG_OPT_RECONNMAXT, 10)) != 0)) { + goto done; + } if ((rv = nng_dial(s2, url, NULL, 0)) != 0) { goto done; } From 1d56a7f7d1f83269c0a8331449485df1d45360c3 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sun, 28 Nov 2021 08:48:55 -0800 Subject: [PATCH 162/180] Don't use deprecated function in test. --- src/testing/marry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/testing/marry.c b/src/testing/marry.c index 2fc0e9acb..cfaec6cc7 100644 --- a/src/testing/marry.c +++ b/src/testing/marry.c @@ -281,8 +281,8 @@ nuts_marry_ex( replace_port_zero(url, addr, port); url = addr; } - if (((rv = nng_setopt_ms(s2, NNG_OPT_RECONNMINT, 10)) != 0) || - ((rv = nng_setopt_ms(s2, NNG_OPT_RECONNMAXT, 10)) != 0)) { + if (((rv = nng_socket_set_ms(s2, NNG_OPT_RECONNMINT, 10)) != 0) || + ((rv = nng_socket_set_ms(s2, NNG_OPT_RECONNMAXT, 10)) != 0)) { goto done; } if ((rv = nng_dial(s2, url, NULL, 0)) != 0) { From 2d513b4eb308062973a6b985cc27890157a3448c Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 29 Nov 2021 14:56:03 +0800 Subject: [PATCH 163/180] * FIX [transport/mqtt_tcp] adapt to the fix of upstream. --- src/sp/transport/mqtt/broker_tcp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sp/transport/mqtt/broker_tcp.c b/src/sp/transport/mqtt/broker_tcp.c index b11f193f8..b246a1e7a 100644 --- a/src/sp/transport/mqtt/broker_tcp.c +++ b/src/sp/transport/mqtt/broker_tcp.c @@ -342,6 +342,13 @@ tcptran_pipe_nego_cb(void *arg) return; error: + // If the connection is closed, we need to pass back a different + // error code. This is necessary to avoid a problem where the + // closed status is confused with the accept file descriptor + // being closed. + if (rv == NNG_ECLOSED) { + rv = NNG_ECONNSHUT; + } nng_stream_close(p->conn); if ((uaio = ep->useraio) != NULL) { From 50b80218b0e43ba7ea3203cc5f988b5a65a4e443 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Mon, 29 Nov 2021 19:10:06 +0800 Subject: [PATCH 164/180] * FIX [protocol/CMakeList] fix compiling errors --- include/nng/protocol/mqtt/nmq_mqtt.h | 10 +++++----- src/sp/protocol/mqtt/CMakeLists.txt | 6 +++--- src/sp/transport/CMakeLists.txt | 3 +-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/nng/protocol/mqtt/nmq_mqtt.h b/include/nng/protocol/mqtt/nmq_mqtt.h index a93ab1894..ac4844168 100755 --- a/include/nng/protocol/mqtt/nmq_mqtt.h +++ b/include/nng/protocol/mqtt/nmq_mqtt.h @@ -7,8 +7,8 @@ // found online at https://opensource.org/licenses/MIT. // -#ifndef NNG_PROTOCOL_REQREP0_REP_H -#define NNG_PROTOCOL_REQREP0_REP_H +#ifndef NNG_PROTOCOL_MQTT_BROKER_H +#define NNG_PROTOCOL_MQTT_BROKER_H #ifdef __cplusplus extern "C" { @@ -16,8 +16,8 @@ extern "C" { NNG_DECL int nng_nmq_tcp0_open(nng_socket *); -#ifndef nng_nano_tcp_open -#define nng_nano_tcp_open nng_nano_tcp0_open +#ifndef nng_nmq_tcp_open +#define nng_nmq_tcp_open nng_nmq_tcp0_open #endif #define NNG_NANO_TCP_SELF 0x31 @@ -29,4 +29,4 @@ NNG_DECL int nng_nmq_tcp0_open(nng_socket *); } #endif -#endif // NNG_PROTOCOL_REQREP0_REP_H +#endif // NNG_PROTOCOL_MQTT_BROKER_H diff --git a/src/sp/protocol/mqtt/CMakeLists.txt b/src/sp/protocol/mqtt/CMakeLists.txt index 3af54eada..38beece9a 100755 --- a/src/sp/protocol/mqtt/CMakeLists.txt +++ b/src/sp/protocol/mqtt/CMakeLists.txt @@ -4,9 +4,9 @@ # nng_directory(mqtt) -nng_sources_if(NNG_PROTO_BROKER mqtt_parser.c nmq_mqtt.c) -nng_headers_if(NNG_PROTO_BROKER nng/protocol/mqtt/mqtt_parser.h nng/protocol/mqtt/nmq_mqtt.h) -nng_defines_if(NNG_PROTO_BROKER NNG_HAVE_MQTT_BROKER) +nng_sources_if(NNG_PROTO_MQTT_BROKER mqtt_parser.c nmq_mqtt.c) +nng_headers_if(NNG_PROTO_MQTT_BROKER nng/protocol/mqtt/mqtt_parser.h nng/protocol/mqtt/nmq_mqtt.h) +nng_defines_if(NNG_PROTO_MQTT_BROKER NNG_HAVE_MQTT_BROKER) #nng_sources_if(NNG_PROTO_MQTT_CLIENT mqtt_client.c) diff --git a/src/sp/transport/CMakeLists.txt b/src/sp/transport/CMakeLists.txt index 0007ebbf6..77d1bc8ed 100644 --- a/src/sp/transport/CMakeLists.txt +++ b/src/sp/transport/CMakeLists.txt @@ -13,8 +13,7 @@ nng_directory(transport) add_subdirectory(inproc) add_subdirectory(ipc) add_subdirectory(tcp) -add_subdirectory(mqtt) add_subdirectory(tls) add_subdirectory(ws) add_subdirectory(zerotier) - +add_subdirectory(mqtt) From f38eeb6d873f9ce9f3063daf575ad37836f92749 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Sun, 28 Nov 2021 11:50:54 +0800 Subject: [PATCH 165/180] *NEW [mqtt_tls] tls support --- cmake/NNGOptions.cmake | 6 +- demo/mqtt_async/CMakeLists.txt | 5 +- demo/mqtt_async/mqtt_async.c | 109 +- include/nng/transport/mqtts/mqtt_tls.h | 30 + src/core/stream.c | 15 + src/nng.c | 2 +- src/sp/transport.c | 6 + src/sp/transport/CMakeLists.txt | 1 + src/sp/transport/mqtt/mqtt_tcp.c | 38 +- src/sp/transport/mqtts/CMakeLists.txt | 16 + src/sp/transport/mqtts/mqtt_tls.c | 1527 ++++++++++++++++++++++++ 11 files changed, 1729 insertions(+), 26 deletions(-) create mode 100644 include/nng/transport/mqtts/mqtt_tls.h create mode 100644 src/sp/transport/mqtts/CMakeLists.txt create mode 100644 src/sp/transport/mqtts/mqtt_tls.c diff --git a/cmake/NNGOptions.cmake b/cmake/NNGOptions.cmake index 16680798e..4491b7187 100644 --- a/cmake/NNGOptions.cmake +++ b/cmake/NNGOptions.cmake @@ -118,7 +118,7 @@ mark_as_advanced(NNG_TRANSPORT_IPC) option (NNG_TRANSPORT_TCP "Enable TCP transport." ON) mark_as_advanced(NNG_TRANSPORT_TCP) -# TCP transport +# MQTT TCP transport option (NNG_TRANSPORT_MQTT_TCP "Enable MQTT TCP transport." ON) mark_as_advanced(NNG_TRANSPORT_MQTT_TCP) @@ -126,6 +126,10 @@ mark_as_advanced(NNG_TRANSPORT_MQTT_TCP) option (NNG_TRANSPORT_TLS "Enable TLS transport." ON) mark_as_advanced(NNG_TRANSPORT_TLS) +# MQTT TLS transport +option (NNG_TRANSPORT_MQTT_TLS "Enable MQTT TLS transport." ON ) +mark_as_advanced(NNG_TRANSPORT_MQTT_TLS) + # WebSocket option (NNG_TRANSPORT_WS "Enable WebSocket transport." ON) mark_as_advanced(NNG_TRANSPORT_WS) diff --git a/demo/mqtt_async/CMakeLists.txt b/demo/mqtt_async/CMakeLists.txt index ca7d3caf6..c4b09eeb3 100644 --- a/demo/mqtt_async/CMakeLists.txt +++ b/demo/mqtt_async/CMakeLists.txt @@ -9,9 +9,10 @@ cmake_minimum_required (VERSION 2.8.7) project(mqtt_async) find_package(nng CONFIG REQUIRED) - find_package(Threads) +find_package(MbedTLS) add_executable(mqtt_async mqtt_async.c) -target_link_libraries(mqtt_async nng) +target_link_libraries(mqtt_async nng ) +target_link_libraries(mqtt_async mbedtls mbedx509 mbedcrypto) target_link_libraries(mqtt_async ${CMAKE_THREAD_LIBS_INIT}) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index 5e2ac1877..c156fd192 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -7,6 +7,7 @@ #include #include +#include #include #ifndef PARALLEL @@ -200,18 +201,120 @@ client(const char *url) } } +static int +init_dialer_tls_ex( + nng_dialer d, const char *cert, const char *key, bool own_cert) +{ + nng_tls_config *cfg; + int rv; + + if ((rv = nng_tls_config_alloc(&cfg, NNG_TLS_MODE_CLIENT)) != 0) { + return (rv); + } + + if ((rv = nng_tls_config_ca_chain(cfg, cert, NULL)) != 0) { + goto out; + } + + if ((rv = nng_tls_config_server_name(cfg, "www.fabric.com")) != 0) { + goto out; + } + // nng_tls_config_auth_mode(cfg, NNG_TLS_AUTH_MODE_REQUIRED); + nng_tls_config_auth_mode(cfg, NNG_TLS_AUTH_MODE_NONE); + + if (own_cert) { + if ((rv = nng_tls_config_own_cert(cfg, cert, key, NULL)) != + 0) { + goto out; + } + } + + rv = nng_dialer_setopt_ptr(d, NNG_OPT_TLS_CONFIG, cfg); + +out: + nng_tls_config_free(cfg); + return (rv); +} + +static int +init_dialer_tls(nng_dialer d, const char *cert, const char *key) +{ + return (init_dialer_tls_ex(d, cert, key, false)); +} + int -main(int argc, const char **argv) +tls_client(const char *url, const char *cert, const char *key) { + nng_socket sock; + nng_dialer dialer; + struct work *works[PARALLEL]; + int i; + int rv; + + if ((rv = nng_mqtt_client_open(&sock)) != 0) { + fatal("nng_socket", rv); + } + + for (i = 0; i < PARALLEL; i++) { + works[i] = alloc_work(sock, i); + } + + if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { + fatal("nng_dialer_create", rv); + } - int rc; + // Mqtt connect message + nng_msg *msg; + nng_mqtt_msg_alloc(&msg, 0); + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); + nng_mqtt_msg_set_connect_keep_alive(msg, 60); + nng_mqtt_msg_set_connect_clean_session(msg, true); + + init_dialer_tls(dialer, cert, key); + nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); + nng_dialer_set_cb(dialer, connect_cb, NULL); + nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); + + nng_msleep(1000); + + for (i = 0; i < PARALLEL; i++) { + client_cb(works[i]); + } + + for (;;) { + nng_msleep(3600000); // neither pause() nor sleep() portable + } +} + +int +main(int argc, const char **argv) +{ + int rc; + char *url; + char *cert; + char *key; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(EXIT_FAILURE); } - client(argv[1]); + url = (char *) argv[1]; + + if (argc >= 3) { + cert = (char *)argv[2]; + if (argc >= 4) { + key = (char *)argv[3]; + } + + tls_client(url, cert, key); + + nng_strfree(cert); + nng_strfree(key); + + } else { + client(url); + } return 0; } diff --git a/include/nng/transport/mqtts/mqtt_tls.h b/include/nng/transport/mqtts/mqtt_tls.h new file mode 100644 index 000000000..5606d04e0 --- /dev/null +++ b/include/nng/transport/mqtts/mqtt_tls.h @@ -0,0 +1,30 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2017 Capitar IT Group BV +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef NNG_TRANSPORT_MQTT_TLS_TLS_H +#define NNG_TRANSPORT_MQTT_TLS_TLS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// TCP transport. This is used for communication over TCP/IP. + +#ifndef NNG_ELIDE_DEPRECATED +NNG_DECL int nng_mqtts_tcp_register(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif // NNG_TRANSPORT_MQTT_TLS_TLS_H diff --git a/src/core/stream.c b/src/core/stream.c index 27560d09b..ea57e2800 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -59,6 +59,21 @@ static struct { .dialer_alloc = nni_tcp_dialer_alloc, .listener_alloc = nni_tcp_listener_alloc, }, + { + .scheme = "tls+mqtt-tcp", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, + { + .scheme = "tls+mqtt-tcp4", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, + { + .scheme = "tls+mqtt-tcp6", + .dialer_alloc = nni_tcp_dialer_alloc, + .listener_alloc = nni_tcp_listener_alloc, + }, { .scheme = "tcp", .dialer_alloc = nni_tcp_dialer_alloc, diff --git a/src/nng.c b/src/nng.c index f1878cef5..af373b669 100644 --- a/src/nng.c +++ b/src/nng.c @@ -1909,7 +1909,7 @@ nng_version(void) NNG_PATCH_VERSION) NNG_RELEASE_SUFFIX); } -#ifdef NNG_TRANSPORT_MQTT_TCP +#if defined(NNG_TRANSPORT_MQTT_TCP) || defined(NNG_TRANSPORT_MQTT_TLS) int nng_mqtt_msg_proto_data_alloc(nng_msg *msg) diff --git a/src/sp/transport.c b/src/sp/transport.c index e69030bd8..fc215e57d 100644 --- a/src/sp/transport.c +++ b/src/sp/transport.c @@ -60,6 +60,9 @@ extern void nni_sp_tcp_register(void); #ifdef NNG_TRANSPORT_MQTT_TCP extern void nni_mqtt_tcp_register(); #endif +#ifdef NNG_TRANSPORT_MQTT_TLS +extern void nni_mqtts_tcp_register(); +#endif #ifdef NNG_TRANSPORT_TLS extern void nni_sp_tls_register(void); #endif @@ -91,6 +94,9 @@ nni_sp_tran_sys_init(void) #ifdef NNG_TRANSPORT_MQTT_TCP nni_mqtt_tcp_register(); #endif +#ifdef NNG_TRANSPORT_MQTT_TLS + nni_mqtts_tcp_register(); +#endif #ifdef NNG_TRANSPORT_TLS nni_sp_tls_register(); #endif diff --git a/src/sp/transport/CMakeLists.txt b/src/sp/transport/CMakeLists.txt index fdc04e865..9bf80791c 100644 --- a/src/sp/transport/CMakeLists.txt +++ b/src/sp/transport/CMakeLists.txt @@ -16,5 +16,6 @@ add_subdirectory(tcp) add_subdirectory(tls) add_subdirectory(ws) add_subdirectory(mqtt) +add_subdirectory(mqtts) add_subdirectory(zerotier) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 6574d13be..640299a72 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -85,14 +85,14 @@ struct mqtt_tcptran_ep { #endif }; -static void mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *); -static void mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *); -static void mqtt_tcptran_pipe_send_cb(void *); -static void mqtt_tcptran_pipe_recv_cb(void *); -static void mqtt_tcptran_pipe_nego_cb(void *); -static void mqtt_tcptran_ep_fini(void *); -static void mqtt_tcptran_pipe_fini(void *); -uint16_t nni_msg_get_pub_pid(nni_msg *m); +static void mqtt_tcptran_pipe_send_start(mqtt_tcptran_pipe *); +static void mqtt_tcptran_pipe_recv_start(mqtt_tcptran_pipe *); +static void mqtt_tcptran_pipe_send_cb(void *); +static void mqtt_tcptran_pipe_recv_cb(void *); +static void mqtt_tcptran_pipe_nego_cb(void *); +static void mqtt_tcptran_ep_fini(void *); +static void mqtt_tcptran_pipe_fini(void *); +static uint16_t nni_msg_get_pub_pid(nni_msg *m); static nni_reap_list tcptran_ep_reap_list = { .rl_offset = offsetof(mqtt_tcptran_ep, reap), @@ -114,7 +114,7 @@ mqtt_tcptran_fini(void) { } -uint16_t +static uint16_t nni_msg_get_pub_pid(nni_msg *m) { uint16_t pid; @@ -557,7 +557,7 @@ mqtt_tcptran_pipe_recv_cb(void *arg) mqtt_tcptran_pipe_recv_start(p); nni_aio_set_msg(aio, msg); - nni_mtx_unlock(&p->mtx); + nni_mtx_unlock(&p->mtx); nni_aio_finish_sync(aio, 0, n); return; @@ -572,13 +572,13 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_aio_finish_error(aio, rv); printf("mqtt_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); return; -notify: - // nni_pipe_bump_rx(p->npipe, n); - nni_aio_list_remove(aio); - mqtt_tcptran_pipe_recv_start(p); - nni_mtx_unlock(&p->mtx); - nni_aio_set_msg(aio, NULL); - nni_aio_finish(aio, 0, 0); + // notify: + // // nni_pipe_bump_rx(p->npipe, n); + // nni_aio_list_remove(aio); + // mqtt_tcptran_pipe_recv_start(p); + // nni_mtx_unlock(&p->mtx); + // nni_aio_set_msg(aio, NULL); + // nni_aio_finish(aio, 0, 0); return; } @@ -780,8 +780,8 @@ mqtt_tcptran_pipe_start( p->ep = ep; p->proto = ep->proto; - rv = nni_dialer_getopt( - ep->ndialer, NNG_OPT_MQTT_CONNMSG, &connmsg, NULL, NNI_TYPE_POINTER); + rv = nni_dialer_getopt(ep->ndialer, NNG_OPT_MQTT_CONNMSG, &connmsg, + NULL, NNI_TYPE_POINTER); if (!connmsg) { nni_list_append(&ep->waitpipes, p); mqtt_tcptran_ep_match(ep); diff --git a/src/sp/transport/mqtts/CMakeLists.txt b/src/sp/transport/mqtts/CMakeLists.txt new file mode 100644 index 000000000..5a026f670 --- /dev/null +++ b/src/sp/transport/mqtts/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright 2020 Staysail Systems, Inc. +# Copyright 2018 Capitar IT Group BV +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. +# + +# TCP protocol +nng_directory(mqtts) + +nng_sources_if(NNG_TRANSPORT_MQTT_TLS mqtt_tls.c) +nng_headers_if(NNG_TRANSPORT_MQTT_TLS nng/transport/mqtts/mqtt_tls.h) +nng_defines_if(NNG_TRANSPORT_MQTT_TLS NNG_TRANSPORT_MQTT_TLS) diff --git a/src/sp/transport/mqtts/mqtt_tls.c b/src/sp/transport/mqtts/mqtt_tls.c new file mode 100644 index 000000000..4b873b350 --- /dev/null +++ b/src/sp/transport/mqtts/mqtt_tls.c @@ -0,0 +1,1527 @@ +// +// Copyright 2021 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// Copyright 2019 Devolutions +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include +#include +#include + +#include "core/nng_impl.h" +#include "mqtt/mqtt.h" +#include "nng/supplemental/tls/tls.h" + +// TLS Over TCP transport. Platform specific TLS Over TCP operations must be +// supplied as well. + +typedef struct mqtts_tcptran_pipe mqtts_tcptran_pipe; +typedef struct mqtts_tcptran_ep mqtts_tcptran_ep; + +#define NNI_NANO_MAX_HEADER_SIZE 5 + +// tcp_pipe is one end of a TCP connection. +struct mqtts_tcptran_pipe { + nng_stream * conn; + nni_pipe * npipe; + uint16_t peer; + uint16_t proto; + size_t rcvmax; + bool closed; + nni_list_node node; + mqtts_tcptran_ep *ep; + nni_atomic_flag reaped; + nni_reap_node reap; + uint8_t txlen[sizeof(uint64_t)]; + uint8_t rxlen[sizeof(uint64_t)]; // fixed header + size_t gottxhead; + size_t gotrxhead; + size_t wanttxhead; + size_t wantrxhead; + nni_list recvq; + nni_list sendq; + nni_aio * txaio; + nni_aio * rxaio; + nni_aio * rsaio; + nni_aio * qsaio; + nni_aio * rpaio; + nni_aio * negoaio; + nni_msg * rxmsg; + nni_msg * smsg; + nni_mtx mtx; +}; + +struct mqtts_tcptran_ep { + nni_mtx mtx; + uint16_t proto; + size_t rcvmax; + bool fini; + bool started; + bool closed; + nng_url * url; + const char * host; // for dialers + nng_sockaddr src; + nng_sockaddr sa; + int refcnt; // active pipes + int authmode; + nni_aio * useraio; + nni_aio * connaio; + nni_aio * timeaio; + nni_list busypipes; // busy pipes -- ones passed to socket + nni_list waitpipes; // pipes waiting to match to socket + nni_list negopipes; // pipes busy negotiating + nni_reap_node reap; + nng_stream_dialer * dialer; + nng_stream_listener *listener; + nni_dialer * ndialer; + void * connmsg; + void (*conncb)(void *, nng_msg *); + void *arg; + +#ifdef NNG_ENABLE_STATS + nni_stat_item st_rcv_max; +#endif +}; + +static void mqtts_tcptran_pipe_send_start(mqtts_tcptran_pipe *); +static void mqtts_tcptran_pipe_recv_start(mqtts_tcptran_pipe *); +static void mqtts_tcptran_pipe_send_cb(void *); +static void mqtts_tcptran_pipe_recv_cb(void *); +static void mqtts_tcptran_pipe_nego_cb(void *); +static void mqtts_tcptran_ep_fini(void *); +static void mqtts_tcptran_pipe_fini(void *); +static uint16_t nni_msg_get_pub_pid(nni_msg *m); + +static nni_reap_list tcptran_ep_reap_list = { + .rl_offset = offsetof(mqtts_tcptran_ep, reap), + .rl_func = mqtts_tcptran_ep_fini, +}; + +static nni_reap_list tcptran_pipe_reap_list = { + .rl_offset = offsetof(mqtts_tcptran_pipe, reap), + .rl_func = mqtts_tcptran_pipe_fini, +}; + +static void +mqtts_tcptran_init(void) +{ +} + +static void +mqtts_tcptran_fini(void) +{ +} + +static uint16_t +nni_msg_get_pub_pid(nni_msg *m) +{ + uint16_t pid; + uint8_t *pos, len; + + pos = nni_msg_body(m); + NNI_GET16(pos, len); + NNI_GET16(pos + len + 2, pid); + return pid; +} + +static void +mqtts_tcptran_pipe_close(void *arg) +{ + mqtts_tcptran_pipe *p = arg; + + // nni_mtx_lock(&p->mtx); + // p->closed = true; + // nni_mtx_unlock(&p->mtx); + + nni_aio_close(p->rxaio); + nni_aio_close(p->rsaio); + nni_aio_close(p->qsaio); + nni_aio_close(p->txaio); + nni_aio_close(p->rpaio); + nni_aio_close(p->negoaio); + + nng_stream_close(p->conn); +} + +static void +mqtts_tcptran_pipe_stop(void *arg) +{ + mqtts_tcptran_pipe *p = arg; + + nni_aio_stop(p->rxaio); + nni_aio_stop(p->rsaio); + nni_aio_stop(p->qsaio); + nni_aio_stop(p->rpaio); + nni_aio_stop(p->txaio); + nni_aio_stop(p->negoaio); +} + +static int +mqtts_tcptran_pipe_init(void *arg, nni_pipe *npipe) +{ + mqtts_tcptran_pipe *p = arg; + p->npipe = npipe; + + return (0); +} + +static void +mqtts_tcptran_pipe_fini(void *arg) +{ + mqtts_tcptran_pipe *p = arg; + mqtts_tcptran_ep * ep; + + mqtts_tcptran_pipe_stop(p); + if ((ep = p->ep) != NULL) { + nni_mtx_lock(&ep->mtx); + nni_list_node_remove(&p->node); + ep->refcnt--; + if (ep->fini && (ep->refcnt == 0)) { + nni_reap(&tcptran_ep_reap_list, ep); + } + nni_mtx_unlock(&ep->mtx); + } + + nni_aio_free(p->rxaio); + nni_aio_free(p->txaio); + nni_aio_free(p->rsaio); + nni_aio_free(p->qsaio); + nni_aio_free(p->rpaio); + nni_aio_free(p->negoaio); + nng_stream_free(p->conn); + nni_msg_free(p->rxmsg); + // nni_mtx_fini(&p->mtx); + NNI_FREE_STRUCT(p); +} + +static void +mqtts_tcptran_pipe_reap(mqtts_tcptran_pipe *p) +{ + if (!nni_atomic_flag_test_and_set(&p->reaped)) { + if (p->conn != NULL) { + nng_stream_close(p->conn); + } + nni_reap(&tcptran_pipe_reap_list, p); + } +} + +static int +mqtts_tcptran_pipe_alloc(mqtts_tcptran_pipe **pipep) +{ + mqtts_tcptran_pipe *p; + int rv; + + if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&p->mtx); + if (((rv = nni_aio_alloc(&p->txaio, mqtts_tcptran_pipe_send_cb, p)) != + 0) || + ((rv = nni_aio_alloc(&p->rxaio, mqtts_tcptran_pipe_recv_cb, p)) != + 0) || + ((rv = nni_aio_alloc(&p->rsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->qsaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc(&p->rpaio, NULL, p)) != 0) || + ((rv = nni_aio_alloc( + &p->negoaio, mqtts_tcptran_pipe_nego_cb, p)) != 0)) { + mqtts_tcptran_pipe_fini(p); + return (rv); + } + nni_aio_list_init(&p->recvq); + nni_aio_list_init(&p->sendq); + nni_atomic_flag_reset(&p->reaped); + + *pipep = p; + + return (0); +} + +static void +mqtts_tcptran_ep_match(mqtts_tcptran_ep *ep) +{ + nni_aio * aio; + mqtts_tcptran_pipe *p; + + if (((aio = ep->useraio) == NULL) || + ((p = nni_list_first(&ep->waitpipes)) == NULL)) { + return; + } + nni_list_remove(&ep->waitpipes, p); + nni_list_append(&ep->busypipes, p); + ep->useraio = NULL; + p->rcvmax = ep->rcvmax; + nni_aio_set_output(aio, 0, p); + nni_aio_finish(aio, 0, 0); +} + +static void +mqtts_tcptran_pipe_nego_cb(void *arg) +{ + mqtts_tcptran_pipe *p = arg; + mqtts_tcptran_ep * ep = p->ep; + nni_aio * aio = p->negoaio; + nni_aio * uaio; + int rv; + uint8_t pos = 0; + int var_int; + nni_msg * rmsg = p->rxmsg; + + nni_mtx_lock(&ep->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + // We start transmitting before we receive. + if (p->gottxhead < p->wanttxhead) { + p->gottxhead += nni_aio_count(aio); + } else if (p->gotrxhead < p->wantrxhead) { + p->gotrxhead += nni_aio_count(aio); + } + + if (p->gottxhead < p->wanttxhead) { + nni_iov iov; + iov.iov_len = p->wanttxhead - p->gottxhead; + iov.iov_buf = &p->txlen[p->gottxhead]; + // send it down... + nni_aio_set_iov(aio, 1, &iov); + nng_stream_send(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + + // receving fixed header + if (p->gotrxhead == 0 || + (p->gotrxhead <= 5 && p->rxlen[p->gotrxhead - 1] > 0x7f && + p->rxmsg == NULL)) { + nni_iov iov; + iov.iov_buf = &p->rxlen[p->gotrxhead]; + if (p->gotrxhead == 0) { + iov.iov_len = p->wantrxhead - p->gotrxhead; + } else { + iov.iov_len = 1; + } + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + + // finish recevied fixed header + if (p->rxmsg == NULL) { + if ((p->rxlen[0] & 0x20) != 0x20) { + rv = NNG_EPROTO; + goto error; + } + + pos = 0; + if ((rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, + (uint32_t *) &var_int, &pos)) != 0) { + goto error; + } + + if ((rv = nni_mqtt_msg_alloc(&p->rxmsg, var_int)) != 0) { + rv = NNG_ENOMEM; + goto error; + } + + nni_msg_header_append(p->rxmsg, p->rxlen, pos + 1); + + p->wantrxhead = var_int + 1 + pos; + if ((rv = (p->wantrxhead <= 4) ? 0 : NNG_EPROTO) != 0) { + // TODO BUG here + goto error; + } + } + // remaining length + // TODO CPU Waste + if (p->gotrxhead < p->wantrxhead) { + nni_iov iov; + iov.iov_len = p->wantrxhead - p->gotrxhead; + iov.iov_buf = nni_msg_body(p->rxmsg); + nni_aio_set_iov(aio, 1, &iov); + nng_stream_recv(p->conn, aio); + nni_mtx_unlock(&ep->mtx); + return; + } + if (p->gotrxhead >= p->wantrxhead) { + nni_mqtt_msg_decode(p->rxmsg); + p->rxmsg = NULL; + } + + // We are all ready now. We put this in the wait list, and + // then try to run the matcher. + nni_list_remove(&ep->negopipes, p); + nni_list_append(&ep->waitpipes, p); + + mqtts_tcptran_ep_match(ep); + nni_mtx_unlock(&ep->mtx); + + // Run user callback + if (ep->conncb != NULL) { + ep->conncb(ep->arg, rmsg); + } + + return; + +error: + nng_stream_close(p->conn); + + if (p->rxmsg != NULL) { + nni_msg_free(p->rxmsg); + p->rxmsg = NULL; + } + + if ((uaio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(uaio, rv); + } + nni_mtx_unlock(&ep->mtx); + mqtts_tcptran_pipe_reap(p); +} + +static void +mqtts_tcptran_pipe_send_cb(void *arg) +{ + mqtts_tcptran_pipe *p = arg; + int rv; + nni_aio * aio; + size_t n; + nni_msg * msg; + nni_aio * txaio = p->txaio; + + nni_mtx_lock(&p->mtx); + aio = nni_list_first(&p->sendq); + + if ((rv = nni_aio_result(txaio)) != 0) { + + // Intentionally we do not queue up another transfer. + // There's an excellent chance that the pipe is no longer + // usable, with a partial transfer. + // The protocol should see this error, and close the + // pipe itself, we hope. + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + nni_pipe_bump_error(p->npipe, rv); + return; + } + + n = nni_aio_count(txaio); + nni_aio_iov_advance(txaio, n); + if (nni_aio_iov_count(txaio) > 0) { + nng_stream_send(p->conn, txaio); + nni_mtx_unlock(&p->mtx); + return; + } + + nni_aio_list_remove(aio); + mqtts_tcptran_pipe_send_start(p); + + msg = nni_aio_get_msg(aio); + n = nni_msg_len(msg); + nni_pipe_bump_tx(p->npipe, n); + nni_mtx_unlock(&p->mtx); + + nni_aio_set_msg(aio, NULL); + nni_msg_free(msg); + nni_aio_finish_sync(aio, 0, n); +} + +static void +mqtts_tcptran_pipe_recv_cb(void *arg) +{ + nni_aio * aio; + nni_iov iov; + uint8_t type, pos, flags; + uint32_t len = 0, rv; + size_t n; + nni_msg * msg; + mqtts_tcptran_pipe *p = arg; + nni_aio * rxaio = p->rxaio; + + nni_mtx_lock(&p->mtx); + + aio = nni_list_first(&p->recvq); + + if ((rv = nni_aio_result(rxaio)) != 0) { + goto recv_error; + } + + n = nni_aio_count(rxaio); + p->gotrxhead += n; + + nni_aio_iov_advance(rxaio, n); + + rv = mqtt_get_remaining_length(p->rxlen, p->gotrxhead, &len, &pos); + p->wantrxhead = len + 1 + pos; + if (p->gotrxhead <= 5 && p->rxlen[p->gotrxhead - 1] > 0x7f) { + if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { + rv = NNG_EMSGSIZE; + goto recv_error; + } + // same packet, continue receving next byte of remaining length + iov.iov_buf = &p->rxlen[p->gotrxhead]; + iov.iov_len = 1; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + + // fixed header finished + if (NULL == p->rxmsg) { + // Make sure the message payload is not too big. If it is + // the caller will shut down the pipe. + // if ((len > p->rcvmax) && (p->rcvmax > 0)) { + // rv = NNG_EMSGSIZE; + // goto recv_error; + // } + + if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + goto recv_error; + } + + // Submit the rest of the data for a read -- seperate Fixed + // header with variable header and so on + // we want to read the entire message now. + if (len != 0) { + iov.iov_buf = nni_msg_body(p->rxmsg); + iov.iov_len = (size_t) len; + + nni_aio_set_iov(rxaio, 1, &iov); + // second recv action + nng_stream_recv(p->conn, rxaio); + nni_mtx_unlock(&p->mtx); + return; + } + } + + // We read a message completely. Let the user know the good news. use + // as application message callback of users + nni_aio_list_remove(aio); + nni_msg_header_append(p->rxmsg, p->rxlen, pos + 1); + msg = p->rxmsg; + p->rxmsg = NULL; + n = nni_msg_len(msg); + type = p->rxlen[0] & 0xf0; + flags = p->rxlen[0] & 0x0f; + // set the payload pointer of msg according to packet_type + if (type == 0x30) { + uint8_t qos_pac; + uint16_t pid; + + qos_pac = nni_msg_get_pub_qos(msg); + if (qos_pac > 0) { + nng_aio_wait(p->rsaio); + if (qos_pac == 1) { + p->txlen[0] = 0X40; + } else if (qos_pac == 2) { + p->txlen[0] = 0X50; + } + p->txlen[1] = 0x02; + pid = nni_msg_get_pub_pid(msg); + NNI_PUT16(p->txlen + 2, pid); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + printf("PUBRECV\n"); + nni_aio_set_iov(p->rsaio, 1, &iov); + nng_stream_send(p->conn, p->rsaio); + } + } else if (type == 0x50) { + nng_aio_wait(p->qsaio); + p->txlen[0] = 0X62; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(msg), 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + nni_aio_set_iov(p->qsaio, 1, &iov); + nng_stream_send(p->conn, p->qsaio); + } else if (type == 0x60 && flags == 0x02) { + nng_aio_wait(p->rpaio); + p->txlen[0] = 0x70; + p->txlen[1] = 0x02; + memcpy(p->txlen + 2, nni_msg_body(msg), 2); + iov.iov_len = 4; + iov.iov_buf = &p->txlen; + // send it down... + printf("PUBCOMP\n"); + nni_aio_set_iov(p->rpaio, 1, &iov); + nng_stream_send(p->conn, p->rpaio); + } + + // keep connection & Schedule next receive + // nni_pipe_bump_rx(p->npipe, n); + if (!nni_list_empty(&p->recvq)) { + mqtts_tcptran_pipe_recv_start(p); + } + + nni_aio_set_msg(aio, msg); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_sync(aio, 0, n); + return; + +recv_error: + nni_aio_list_remove(aio); + msg = p->rxmsg; + p->rxmsg = NULL; + nni_pipe_bump_error(p->npipe, rv); + nni_mtx_unlock(&p->mtx); + + nni_msg_free(msg); + nni_aio_finish_error(aio, rv); + printf("mqtts_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); + return; +// notify: +// // nni_pipe_bump_rx(p->npipe, n); +// nni_aio_list_remove(aio); +// mqtts_tcptran_pipe_recv_start(p); +// nni_mtx_unlock(&p->mtx); +// nni_aio_set_msg(aio, NULL); +// nni_aio_finish(aio, 0, 0); + return; +} + +static void +mqtts_tcptran_pipe_send_cancel(nni_aio *aio, void *arg, int rv) +{ + mqtts_tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (!nni_aio_list_active(aio)) { + nni_mtx_unlock(&p->mtx); + return; + } + // If this is being sent, then cancel the pending transfer. + // The callback on the txaio will cause the user aio to + // be canceled too. + if (nni_list_first(&p->sendq) == aio) { + nni_aio_abort(p->txaio, rv); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + + nni_aio_finish_error(aio, rv); +} + +static void +mqtts_tcptran_pipe_send_start(mqtts_tcptran_pipe *p) +{ + nni_aio *aio; + nni_aio *txaio; + nni_msg *msg; + int niov; + nni_iov iov[3]; + // uint64_t len; + + if ((aio = nni_list_first(&p->sendq)) == NULL) { + return; + } + + // This runs to send the message. + msg = nni_aio_get_msg(aio); + + // len = nni_msg_len(msg) + nni_msg_header_len(msg); + // NNI_PUT64(p->txlen, len); + + txaio = p->txaio; + niov = 0; + + if (nni_msg_header_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_header(msg); + iov[niov].iov_len = nni_msg_header_len(msg); + niov++; + } + if (nni_msg_len(msg) > 0) { + iov[niov].iov_buf = nni_msg_body(msg); + iov[niov].iov_len = nni_msg_len(msg); + niov++; + } + nni_aio_set_iov(txaio, niov, iov); + nng_stream_send(p->conn, txaio); +} + +static void +mqtts_tcptran_pipe_send(void *arg, nni_aio *aio) +{ + mqtts_tcptran_pipe *p = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, mqtts_tcptran_pipe_send_cancel, p)) != + 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + nni_list_append(&p->sendq, aio); + if (nni_list_first(&p->sendq) == aio) { + mqtts_tcptran_pipe_send_start(p); + } + nni_mtx_unlock(&p->mtx); +} + +static void +mqtts_tcptran_pipe_recv_cancel(nni_aio *aio, void *arg, int rv) +{ + mqtts_tcptran_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (!nni_aio_list_active(aio)) { + nni_mtx_unlock(&p->mtx); + return; + } + // If receive in progress, then cancel the pending transfer. + // The callback on the rxaio will cause the user aio to + // be canceled too. + if (nni_list_first(&p->recvq) == aio) { + nni_aio_abort(p->rxaio, rv); + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_list_remove(aio); + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); +} + +static void +mqtts_tcptran_pipe_recv_start(mqtts_tcptran_pipe *p) +{ + nni_aio *rxaio; + nni_iov iov; + NNI_ASSERT(p->rxmsg == NULL); + + // Schedule a read of the header. + rxaio = p->rxaio; + p->gotrxhead = 0; + p->wantrxhead = 2; + iov.iov_buf = p->rxlen; + iov.iov_len = 2; + nni_aio_set_iov(rxaio, 1, &iov); + nng_stream_recv(p->conn, rxaio); +} + +static void +mqtts_tcptran_pipe_recv(void *arg, nni_aio *aio) +{ + mqtts_tcptran_pipe *p = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&p->mtx); + if ((rv = nni_aio_schedule(aio, mqtts_tcptran_pipe_recv_cancel, p)) != + 0) { + nni_mtx_unlock(&p->mtx); + nni_aio_finish_error(aio, rv); + return; + } + + nni_aio_list_append(&p->recvq, aio); + if (nni_list_first(&p->recvq) == aio) { + mqtts_tcptran_pipe_recv_start(p); + } + nni_mtx_unlock(&p->mtx); +} + +static uint16_t +mqtts_tcptran_pipe_peer(void *arg) +{ + mqtts_tcptran_pipe *p = arg; + + return (p->peer); +} + +static int +mqtts_tcptran_pipe_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + mqtts_tcptran_pipe *p = arg; + return (nni_stream_get(p->conn, name, buf, szp, t)); +} + +static void +mqtts_tcptran_pipe_start( + mqtts_tcptran_pipe *p, nng_stream *conn, mqtts_tcptran_ep *ep) +{ + nni_iov iov[2]; + nni_msg *connmsg; + int rv, niov = 0; + + ep->refcnt++; + + p->conn = conn; + p->ep = ep; + p->proto = ep->proto; + + rv = nni_dialer_getopt(ep->ndialer, NNG_OPT_MQTT_CONNMSG, &connmsg, + NULL, NNI_TYPE_POINTER); + if (!connmsg) { + nni_list_append(&ep->waitpipes, p); + mqtts_tcptran_ep_match(ep); + return; + } + if ((rv = nni_mqtt_msg_encode(connmsg)) != 0) { + nni_list_append(&ep->waitpipes, p); + mqtts_tcptran_ep_match(ep); + return; + } + + p->gotrxhead = 0; + p->gottxhead = 0; + // TODO TX length for MQTT 5 + p->wantrxhead = 2; + p->wanttxhead = nni_msg_header_len(connmsg) + nni_msg_len(connmsg); + p->rxmsg = NULL; + + if (nni_msg_header_len(connmsg) > 0) { + iov[niov].iov_buf = nni_msg_header(connmsg); + iov[niov].iov_len = nni_msg_header_len(connmsg); + niov++; + } + if (nni_msg_len(connmsg) > 0) { + iov[niov].iov_buf = nni_msg_body(connmsg); + iov[niov].iov_len = nni_msg_len(connmsg); + niov++; + } + nni_aio_set_iov(p->negoaio, niov, iov); + nni_list_append(&ep->negopipes, p); + + nni_aio_set_timeout(p->negoaio, 10000); // 10 sec timeout to negotiate + nng_stream_send(p->conn, p->negoaio); +} + +static void +mqtts_tcptran_ep_fini(void *arg) +{ + mqtts_tcptran_ep *ep = arg; + + nni_mtx_lock(&ep->mtx); + ep->fini = true; + if (ep->refcnt != 0) { + nni_mtx_unlock(&ep->mtx); + return; + } + nni_mtx_unlock(&ep->mtx); + nni_aio_stop(ep->timeaio); + nni_aio_stop(ep->connaio); + nng_stream_dialer_free(ep->dialer); + nng_stream_listener_free(ep->listener); + nni_aio_free(ep->timeaio); + nni_aio_free(ep->connaio); + + nni_mtx_fini(&ep->mtx); + NNI_FREE_STRUCT(ep); +} + +static void +mqtts_tcptran_ep_close(void *arg) +{ + mqtts_tcptran_ep * ep = arg; + mqtts_tcptran_pipe *p; + + nni_mtx_lock(&ep->mtx); + + ep->closed = true; + nni_aio_close(ep->timeaio); + if (ep->dialer != NULL) { + nng_stream_dialer_close(ep->dialer); + } + if (ep->listener != NULL) { + nng_stream_listener_close(ep->listener); + } + NNI_LIST_FOREACH (&ep->negopipes, p) { + mqtts_tcptran_pipe_close(p); + } + NNI_LIST_FOREACH (&ep->waitpipes, p) { + mqtts_tcptran_pipe_close(p); + } + NNI_LIST_FOREACH (&ep->busypipes, p) { + mqtts_tcptran_pipe_close(p); + } + if (ep->useraio != NULL) { + nni_aio_finish_error(ep->useraio, NNG_ECLOSED); + ep->useraio = NULL; + } + + nni_mtx_unlock(&ep->mtx); +} + +// This parses off the optional source address that this transport uses. +// The special handling of this URL format is quite honestly an historical +// mistake, which we would remove if we could. +static int +mqtts_tcptran_url_parse_source( + nng_url *url, nng_sockaddr *sa, const nng_url *surl) +{ + int af; + char * semi; + char * src; + size_t len; + int rv; + nni_aio *aio; + + // We modify the URL. This relies on the fact that the underlying + // transport does not free this, so we can just use references. + + url->u_scheme = surl->u_scheme; + url->u_port = surl->u_port; + url->u_hostname = surl->u_hostname; + + if ((semi = strchr(url->u_hostname, ';')) == NULL) { + memset(sa, 0, sizeof(*sa)); + return (0); + } + + len = (size_t)(semi - url->u_hostname); + url->u_hostname = semi + 1; + + if (strcmp(surl->u_scheme, "tls+tcp") == 0) { + af = NNG_AF_UNSPEC; + } else if (strcmp(surl->u_scheme, "tls+tcp4") == 0) { + af = NNG_AF_INET; + } else if (strcmp(surl->u_scheme, "tls+tcp6") == 0) { + af = NNG_AF_INET6; + } else { + return (NNG_EADDRINVAL); + } + + if ((src = nni_alloc(len + 1)) == NULL) { + return (NNG_ENOMEM); + } + memcpy(src, surl->u_hostname, len); + src[len] = '\0'; + + if ((rv = nni_aio_alloc(&aio, NULL, NULL)) != 0) { + nni_free(src, len + 1); + return (rv); + } + + nni_resolv_ip(src, "0", af, true, sa, aio); + nni_aio_wait(aio); + rv = nni_aio_result(aio); + nni_aio_free(aio); + nni_free(src, len + 1); + return (rv); +} + +static void +mqtts_tcptran_timer_cb(void *arg) +{ + mqtts_tcptran_ep *ep = arg; + if (nni_aio_result(ep->timeaio) == 0) { + nng_stream_listener_accept(ep->listener, ep->connaio); + } +} + +static void +mqtts_tcptran_accept_cb(void *arg) +{ + mqtts_tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + mqtts_tcptran_pipe *p; + int rv; + nng_stream * conn; + + nni_mtx_lock(&ep->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + conn = nni_aio_get_output(aio, 0); + if ((rv = mqtts_tcptran_pipe_alloc(&p)) != 0) { + nng_stream_free(conn); + goto error; + } + + if (ep->closed) { + mqtts_tcptran_pipe_fini(p); + nng_stream_free(conn); + rv = NNG_ECLOSED; + goto error; + } + mqtts_tcptran_pipe_start(p, conn, ep); + nng_stream_listener_accept(ep->listener, ep->connaio); + nni_mtx_unlock(&ep->mtx); + return; + +error: + // When an error here occurs, let's send a notice up to the consumer. + // That way it can be reported properly. + if ((aio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + switch (rv) { + + case NNG_ENOMEM: + case NNG_ENOFILES: + nng_sleep_aio(10, ep->timeaio); + break; + + default: + if (!ep->closed) { + nng_stream_listener_accept(ep->listener, ep->connaio); + } + break; + } + nni_mtx_unlock(&ep->mtx); +} + +static void +mqtts_tcptran_dial_cb(void *arg) +{ + mqtts_tcptran_ep * ep = arg; + nni_aio * aio = ep->connaio; + mqtts_tcptran_pipe *p; + int rv; + nng_stream * conn; + + if ((rv = nni_aio_result(aio)) != 0) { + goto error; + } + + conn = nni_aio_get_output(aio, 0); + if ((rv = mqtts_tcptran_pipe_alloc(&p)) != 0) { + nng_stream_free(conn); + goto error; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + mqtts_tcptran_pipe_fini(p); + nng_stream_free(conn); + rv = NNG_ECLOSED; + nni_mtx_unlock(&ep->mtx); + goto error; + } else { + mqtts_tcptran_pipe_start(p, conn, ep); + } + nni_mtx_unlock(&ep->mtx); + return; + +error: + // Error connecting. We need to pass this straight back + // to the user. + nni_mtx_lock(&ep->mtx); + if ((aio = ep->useraio) != NULL) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + +static int +mqtts_tcptran_ep_init(mqtts_tcptran_ep **epp, nng_url *url, nni_sock *sock) +{ + mqtts_tcptran_ep *ep; + + if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&ep->mtx); + NNI_LIST_INIT(&ep->busypipes, mqtts_tcptran_pipe, node); + NNI_LIST_INIT(&ep->waitpipes, mqtts_tcptran_pipe, node); + NNI_LIST_INIT(&ep->negopipes, mqtts_tcptran_pipe, node); + + ep->proto = nni_sock_proto_id(sock); + ep->url = url; + ep->conncb = NULL; + ep->arg = NULL; + +#ifdef NNG_ENABLE_STATS + static const nni_stat_info rcv_max_info = { + .si_name = "rcv_max", + .si_desc = "maximum receive size", + .si_type = NNG_STAT_LEVEL, + .si_unit = NNG_UNIT_BYTES, + .si_atomic = true, + }; + nni_stat_init(&ep->st_rcv_max, &rcv_max_info); +#endif + + *epp = ep; + return (0); +} + +static int +mqtts_tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) +{ + mqtts_tcptran_ep *ep; + int rv; + nng_sockaddr srcsa; + nni_sock * sock = nni_dialer_sock(ndialer); + nng_url myurl; + + // Check for invalid URL components. only one dialer is allowed + if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { + return (NNG_EADDRINVAL); + } + if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || + (url->u_query != NULL) || (strlen(url->u_hostname) == 0) || + (strlen(url->u_port) == 0)) { + return (NNG_EADDRINVAL); + } + + if ((rv = mqtts_tcptran_url_parse_source(&myurl, &srcsa, url)) != 0) { + return (rv); + } + + if (((rv = mqtts_tcptran_ep_init(&ep, url, sock)) != 0) || + ((rv = nni_aio_alloc(&ep->connaio, mqtts_tcptran_dial_cb, ep)) != + 0)) { + return (rv); + } + ep->ndialer = ndialer; + ep->authmode = NNG_TLS_AUTH_MODE_REQUIRED; + + if ((rv != 0) || + ((rv = nng_stream_dialer_alloc_url(&ep->dialer, &myurl)) != 0)) { + mqtts_tcptran_ep_fini(ep); + return (rv); + } + if ((srcsa.s_family != NNG_AF_UNSPEC) && + ((rv = nni_stream_dialer_set(ep->dialer, NNG_OPT_LOCADDR, &srcsa, + sizeof(srcsa), NNI_TYPE_SOCKADDR)) != 0)) { + mqtts_tcptran_ep_fini(ep); + return (rv); + } +#ifdef NNG_ENABLE_STATS +#endif + *dp = ep; + return (0); +} + +static int +mqtts_tcptran_listener_init(void **lp, nng_url *url, nni_listener *nlistener) +{ + mqtts_tcptran_ep *ep; + uint16_t af; + char * host = url->u_hostname; + nni_aio * aio; + int rv; + nni_sock * sock = nni_listener_sock(nlistener); + + if (strcmp(url->u_scheme, "tls+tcp") == 0) { + af = NNG_AF_UNSPEC; + } else if (strcmp(url->u_scheme, "tls+tcp4") == 0) { + af = NNG_AF_INET; + } else if (strcmp(url->u_scheme, "tls+tcp6") == 0) { + af = NNG_AF_INET6; + } else { + return (NNG_EADDRINVAL); + } + + // Check for invalid URL components. + if ((strlen(url->u_path) != 0) && (strcmp(url->u_path, "/") != 0)) { + return (NNG_EADDRINVAL); + } + if ((url->u_fragment != NULL) || (url->u_userinfo != NULL) || + (url->u_query != NULL)) { + return (NNG_EADDRINVAL); + } + + if (((rv = mqtts_tcptran_ep_init(&ep, url, sock)) != 0) || + ((rv = nni_aio_alloc(&ep->connaio, mqtts_tcptran_accept_cb, ep)) != + 0) || + ((rv = nni_aio_alloc(&ep->timeaio, mqtts_tcptran_timer_cb, ep)) != + 0)) { + return (rv); + } + + ep->authmode = NNG_TLS_AUTH_MODE_NONE; + + if (strlen(host) == 0) { + host = NULL; + } + + // XXX: We are doing lookup at listener initialization. There is + // a valid argument that this should be done at bind time, but that + // would require making bind asynchronous. In some ways this would + // be worse than the cost of just waiting here. We always recommend + // using local IP addresses rather than names when possible. + + if ((rv = nni_aio_alloc(&aio, NULL, NULL)) != 0) { + mqtts_tcptran_ep_fini(ep); + return (rv); + } + nni_resolv_ip(host, url->u_port, af, true, &ep->sa, aio); + nni_aio_wait(aio); + rv = nni_aio_result(aio); + nni_aio_free(aio); + + if (((rv = nng_stream_listener_alloc_url(&ep->listener, url)) != 0) || + ((rv = nni_stream_listener_set(ep->listener, NNG_OPT_TLS_AUTH_MODE, + &ep->authmode, sizeof(ep->authmode), NNI_TYPE_INT32)) != + 0)) { + mqtts_tcptran_ep_fini(ep); + return (rv); + } +#ifdef NNG_ENABLE_STATS + nni_listener_add_stat(nlistener, &ep->st_rcv_max); +#endif + + *lp = ep; + return (0); +} + +static void +mqtts_tcptran_ep_cancel(nni_aio *aio, void *arg, int rv) +{ + mqtts_tcptran_ep *ep = arg; + nni_mtx_lock(&ep->mtx); + if (ep->useraio == aio) { + ep->useraio = NULL; + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + +static void +mqtts_tcptran_ep_connect(void *arg, nni_aio *aio) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + if (ep->useraio != NULL) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + if ((rv = nni_aio_schedule(aio, mqtts_tcptran_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, rv); + return; + } + ep->useraio = aio; + + nng_stream_dialer_dial(ep->dialer, ep->connaio); + nni_mtx_unlock(&ep->mtx); +} + +static int +mqtts_tcptran_ep_get_url(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + mqtts_tcptran_ep *ep = arg; + char * s; + int rv; + int port = 0; + + if (ep->listener != NULL) { + (void) nng_stream_listener_get_int( + ep->listener, NNG_OPT_TCP_BOUND_PORT, &port); + } + + if ((rv = nni_url_asprintf_port(&s, ep->url, port)) == 0) { + rv = nni_copyout_str(s, v, szp, t); + nni_strfree(s); + } + return (rv); +} + +static int +mqtts_tcptran_ep_get_recvmaxsz(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + rv = nni_copyout_size(ep->rcvmax, v, szp, t); + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static int +mqtts_tcptran_ep_set_recvmaxsz( + void *arg, const void *v, size_t sz, nni_opt_type t) +{ + mqtts_tcptran_ep *ep = arg; + size_t val; + int rv; + if ((rv = nni_copyin_size(&val, v, sz, 0, NNI_MAXSZ, t)) == 0) { + mqtts_tcptran_pipe *p; + nni_mtx_lock(&ep->mtx); + ep->rcvmax = val; + NNI_LIST_FOREACH (&ep->waitpipes, p) { + p->rcvmax = val; + } + NNI_LIST_FOREACH (&ep->negopipes, p) { + p->rcvmax = val; + } + NNI_LIST_FOREACH (&ep->busypipes, p) { + p->rcvmax = val; + } + nni_mtx_unlock(&ep->mtx); +#ifdef NNG_ENABLE_STATS + nni_stat_set_value(&ep->st_rcv_max, val); +#endif + } + return (rv); +} + +static int +mqtts_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + // nni_mtx_lock(&ep->mtx); + nni_copyout_ptr(ep->connmsg, v, szp, t); + // ep->connmsg = NULL; + // nni_mtx_unlock(&ep->mtx); + rv = 0; + + return (rv); +} + +static int +mqtts_tcptran_dialer_setcb( + void *arg, void (*cb)(void *, nng_msg *), void *args) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + ep->conncb = cb; + ep->arg = args; + nni_mtx_unlock(&ep->mtx); + + rv = 0; + return (rv); +} + +static int +mqtts_tcptran_ep_set_connmsg( + void *arg, const void *v, size_t sz, nni_opt_type t) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + nni_copyin_ptr(&ep->connmsg, v, sz, t); + nni_mtx_unlock(&ep->mtx); + rv = 0; + + return (rv); +} + +static int +mqtts_tcptran_ep_bind(void *arg) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + rv = nng_stream_listener_listen(ep->listener); + nni_mtx_unlock(&ep->mtx); + + return (rv); +} + +static void +mqtts_tcptran_ep_accept(void *arg, nni_aio *aio) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + if (nni_aio_begin(aio) != 0) { + return; + } + nni_mtx_lock(&ep->mtx); + if (ep->closed) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + if (ep->useraio != NULL) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, NNG_EBUSY); + return; + } + if ((rv = nni_aio_schedule(aio, mqtts_tcptran_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + nni_aio_finish_error(aio, rv); + return; + } + ep->useraio = aio; + if (!ep->started) { + ep->started = true; + nng_stream_listener_accept(ep->listener, ep->connaio); + } else { + mqtts_tcptran_ep_match(ep); + } + nni_mtx_unlock(&ep->mtx); +} + +static nni_sp_pipe_ops mqtts_tcptran_pipe_ops = { + .p_init = mqtts_tcptran_pipe_init, + .p_fini = mqtts_tcptran_pipe_fini, + .p_stop = mqtts_tcptran_pipe_stop, + .p_send = mqtts_tcptran_pipe_send, + .p_recv = mqtts_tcptran_pipe_recv, + .p_close = mqtts_tcptran_pipe_close, + .p_peer = mqtts_tcptran_pipe_peer, + .p_getopt = mqtts_tcptran_pipe_getopt, +}; + +static const nni_option mqtts_tcptran_ep_opts[] = { + { + .o_name = NNG_OPT_RECVMAXSZ, + .o_get = mqtts_tcptran_ep_get_recvmaxsz, + .o_set = mqtts_tcptran_ep_set_recvmaxsz, + }, + { + .o_name = NNG_OPT_URL, + .o_get = mqtts_tcptran_ep_get_url, + }, + { + .o_name = NNG_OPT_MQTT_CONNMSG, + .o_get = mqtts_tcptran_ep_get_connmsg, + .o_set = mqtts_tcptran_ep_set_connmsg, + }, + // terminate list + { + .o_name = NULL, + }, +}; + +static int +mqtts_tcptran_dialer_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_dialer_get(ep->dialer, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(mqtts_tcptran_ep_opts, name, ep, buf, szp, t); + } + return (rv); +} + +static int +mqtts_tcptran_dialer_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + // TODO get mqtts dialer's option + rv = nni_stream_dialer_set(ep->dialer, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(mqtts_tcptran_ep_opts, name, ep, buf, sz, t); + } + return (rv); +} + +static int +mqtts_tcptran_listener_getopt( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_listener_get(ep->listener, name, buf, szp, t); + if (rv == NNG_ENOTSUP) { + rv = nni_getopt(mqtts_tcptran_ep_opts, name, ep, buf, szp, t); + } + return (rv); +} + +static int +mqtts_tcptran_listener_setopt( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + mqtts_tcptran_ep *ep = arg; + int rv; + + rv = nni_stream_listener_set(ep->listener, name, buf, sz, t); + if (rv == NNG_ENOTSUP) { + rv = nni_setopt(mqtts_tcptran_ep_opts, name, ep, buf, sz, t); + } + return (rv); +} + +static nni_sp_dialer_ops mqtts_tcptran_dialer_ops = { + .d_init = mqtts_tcptran_dialer_init, + .d_fini = mqtts_tcptran_ep_fini, + .d_connect = mqtts_tcptran_ep_connect, + .d_close = mqtts_tcptran_ep_close, + .d_getopt = mqtts_tcptran_dialer_getopt, + .d_setopt = mqtts_tcptran_dialer_setopt, + .d_connsetcb = mqtts_tcptran_dialer_setcb, +}; + +static nni_sp_listener_ops mqtts_tcptran_listener_ops = { + .l_init = mqtts_tcptran_listener_init, + .l_fini = mqtts_tcptran_ep_fini, + .l_bind = mqtts_tcptran_ep_bind, + .l_accept = mqtts_tcptran_ep_accept, + .l_close = mqtts_tcptran_ep_close, + .l_getopt = mqtts_tcptran_listener_getopt, + .l_setopt = mqtts_tcptran_listener_setopt, +}; + +static nni_sp_tran mqtts_tcp_tran = { + .tran_scheme = "tls+mqtt-tcp", + .tran_dialer = &mqtts_tcptran_dialer_ops, + .tran_listener = &mqtts_tcptran_listener_ops, + .tran_pipe = &mqtts_tcptran_pipe_ops, + .tran_init = mqtts_tcptran_init, + .tran_fini = mqtts_tcptran_fini, +}; + +static nni_sp_tran mqtts_tcp4_tran = { + .tran_scheme = "tls+mqtt-tcp4", + .tran_dialer = &mqtts_tcptran_dialer_ops, + .tran_listener = &mqtts_tcptran_listener_ops, + .tran_pipe = &mqtts_tcptran_pipe_ops, + .tran_init = mqtts_tcptran_init, + .tran_fini = mqtts_tcptran_fini, +}; + +static nni_sp_tran mqtts_tcp6_tran = { + .tran_scheme = "tls+mqtt-tcp6", + .tran_dialer = &mqtts_tcptran_dialer_ops, + .tran_listener = &mqtts_tcptran_listener_ops, + .tran_pipe = &mqtts_tcptran_pipe_ops, + .tran_init = mqtts_tcptran_init, + .tran_fini = mqtts_tcptran_fini, +}; + +#ifndef NNG_ELIDE_DEPRECATED +int +nng_mqtts_tcp_register(void) +{ + return (nni_init()); +} +#endif + +void +nni_mqtts_tcp_register(void) +{ + nni_sp_tran_register(&mqtts_tcp_tran); + nni_sp_tran_register(&mqtts_tcp4_tran); + nni_sp_tran_register(&mqtts_tcp6_tran); +} From 98531896655239bb419946f092c945d6eaafb580 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Sun, 28 Nov 2021 11:50:54 +0800 Subject: [PATCH 166/180] FIX [mqtt_tls] set tls config failed --- demo/mqtt_async/mqtt_async.c | 30 ++++++++++++++++++++++-------- src/core/stream.c | 12 ++++++------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index c156fd192..44640b447 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -212,7 +212,11 @@ init_dialer_tls_ex( return (rv); } - if ((rv = nng_tls_config_ca_chain(cfg, cert, NULL)) != 0) { + // if ((rv = nng_tls_config_ca_chain(cfg, cert, NULL)) != 0) { + // goto out; + // } + + if ((rv = nng_tls_config_ca_file(cfg, cert)) != 0) { goto out; } @@ -270,7 +274,20 @@ tls_client(const char *url, const char *cert, const char *key) nng_mqtt_msg_set_connect_keep_alive(msg, 60); nng_mqtt_msg_set_connect_clean_session(msg, true); - init_dialer_tls(dialer, cert, key); + if((rv = init_dialer_tls(dialer, cert, key)) != 0) { + fatal("init_dialer_tls", rv); + } + + // rv = nng_dialer_setopt_string(dialer, NNG_OPT_TLS_CA_FILE, cert); + // if (rv != 0) { + // fatal("nng_dialer_setopt_string: NNG_OPT_TLS_CA_FILE", rv); + // } + // rv = nng_dialer_setopt_string( + // dialer, NNG_OPT_TLS_SERVER_NAME, "www.fabric.com"); + // if (rv != 0) { + // fatal("nng_dialer_setopt_string: NNG_OPT_TLS_SERVER_NAME", rv); + // } + nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); nng_dialer_set_cb(dialer, connect_cb, NULL); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); @@ -299,19 +316,16 @@ main(int argc, const char **argv) exit(EXIT_FAILURE); } - url = (char *) argv[1]; + url = (char *) (argv[1]); if (argc >= 3) { - cert = (char *)argv[2]; + cert = (char *) (argv[2]); if (argc >= 4) { - key = (char *)argv[3]; + key = (char *) (argv[3]); } tls_client(url, cert, key); - nng_strfree(cert); - nng_strfree(key); - } else { client(url); } diff --git a/src/core/stream.c b/src/core/stream.c index ea57e2800..782743799 100644 --- a/src/core/stream.c +++ b/src/core/stream.c @@ -61,18 +61,18 @@ static struct { }, { .scheme = "tls+mqtt-tcp", - .dialer_alloc = nni_tcp_dialer_alloc, - .listener_alloc = nni_tcp_listener_alloc, + .dialer_alloc = nni_tls_dialer_alloc, + .listener_alloc = nni_tls_listener_alloc, }, { .scheme = "tls+mqtt-tcp4", - .dialer_alloc = nni_tcp_dialer_alloc, - .listener_alloc = nni_tcp_listener_alloc, + .dialer_alloc = nni_tls_dialer_alloc, + .listener_alloc = nni_tls_listener_alloc, }, { .scheme = "tls+mqtt-tcp6", - .dialer_alloc = nni_tcp_dialer_alloc, - .listener_alloc = nni_tcp_listener_alloc, + .dialer_alloc = nni_tls_dialer_alloc, + .listener_alloc = nni_tls_listener_alloc, }, { .scheme = "tcp", From 3bc84d2a0b06663663ada88d051be53ae24ec162 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 29 Nov 2021 18:32:15 +0800 Subject: [PATCH 167/180] * FIX [mqtt_tls] connect fail & tls config error --- demo/mqtt_async/mqtt_async.c | 240 ++++++++++++++++++++++-------- src/mqtt/mqtt_codec.c | 9 +- src/sp/transport/mqtts/mqtt_tls.c | 18 +-- 3 files changed, 182 insertions(+), 85 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index 44640b447..1d7763a0f 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -1,18 +1,19 @@ #include +#include +#include #include #include #include #include #include +#include #include #include #include #include -#ifndef PARALLEL -#define PARALLEL 32 -#endif +static size_t nwork = 32; struct work { enum { INIT, RECV, WAIT, SEND } state; @@ -163,7 +164,7 @@ client(const char *url) { nng_socket sock; nng_dialer dialer; - struct work *works[PARALLEL]; + struct work *works[nwork]; int i; int rv; @@ -171,7 +172,7 @@ client(const char *url) fatal("nng_socket", rv); } - for (i = 0; i < PARALLEL; i++) { + for (i = 0; i < nwork; i++) { works[i] = alloc_work(sock, i); } @@ -190,9 +191,7 @@ client(const char *url) nng_dialer_set_cb(dialer, connect_cb, NULL); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); - nng_msleep(1000); - - for (i = 0; i < PARALLEL; i++) { + for (i = 0; i < nwork; i++) { client_cb(works[i]); } @@ -201,9 +200,71 @@ client(const char *url) } } +// This reads a file into memory. Care is taken to ensure that +// the buffer is one byte larger and contains a terminating +// NUL. (Useful for key files and such.) +static void +loadfile(const char *path, void **datap, size_t *lenp) +{ + FILE * f; + size_t total_read = 0; + size_t allocation_size = BUFSIZ; + char * fdata; + char * realloc_result; + + if (strcmp(path, "-") == 0) { + f = stdin; + } else { + if ((f = fopen(path, "rb")) == NULL) { + fprintf(stderr, "Cannot open file %s: %s", path, + strerror(errno)); + exit(1); + } + } + + if ((fdata = malloc(allocation_size + 1)) == NULL) { + fprintf(stderr, "Out of memory."); + } + + while (1) { + total_read += fread( + fdata + total_read, 1, allocation_size - total_read, f); + if (ferror(f)) { + if (errno == EINTR) { + continue; + } + fprintf(stderr, "Read from %s failed: %s", path, + strerror(errno)); + exit(1); + } + if (feof(f)) { + break; + } + if (total_read == allocation_size) { + if (allocation_size > SIZE_MAX / 2) { + fprintf(stderr, "Out of memory."); + } + allocation_size *= 2; + if ((realloc_result = realloc( + fdata, allocation_size + 1)) == NULL) { + free(fdata); + fprintf(stderr, "Out of memory."); + exit(1); + } + fdata = realloc_result; + } + } + if (f != stdin) { + fclose(f); + } + fdata[total_read] = '\0'; + *datap = fdata; + *lenp = total_read; +} + static int -init_dialer_tls_ex( - nng_dialer d, const char *cert, const char *key, bool own_cert) +init_dialer_tls(nng_dialer d, const char *cacert, const char *cert, + const char *key, const char *pass) { nng_tls_config *cfg; int rv; @@ -212,23 +273,18 @@ init_dialer_tls_ex( return (rv); } - // if ((rv = nng_tls_config_ca_chain(cfg, cert, NULL)) != 0) { - // goto out; - // } - - if ((rv = nng_tls_config_ca_file(cfg, cert)) != 0) { - goto out; - } - - if ((rv = nng_tls_config_server_name(cfg, "www.fabric.com")) != 0) { - goto out; + if (cert != NULL && key != NULL) { + nng_tls_config_auth_mode(cfg, NNG_TLS_AUTH_MODE_REQUIRED); + if ((rv = nng_tls_config_own_cert(cfg, cert, key, pass)) != + 0) { + goto out; + } + } else { + nng_tls_config_auth_mode(cfg, NNG_TLS_AUTH_MODE_NONE); } - // nng_tls_config_auth_mode(cfg, NNG_TLS_AUTH_MODE_REQUIRED); - nng_tls_config_auth_mode(cfg, NNG_TLS_AUTH_MODE_NONE); - if (own_cert) { - if ((rv = nng_tls_config_own_cert(cfg, cert, key, NULL)) != - 0) { + if (cacert != NULL) { + if ((rv = nng_tls_config_ca_chain(cfg, cacert, NULL)) != 0) { goto out; } } @@ -240,18 +296,13 @@ init_dialer_tls_ex( return (rv); } -static int -init_dialer_tls(nng_dialer d, const char *cert, const char *key) -{ - return (init_dialer_tls_ex(d, cert, key, false)); -} - int -tls_client(const char *url, const char *cert, const char *key) +tls_client(const char *url, const char *ca, const char *cert, const char *key, + const char *pass) { nng_socket sock; nng_dialer dialer; - struct work *works[PARALLEL]; + struct work *works[nwork]; int i; int rv; @@ -259,7 +310,7 @@ tls_client(const char *url, const char *cert, const char *key) fatal("nng_socket", rv); } - for (i = 0; i < PARALLEL; i++) { + for (i = 0; i < nwork; i++) { works[i] = alloc_work(sock, i); } @@ -274,27 +325,15 @@ tls_client(const char *url, const char *cert, const char *key) nng_mqtt_msg_set_connect_keep_alive(msg, 60); nng_mqtt_msg_set_connect_clean_session(msg, true); - if((rv = init_dialer_tls(dialer, cert, key)) != 0) { + if ((rv = init_dialer_tls(dialer, ca, cert, key, pass)) != 0) { fatal("init_dialer_tls", rv); } - // rv = nng_dialer_setopt_string(dialer, NNG_OPT_TLS_CA_FILE, cert); - // if (rv != 0) { - // fatal("nng_dialer_setopt_string: NNG_OPT_TLS_CA_FILE", rv); - // } - // rv = nng_dialer_setopt_string( - // dialer, NNG_OPT_TLS_SERVER_NAME, "www.fabric.com"); - // if (rv != 0) { - // fatal("nng_dialer_setopt_string: NNG_OPT_TLS_SERVER_NAME", rv); - // } - nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); nng_dialer_set_cb(dialer, connect_cb, NULL); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); - nng_msleep(1000); - - for (i = 0; i < PARALLEL; i++) { + for (i = 0; i < nwork; i++) { client_cb(works[i]); } @@ -303,28 +342,97 @@ tls_client(const char *url, const char *cert, const char *key) } } -int -main(int argc, const char **argv) +void +usage(void) { - int rc; - char *url; - char *cert; - char *key; - - if (argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); - exit(EXIT_FAILURE); - } - - url = (char *) (argv[1]); + printf("mqtt_async: \n"); + printf(" -u \n"); + printf(" -s enable ssl/tls mode (default: disable)\n"); + printf(" -a \n"); + printf(" -c \n"); + printf(" -k \n"); + printf(" -p \n"); + printf(" -n number of works (default: 32)\n"); +} - if (argc >= 3) { - cert = (char *) (argv[2]); - if (argc >= 4) { - key = (char *) (argv[3]); +int +main(int argc, char **argv) +{ + int rc; + char * path; + size_t file_len; + + bool enable_ssl = false; + char *url = NULL; + char *cafile = NULL; + char *cert = NULL; + char *key = NULL; + char *key_psw = NULL; + + int opt; + int digit_optind = 0; + int option_index = 0; + char *short_options = "u:sa:c:k:p:n:W;"; + + static struct option long_options[] = { + { "url", required_argument, NULL, 0 }, + { "ssl", no_argument, NULL, false }, + { "cafile", required_argument, NULL, 0 }, + { "cert", required_argument, NULL, 0 }, + { "key", required_argument, NULL, 0 }, + { "psw", required_argument, NULL, 0 }, + { "help", no_argument, NULL, 'h' }, + { "nwork", no_argument, NULL, 'n' }, + { NULL, 0, NULL, 0 }, + }; + + while ((opt = getopt_long(argc, argv, short_options, long_options, + &option_index)) != -1) { + switch (opt) { + case 0: + // TODO + break; + case '?': + case 'h': + usage(); + exit(0); + case 'u': + url = argv[optind - 1]; + break; + case 's': + enable_ssl = true; + break; + case 'a': + path = argv[optind - 1]; + loadfile(path, (void **) &cafile, &file_len); + printf("cafile:\n%s\n", cafile); + break; + case 'c': + path = argv[optind - 1]; + loadfile(path, (void **) &cert, &file_len); + printf("cert:\n%s\n", cert); + break; + case 'k': + path = argv[optind - 1]; + loadfile(path, (void **) &key, &file_len); + printf("key:\n%s\n", key); + break; + case 'p': + key_psw = argv[optind - 1]; + break; + case 'n': + nwork = atoi(argv[optind - 1]); + break; + + default: + fprintf(stderr, "invalid argument: '%c'\n", opt); + usage(); + exit(1); } + } - tls_client(url, cert, key); + if (enable_ssl) { + tls_client(url, cafile, cert, key, key_psw); } else { client(url); diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index 3395aba10..2d118491f 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -322,6 +322,7 @@ dup_unsubscribe(nni_mqtt_proto_data *dest, nni_mqtt_proto_data *src) static void destory_connect(nni_mqtt_proto_data *mqtt) { + mqtt_buf_free(&mqtt->var_header.connect.protocol_name); mqtt_buf_free(&mqtt->payload.connect.client_id); mqtt_buf_free(&mqtt->payload.connect.user_name); mqtt_buf_free(&mqtt->payload.connect.password); @@ -406,16 +407,16 @@ static int nni_mqtt_msg_encode_connect(nni_msg *msg) { nni_mqtt_proto_data *mqtt = nni_msg_get_proto_data(msg); - char name[4] = "MQTT"; char client_id[20] = { 0 }; nni_msg_clear(msg); int poslength = 6; - mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; - var_header->protocol_name.buf = (uint8_t *) name; - var_header->protocol_name.length = 4; + mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; + + mqtt_buf_create(&var_header->protocol_name, + (const uint8_t *) MQTT_PROTOCOL_NAME, strlen(MQTT_PROTOCOL_NAME)); if (var_header->protocol_version == 0) { var_header->protocol_version = 4; diff --git a/src/sp/transport/mqtts/mqtt_tls.c b/src/sp/transport/mqtts/mqtt_tls.c index 4b873b350..d6ef2a2cb 100644 --- a/src/sp/transport/mqtts/mqtt_tls.c +++ b/src/sp/transport/mqtts/mqtt_tls.c @@ -398,7 +398,6 @@ mqtts_tcptran_pipe_send_cb(void *arg) aio = nni_list_first(&p->sendq); if ((rv = nni_aio_result(txaio)) != 0) { - // Intentionally we do not queue up another transfer. // There's an excellent chance that the pipe is no longer // usable, with a partial transfer. @@ -578,14 +577,6 @@ mqtts_tcptran_pipe_recv_cb(void *arg) nni_aio_finish_error(aio, rv); printf("mqtts_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); return; -// notify: -// // nni_pipe_bump_rx(p->npipe, n); -// nni_aio_list_remove(aio); -// mqtts_tcptran_pipe_recv_start(p); -// nni_mtx_unlock(&p->mtx); -// nni_aio_set_msg(aio, NULL); -// nni_aio_finish(aio, 0, 0); - return; } static void @@ -786,12 +777,9 @@ mqtts_tcptran_pipe_start( p->wanttxhead = nni_msg_header_len(connmsg) + nni_msg_len(connmsg); p->rxmsg = NULL; - if (nni_msg_header_len(connmsg) > 0) { - iov[niov].iov_buf = nni_msg_header(connmsg); - iov[niov].iov_len = nni_msg_header_len(connmsg); - niov++; - } if (nni_msg_len(connmsg) > 0) { + nni_msg_insert(connmsg, nni_msg_header(connmsg), + nni_msg_header_len(connmsg)); iov[niov].iov_buf = nni_msg_body(connmsg); iov[niov].iov_len = nni_msg_len(connmsg); niov++; @@ -1079,7 +1067,7 @@ mqtts_tcptran_dialer_init(void **dp, nng_url *url, nni_dialer *ndialer) return (rv); } - if (((rv = mqtts_tcptran_ep_init(&ep, url, sock)) != 0) || + if (((rv = mqtts_tcptran_ep_init(&ep, url, sock)) != 0) || ((rv = nni_aio_alloc(&ep->connaio, mqtts_tcptran_dial_cb, ep)) != 0)) { return (rv); From 54073bf712f71ae1968255931b2fb89036a9b2cf Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Mon, 29 Nov 2021 18:57:23 +0800 Subject: [PATCH 168/180] * FIX [mqtt_codec] double free proto name --- src/mqtt/mqtt_codec.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/mqtt/mqtt_codec.c b/src/mqtt/mqtt_codec.c index 2d118491f..486f67baa 100644 --- a/src/mqtt/mqtt_codec.c +++ b/src/mqtt/mqtt_codec.c @@ -254,6 +254,8 @@ nni_mqtt_msg_dup(void **dest, const void *src) static void dup_connect(nni_mqtt_proto_data *dest, nni_mqtt_proto_data *src) { + mqtt_buf_dup(&dest->var_header.connect.protocol_name, + &src->var_header.connect.protocol_name); mqtt_buf_dup( &dest->payload.connect.client_id, &src->payload.connect.client_id); mqtt_buf_dup( @@ -415,8 +417,11 @@ nni_mqtt_msg_encode_connect(nni_msg *msg) mqtt_connect_vhdr *var_header = &mqtt->var_header.connect; - mqtt_buf_create(&var_header->protocol_name, - (const uint8_t *) MQTT_PROTOCOL_NAME, strlen(MQTT_PROTOCOL_NAME)); + if (var_header->protocol_name.length == 0) { + mqtt_buf_create(&var_header->protocol_name, + (const uint8_t *) MQTT_PROTOCOL_NAME, + strlen(MQTT_PROTOCOL_NAME)); + } if (var_header->protocol_version == 0) { var_header->protocol_version = 4; @@ -428,11 +433,7 @@ nni_mqtt_msg_encode_connect(nni_msg *msg) (const uint8_t *) client_id, (uint32_t) strlen(client_id)); } - /* length of protocol-name (consider "MQTT" by default */ - poslength += (var_header->protocol_name.length == 0) - ? 4 - : var_header->protocol_name.length; - + poslength += var_header->protocol_name.length; /* add the length of payload part */ mqtt_connect_payload *payload = &mqtt->payload.connect; /* Clientid length */ From 64b4ded11ef7177fb66d60fcd332cbadaa676f08 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Tue, 30 Nov 2021 15:28:13 +0800 Subject: [PATCH 169/180] * NEW [dialer] New callback interface for dialer. --- demo/mqtt_async/mqtt_async.c | 19 +++++++++++++++++-- include/nng/mqtt/mqtt_client.h | 7 +++++++ include/nng/nng.h | 3 +-- src/core/dialer.c | 4 ++-- src/core/dialer.h | 2 +- src/nng.c | 4 ++-- src/sp/transport.h | 2 +- src/sp/transport/mqtt/mqtt_tcp.c | 27 ++++++++++++++++++--------- 8 files changed, 49 insertions(+), 19 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index 1d7763a0f..bb1970f41 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -159,6 +159,21 @@ connect_cb(void *arg, nng_msg *msg) nng_msg_free(msg); } +// Disconnect message callback function +static void +disconnect_cb(void *arg, nng_msg *msg) +{ + (void) arg; + printf("Disconnected\n"); +} + +static nng_mqtt_cb usercb = { + .name = "usercb", + .on_connected = connect_cb, + .on_disconnected = disconnect_cb, + .arg = "Args", // void * +}; + int client(const char *url) { @@ -188,7 +203,7 @@ client(const char *url) nng_mqtt_msg_set_connect_clean_session(msg, true); nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); - nng_dialer_set_cb(dialer, connect_cb, NULL); + nng_dialer_set_cb(dialer, &usercb); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); for (i = 0; i < nwork; i++) { @@ -330,7 +345,7 @@ tls_client(const char *url, const char *ca, const char *cert, const char *key, } nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); - nng_dialer_set_cb(dialer, connect_cb, NULL); + nng_dialer_set_cb(dialer, connect_cb); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); for (i = 0; i < nwork; i++) { diff --git a/include/nng/mqtt/mqtt_client.h b/include/nng/mqtt/mqtt_client.h index 79d15b52f..98867fb76 100644 --- a/include/nng/mqtt/mqtt_client.h +++ b/include/nng/mqtt/mqtt_client.h @@ -204,6 +204,13 @@ typedef struct { nng_mqtt_user_prop_t *up_props; } nng_mqtt_user_props_t; +typedef struct { + char *name; + void (*on_connected)(void *, nng_msg *); + void (*on_disconnected)(void *, nng_msg *); + void *arg; +} nng_mqtt_cb; + extern int nng_mqtt_user_props_alloc(nng_mqtt_user_props_t **); extern int nng_mqtt_user_props_add( nng_mqtt_user_props_t *, const char *, const char *); diff --git a/include/nng/nng.h b/include/nng/nng.h index 1bd9d0063..56bfe60f3 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -280,8 +280,7 @@ NNG_DECL int nng_dialer_create(nng_dialer *, nng_socket, const char *); NNG_DECL int nng_listener_create(nng_listener *, nng_socket, const char *); // nng_dialer_set_cb set the cb to the dialer. Cb runs when dialer finished. -NNG_DECL int nng_dialer_set_cb( - nng_dialer, void (*)(void *, nng_msg *), void *); +NNG_DECL int nng_dialer_set_cb(nng_dialer, void *); // nng_dialer_start starts the endpoint dialing. This is only possible if // the dialer is not already dialing. diff --git a/src/core/dialer.c b/src/core/dialer.c index fc8c464d9..5592a0b9f 100644 --- a/src/core/dialer.c +++ b/src/core/dialer.c @@ -574,8 +574,8 @@ nni_dialer_add_stat(nni_dialer *d, nni_stat_item *item) // NNG-MQTT void -nni_dialer_setcb(nni_dialer *d, void (*cb)(void *, nng_msg *), void *arg) +nni_dialer_setcb(nni_dialer *d, void * cb) { - d->d_ops.d_connsetcb(d->d_data, cb, arg); + d->d_ops.d_connsetcb(d->d_data, cb); } diff --git a/src/core/dialer.h b/src/core/dialer.h index 4f03ff5e6..87ed2f10d 100644 --- a/src/core/dialer.h +++ b/src/core/dialer.h @@ -31,6 +31,6 @@ extern void nni_dialer_add_stat(nni_dialer *, nni_stat_item *); extern void nni_dialer_bump_error(nni_dialer *, int); // NNG-MQTT -extern void nni_dialer_setcb(nni_dialer *, void (*cb)(void *, nng_msg *), void *); +extern void nni_dialer_setcb(nni_dialer *, void * cb); #endif // CORE_DIALER_H diff --git a/src/nng.c b/src/nng.c index af373b669..b5365e846 100644 --- a/src/nng.c +++ b/src/nng.c @@ -579,7 +579,7 @@ nng_dialer_create(nng_dialer *dp, nng_socket sid, const char *addr) } int -nng_dialer_set_cb(nng_dialer did, void (*cb)(void *, nng_msg *), void *arg) +nng_dialer_set_cb(nng_dialer did, void * cb) { nni_dialer *d; int rv; @@ -588,7 +588,7 @@ nng_dialer_set_cb(nng_dialer did, void (*cb)(void *, nng_msg *), void *arg) return (rv); } - nni_dialer_setcb(d, cb, arg); + nni_dialer_setcb(d, cb); return (0); } diff --git a/src/sp/transport.h b/src/sp/transport.h index deea685e1..2fb7b0b8e 100644 --- a/src/sp/transport.h +++ b/src/sp/transport.h @@ -50,7 +50,7 @@ struct nni_sp_dialer_ops { int (*d_setopt)(void *, const char *, const void *, size_t, nni_type); //d_setconncb is used to set callback for connection. - int (*d_connsetcb)(void *, void (*)(void *, nng_msg *), void *); + int (*d_connsetcb)(void *, void *); // d_options is an array of dialer options. The final // element must have a NULL name. If this member is NULL, then diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 640299a72..42dd96a44 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -15,6 +15,7 @@ #include "core/nng_impl.h" #include "mqtt/mqtt.h" +#include "nng/mqtt/mqtt_client.h" // TCP transport. Platform specific TCP operations must be // supplied as well. @@ -77,8 +78,7 @@ struct mqtt_tcptran_ep { nng_stream_listener *listener; nni_dialer * ndialer; void * connmsg; - void (*conncb)(void *, nng_msg *); - void *arg; + nng_mqtt_cb * usercb; #ifdef NNG_ENABLE_STATS nni_stat_item st_rcv_max; @@ -184,6 +184,10 @@ mqtt_tcptran_pipe_fini(void *arg) nni_mtx_unlock(&ep->mtx); } + if (ep && ep->usercb) { + ep->usercb->on_disconnected(ep->usercb->arg, NULL); + } + nni_aio_free(p->rxaio); nni_aio_free(p->txaio); nni_aio_free(p->rsaio); @@ -359,8 +363,8 @@ mqtt_tcptran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); // Run user callback - if (ep->conncb != NULL) { - ep->conncb(ep->arg, rmsg); + if (ep->usercb != NULL) { + ep->usercb->on_connected(ep->usercb->arg, rmsg); } return; @@ -568,6 +572,9 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_pipe_bump_error(p->npipe, rv); nni_mtx_unlock(&p->mtx); + if (p->ep->usercb) + p->ep->usercb->on_disconnected(p->ep->usercb->arg, NULL); + nni_msg_free(msg); nni_aio_finish_error(aio, rv); printf("mqtt_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); @@ -870,6 +877,10 @@ mqtt_tcptran_ep_close(void *arg) ep->useraio = NULL; } + if (ep->usercb) { + ep->usercb->on_disconnected(ep->usercb->arg, NULL); + } + nni_mtx_unlock(&ep->mtx); } @@ -1052,8 +1063,7 @@ mqtt_tcptran_ep_init(mqtt_tcptran_ep **epp, nng_url *url, nni_sock *sock) ep->proto = nni_sock_proto_id(sock); ep->url = url; - ep->conncb = NULL; - ep->arg = NULL; + ep->usercb = NULL; #ifdef NNG_ENABLE_STATS static const nni_stat_info rcv_max_info = { @@ -1272,14 +1282,13 @@ mqtt_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) } static int -mqtt_tcptran_dialer_setcb(void *arg, void (*cb)(void *, nng_msg *), void *args) +mqtt_tcptran_dialer_setcb(void *arg, void * cb) { mqtt_tcptran_ep *ep = arg; int rv; nni_mtx_lock(&ep->mtx); - ep->conncb = cb; - ep->arg = args; + ep->usercb = cb; nni_mtx_unlock(&ep->mtx); rv = 0; From 408ef821ceed24847f5b0a0a4706b1a8c6b936fa Mon Sep 17 00:00:00 2001 From: Jaylin Date: Tue, 30 Nov 2021 16:19:23 +0800 Subject: [PATCH 170/180] * RM [nano_tcp] rm old nano_tcp file from reqrep protocol. --- src/sp/protocol/mqtt/nmq_mqtt.c | 2 +- src/sp/protocol/reqrep0/nano_tcp.c | 1037 ---------------------------- 2 files changed, 1 insertion(+), 1038 deletions(-) delete mode 100644 src/sp/protocol/reqrep0/nano_tcp.c diff --git a/src/sp/protocol/mqtt/nmq_mqtt.c b/src/sp/protocol/mqtt/nmq_mqtt.c index ece530986..0aba5d5d9 100644 --- a/src/sp/protocol/mqtt/nmq_mqtt.c +++ b/src/sp/protocol/mqtt/nmq_mqtt.c @@ -18,7 +18,7 @@ #include "nng/nng.h" #include "nng/protocol/mqtt/mqtt.h" #include "nng/protocol/mqtt/mqtt_parser.h" -#include "nng/protocol/mqtt/nano_tcp.h" +#include "nng/protocol/mqtt/nmq_mqtt.h" #include diff --git a/src/sp/protocol/reqrep0/nano_tcp.c b/src/sp/protocol/reqrep0/nano_tcp.c deleted file mode 100644 index 14629a991..000000000 --- a/src/sp/protocol/reqrep0/nano_tcp.c +++ /dev/null @@ -1,1037 +0,0 @@ -// -// Copyright 2020 NanoMQ Team, Inc. -// -// This software is supplied under the terms of the MIT License, a -// copy of which should be located in the distribution where this -// file was obtained (LICENSE.txt). A copy of the license may also be -// found online at https://opensource.org/licenses/MIT. -// - -#include -#include -#include -#include -#include - -#include "core/nng_impl.h" -#include "core/sockimpl.h" -#include "nng/nng.h" -#include "nng/protocol/mqtt/mqtt.h" -#include "nng/protocol/mqtt/mqtt_parser.h" -#include "nng/protocol/mqtt/nano_tcp.h" - -#include - -// TODO rewrite as nano_mq protocol with RPC support - -typedef struct nano_pipe nano_pipe; -typedef struct nano_sock nano_sock; -typedef struct nano_ctx nano_ctx; -typedef struct cs_msg_list cs_msg_list; - -static void nano_pipe_send_cb(void *); -static void nano_pipe_recv_cb(void *); -static void nano_pipe_fini(void *); -static void nano_pipe_close(void *); -static inline void close_pipe(nano_pipe *p); -// static void nano_period_check(nano_sock *s, nni_list *sent_list, void *arg); -// static void nano_keepalive(nano_pipe *p, void *arg); - -// huge context/ dynamic context? -struct nano_ctx { - nano_sock *sock; - uint32_t pipe_id; - // uint32_t resend_count; - // uint32_t pipe_len; //record total length of pipe_id queue - // when resending - nano_pipe *spipe, *qos_pipe; // send pipe - nni_aio * saio; // send aio - nni_aio * raio; // recv aio - // uint32_t* rspipes;// pub resend pipe queue Qos 1/2 - // nni_list send_queue; // contexts waiting to send. - nni_list_node sqnode; - nni_list_node rqnode; - // nni_timer_node qos_timer; -}; - -// nano_sock is our per-socket protocol private structure. -struct nano_sock { - nni_mtx lk; - nni_atomic_int ttl; - nni_id_map pipes; - nni_lmq waitlmq; - nni_list recvpipes; // list of pipes with data to receive - nni_list recvq; - nano_ctx ctx; // base socket - nni_pollable readable; - nni_pollable writable; - conf * conf; - void * db; -}; - -// nano_pipe is our per-pipe protocol private structure. -struct nano_pipe { - nni_mtx lk; - nni_pipe * pipe; - nano_sock * rep; - uint32_t id; - void * tree; // root node of db tree - nni_aio aio_send; - nni_aio aio_recv; - nni_aio aio_timer; - nni_list_node rnode; // receivable list linkage - bool busy; - bool closed; - bool kicked; - uint8_t reason_code; - uint8_t ka_refresh; - nano_conn_param *conn_param; - nni_lmq rlmq; -}; - -static inline int -nano_nni_lmq_getq(nni_lmq *lmq, nng_msg **msg, uint8_t *qos) -{ - int rv = nni_lmq_getq(lmq, msg); - if (rv == 0) { - if (qos) { - *qos = NANO_NNI_LMQ_GET_QOS_BITS(*msg); - } - *msg = NANO_NNI_LMQ_GET_MSG_POINTER(*msg); - } - return rv; -} - -void -nano_nni_lmq_flush(nni_lmq *lmq) -{ - while (lmq->lmq_len > 0) { - nng_msg *msg = lmq->lmq_msgs[lmq->lmq_get++]; - lmq->lmq_get &= lmq->lmq_mask; - lmq->lmq_len--; - nni_msg_free(NANO_NNI_LMQ_GET_MSG_POINTER(msg)); - } -} - -int -nano_nni_lmq_resize(nni_lmq *lmq, size_t cap) -{ - nng_msg * msg; - nng_msg **newq; - size_t alloc; - size_t len; - - alloc = 2; - while (alloc < cap) { - alloc *= 2; - } - - newq = nni_alloc(sizeof(nng_msg *) * alloc); - if (newq == NULL) { - return (NNG_ENOMEM); - } - - len = 0; - while ((len < cap) && (nni_lmq_getq(lmq, &msg) == 0)) { - newq[len++] = msg; - } - - // Flush anything left over. - nano_nni_lmq_flush(lmq); - - nni_free(lmq->lmq_msgs, lmq->lmq_alloc * sizeof(nng_msg *)); - lmq->lmq_msgs = newq; - lmq->lmq_cap = cap; - lmq->lmq_alloc = alloc; - lmq->lmq_mask = alloc - 1; - lmq->lmq_len = len; - lmq->lmq_put = len; - lmq->lmq_get = 0; - - return (0); -} - -void -nano_nni_lmq_fini(nni_lmq *lmq) -{ - if (lmq == NULL) { - return; - } - - /* Free any orphaned messages. */ - while (lmq->lmq_len > 0) { - nng_msg *msg = lmq->lmq_msgs[lmq->lmq_get++]; - lmq->lmq_get &= lmq->lmq_mask; - lmq->lmq_len--; - nni_msg_free(NANO_NNI_LMQ_GET_MSG_POINTER(msg)); - } - - nni_free(lmq->lmq_msgs, lmq->lmq_alloc * sizeof(nng_msg *)); -} - -static void -nano_pipe_timer_cb(void *arg) -{ - nano_pipe *p = arg; - int qos_duration = p->rep->conf->qos_duration; - nni_msg * msg, *rmsg; - nni_time time; - nni_pipe * npipe = p->pipe; - uint16_t pid; - uint8_t qos; - - if (nng_aio_result(&p->aio_timer) != 0) { - return; - } - nni_mtx_lock(&p->lk); - if (p->ka_refresh * (qos_duration) > p->conn_param->keepalive_mqtt) { - nni_println("Warning: close pipe & kick client due to KeepAlive " - "timeout!"); - // TODO check keepalived timer interval - p->reason_code = 0x8D; - nni_aio_finish_error(&p->aio_recv, NNG_ECONNREFUSED); - nni_mtx_unlock(&p->lk); - return; - } - p->ka_refresh++; - if (!p->busy) { - msg = nni_id_get_any(npipe->nano_qos_db, &pid); - if (msg != NULL) { - qos = NANO_NNI_LMQ_GET_QOS_BITS(msg); - rmsg = NANO_NNI_LMQ_GET_MSG_POINTER(msg); - time = nni_msg_get_timestamp(msg); - if ((nni_clock() - time) >= - (long unsigned) qos_duration * 1250) { - p->busy = true; - //TODO set max retrying times in nanomq.conf - nni_msg_clone(rmsg); - nano_msg_set_dup(rmsg); - nni_aio_set_packetid(&p->aio_send, pid); - nni_aio_set_msg(&p->aio_send, rmsg); - debug_msg("resending qos msg packetid: %d", pid); - nni_pipe_send(p->pipe, &p->aio_send); - nni_id_remove(npipe->nano_qos_db, pid); - } - } - } - - nni_mtx_unlock(&p->lk); - nni_sleep_aio(qos_duration * 1000, &p->aio_timer); - return; -} - -/* -static void -nano_keepalive(nano_pipe *p, void *arg) -{ - uint16_t interval; - - interval = conn_param_get_keepalive(p->conn_param); - debug_msg("KeepAlive: %d", interval); - //20% KeepAlive as buffer time for multi-threading - nni_timer_schedule(&p->ka_timer, nni_clock() + NNI_SECOND * interval * -0.8); -} -*/ - -static void -nano_ctx_close(void *arg) -{ - nano_ctx * ctx = arg; - nano_sock *s = ctx->sock; - nni_aio * aio; - - debug_msg("nano_ctx_close"); - nni_mtx_lock(&s->lk); - if ((aio = ctx->saio) != NULL) { - // nano_pipe *pipe = ctx->spipe; - ctx->saio = NULL; - ctx->spipe = NULL; - ctx->qos_pipe = NULL; - nni_aio_finish_error(aio, NNG_ECLOSED); - } - if ((aio = ctx->raio) != NULL) { - nni_list_remove(&s->recvq, ctx); - ctx->raio = NULL; - nni_aio_finish_error(aio, NNG_ECLOSED); - } - nni_mtx_unlock(&s->lk); -} - -static void -nano_ctx_fini(void *arg) -{ - nano_ctx *ctx = arg; - - nano_ctx_close(ctx); - - // timer - debug_msg("========= nano_ctx_fini ========="); - // nni_timer_cancel(&ctx->qos_timer); - // nni_timer_fini(&ctx->qos_timer); -} - -static int -nano_ctx_init(void *carg, void *sarg) -{ - nano_sock *s = sarg; - nano_ctx * ctx = carg; - - debug_msg("&&&&&&&& nano_ctx_init %p &&&&&&&&&", ctx); - NNI_LIST_NODE_INIT(&ctx->sqnode); - NNI_LIST_NODE_INIT(&ctx->rqnode); - - ctx->sock = s; - ctx->pipe_id = 0; - - return (0); -} - -static void -nano_ctx_cancel_send(nni_aio *aio, void *arg, int rv) -{ - nano_ctx * ctx = arg; - nano_sock *s = ctx->sock; - - debug_msg("*********** nano_ctx_cancel_send ***********"); - nni_mtx_lock(&s->lk); - if (ctx->saio != aio) { - nni_mtx_unlock(&s->lk); - return; - } - nni_list_node_remove(&ctx->sqnode); - ctx->saio = NULL; - nni_mtx_unlock(&s->lk); - - nni_msg_header_clear(nni_aio_get_msg(aio)); // reset the headers - nni_aio_finish_error(aio, rv); -} - -static void -nano_ctx_send(void *arg, nni_aio *aio) -{ - nano_ctx * ctx = arg; - nano_sock *s = ctx->sock; - nano_pipe *p; - nni_msg * msg; - int rv; - uint32_t pipe; - size_t qos = 0; - - msg = nni_aio_get_msg(aio); - - if (nni_aio_begin(aio) != 0) { - return; - } - - debug_msg("#### nano_ctx_send with ctx %p msg type %x ####", - ctx, nni_msg_cmd_type(msg)); - - if ((pipe = nni_msg_get_pipe(msg)) != 0) { - nni_msg_set_pipe(msg, 0); - } else { - pipe = ctx->pipe_id; // reply to self - } - ctx->pipe_id = 0; // ensure connack/PING/DISCONNECT/PUBACK only sends once - - if (ctx == &s->ctx) { - nni_pollable_clear(&s->writable); - } - - nni_mtx_lock(&s->lk); - debug_msg(" ******** working with pipe id : %d ctx ********", pipe); - if ((p = nni_id_get(&s->pipes, pipe)) == NULL) { - // Pipe is gone. Make this look like a good send to avoid - // disrupting the state machine. We don't care if the peer - // lost interest in our reply. - nni_mtx_unlock(&s->lk); - nni_aio_set_msg(aio, NULL); - // TODO lastwill/SYS topic will trigger this (sub to the topic - // that publish to by itself) - debug_syslog("ERROR: pipe is gone, pub failed"); - nni_msg_free(msg); - return; - } - nni_mtx_unlock(&s->lk); - nni_mtx_lock(&p->lk); - qos = (size_t) nni_aio_get_prov_extra(aio, 0); - msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); - if (!p->busy) { - p->busy = true; - nni_aio_set_msg(&p->aio_send, msg); - nni_pipe_send(p->pipe, &p->aio_send); - nni_mtx_unlock(&p->lk); - nni_aio_set_msg(aio, NULL); - return; - } - - if ((rv = nni_aio_schedule(aio, nano_ctx_cancel_send, ctx)) != 0) { - nni_msg_free(msg); - nni_mtx_unlock(&p->lk); - return; - } - debug_msg("WARNING: pipe %d occupied! resending in cb!", pipe); - if (nni_lmq_full(&p->rlmq)) { - // Make space for the new message. TODO add max limit of msgq - // len in conf - if ((rv = nano_nni_lmq_resize( - &p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { - debug_syslog("warning msg dropped!"); - nni_msg *old; - (void) nano_nni_lmq_getq(&p->rlmq, &old, NULL); - nni_msg_free(old); - } - } - - nni_lmq_putq(&p->rlmq, msg); - - nni_mtx_unlock(&p->lk); - nni_aio_set_msg(aio, NULL); - return; -} - -static void -nano_sock_fini(void *arg) -{ - nano_sock *s = arg; - - nni_id_map_fini(&s->pipes); - nni_lmq_fini(&s->waitlmq); - nano_ctx_fini(&s->ctx); - nni_pollable_fini(&s->writable); - nni_pollable_fini(&s->readable); - nni_mtx_fini(&s->lk); - - conf_fini(s->conf); -} - -static int -nano_sock_init(void *arg, nni_sock *sock) -{ - nano_sock *s = arg; - - NNI_ARG_UNUSED(sock); - - nni_mtx_init(&s->lk); - - nni_id_map_init(&s->pipes, 0, 0, false); - nni_lmq_init(&s->waitlmq, 256); - NNI_LIST_INIT(&s->recvq, nano_ctx, rqnode); - NNI_LIST_INIT(&s->recvpipes, nano_pipe, rnode); - - nni_atomic_init(&s->ttl); - nni_atomic_set(&s->ttl, 8); - - (void) nano_ctx_init(&s->ctx, s); - - debug_msg("************* nano_sock_init %p *************", s); - // We start off without being either readable or writable. - // Readability comes when there is something on the socket. - nni_pollable_init(&s->writable); - nni_pollable_init(&s->readable); - - return (0); -} - -static void -nano_sock_open(void *arg) -{ - NNI_ARG_UNUSED(arg); -} - -static void -nano_sock_close(void *arg) -{ - nano_sock *s = arg; - - nano_ctx_close(&s->ctx); -} - -static void -nano_pipe_stop(void *arg) -{ - nano_pipe *p = arg; - - debug_msg("##########nano_pipe_stop###############"); - nni_aio_stop(&p->aio_send); - nni_aio_stop(&p->aio_timer); - nni_aio_stop(&p->aio_recv); -} - -static void -nano_pipe_fini(void *arg) -{ - nano_pipe * p = arg; - nng_msg * msg; - - debug_msg("########## nano_pipe_fini ###############"); - if ((msg = nni_aio_get_msg(&p->aio_recv)) != NULL) { - nni_aio_set_msg(&p->aio_recv, NULL); - nni_msg_free(msg); - } - - if ((msg = nni_aio_get_msg(&p->aio_send)) != NULL) { - nni_aio_set_msg(&p->aio_recv, NULL); - nni_msg_free(msg); - } - - nni_id_map * nano_qos_db = p->pipe->nano_qos_db; - - //TODO safely free the msgs in qos_db - // nni_id_iterate(nano_qos_db, nni_id_msgfree_cb); - nni_id_map_fini(nano_qos_db); - nng_free(nano_qos_db, sizeof(struct nni_id_map)); - - nni_mtx_fini(&p->lk); - nni_aio_fini(&p->aio_send); - nni_aio_fini(&p->aio_recv); - nni_aio_fini(&p->aio_timer); - nano_nni_lmq_fini(&p->rlmq); -} - -static int -nano_pipe_init(void *arg, nni_pipe *pipe, void *s) -{ - nano_pipe *p = arg; - nano_sock *sock = s; - - debug_msg("##########nano_pipe_init###############"); - - nni_mtx_init(&p->lk); - nni_lmq_init(&p->rlmq, sock->conf->msq_len); - nni_aio_init(&p->aio_send, nano_pipe_send_cb, p); - nni_aio_init(&p->aio_timer, nano_pipe_timer_cb, p); - nni_aio_init(&p->aio_recv, nano_pipe_recv_cb, p); - - p->reason_code = 0x00; - p->id = nni_pipe_id(pipe); - p->pipe = pipe; - p->rep = s; - p->ka_refresh = 0; - p->kicked = false; - p->conn_param = nni_pipe_get_conn_param(pipe); - p->tree = sock->db; - p->conn_param->nano_qos_db = p->pipe->nano_qos_db; - - return (0); -} - -static int -nano_pipe_start(void *arg) -{ - nano_pipe *p = arg; - nano_sock *s = p->rep; - nni_msg * msg; - uint8_t rv, *reason; // reason code of CONNACK - uint8_t buf[4] = { 0x20, 0x02, 0x00, 0x00 }; - nni_pipe * npipe = p->pipe; - char * clientid = NULL; - uint32_t clientid_key = 0; - nni_msg ** msgq = NULL; - uint16_t pid = 0; - - debug_msg("##########nano_pipe_start################"); - /* - // TODO check peer protocol ver (websocket or tcp or quic??) - if (nni_pipe_peer(p->pipe) != NNG_NANO_TCP_PEER) { - // Peer protocol mismatch. - return (NNG_EPROTO); - } - */ - nni_msg_alloc(&msg, 0); - nni_msg_header_append(msg, buf, 4); - reason = nni_msg_header(msg) + 2; - nni_mtx_lock(&s->lk); - // TODO replace pipe_id with hash key of client_id - // pipe_id is just random value of id_dyn_val with self-increment. - nni_id_set(&s->pipes, nni_pipe_id(p->pipe), p); - rv = verify_connect(p->conn_param, s->conf); - if (rv != 0) { - // TODO disconnect client && send connack with reason code 0x05 - debug_syslog("Invalid auth info."); - *(reason + 1) = rv; // set return code - } - nni_mtx_unlock(&s->lk); - - // restore cached qos msg - clientid = (char *) conn_param_get_clientid(p->conn_param); - clientid_key = DJBHashn(clientid, strlen(clientid)); - if (cached_check_id(clientid_key)) { - msgq = (nni_msg **)dbtree_restore_session_msg(p->tree, clientid_key); - for(int i=0; i< (int) cvector_size(msgq); i++) { - pid = nni_pipe_inc_packetid(npipe); - nni_id_set(npipe->nano_qos_db, pid, msgq[i]); - } - cvector_free(msgq); - } - - // TODO MQTT V5 check return code - if (*(reason + 1) == 0) { - nni_sleep_aio(s->conf->qos_duration * 1500, &p->aio_timer); - } - nni_msg_set_cmd_type(msg, CMD_CONNACK); - nni_msg_set_conn_param(msg, p->conn_param); - // There is no need to check the state of aio_recv - // Since pipe_start is definetly the first cb to be excuted of pipe. - nni_aio_set_msg(&p->aio_recv, msg); - nni_aio_finish(&p->aio_recv, 0, nni_msg_len(msg)); - return (rv); -} - -static inline void -close_pipe(nano_pipe *p) -{ - nano_sock *s = p->rep; - nano_ctx * ctx; - - nni_aio_close(&p->aio_send); - nni_aio_close(&p->aio_recv); - nni_aio_close(&p->aio_timer); - - // nni_mtx_lock(&s->lk); - p->closed = true; - if (nni_list_active(&s->recvpipes, p)) { - nni_list_remove(&s->recvpipes, p); - } - nano_nni_lmq_flush(&p->rlmq); - - nni_id_remove(&s->pipes, nni_pipe_id(p->pipe)); -} - -static void -nano_pipe_close(void *arg) -{ - nano_pipe *p = arg; - nano_sock *s = p->rep; - nano_ctx * ctx; - nni_aio * aio = NULL; - nni_msg * msg; - nni_pipe * npipe = p->pipe; - uint16_t packetid = 0; - char * clientid = NULL; - uint32_t clientid_key = 0; - - debug_msg("################# nano_pipe_close ##############"); - nni_mtx_lock(&s->lk); - close_pipe(p); - - // cache qos msg TODO optimization in processing - if (p->conn_param->clean_start == 0) { - clientid = (char *)conn_param_get_clientid(p->conn_param); - clientid_key = DJBHashn(clientid, strlen(clientid)); - while((msg = nni_id_get_any(npipe->nano_qos_db, &packetid)) != NULL) { - while(nni_msg_shared(msg)) - nni_msg_free(msg); - dbtree_cache_session_msg(p->tree, msg, clientid_key); - nni_id_remove(npipe->nano_qos_db, packetid); - } - } - - // create disconnect event msg - msg = nano_msg_notify_disconnect(p->conn_param, p->reason_code); - if (msg == NULL) { - nni_mtx_unlock(&s->lk); - return; - } - nni_msg_set_conn_param(msg, p->conn_param); - nni_msg_set_cmd_type(msg, CMD_DISCONNECT_EV); - nni_msg_set_pipe(msg, p->id); - - // expose disconnect event - if ((ctx = nni_list_first(&s->recvq)) != NULL) { - aio = ctx->raio; - ctx->raio = NULL; - nni_list_remove(&s->recvq, ctx); - nni_mtx_unlock(&s->lk); - nni_aio_set_msg(aio, msg); - nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); - return; - } else { - // no enough ctx, so cache to waitlmq - if (nni_lmq_full(&s->waitlmq)) { - if (nni_lmq_resize(&s->waitlmq, nni_lmq_cap(&s->waitlmq) * 2) != 0) { - debug_msg("wait lmq resize failed."); - } - } - nni_lmq_putq(&s->waitlmq, msg); - } - nni_mtx_unlock(&s->lk); -} - -static void -nano_pipe_send_cb(void *arg) -{ - nano_pipe *p = arg; - nni_msg * msg; - uint8_t qos; - - debug_msg("******** nano_pipe_send_cb %d ****", p->id); - // retry here - if (nni_aio_result(&p->aio_send) != 0) { - nni_msg_free(nni_aio_get_msg(&p->aio_send)); - nni_aio_set_msg(&p->aio_send, NULL); - nni_pipe_close(p->pipe); - return; - } - nni_mtx_lock(&p->lk); - - nni_aio_set_packetid(&p->aio_send, 0); - if (nni_lmq_getq(&p->rlmq, &msg) == 0) { - // msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); - nni_aio_set_msg(&p->aio_send, msg); - debug_msg("rlmq msg resending! %ld msgs left\n", nni_lmq_len(&p->rlmq)); - nni_pipe_send(p->pipe, &p->aio_send); - nni_mtx_unlock(&p->lk); - return; - } - - p->busy = false; - nni_mtx_unlock(&p->lk); - return; -} - -static void -nano_cancel_recv(nni_aio *aio, void *arg, int rv) -{ - nano_ctx * ctx = arg; - nano_sock *s = ctx->sock; - - debug_msg("*********** nano_cancel_recv ***********"); - nni_mtx_lock(&s->lk); - if (ctx->raio == aio) { - nni_list_remove(&s->recvq, ctx); - ctx->raio = NULL; - nni_aio_finish_error(aio, rv); - } - nni_mtx_unlock(&s->lk); -} - -static void -nano_ctx_recv(void *arg, nni_aio *aio) -{ - nano_ctx * ctx = arg; - nano_sock *s = ctx->sock; - nano_pipe *p; - // size_t len; - nni_msg *msg = NULL; - - if (nni_aio_begin(aio) != 0) { - return; - } - - debug_msg("nano_ctx_recv start %p", ctx); - nni_mtx_lock(&s->lk); - - if (nni_lmq_getq(&s->waitlmq, &msg) == 0) { - nni_mtx_unlock(&s->lk); - debug_msg("handle msg in waitlmq."); - nni_aio_set_msg(aio, msg); - nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); - return; - } - - if ((p = nni_list_first(&s->recvpipes)) == NULL) { - int rv; - if ((rv = nni_aio_schedule(aio, nano_cancel_recv, ctx)) != 0) { - nni_mtx_unlock(&s->lk); - nni_aio_finish_error(aio, rv); - return; - } - if (ctx->raio != NULL) { - // Cannot have a second receive operation pending. - // This could be ESTATE, or we could cancel the first - // with ECANCELED. We elect the former. - debug_msg("ERROR: former aio not finish yet"); - nni_mtx_unlock(&s->lk); - nni_aio_finish_error(aio, NNG_ESTATE); - return; - } - ctx->raio = aio; - nni_list_append(&s->recvq, ctx); - nni_mtx_unlock(&s->lk); - return; - } - msg = nni_aio_get_msg(&p->aio_recv); - nni_aio_set_msg(&p->aio_recv, NULL); - nni_list_remove(&s->recvpipes, p); - if (nni_list_empty(&s->recvpipes)) { - nni_pollable_clear(&s->readable); - } - nni_pipe_recv(p->pipe, &p->aio_recv); - if ((ctx == &s->ctx) && !p->busy) { - nni_pollable_raise(&s->writable); - } - - // TODO MQTT 5 property - - ctx->pipe_id = nni_pipe_id(p->pipe); - debug_msg("nano_ctx_recv ends %p pipe: %p pipe_id: %d", ctx, p, - ctx->pipe_id); - nni_mtx_unlock(&s->lk); - - nni_aio_set_msg(aio, msg); - nni_aio_finish(aio, 0, nni_msg_len(msg)); -} - -static void -nano_pipe_recv_cb(void *arg) -{ - nano_pipe * p = arg; - nano_sock * s = p->rep; - nano_conn_param *cparam = NULL; - uint32_t len, len_of_varint = 0; - nano_ctx * ctx; - nni_msg * msg, *qos_msg = NULL; - nni_aio * aio; - nni_pipe * npipe = p->pipe; - uint8_t * ptr; - uint16_t ackid; - - if (nni_aio_result(&p->aio_recv) != 0) { - // unexpected disconnect - nni_pipe_close(p->pipe); - return; - } - debug_msg("######### nano_pipe_recv_cb ############"); - p->ka_refresh = 0; - msg = nni_aio_get_msg(&p->aio_recv); - if (msg == NULL) { - goto end; - } - - // ttl = nni_atomic_get(&s->ttl); - nni_msg_set_pipe(msg, p->id); - ptr = nni_msg_body(msg); - - // TODO HOOK - switch (nng_msg_cmd_type(msg)) { - case CMD_UNSUBSCRIBE: - case CMD_SUBSCRIBE: - cparam = p->conn_param; - if (cparam->pro_ver == PROTOCOL_VERSION_v5) { - len = get_var_integer(ptr + 2, &len_of_varint); - nni_msg_set_payload_ptr( - msg, ptr + 2 + len + len_of_varint); - } else { - nni_msg_set_payload_ptr(msg, ptr + 2); - } - break; - case CMD_DISCONNECT: - nni_pipe_close(p->pipe); - case CMD_CONNACK: - case CMD_PUBLISH: - case CMD_PINGREQ: - // Websocket need to reply PINGREQ in application layer - break; - case CMD_PUBACK: - case CMD_PUBCOMP: - nni_mtx_lock(&p->lk); - NNI_GET16(ptr, ackid); - if ((qos_msg = nni_id_get(npipe->nano_qos_db, ackid)) != - NULL) { - qos_msg = NANO_NNI_LMQ_GET_MSG_POINTER(qos_msg); - nni_msg_free(qos_msg); - nni_id_remove(npipe->nano_qos_db, ackid); - } else { - // shouldn't get here BUG TODO - debug_syslog("qos msg not found!"); - } - nni_mtx_unlock(&p->lk); - case CMD_CONNECT: - case CMD_PUBREC: - case CMD_PUBREL: - goto drop; - default: - goto drop; - } - - if (p->closed) { - // If we are closed, then we can't return data. - nni_aio_set_msg(&p->aio_recv, NULL); - nni_msg_free(msg); - debug_msg("ERROR: pipe is closed abruptly!!"); - return; - } - - nni_mtx_lock(&s->lk); - if ((ctx = nni_list_first(&s->recvq)) == NULL) { - // No one waiting to receive yet, holding pattern. - nni_list_append(&s->recvpipes, p); - nni_pollable_raise(&s->readable); - nni_mtx_unlock(&s->lk); - debug_msg("ERROR: no ctx found!! create more ctxs!"); - // nni_println("ERROR: no ctx found!! create more ctxs!"); - return; - } - - nni_list_remove(&s->recvq, ctx); - aio = ctx->raio; - ctx->raio = NULL; - nni_aio_set_msg(&p->aio_recv, NULL); - if ((ctx == &s->ctx) && !p->busy) { - nni_pollable_raise(&s->writable); - } - - // schedule another receive - nni_pipe_recv(p->pipe, &p->aio_recv); - - ctx->pipe_id = p->id; - debug_msg("currently processing pipe_id: %d", p->id); - - nni_mtx_unlock(&s->lk); - nni_aio_set_msg(aio, msg); - - nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); - debug_msg("end of nano_pipe_recv_cb %p", ctx); - return; - -drop: - nni_msg_free(msg); -end: - nni_aio_set_msg(&p->aio_recv, NULL); - nni_pipe_recv(p->pipe, &p->aio_recv); - debug_msg("Warning:dropping msg"); - return; -} - -static int -nano_sock_set_max_ttl(void *arg, const void *buf, size_t sz, nni_opt_type t) -{ - nano_sock *s = arg; - int ttl; - int rv; - - if ((rv = nni_copyin_int(&ttl, buf, sz, 1, NNI_MAX_MAX_TTL, t)) == 0) { - nni_atomic_set(&s->ttl, ttl); - } - return (rv); -} - -static int -nano_sock_get_max_ttl(void *arg, void *buf, size_t *szp, nni_opt_type t) -{ - nano_sock *s = arg; - - return (nni_copyout_int(nni_atomic_get(&s->ttl), buf, szp, t)); -} - -static int -nano_sock_get_sendfd(void *arg, void *buf, size_t *szp, nni_opt_type t) -{ - nano_sock *s = arg; - int rv; - int fd; - - if ((rv = nni_pollable_getfd(&s->writable, &fd)) != 0) { - return (rv); - } - return (nni_copyout_int(fd, buf, szp, t)); -} - -static int -nano_sock_get_recvfd(void *arg, void *buf, size_t *szp, nni_opt_type t) -{ - nano_sock *s = arg; - int rv; - int fd; - - if ((rv = nni_pollable_getfd(&s->readable, &fd)) != 0) { - return (rv); - } - - return (nni_copyout_int(fd, buf, szp, t)); -} - -static void -nano_sock_send(void *arg, nni_aio *aio) -{ - nano_sock *s = arg; - - nano_ctx_send(&s->ctx, aio); -} - -static void -nano_sock_recv(void *arg, nni_aio *aio) -{ - nano_sock *s = arg; - - nano_ctx_recv(&s->ctx, aio); -} - -static void -nano_sock_setdb(void *arg, void *data) -{ - nano_sock *s = arg; - conf * nano_conf = data; - - s->conf = nano_conf; - s->db = nano_conf->db_root; - - conf_auth_parser(s->conf); -} - -// This is the global protocol structure -- our linkage to the core. -// This should be the only global non-static symbol in this file. -static nni_proto_pipe_ops nano_pipe_ops = { - .pipe_size = sizeof(nano_pipe), - .pipe_init = nano_pipe_init, - .pipe_fini = nano_pipe_fini, - .pipe_start = nano_pipe_start, - .pipe_close = nano_pipe_close, - .pipe_stop = nano_pipe_stop, -}; - -static nni_proto_ctx_ops nano_ctx_ops = { - .ctx_size = sizeof(nano_ctx), - .ctx_init = nano_ctx_init, - .ctx_fini = nano_ctx_fini, - .ctx_send = nano_ctx_send, - .ctx_recv = nano_ctx_recv, -}; - -static nni_option nano_sock_options[] = { - { - .o_name = NNG_OPT_MAXTTL, - .o_get = nano_sock_get_max_ttl, - .o_set = nano_sock_set_max_ttl, - }, - { - .o_name = NNG_OPT_RECVFD, - .o_get = nano_sock_get_recvfd, - }, - { - .o_name = NNG_OPT_SENDFD, - .o_get = nano_sock_get_sendfd, - }, - { - .o_name = NULL, - }, -}; - -static nni_proto_sock_ops nano_sock_ops = { - .sock_size = sizeof(nano_sock), - .sock_init = nano_sock_init, - .sock_fini = nano_sock_fini, - .sock_open = nano_sock_open, - .sock_close = nano_sock_close, - .sock_options = nano_sock_options, - .sock_send = nano_sock_send, - .sock_recv = nano_sock_recv, -}; - -static nni_proto nano_tcp_proto = { - .proto_version = NNI_PROTOCOL_VERSION, - .proto_self = { NNG_NANO_TCP_SELF, NNG_NANO_TCP_SELF_NAME }, - .proto_peer = { NNG_NANO_TCP_PEER, NNG_NANO_TCP_PEER_NAME }, - .proto_flags = NNI_PROTO_FLAG_SNDRCV, - .proto_sock_ops = &nano_sock_ops, - .proto_pipe_ops = &nano_pipe_ops, - .proto_ctx_ops = &nano_ctx_ops, -}; - -int -nng_nano_tcp0_open(nng_socket *sidp) -{ - // TODO Global binary tree init here - return (nni_proto_mqtt_open(sidp, &nano_tcp_proto, nano_sock_setdb)); -} From 795bcf8a1d0ef68489da02a0c658534b0dadea23 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Tue, 30 Nov 2021 16:24:11 +0800 Subject: [PATCH 171/180] * FIX [mqtt_client] set more args for nng_mqtt_cb. --- demo/mqtt_async/mqtt_async.c | 11 ++++++----- include/nng/mqtt/mqtt_client.h | 3 ++- src/sp/transport/mqtt/mqtt_tcp.c | 12 +++++++----- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index bb1970f41..c2e6a6c79 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -151,9 +151,9 @@ alloc_work(nng_socket sock, uint32_t index) // Connack message callback function static void -connect_cb(void *arg, nng_msg *msg) +connect_cb(void *connect_arg, nng_msg *msg) { - (void) arg; + (void) connect_arg; printf( "Connack status: %d\n", nng_mqtt_msg_get_connack_return_code(msg)); nng_msg_free(msg); @@ -161,9 +161,9 @@ connect_cb(void *arg, nng_msg *msg) // Disconnect message callback function static void -disconnect_cb(void *arg, nng_msg *msg) +disconnect_cb(void *disconn_arg, nng_msg *msg) { - (void) arg; + (void) disconn_arg; printf("Disconnected\n"); } @@ -171,7 +171,8 @@ static nng_mqtt_cb usercb = { .name = "usercb", .on_connected = connect_cb, .on_disconnected = disconnect_cb, - .arg = "Args", // void * + .connect_arg = "Args", // void * + .disconn_arg = "Args", // void * }; int diff --git a/include/nng/mqtt/mqtt_client.h b/include/nng/mqtt/mqtt_client.h index 98867fb76..40a8a5a3d 100644 --- a/include/nng/mqtt/mqtt_client.h +++ b/include/nng/mqtt/mqtt_client.h @@ -208,7 +208,8 @@ typedef struct { char *name; void (*on_connected)(void *, nng_msg *); void (*on_disconnected)(void *, nng_msg *); - void *arg; + void *connect_arg; + void *disconn_arg; } nng_mqtt_cb; extern int nng_mqtt_user_props_alloc(nng_mqtt_user_props_t **); diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 42dd96a44..02df0c9e8 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -185,7 +185,7 @@ mqtt_tcptran_pipe_fini(void *arg) } if (ep && ep->usercb) { - ep->usercb->on_disconnected(ep->usercb->arg, NULL); + ep->usercb->on_disconnected(ep->usercb->disconn_arg, NULL); } nni_aio_free(p->rxaio); @@ -364,7 +364,7 @@ mqtt_tcptran_pipe_nego_cb(void *arg) // Run user callback if (ep->usercb != NULL) { - ep->usercb->on_connected(ep->usercb->arg, rmsg); + ep->usercb->on_connected(ep->usercb->connect_arg, rmsg); } return; @@ -572,8 +572,10 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_pipe_bump_error(p->npipe, rv); nni_mtx_unlock(&p->mtx); - if (p->ep->usercb) - p->ep->usercb->on_disconnected(p->ep->usercb->arg, NULL); + if (p->ep->usercb) { + p->ep->usercb->on_disconnected( + p->ep->usercb->disconn_arg, NULL); + } nni_msg_free(msg); nni_aio_finish_error(aio, rv); @@ -878,7 +880,7 @@ mqtt_tcptran_ep_close(void *arg) } if (ep->usercb) { - ep->usercb->on_disconnected(ep->usercb->arg, NULL); + ep->usercb->on_disconnected(ep->usercb->disconn_arg, NULL); } nni_mtx_unlock(&ep->mtx); From b31eba5caee7dafd899fcf2551b61ecf5da80846 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Tue, 30 Nov 2021 18:41:35 +0800 Subject: [PATCH 172/180] * MDF [mqtt_tls] adapt to mqtt_tcp --- demo/mqtt_async/CMakeLists.txt | 11 +- demo/mqtt_async/mqtt_async.c | 169 ++++++++++++++++-------------- src/sp/transport/mqtt/mqtt_tcp.c | 8 -- src/sp/transport/mqtts/mqtt_tls.c | 29 +++-- 4 files changed, 117 insertions(+), 100 deletions(-) diff --git a/demo/mqtt_async/CMakeLists.txt b/demo/mqtt_async/CMakeLists.txt index c4b09eeb3..9fe1e8592 100644 --- a/demo/mqtt_async/CMakeLists.txt +++ b/demo/mqtt_async/CMakeLists.txt @@ -10,9 +10,14 @@ project(mqtt_async) find_package(nng CONFIG REQUIRED) find_package(Threads) -find_package(MbedTLS) add_executable(mqtt_async mqtt_async.c) -target_link_libraries(mqtt_async nng ) -target_link_libraries(mqtt_async mbedtls mbedx509 mbedcrypto) +target_link_libraries(mqtt_async nng) target_link_libraries(mqtt_async ${CMAKE_THREAD_LIBS_INIT}) + +if(NNG_ENABLE_TLS) + find_package(MbedTLS) + target_link_libraries(mqtt_async mbedtls mbedx509 mbedcrypto) + add_definitions(-DNNG_SUPP_TLS) +endif() + diff --git a/demo/mqtt_async/mqtt_async.c b/demo/mqtt_async/mqtt_async.c index c2e6a6c79..644973f8d 100644 --- a/demo/mqtt_async/mqtt_async.c +++ b/demo/mqtt_async/mqtt_async.c @@ -10,9 +10,12 @@ #include #include -#include #include +#ifdef NNG_SUPP_TLS +#include +#endif + static size_t nwork = 32; struct work { @@ -20,31 +23,11 @@ struct work { nng_aio *aio; nng_msg *msg; nng_ctx ctx; - uint32_t index; }; #define SUB_TOPIC1 "/nanomq/msg/1" #define SUB_TOPIC2 "/nanomq/msg/2" #define SUB_TOPIC3 "/nanomq/msg/3" -#define SUB_TOPIC4 "/nanomq/msg/4" - -// Mqtt subscribe array of topic with qos -static nng_mqtt_topic_qos topic_qos[] = { - { .qos = 0, - .topic = { .buf = (uint8_t *) SUB_TOPIC1, - .length = strlen(SUB_TOPIC1) } }, - { .qos = 1, - .topic = { .buf = (uint8_t *) SUB_TOPIC2, - .length = strlen(SUB_TOPIC2) } }, - { .qos = 2, - .topic = { .buf = (uint8_t *) SUB_TOPIC3, - .length = strlen(SUB_TOPIC3) } }, - { .qos = 0, - .topic = { .buf = (uint8_t *) SUB_TOPIC4, - .length = strlen(SUB_TOPIC4) } } -}; - -static size_t topic_qos_count = sizeof(topic_qos) / sizeof(nng_mqtt_topic_qos); void fatal(const char *msg, int rv) @@ -62,22 +45,8 @@ client_cb(void *arg) switch (work->state) { case INIT: - if (work->index == 0) { - // Send subscribe message by work[0] - nng_mqtt_msg_alloc(&msg, 0); - nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); - nng_mqtt_msg_set_subscribe_topics( - msg, topic_qos, topic_qos_count); - - work->msg = msg; - nng_aio_set_msg(work->aio, work->msg); - work->msg = NULL; - work->state = SEND; - nng_ctx_send(work->ctx, work->aio); - } else { - work->state = RECV; - nng_ctx_recv(work->ctx, work->aio); - } + work->state = RECV; + nng_ctx_recv(work->ctx, work->aio); break; case RECV: if ((rv = nng_aio_result(work->aio)) != 0) { @@ -92,7 +61,7 @@ client_cb(void *arg) const char *recv_topic = nng_mqtt_msg_get_publish_topic(msg, &topic_len); - printf("Recv '%.*s' from topic '%.*s'\n", payload_len, + printf("RECV: '%.*s' FROM: '%.*s'\n", payload_len, (char *) payload, topic_len, recv_topic); work->msg = msg; @@ -102,9 +71,9 @@ client_cb(void *arg) case WAIT: nng_msg_header_clear(work->msg); nng_msg_clear(work->msg); + // Send message to another topic - char topic[50] = { 0 }; - snprintf(topic, 50, "/nanomq/msg/%02d/rep", work->index); + char *topic = "/nanomq/msg/reply"; nng_mqtt_msg_set_packet_type(work->msg, NNG_MQTT_PUBLISH); nng_mqtt_msg_set_publish_topic(work->msg, topic); nng_mqtt_msg_set_publish_payload( @@ -130,7 +99,7 @@ client_cb(void *arg) } struct work * -alloc_work(nng_socket sock, uint32_t index) +alloc_work(nng_socket sock) { struct work *w; int rv; @@ -145,7 +114,6 @@ alloc_work(nng_socket sock, uint32_t index) fatal("nng_ctx_open", rv); } w->state = INIT; - w->index = index; return (w); } @@ -153,10 +121,40 @@ alloc_work(nng_socket sock, uint32_t index) static void connect_cb(void *connect_arg, nng_msg *msg) { - (void) connect_arg; - printf( - "Connack status: %d\n", nng_mqtt_msg_get_connack_return_code(msg)); + // Mqtt subscribe array of topic with qos + nng_mqtt_topic_qos topic_qos[] = { + { .qos = 0, + .topic = { .buf = (uint8_t *) SUB_TOPIC1, + .length = strlen(SUB_TOPIC1) } }, + { .qos = 1, + .topic = { .buf = (uint8_t *) SUB_TOPIC2, + .length = strlen(SUB_TOPIC2) } }, + { .qos = 2, + .topic = { .buf = (uint8_t *) SUB_TOPIC3, + .length = strlen(SUB_TOPIC3) } } + }; + + size_t topic_qos_count = + sizeof(topic_qos) / sizeof(nng_mqtt_topic_qos); + + nng_socket sock = *(nng_socket *) connect_arg; + uint8_t ret_code = nng_mqtt_msg_get_connack_return_code(msg); + printf("%s\n", __FUNCTION__); + printf("connack status: %d\n", ret_code); + nng_msg_free(msg); + msg = NULL; + + if (ret_code == 0) { + // Connected succeed + nng_mqtt_msg_alloc(&msg, 0); + nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_SUBSCRIBE); + nng_mqtt_msg_set_subscribe_topics( + msg, topic_qos, topic_qos_count); + + // Send subscribe message + nng_sendmsg(sock, msg, NNG_FLAG_NONBLOCK); + } } // Disconnect message callback function @@ -164,17 +162,9 @@ static void disconnect_cb(void *disconn_arg, nng_msg *msg) { (void) disconn_arg; - printf("Disconnected\n"); + printf("%s\n", __FUNCTION__); } -static nng_mqtt_cb usercb = { - .name = "usercb", - .on_connected = connect_cb, - .on_disconnected = disconnect_cb, - .connect_arg = "Args", // void * - .disconn_arg = "Args", // void * -}; - int client(const char *url) { @@ -189,11 +179,7 @@ client(const char *url) } for (i = 0; i < nwork; i++) { - works[i] = alloc_work(sock, i); - } - - if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { - fatal("nng_dialer_create", rv); + works[i] = alloc_work(sock); } // Mqtt connect message @@ -203,8 +189,20 @@ client(const char *url) nng_mqtt_msg_set_connect_keep_alive(msg, 60); nng_mqtt_msg_set_connect_clean_session(msg, true); + nng_mqtt_cb user_cb = { + .name = "user_cb", + .on_connected = connect_cb, + .on_disconnected = disconnect_cb, + .connect_arg = &sock, + .disconn_arg = "Args", + }; + + if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { + fatal("nng_dialer_create", rv); + } + nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); - nng_dialer_set_cb(dialer, &usercb); + nng_dialer_set_cb(dialer, &user_cb); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); for (i = 0; i < nwork; i++) { @@ -216,6 +214,7 @@ client(const char *url) } } +#ifdef NNG_SUPP_TLS // This reads a file into memory. Care is taken to ensure that // the buffer is one byte larger and contains a terminating // NUL. (Useful for key files and such.) @@ -327,13 +326,8 @@ tls_client(const char *url, const char *ca, const char *cert, const char *key, } for (i = 0; i < nwork; i++) { - works[i] = alloc_work(sock, i); - } - - if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { - fatal("nng_dialer_create", rv); + works[i] = alloc_work(sock); } - // Mqtt connect message nng_msg *msg; nng_mqtt_msg_alloc(&msg, 0); @@ -341,12 +335,24 @@ tls_client(const char *url, const char *ca, const char *cert, const char *key, nng_mqtt_msg_set_connect_keep_alive(msg, 60); nng_mqtt_msg_set_connect_clean_session(msg, true); + nng_mqtt_cb user_cb = { + .name = "user_cb", + .on_connected = connect_cb, + .on_disconnected = disconnect_cb, + .connect_arg = &sock, + .disconn_arg = "Args", + }; + + if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { + fatal("nng_dialer_create", rv); + } + if ((rv = init_dialer_tls(dialer, ca, cert, key, pass)) != 0) { fatal("init_dialer_tls", rv); } nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); - nng_dialer_set_cb(dialer, connect_cb); + nng_dialer_set_cb(dialer, &user_cb); nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); for (i = 0; i < nwork; i++) { @@ -357,18 +363,21 @@ tls_client(const char *url, const char *ca, const char *cert, const char *key, nng_msleep(3600000); // neither pause() nor sleep() portable } } +#endif void usage(void) { printf("mqtt_async: \n"); printf(" -u \n"); + printf(" -n (default: 32)\n"); +#ifdef NNG_SUPP_TLS printf(" -s enable ssl/tls mode (default: disable)\n"); printf(" -a \n"); printf(" -c \n"); - printf(" -k \n"); - printf(" -p \n"); - printf(" -n number of works (default: 32)\n"); + printf(" -k \n"); + printf(" -p \n"); +#endif } int @@ -388,17 +397,17 @@ main(int argc, char **argv) int opt; int digit_optind = 0; int option_index = 0; - char *short_options = "u:sa:c:k:p:n:W;"; + char *short_options = "u:n:sa:c:k:p:W;"; static struct option long_options[] = { { "url", required_argument, NULL, 0 }, + { "nwork", no_argument, NULL, 'n' }, { "ssl", no_argument, NULL, false }, { "cafile", required_argument, NULL, 0 }, { "cert", required_argument, NULL, 0 }, { "key", required_argument, NULL, 0 }, { "psw", required_argument, NULL, 0 }, { "help", no_argument, NULL, 'h' }, - { "nwork", no_argument, NULL, 'n' }, { NULL, 0, NULL, 0 }, }; @@ -415,31 +424,29 @@ main(int argc, char **argv) case 'u': url = argv[optind - 1]; break; + case 'n': + nwork = atoi(argv[optind - 1]); + break; case 's': enable_ssl = true; break; +#ifdef NNG_SUPP_TLS case 'a': path = argv[optind - 1]; loadfile(path, (void **) &cafile, &file_len); - printf("cafile:\n%s\n", cafile); break; case 'c': path = argv[optind - 1]; loadfile(path, (void **) &cert, &file_len); - printf("cert:\n%s\n", cert); break; case 'k': path = argv[optind - 1]; loadfile(path, (void **) &key, &file_len); - printf("key:\n%s\n", key); break; case 'p': key_psw = argv[optind - 1]; break; - case 'n': - nwork = atoi(argv[optind - 1]); - break; - +#endif default: fprintf(stderr, "invalid argument: '%c'\n", opt); usage(); @@ -448,7 +455,11 @@ main(int argc, char **argv) } if (enable_ssl) { +#ifdef NNG_SUPP_TLS tls_client(url, cafile, cert, key, key_psw); +#else + fprintf(stderr, "tls client: Not supported \n"); +#endif } else { client(url); diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 02df0c9e8..6e3976077 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -581,14 +581,6 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_aio_finish_error(aio, rv); printf("mqtt_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); return; - // notify: - // // nni_pipe_bump_rx(p->npipe, n); - // nni_aio_list_remove(aio); - // mqtt_tcptran_pipe_recv_start(p); - // nni_mtx_unlock(&p->mtx); - // nni_aio_set_msg(aio, NULL); - // nni_aio_finish(aio, 0, 0); - return; } static void diff --git a/src/sp/transport/mqtts/mqtt_tls.c b/src/sp/transport/mqtts/mqtt_tls.c index d6ef2a2cb..852a83465 100644 --- a/src/sp/transport/mqtts/mqtt_tls.c +++ b/src/sp/transport/mqtts/mqtt_tls.c @@ -15,6 +15,7 @@ #include "core/nng_impl.h" #include "mqtt/mqtt.h" +#include "nng/mqtt/mqtt_client.h" #include "nng/supplemental/tls/tls.h" // TLS Over TCP transport. Platform specific TLS Over TCP operations must be @@ -80,8 +81,7 @@ struct mqtts_tcptran_ep { nng_stream_listener *listener; nni_dialer * ndialer; void * connmsg; - void (*conncb)(void *, nng_msg *); - void *arg; + nng_mqtt_cb * usercb; #ifdef NNG_ENABLE_STATS nni_stat_item st_rcv_max; @@ -187,6 +187,9 @@ mqtts_tcptran_pipe_fini(void *arg) nni_mtx_unlock(&ep->mtx); } + if (ep && ep->usercb) { + ep->usercb->on_disconnected(ep->usercb->disconn_arg, NULL); + } nni_aio_free(p->rxaio); nni_aio_free(p->txaio); nni_aio_free(p->rsaio); @@ -362,8 +365,8 @@ mqtts_tcptran_pipe_nego_cb(void *arg) nni_mtx_unlock(&ep->mtx); // Run user callback - if (ep->conncb != NULL) { - ep->conncb(ep->arg, rmsg); + if (ep->usercb != NULL) { + ep->usercb->on_connected(ep->usercb->connect_arg, rmsg); } return; @@ -573,6 +576,11 @@ mqtts_tcptran_pipe_recv_cb(void *arg) nni_pipe_bump_error(p->npipe, rv); nni_mtx_unlock(&p->mtx); + if (p->ep->usercb) { + p->ep->usercb->on_disconnected( + p->ep->usercb->disconn_arg, NULL); + } + nni_msg_free(msg); nni_aio_finish_error(aio, rv); printf("mqtts_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); @@ -844,6 +852,10 @@ mqtts_tcptran_ep_close(void *arg) ep->useraio = NULL; } + if (ep->usercb) { + ep->usercb->on_disconnected(ep->usercb->disconn_arg, NULL); + } + nni_mtx_unlock(&ep->mtx); } @@ -1026,8 +1038,7 @@ mqtts_tcptran_ep_init(mqtts_tcptran_ep **epp, nng_url *url, nni_sock *sock) ep->proto = nni_sock_proto_id(sock); ep->url = url; - ep->conncb = NULL; - ep->arg = NULL; + ep->usercb = NULL; #ifdef NNG_ENABLE_STATS static const nni_stat_info rcv_max_info = { @@ -1284,15 +1295,13 @@ mqtts_tcptran_ep_get_connmsg(void *arg, void *v, size_t *szp, nni_opt_type t) } static int -mqtts_tcptran_dialer_setcb( - void *arg, void (*cb)(void *, nng_msg *), void *args) +mqtts_tcptran_dialer_setcb(void *arg, void * cb) { mqtts_tcptran_ep *ep = arg; int rv; nni_mtx_lock(&ep->mtx); - ep->conncb = cb; - ep->arg = args; + ep->usercb = cb; nni_mtx_unlock(&ep->mtx); rv = 0; From d9225512c751fc5656b3648cd0a5eda97ba4c498 Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Wed, 1 Dec 2021 12:10:26 +0800 Subject: [PATCH 173/180] * MDF [mqtt] remove 'printf' --- src/sp/transport/mqtt/mqtt_tcp.c | 3 --- src/sp/transport/mqtts/mqtt_tls.c | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 6e3976077..80ee15880 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -529,7 +529,6 @@ mqtt_tcptran_pipe_recv_cb(void *arg) iov.iov_len = 4; iov.iov_buf = &p->txlen; // send it down... - printf("PUBRECV\n"); nni_aio_set_iov(p->rsaio, 1, &iov); nng_stream_send(p->conn, p->rsaio); } @@ -551,7 +550,6 @@ mqtt_tcptran_pipe_recv_cb(void *arg) iov.iov_len = 4; iov.iov_buf = &p->txlen; // send it down... - printf("PUBCOMP\n"); nni_aio_set_iov(p->rpaio, 1, &iov); nng_stream_send(p->conn, p->rpaio); } @@ -579,7 +577,6 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_msg_free(msg); nni_aio_finish_error(aio, rv); - printf("mqtt_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); return; } diff --git a/src/sp/transport/mqtts/mqtt_tls.c b/src/sp/transport/mqtts/mqtt_tls.c index 852a83465..48c1b0bc0 100644 --- a/src/sp/transport/mqtts/mqtt_tls.c +++ b/src/sp/transport/mqtts/mqtt_tls.c @@ -531,7 +531,6 @@ mqtts_tcptran_pipe_recv_cb(void *arg) iov.iov_len = 4; iov.iov_buf = &p->txlen; // send it down... - printf("PUBRECV\n"); nni_aio_set_iov(p->rsaio, 1, &iov); nng_stream_send(p->conn, p->rsaio); } @@ -553,7 +552,6 @@ mqtts_tcptran_pipe_recv_cb(void *arg) iov.iov_len = 4; iov.iov_buf = &p->txlen; // send it down... - printf("PUBCOMP\n"); nni_aio_set_iov(p->rpaio, 1, &iov); nng_stream_send(p->conn, p->rpaio); } @@ -583,7 +581,6 @@ mqtts_tcptran_pipe_recv_cb(void *arg) nni_msg_free(msg); nni_aio_finish_error(aio, rv); - printf("mqtts_tcptran_pipe_recv_cb: recv error rv: %d\n", rv); return; } From 4307d23c3199aea00d80f46aecb97742b7767f3f Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Wed, 1 Dec 2021 15:18:55 +0800 Subject: [PATCH 174/180] * FIX [mqtt_tcp] fix unnecessary trigger of user disconnect cb. --- src/sp/transport/mqtt/mqtt_tcp.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/sp/transport/mqtt/mqtt_tcp.c b/src/sp/transport/mqtt/mqtt_tcp.c index 80ee15880..b296e538b 100644 --- a/src/sp/transport/mqtt/mqtt_tcp.c +++ b/src/sp/transport/mqtt/mqtt_tcp.c @@ -570,11 +570,6 @@ mqtt_tcptran_pipe_recv_cb(void *arg) nni_pipe_bump_error(p->npipe, rv); nni_mtx_unlock(&p->mtx); - if (p->ep->usercb) { - p->ep->usercb->on_disconnected( - p->ep->usercb->disconn_arg, NULL); - } - nni_msg_free(msg); nni_aio_finish_error(aio, rv); return; @@ -868,10 +863,6 @@ mqtt_tcptran_ep_close(void *arg) ep->useraio = NULL; } - if (ep->usercb) { - ep->usercb->on_disconnected(ep->usercb->disconn_arg, NULL); - } - nni_mtx_unlock(&ep->mtx); } From c287b158189bc984dcca2be7bdb80ec096e7ec8e Mon Sep 17 00:00:00 2001 From: alvin1221 Date: Wed, 1 Dec 2021 12:15:50 +0800 Subject: [PATCH 175/180] * MDF [docs] description of MQTT related APIs --- docs/man/libnng.3.adoc | 49 ++++++++------- docs/man/nng_dialer_set.3.adoc | 5 ++ docs/man/nng_mqtt_callback_function.3.adoc | 69 +++++++++++++++++++++ docs/man/nng_mqtt_client_open.3.adoc | 70 ++++++++++++++++++++++ 4 files changed, 173 insertions(+), 20 deletions(-) create mode 100644 docs/man/nng_mqtt_callback_function.3.adoc create mode 100644 docs/man/nng_mqtt_client_open.3.adoc diff --git a/docs/man/libnng.3.adoc b/docs/man/libnng.3.adoc index 226ec8941..4a2ce7c68 100644 --- a/docs/man/libnng.3.adoc +++ b/docs/man/libnng.3.adoc @@ -136,26 +136,6 @@ mode may need to access the header of messages. |xref:nng_msg_header_trim.3.adoc[nng_msg_header_trim()]|remove data from start of message header |=== -==== MQTT Message Handling - -TIP: - -|=== -|xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc()]|allocate a message with proto_data for mqtt -|xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode()]|decode a mqtt bytes stream from nng_msg_body and nng_msg_header to proto_data -|xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode()]|encode a mqtt message from proto_data to nng_msg_body and nng_msg_header -|xref:nng_mqtt_msg_get_connect.3.adoc[nng_mqtt_msg_get_connect()]|get mqtt connect message -|xref:nng_mqtt_msg_get_packet_type.3.adoc[nng_mqtt_msg_get_packet_type()]|get mqtt packet type -|xref:nng_mqtt_msg_get_publish.3.adoc[nng_mqtt_msg_get_publish()]|get mqtt publish message -|xref:nng_mqtt_msg_get_subscribe.3.adoc[nng_mqtt_msg_get_subscribe()]|get mqtt subscribe message -|xref:nng_mqtt_msg_get_unsubscribe.3.adoc[nng_mqtt_msg_get_unsubscribe()]|get mqtt unsubscribe message -|xref:nng_mqtt_msg_set_connect.3.adoc[nng_mqtt_msg_set_connect()]|set mqtt connect message -|xref:nng_mqtt_msg_set_packet_type.3.adoc[nng_mqtt_msg_set_packet_type()]|set mqtt packet type -|xref:nng_mqtt_msg_set_publish.3.adoc[nng_mqtt_msg_set_publish()]|set mqtt publish message -|xref:nng_mqtt_msg_set_subscribe.3.adoc[nng_mqtt_msg_set_subscribe()]|set mqtt subscribe message -|xref:nng_mqtt_msg_set_unsubscribe.3.adoc[nng_mqtt_msg_set_unsubscribe()]|set mqtt unsubscribe message -|=== - === Asynchronous Operations Most applications will interact with _NNG_ synchronously; that is that @@ -472,6 +452,35 @@ with TLS support. |xref:nng_tls_config_server_name.3tls.adoc[nng_tls_config_server_name()]|set remote server name |=== +=== MQTT Support + +The library support MQTT V3.1.1 for now (V5.0 is being prepared for development) + +==== MQTT Message Handling +|=== +|xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc()]|allocate a message with proto_data for mqtt +|xref:nng_mqtt_msg_decode.3.adoc[nng_mqtt_msg_decode()]|decode a mqtt bytes stream from nng_msg_body and nng_msg_header to proto_data +|xref:nng_mqtt_msg_encode.3.adoc[nng_mqtt_msg_encode()]|encode a mqtt message from proto_data to nng_msg_body and nng_msg_header +|xref:nng_mqtt_msg_get_connect.3.adoc[nng_mqtt_msg_get_connect()]|get mqtt connect message +|xref:nng_mqtt_msg_get_packet_type.3.adoc[nng_mqtt_msg_get_packet_type()]|get mqtt packet type +|xref:nng_mqtt_msg_get_publish.3.adoc[nng_mqtt_msg_get_publish()]|get mqtt publish message +|xref:nng_mqtt_msg_get_subscribe.3.adoc[nng_mqtt_msg_get_subscribe()]|get mqtt subscribe message +|xref:nng_mqtt_msg_get_unsubscribe.3.adoc[nng_mqtt_msg_get_unsubscribe()]|get mqtt unsubscribe message +|xref:nng_mqtt_msg_set_connect.3.adoc[nng_mqtt_msg_set_connect()]|set mqtt connect message +|xref:nng_mqtt_msg_set_packet_type.3.adoc[nng_mqtt_msg_set_packet_type()]|set mqtt packet type +|xref:nng_mqtt_msg_set_publish.3.adoc[nng_mqtt_msg_set_publish()]|set mqtt publish message +|xref:nng_mqtt_msg_set_subscribe.3.adoc[nng_mqtt_msg_set_subscribe()]|set mqtt subscribe message +|xref:nng_mqtt_msg_set_unsubscribe.3.adoc[nng_mqtt_msg_set_unsubscribe()]|set mqtt unsubscribe message +|=== + +==== MQTT Client Functions + +These functions are intended for use with MQTT client applications. + +|=== +|xref:nng_mqtt_client_open.3.adoc[nng_mqtt_client_open]|open mqtt client socket +|xref:nng_mqtt_callback_function.3.adoc[nng_mqtt_cb]|mqtt callback function +|=== == SEE ALSO diff --git a/docs/man/nng_dialer_set.3.adoc b/docs/man/nng_dialer_set.3.adoc index 3363eae9a..dcacc324d 100644 --- a/docs/man/nng_dialer_set.3.adoc +++ b/docs/man/nng_dialer_set.3.adoc @@ -36,6 +36,8 @@ int nng_dialer_set_string(nng_dialer d, const char *opt, const char *str); int nng_dialer_set_uint64(nng_dialer d, const char *opt, uint64_t u64); +int nng_dialer_set_cb(nng_dialer d, void * cb); + ---- == DESCRIPTION @@ -104,6 +106,9 @@ This function is used to configure a 64-bit unsigned value, _u64_. This is typically used for options related to identifiers, network numbers, and such. +`nng_dialer_set_cb()`:: +This function is used to configure callback function for current dialer. + == RETURN VALUES These functions return 0 on success, and non-zero otherwise. diff --git a/docs/man/nng_mqtt_callback_function.3.adoc b/docs/man/nng_mqtt_callback_function.3.adoc new file mode 100644 index 000000000..81c63ba11 --- /dev/null +++ b/docs/man/nng_mqtt_callback_function.3.adoc @@ -0,0 +1,69 @@ += nng_mqtt_cb(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_cb - mqtt client callback function structure + +== SYNOPSIS + +[source, c] +---- +#include +#define NNG_OPT_MQTT_CONNMSG "mqtt-connect-msg" + +#include +typedef struct { + char *name; + void (*on_connected)(void *, nng_msg *); + void (*on_disconnected)(void *, nng_msg *); + void *connect_arg; + void *disconn_arg; +} nng_mqtt_cb; +---- + +== DESCRIPTION + +The `nng_mqtt_cb` define for MQTT client *connect* and *disconnect* callback functions, +and set by xref:nng_dialer_set.3.adoc[nng_dialer_set_cb()] + +client demo snippet: +[source, c] +---- +nng_mqtt_cb user_cb = { + .name = "user_cb", + .on_connected = connect_cb, + .on_disconnected = disconnect_cb, + .connect_arg = "arg", + .disconn_arg = "arg", +}; + +nng_dialer_set_cb(dialer, &user_cb); +---- + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +`NNG_ENOTSUP`:: MQTT not supported. + +== SEE ALSO + +[.text-left] +xref:nng_dialer_create.3.adoc[nng_dialer_create()] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc()] +xref:nng_mqtt_msg_set_connect.3.adoc[nng_mqtt_msg_set_connect()] +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_url_parse.3.adoc[nng_url_parse(3)], +xref:nng.7.adoc[nng(7)] diff --git a/docs/man/nng_mqtt_client_open.3.adoc b/docs/man/nng_mqtt_client_open.3.adoc new file mode 100644 index 000000000..cd9e9edaa --- /dev/null +++ b/docs/man/nng_mqtt_client_open.3.adoc @@ -0,0 +1,70 @@ += nng_mqtt_client_open(3) +// +// Copyright 2018 Staysail Systems, Inc. +// Copyright 2018 Capitar IT Group BV +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_mqtt_client_open - open mqtt socket client + +== SYNOPSIS + +[source, c] +---- +#include +#include + +int nng_mqtt_client_open(nng_socket *sock); +---- + +== DESCRIPTION + +The `nng_mqtt_client_open()` Create a MQTT client dose nit connect it. +Note that MQTT sockets can be connected to at most a single server. + +Must create MQTT CONNECT message for *dialer* by message functions: xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc()], xref:nng_mqtt_msg_set_connect.3.adoc[nng_mqtt_msg_set_connect()] + +client demo snippet +[source, c] +---- +if ((rv = nng_mqtt_client_open(&sock)) != 0) { + fatal("nng_socket", rv); +} + +nng_msg *msg; +nng_mqtt_msg_alloc(&msg, 0); +nng_mqtt_msg_set_packet_type(msg, NNG_MQTT_CONNECT); + +if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) { + fatal("nng_dialer_create", rv); +} + +nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, msg); +nng_dialer_start(dialer, NNG_FLAG_NONBLOCK); +---- + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +`NNG_ENOTSUP`:: MQTT not supported. + +== SEE ALSO + +[.text-left] +xref:nng_dialer_create.3.adoc[nng_dialer_create()] +xref:nng_mqtt_callback_function.3.adoc[nng_mqtt_cb()] +xref:nng_mqtt_msg_alloc.3.adoc[nng_mqtt_msg_alloc()] +xref:nng_mqtt_msg_set_connect.3.adoc[nng_mqtt_msg_set_connect()] +xref:nng_strerror.3.adoc[nng_strerror(3)], +xref:nng_url_parse.3.adoc[nng_url_parse(3)], +xref:nng.7.adoc[nng(7)] From b9a64d630fc0e5b2d20cbde9da4552c98bf23659 Mon Sep 17 00:00:00 2001 From: wanghaemq Date: Wed, 1 Dec 2021 15:34:25 +0800 Subject: [PATCH 176/180] * NEW [nmq_mqtt] Generate random clientid for the clients without clientid. --- src/sp/protocol/mqtt/mqtt_parser.c | 16 +++++++++++++--- src/sp/protocol/mqtt/nmq_mqtt.c | 5 +++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 453cfa165..999444a8e 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -402,8 +402,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) uint8_t property_id; if (packet[pos] != CMD_CONNECT) { - rv = -1; - return rv; + return (-1); } else { pos++; } @@ -525,12 +524,23 @@ conn_handler(uint8_t *packet, conn_param *cparam) } } debug_msg("pos after property: [%d]", pos); + // payload client_id cparam->clientid.body = (char *) copy_utf8_str(packet, &pos, &len_of_str); - rv = len_of_str < 0 ? 1 : 0; cparam->clientid.len = len_of_str; + + if (len_of_str == 0) { + char * clientid_r = nng_alloc(20); + snprintf(clientid_r, 20, "clientid_random_%4d", nni_random()); + clientid_r[19] = '\0'; + cparam->clientid.body = clientid_r; + cparam->clientid.len = 20; + } else if (len_of_str < 0) { + return (1); + } debug_msg("clientid: [%s] [%d]", cparam->clientid.body, len_of_str); + // will topic if (cparam->will_flag != 0) { if (cparam->pro_ver == PROTOCOL_VERSION_v5) { diff --git a/src/sp/protocol/mqtt/nmq_mqtt.c b/src/sp/protocol/mqtt/nmq_mqtt.c index 0aba5d5d9..7351e542f 100644 --- a/src/sp/protocol/mqtt/nmq_mqtt.c +++ b/src/sp/protocol/mqtt/nmq_mqtt.c @@ -555,8 +555,9 @@ nano_pipe_start(void *arg) // restore cached qos msg clientid = (char *) conn_param_get_clientid(p->conn_param); - clientid_key = DJBHashn(clientid, strlen(clientid)); - if (cached_check_id(clientid_key)) { + if (clientid) + clientid_key = DJBHashn(clientid, strlen(clientid)); + if (clientid && cached_check_id(clientid_key)) { msgq = (nni_msg **)dbtree_restore_session_msg(p->tree, clientid_key); for(int i=0; i< (int) cvector_size(msgq); i++) { pid = nni_pipe_inc_packetid(npipe); From 1c033a52d52e8cd3947a8ba025458a387fd21ff6 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Wed, 1 Dec 2021 17:50:09 +0800 Subject: [PATCH 177/180] * FIX [core/message] seperate CMD_TYPE and message type --- include/nng/nng.h | 20 ++++++++++---------- src/core/message.c | 14 +++++++++++++- src/core/message.h | 1 + src/nng.c | 9 ++++++++- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/include/nng/nng.h b/include/nng/nng.h index f041e1010..8fb748d6c 100644 --- a/include/nng/nng.h +++ b/include/nng/nng.h @@ -91,7 +91,7 @@ typedef struct nng_pipe_s { typedef struct nng_socket_s { uint32_t id; - void *data; + void * data; } nng_socket; typedef int32_t nng_duration; // in milliseconds @@ -462,7 +462,7 @@ NNG_DECL void *nng_alloc(size_t); // is probably less convenient for general uses than the C library malloc and // calloc. NNG_DECL void *nng_zalloc(size_t sz); -NNG_DECL void nng_free(void *, size_t); +NNG_DECL void nng_free(void *, size_t); // nng_strdup duplicates the source string, using nng_alloc. The result // should be freed with nng_strfree (or nng_free(strlen(s)+1)). @@ -552,8 +552,8 @@ NNG_DECL int nng_aio_set_output(nng_aio *, unsigned, void *); // nng_aio_get_output retrieves the output result at the given index. NNG_DECL void *nng_aio_get_output(nng_aio *, unsigned); -NNG_DECL void nng_aio_set_prov_extra(nng_aio *, unsigned , void *); -NNG_DECL void *nng_aio_get_prov_extra(nng_aio *, unsigned ); +NNG_DECL void nng_aio_set_prov_extra(nng_aio *, unsigned, void *); +NNG_DECL void *nng_aio_get_prov_extra(nng_aio *, unsigned); // nng_aio_set_timeout sets a timeout on the AIO. This should be called for // operations that should time out after a period. The timeout should be @@ -1381,11 +1381,11 @@ typedef struct conn_param conn_param; typedef struct pub_packet_struct pub_packet_struct; typedef struct pipe_db nano_pipe_db; -NNG_DECL void nng_aio_finish_error(nng_aio *aio, int rv); -NNG_DECL void nng_aio_finish_sync(nng_aio *aio, int rv); -NNG_DECL int nng_msg_cmd_type(nng_msg *msg); -NNG_DECL void * nng_msg_get_conn_param(nng_msg *msg); -NNG_DECL size_t nng_msg_remaining_len(nng_msg *msg); +NNG_DECL void nng_aio_finish_error(nng_aio *aio, int rv); +NNG_DECL void nng_aio_finish_sync(nng_aio *aio, int rv); +NNG_DECL uint8_t nng_msg_cmd_type(nng_msg *msg); +NNG_DECL void * nng_msg_get_conn_param(nng_msg *msg); +NNG_DECL size_t nng_msg_remaining_len(nng_msg *msg); NNG_DECL uint8_t *nng_msg_header_ptr(nng_msg *msg); NNG_DECL uint8_t *nng_msg_payload_ptr(nng_msg *msg); NNG_DECL void nng_msg_set_payload_ptr(nng_msg *msg, uint8_t *ptr); @@ -1417,7 +1417,7 @@ NNG_DECL uint8_t conn_param_get_protover(conn_param *cparam); NNG_DECL void * conn_param_get_qos_db(conn_param *cparam); NNG_DECL void conn_param_set_qos_db(conn_param *cparam, void *); -NNG_DECL void nng_taskq_setter (int num_taskq_threads, int max_taskq_threads); +NNG_DECL void nng_taskq_setter(int num_taskq_threads, int max_taskq_threads); #ifdef __cplusplus } #endif diff --git a/src/core/message.c b/src/core/message.c index 3121663db..fb3bf4079 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -717,6 +717,12 @@ nni_msg_set_cmd_type(nni_msg *m, uint8_t cmd) m->CMD_TYPE = cmd; } +uint8_t +nni_msg_cmd_type(nni_msg *m) +{ + return (m->CMD_TYPE); +} + void nni_msg_set_proto_data(nng_msg *m, nni_proto_msg_ops *ops, void *data) { @@ -733,8 +739,14 @@ nni_msg_get_proto_data(nng_msg *m) return (m->m_proto_data); } +/** + * @brief get MQTT packet Type from msg header + * + * @param m + * @return uint8_t + */ uint8_t -nni_msg_cmd_type(nni_msg *m) +nni_msg_get_type(nni_msg *m) { return ((uint8_t) m->m_header_buf[0] & 0xF0); } diff --git a/src/core/message.h b/src/core/message.h index 7639c6918..15e69e282 100644 --- a/src/core/message.h +++ b/src/core/message.h @@ -68,6 +68,7 @@ extern nni_msg *nni_msg_pull_up(nni_msg *); extern nni_time nni_msg_get_timestamp(nni_msg *m); extern void nni_msg_set_timestamp(nni_msg *m, nni_time time); extern uint8_t nni_msg_cmd_type(nni_msg *m); +extern uint8_t nni_msg_get_type(nni_msg *m); extern uint8_t * nni_msg_header_ptr(const nni_msg *m); extern uint8_t * nni_msg_payload_ptr(const nni_msg *m); extern uint8_t nni_msg_get_pub_qos(nni_msg *m); diff --git a/src/nng.c b/src/nng.c index aafcc8b48..46ce441c0 100644 --- a/src/nng.c +++ b/src/nng.c @@ -1932,7 +1932,14 @@ nng_version(void) } // NANOMQ MQTT APIs -int +/** + * @brief CMD specifically for app layer acting + * + * + * @param msg + * @return int + */ +uint8_t nng_msg_cmd_type(nng_msg *msg) { return (nni_msg_cmd_type(msg)); From d6852488c2ce75c5b92d6c0d9d94040a451ee885 Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Wed, 1 Dec 2021 18:27:44 +0800 Subject: [PATCH 178/180] * MDF [transport/mqtt_tls] remove duplicated msg_get_oub_id. --- src/sp/transport/mqtts/mqtt_tls.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/sp/transport/mqtts/mqtt_tls.c b/src/sp/transport/mqtts/mqtt_tls.c index 48c1b0bc0..83653ecbe 100644 --- a/src/sp/transport/mqtts/mqtt_tls.c +++ b/src/sp/transport/mqtts/mqtt_tls.c @@ -17,6 +17,7 @@ #include "mqtt/mqtt.h" #include "nng/mqtt/mqtt_client.h" #include "nng/supplemental/tls/tls.h" +#include "nng/protocol/mqtt/mqtt_parser.h" // TLS Over TCP transport. Platform specific TLS Over TCP operations must be // supplied as well. @@ -95,7 +96,6 @@ static void mqtts_tcptran_pipe_recv_cb(void *); static void mqtts_tcptran_pipe_nego_cb(void *); static void mqtts_tcptran_ep_fini(void *); static void mqtts_tcptran_pipe_fini(void *); -static uint16_t nni_msg_get_pub_pid(nni_msg *m); static nni_reap_list tcptran_ep_reap_list = { .rl_offset = offsetof(mqtts_tcptran_ep, reap), @@ -117,18 +117,6 @@ mqtts_tcptran_fini(void) { } -static uint16_t -nni_msg_get_pub_pid(nni_msg *m) -{ - uint16_t pid; - uint8_t *pos, len; - - pos = nni_msg_body(m); - NNI_GET16(pos, len); - NNI_GET16(pos + len + 2, pid); - return pid; -} - static void mqtts_tcptran_pipe_close(void *arg) { From dc23f4e390b187ed6aceeb8ed8245b1fd5629e0e Mon Sep 17 00:00:00 2001 From: JaylinYu Date: Wed, 1 Dec 2021 19:15:21 +0800 Subject: [PATCH 179/180] * FIX [protocol/mqtt] temp fix for auto-reconnect. --- src/sp/protocol/mqtt/mqtt_client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sp/protocol/mqtt/mqtt_client.c b/src/sp/protocol/mqtt/mqtt_client.c index fa85d4493..0f1b0c4ad 100644 --- a/src/sp/protocol/mqtt/mqtt_client.c +++ b/src/sp/protocol/mqtt/mqtt_client.c @@ -398,7 +398,6 @@ mqtt_pipe_close(void *arg) mqtt_sock_t *s = p->mqtt_sock; nni_mtx_lock(&s->mtx); - mqtt_sock_close(s); s->mqtt_pipe = NULL; nni_aio_close(&p->send_aio); nni_aio_close(&p->recv_aio); From 7bdb9197c4f11118ef48911419d9f2b756c15f67 Mon Sep 17 00:00:00 2001 From: lee-emqx <66231514+lee-emqx@users.noreply.github.com> Date: Thu, 2 Dec 2021 10:40:39 +0800 Subject: [PATCH 180/180] * NEW [nng] Add new log system. --- include/nng/nng_log.h | 59 +++++++++++ src/CMakeLists.txt | 4 +- src/core/aio.c | 10 +- src/core/idhash.c | 4 +- src/core/message.c | 2 +- src/core/nng_impl.h | 2 +- src/core/taskq.c | 6 +- src/nng.c | 3 +- src/nng_log.c | 155 ++++++++++++++++++++++++++++ src/sp/protocol/mqtt/mqtt_parser.c | 78 +++++++------- src/sp/protocol/mqtt/nmq_mqtt.c | 66 ++++++------ src/sp/transport/mqtt/broker_tcp.c | 58 +++++------ src/sp/transport/ws/nmq_websocket.c | 12 +-- 13 files changed, 336 insertions(+), 123 deletions(-) create mode 100644 include/nng/nng_log.h create mode 100644 src/nng_log.c diff --git a/include/nng/nng_log.h b/include/nng/nng_log.h new file mode 100644 index 000000000..e0dc3d2f8 --- /dev/null +++ b/include/nng/nng_log.h @@ -0,0 +1,59 @@ +#ifndef NNG_LOG_H +#define NNG_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include + +#define LOG_VERSION "0.1.0" + +typedef struct { + va_list ap; + const char *fmt; + const char *file; + const char *func; + struct tm * time; + void * udata; + int line; + int level; +} log_Event; + +typedef void (*log_LogFn)(log_Event *ev); +typedef void (*log_LockFn)(bool lock, void *udata); + +enum { NNG_LOG_TRACE, NNG_LOG_DEBUG, NNG_LOG_INFO, NNG_LOG_WARN, NNG_LOG_ERROR, NNG_LOG_FATAL }; + +extern const char *log_level_string(int level); +extern void log_set_lock(log_LockFn fn, void *udata); +extern void log_set_level(int level); +extern void log_set_quiet(bool enable); +extern int log_add_callback(log_LogFn fn, void *udata, int level); +extern int log_add_fp(FILE *fp, int level); +extern void log_log(int level, const char *file, int line, const char *func, + const char *fmt, ...); + +#define log_trace(...) \ + log_log(NNG_LOG_TRACE, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define log_debug(...) \ + log_log(NNG_LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define log_info(...) \ + log_log(NNG_LOG_INFO, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define log_warn(...) \ + log_log(NNG_LOG_WARN, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define log_error(...) \ + log_log(NNG_LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define log_fatal(...) \ + log_log(NNG_LOG_FATAL, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e1ab412c3..65acd9a5d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,8 +8,8 @@ # found online at https://opensource.org/licenses/MIT. # -nng_sources(nng.c nng_legacy.c) -nng_headers(nng/nng.h) +nng_sources(nng.c nng_legacy.c nng_log.c) +nng_headers(nng/nng.h nng/nng_log.h) include_directories(${CMAKE_SOURCE_DIR}/nanolib/include) include_directories(${CMAKE_SOURCE_DIR}/nanomq/include) diff --git a/src/core/aio.c b/src/core/aio.c index 2f96f89f3..1f483c2f6 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -9,7 +9,7 @@ // #include "core/nng_impl.h" -#include "nng/nng_debug.h" +#include "nng/nng_log.h" #include struct nni_aio_expire_q { @@ -389,7 +389,7 @@ nni_aio_schedule(nni_aio *aio, nni_aio_cancel_fn cancel, void *data) } #if defined(DEBUG) - debug_msg("aio->a_cancel_fn NULL %d?", (aio->a_cancel_fn == NULL)); + log_trace("aio->a_cancel_fn NULL %d?", (aio->a_cancel_fn == NULL)); #else NNI_ASSERT(aio->a_cancel_fn == NULL); @@ -462,21 +462,21 @@ nni_aio_finish_impl( void nni_aio_finish(nni_aio *aio, int result, size_t count) { - debug_msg("aio finish"); + log_trace("aio finish"); nni_aio_finish_impl(aio, result, count, NULL, false); } void nni_aio_finish_sync(nni_aio *aio, int result, size_t count) { - debug_msg("nni_aio_finish_sync"); + log_trace("nni_aio_finish_sync"); nni_aio_finish_impl(aio, result, count, NULL, true); } void nni_aio_finish_error(nni_aio *aio, int result) { - debug_msg("nni_aio_finish_error"); + log_trace("nni_aio_finish_error"); nni_aio_finish_impl(aio, result, 0, NULL, false); } diff --git a/src/core/idhash.c b/src/core/idhash.c index 623b798aa..836fa025e 100644 --- a/src/core/idhash.c +++ b/src/core/idhash.c @@ -339,7 +339,7 @@ void nni_id_show_cb(nni_msg* msg) { NNI_ARG_UNUSED(msg); - debug_msg("message has an address: %p", msg); + log_trace("message has an address: %p", msg); } // this function iterates through the the idhash table, and store the entries in a linked list @@ -354,7 +354,7 @@ nni_id_iterate(nni_id_map *m, void (func_cb)(nni_msg*)) func_cb(m->id_entries[i].val); } } - //debug_msg("This id_map has %d entries.\n", count); + //log_trace("This id_map has %d entries.\n", count); } void* diff --git a/src/core/message.c b/src/core/message.c index fb3bf4079..49fa8b06f 100644 --- a/src/core/message.c +++ b/src/core/message.c @@ -11,7 +11,7 @@ #include #include "core/nng_impl.h" -#include "nng/nng_debug.h" +#include "nng/nng_log.h" #include "nng/protocol/mqtt/mqtt_parser.h" // Message API. diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h index b71c3a625..13e5266ea 100644 --- a/src/core/nng_impl.h +++ b/src/core/nng_impl.h @@ -12,7 +12,7 @@ #include "nng/nng.h" // NanoMQ -#include "nng/nng_debug.h" +#include "nng/nng_log.h" // Internal implementation things for NNG, common definitions, etc. // All internal modules wind up including this file to avoid having // to figure out which header(s) to include. diff --git a/src/core/taskq.c b/src/core/taskq.c index a70719f13..054393582 100644 --- a/src/core/taskq.c +++ b/src/core/taskq.c @@ -242,7 +242,7 @@ nni_taskq_setter(int num_taskq_threads, int max_taskq_threads) var_num_taskq_threads = num_taskq_threads; if (max_taskq_threads) var_max_taskq_threads = max_taskq_threads; - debug_msg("command line given: tq [%d], max_tq [%d]", + log_trace("command line given: tq [%d], max_tq [%d]", var_num_taskq_threads, var_max_taskq_threads); } @@ -253,7 +253,7 @@ nni_taskq_getter(void) if (var_num_taskq_threads >= var_max_taskq_threads) return var_max_taskq_threads; } - debug_msg("command line given: tq [%d], max_tq [%d]", + log_trace("command line given: tq [%d], max_tq [%d]", var_num_taskq_threads, var_max_taskq_threads); return var_num_taskq_threads ? var_num_taskq_threads : var_max_taskq_threads; @@ -276,7 +276,7 @@ nni_taskq_sys_init(void) #endif int result = nni_taskq_getter(); - debug_msg("result is %d", result); + log_trace("result is %d", result); if (result) { nthrs = result; } diff --git a/src/nng.c b/src/nng.c index 5708cd0a8..edaf25583 100644 --- a/src/nng.c +++ b/src/nng.c @@ -8,6 +8,7 @@ // found online at https://opensource.org/licenses/MIT. // +#include "nng/nng_log.h" #include "nng/nng.h" #include "core/nng_impl.h" @@ -292,7 +293,7 @@ nng_ctx_recv(nng_ctx cid, nng_aio *aio) int rv; nni_ctx *ctx; - debug_msg(" ######## nng_ctx_recv context id %d ######## ", cid.id); + log_trace(" ######## nng_ctx_recv context id %d ######## ", cid.id); if ((rv = nni_ctx_find(&ctx, cid.id, false)) != 0) { if (nni_aio_begin(aio) == 0) { nni_aio_finish_error(aio, rv); diff --git a/src/nng_log.c b/src/nng_log.c new file mode 100644 index 000000000..0becc3682 --- /dev/null +++ b/src/nng_log.c @@ -0,0 +1,155 @@ + +#include "nng/nng_log.h" + +#define MAX_CALLBACKS 32 +// #define LOG_USE_COLOR 1 + +typedef struct { + log_LogFn fn; + void * udata; + int level; +} Callback; + +static struct { + void * udata; + log_LockFn lock; + int level; + bool quiet; + Callback callbacks[MAX_CALLBACKS]; +} L; + +static const char *level_strings[] = { "TRACE", "DEBUG", "INFO", + "WARN", "ERROR", "FATAL" }; + +#ifdef LOG_USE_COLOR +static const char *level_colors[] = { "\x1b[94m", "\x1b[36m", "\x1b[32m", + "\x1b[33m", "\x1b[31m", "\x1b[35m" }; +#endif + +static void stdout_callback(log_Event *ev) +{ + char buf[64]; + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; +#ifdef LOG_USE_COLOR + fprintf(ev->udata, "%s [%i] %s%-5s\x1b[0m \x1b[90m%s:%d \x1b[0m %s: ", buf, + getpid(), level_colors[ev->level], level_strings[ev->level], + ev->file, ev->line, ev->func); +#else + fprintf(ev->udata, "%s [%i] %-5s %s:%d %s: ", buf, getpid(), + level_strings[ev->level], ev->file, ev->line, ev->func); +#endif + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void file_callback(log_Event *ev) +{ + char buf[64]; + buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; + fprintf(ev->udata, "%s [%i] %-5s %s:%d: ", buf, getpid(), + level_strings[ev->level], ev->file, ev->line); + vfprintf(ev->udata, ev->fmt, ev->ap); + fprintf(ev->udata, "\n"); + fflush(ev->udata); +} + +static void lock(void) +{ + if (L.lock) { + L.lock(true, L.udata); + } +} + +static void unlock(void) +{ + if (L.lock) { + L.lock(false, L.udata); + } +} + +const char *log_level_string(int level) +{ + return level_strings[level]; +} + +void log_set_lock(log_LockFn fn, void *udata) +{ + L.lock = fn; + L.udata = udata; +} + +void log_set_level(int level) +{ + L.level = level; +} + +void log_set_quiet(bool enable) +{ + L.quiet = enable; +} + +int log_add_callback(log_LogFn fn, void *udata, int level) +{ + for (int i = 0; i < MAX_CALLBACKS; i++) { + if (!L.callbacks[i].fn) { + L.callbacks[i] = (Callback) { fn, udata, level }; + return 0; + } + } + return -1; +} + +int log_add_fp(FILE *fp, int level) +{ + return log_add_callback(file_callback, fp, level); +} + +static void init_event(log_Event *ev, void *udata) +{ + if (!ev->time) { + time_t t = time(NULL); + ev->time = localtime(&t); + } + ev->udata = udata; +} + +#ifdef PROJECT_ROOT_DIR +#define PRJ_ROOT_DIR_LEN sizeof(PROJECT_ROOT_DIR); +#else +#define PRJ_ROOT_DIR_LEN 0 +#endif + +void log_log(int level, const char *file, int line, const char *func, + const char *fmt, ...) +{ + const char *file_name = file + PRJ_ROOT_DIR_LEN; + + log_Event ev = { .fmt = fmt, + .file = file_name, + .line = line, + .level = level, + .func = func }; + + lock(); + + if (!L.quiet && level >= L.level) { + init_event(&ev, stderr); + va_start(ev.ap, fmt); + stdout_callback(&ev); + va_end(ev.ap); + } + + for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) { + Callback *cb = &L.callbacks[i]; + if (level >= cb->level) { + init_event(&ev, cb->udata); + va_start(ev.ap, fmt); + cb->fn(&ev); + va_end(ev.ap); + } + } + + unlock(); +} + diff --git a/src/sp/protocol/mqtt/mqtt_parser.c b/src/sp/protocol/mqtt/mqtt_parser.c index 999444a8e..60089ef23 100644 --- a/src/sp/protocol/mqtt/mqtt_parser.c +++ b/src/sp/protocol/mqtt/mqtt_parser.c @@ -9,7 +9,7 @@ #include "nng/protocol/mqtt/mqtt_parser.h" #include "core/nng_impl.h" -#include "nng/nng_debug.h" +#include "nng/nng_log.h" #include "nng/protocol/mqtt/mqtt.h" #include @@ -415,7 +415,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) (char *) copy_utf8_str(packet, &pos, &len_of_str); cparam->pro_name.len = len_of_str; rv = len_of_str < 0 ? 1 : 0; - debug_msg("pro_name: %s", cparam->pro_name.body); + log_trace("pro_name: %s", cparam->pro_name.body); // protocol ver cparam->pro_ver = packet[pos]; pos++; @@ -425,7 +425,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) cparam->will_flag = (cparam->con_flag & 0x04) >> 2; cparam->will_qos = (cparam->con_flag & 0x18) >> 3; cparam->will_retain = (cparam->con_flag & 0x20) >> 5; - debug_msg("conn flag:%x", cparam->con_flag); + log_trace("conn flag:%x", cparam->con_flag); pos++; // keepalive NNI_GET16(packet + pos, tmp); @@ -433,10 +433,10 @@ conn_handler(uint8_t *packet, conn_param *cparam) pos += 2; // properties if (cparam->pro_ver == PROTOCOL_VERSION_v5) { - debug_msg("MQTT 5 Properties"); + log_trace("MQTT 5 Properties"); len_of_properties = (uint32_t) get_var_integer(packet, &pos); uint32_t target_pos = pos + len_of_properties; - debug_msg("propertyLen in variable [%d]", len_of_properties); + log_trace("propertyLen in variable [%d]", len_of_properties); // parse property in variable header if (len_of_properties > 0) { @@ -444,42 +444,42 @@ conn_handler(uint8_t *packet, conn_param *cparam) property_id = packet[pos++]; switch (property_id) { case SESSION_EXPIRY_INTERVAL: - debug_msg("SESSION_EXPIRY_INTERVAL"); + log_trace("SESSION_EXPIRY_INTERVAL"); NNI_GET32(packet + pos, cparam->session_expiry_interval); pos += 4; break; case RECEIVE_MAXIMUM: - debug_msg("RECEIVE_MAXIMUM"); + log_trace("RECEIVE_MAXIMUM"); NNI_GET16( packet + pos, cparam->rx_max); pos += 2; break; case MAXIMUM_PACKET_SIZE: - debug_msg("MAXIMUM_PACKET_SIZE"); + log_trace("MAXIMUM_PACKET_SIZE"); NNI_GET32(packet + pos, cparam->max_packet_size); pos += 4; break; case TOPIC_ALIAS_MAXIMUM: - debug_msg("TOPIC_ALIAS_MAXIMUM"); + log_trace("TOPIC_ALIAS_MAXIMUM"); NNI_GET16(packet + pos, cparam->topic_alias_max); pos += 2; break; case REQUEST_RESPONSE_INFORMATION: - debug_msg( + log_trace( "REQUEST_RESPONSE_INFORMATION"); cparam->req_resp_info = packet[pos++]; break; case REQUEST_PROBLEM_INFORMATION: - debug_msg( + log_trace( "REQUEST_PROBLEM_INFORMATION"); cparam->req_problem_info = packet[pos++]; break; case USER_PROPERTY: - debug_msg("USER_PROPERTY"); + log_trace("USER_PROPERTY"); // key cparam->user_property.key = (char *) copy_utf8_str( @@ -496,7 +496,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) rv = len_of_str < 0 ? 1 : 0; break; case AUTHENTICATION_METHOD: - debug_msg("AUTHENTICATION_METHOD"); + log_trace("AUTHENTICATION_METHOD"); cparam->auth_method.body = (char *) copy_utf8_str( packet, &pos, &len_of_str); @@ -505,7 +505,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) len_of_str = 0; break; case AUTHENTICATION_DATA: - debug_msg("AUTHENTICATION_DATA"); + log_trace("AUTHENTICATION_DATA"); cparam->auth_data.body = copy_utf8_str( packet, &pos, &len_of_str); rv = len_of_str < 0 ? 1 : 0; @@ -517,14 +517,13 @@ conn_handler(uint8_t *packet, conn_param *cparam) if (pos == target_pos) { break; } else if (pos > target_pos) { - debug_msg("ERROR: protocol error"); + log_trace("ERROR: protocol error"); return PROTOCOL_ERROR; } } } } - debug_msg("pos after property: [%d]", pos); - + log_trace("pos after property: [%d]", pos); // payload client_id cparam->clientid.body = (char *) copy_utf8_str(packet, &pos, &len_of_str); @@ -539,14 +538,13 @@ conn_handler(uint8_t *packet, conn_param *cparam) } else if (len_of_str < 0) { return (1); } - debug_msg("clientid: [%s] [%d]", cparam->clientid.body, len_of_str); - + log_trace("clientid: [%s] [%d]", cparam->clientid.body, len_of_str); // will topic if (cparam->will_flag != 0) { if (cparam->pro_ver == PROTOCOL_VERSION_v5) { len_of_properties = get_var_integer(packet, &pos); uint32_t target_pos = pos + len_of_properties; - debug_msg( + log_trace( "propertyLen in payload [%d]", len_of_properties); // parse property in variable header @@ -555,7 +553,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) property_id = packet[pos++]; switch (property_id) { case WILL_DELAY_INTERVAL: - debug_msg( + log_trace( "WILL_DELAY_INTERVAL"); NNI_GET32(packet + pos, cparam @@ -563,14 +561,14 @@ conn_handler(uint8_t *packet, conn_param *cparam) pos += 4; break; case PAYLOAD_FORMAT_INDICATOR: - debug_msg("PAYLOAD_FORMAT_" + log_trace("PAYLOAD_FORMAT_" "INDICATOR"); cparam ->payload_format_indicator = packet[pos++]; break; case MESSAGE_EXPIRY_INTERVAL: - debug_msg( + log_trace( "MESSAGE_EXPIRY_INTERVAL"); NNI_GET32(packet + pos, cparam @@ -578,7 +576,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) pos += 4; break; case CONTENT_TYPE: - debug_msg("CONTENT_TYPE"); + log_trace("CONTENT_TYPE"); cparam->content_type.body = (char *) copy_utf8_str( packet, &pos, @@ -586,13 +584,13 @@ conn_handler(uint8_t *packet, conn_param *cparam) cparam->content_type.len = len_of_str; rv = len_of_str < 0 ? 1 : 0; - debug_msg( + log_trace( "content type: %s %d", cparam->content_type.body, rv); break; case RESPONSE_TOPIC: - debug_msg("RESPONSE_TOPIC"); + log_trace("RESPONSE_TOPIC"); cparam->resp_topic.body = (char *) copy_utf8_str( packet, &pos, @@ -600,24 +598,24 @@ conn_handler(uint8_t *packet, conn_param *cparam) cparam->resp_topic.len = len_of_str; rv = len_of_str < 0 ? 1 : 0; - debug_msg("resp topic: %s %d", + log_trace("resp topic: %s %d", cparam->resp_topic.body, rv); break; case CORRELATION_DATA: - debug_msg("CORRELATION_DATA"); + log_trace("CORRELATION_DATA"); cparam->corr_data.body = copy_utf8_str(packet, &pos, &len_of_str); cparam->corr_data.len = len_of_str; rv = len_of_str < 0 ? 1 : 0; - debug_msg("corr_data: %s %d", + log_trace("corr_data: %s %d", cparam->corr_data.body, rv); break; case USER_PROPERTY: - debug_msg("USER_PROPERTY"); + log_trace("USER_PROPERTY"); // key cparam->payload_user_property .key = @@ -643,7 +641,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) if (pos == target_pos) { break; } else if (pos > target_pos) { - debug_msg( + log_trace( "ERROR: protocol error"); return PROTOCOL_ERROR; } @@ -654,13 +652,13 @@ conn_handler(uint8_t *packet, conn_param *cparam) (char *) copy_utf8_str(packet, &pos, &len_of_str); cparam->will_topic.len = len_of_str; rv = len_of_str < 0 ? 1 : 0; - debug_msg("will_topic: %s %d", cparam->will_topic.body, rv); + log_trace("will_topic: %s %d", cparam->will_topic.body, rv); // will msg cparam->will_msg.body = (char *) copy_utf8_str(packet, &pos, &len_of_str); cparam->will_msg.len = len_of_str; rv = len_of_str < 0 ? 1 : 0; - debug_msg("will_msg: %s %d", cparam->will_msg.body, rv); + log_trace("will_msg: %s %d", cparam->will_msg.body, rv); } // username if ((cparam->con_flag & 0x80) > 0) { @@ -668,7 +666,7 @@ conn_handler(uint8_t *packet, conn_param *cparam) (char *) copy_utf8_str(packet, &pos, &len_of_str); cparam->username.len = len_of_str; rv = len_of_str < 0 ? 1 : 0; - debug_msg( + log_trace( "username: %s %d", cparam->username.body, len_of_str); } // password @@ -677,12 +675,12 @@ conn_handler(uint8_t *packet, conn_param *cparam) copy_utf8_str(packet, &pos, &len_of_str); cparam->password.len = len_of_str; rv = len_of_str < 0 ? 1 : 0; - debug_msg( + log_trace( "password: %s %d", cparam->password.body, len_of_str); } // what if rv = 0? if (len + len_of_var + 1 != pos) { - debug_msg("ERROR in connect handler"); + log_trace("ERROR in connect handler"); } return rv; } @@ -745,7 +743,7 @@ conn_param_free(conn_param *cparam) if (nni_atomic_dec_nv(&cparam->refcnt) != 0) { return; } - debug_msg("destroy conn param"); + log_trace("destroy conn param"); nng_free(cparam->pro_name.body, cparam->pro_name.len); nng_free(cparam->clientid.body, cparam->clientid.len); nng_free(cparam->will_topic.body, cparam->will_topic.len); @@ -886,7 +884,7 @@ verify_connect(conn_param *cparam, conf *conf) char *password = (char *) cparam->password.body; if (conf->auths.count == 0 || conf->allow_anonymous == true) { - debug_msg("WARNING: no valid entry in " + log_trace("WARNING: no valid entry in " "etc/nanomq_auth_username.conf."); return 0; } @@ -987,7 +985,7 @@ nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) if (len_of_topic != 0) { - debug_msg("The current process topic is %s", + log_trace("The current process topic is %s", payload_ptr + bpos + 2); iter = root; while (iter) { @@ -1041,7 +1039,7 @@ nano_msg_get_subtopic(nni_msg *msg, nano_pipe_db *root, conn_param *cparam) } db->qos = *(payload_ptr + bpos); db->next = NULL; - debug_msg("sub topic: %s qos : %x\n", db->topic, db->qos); + log_trace("sub topic: %s qos : %x\n", db->topic, db->qos); bpos += 1; } diff --git a/src/sp/protocol/mqtt/nmq_mqtt.c b/src/sp/protocol/mqtt/nmq_mqtt.c index 17f97587f..c8c937d29 100644 --- a/src/sp/protocol/mqtt/nmq_mqtt.c +++ b/src/sp/protocol/mqtt/nmq_mqtt.c @@ -207,7 +207,7 @@ nano_pipe_timer_cb(void *arg) nano_msg_set_dup(rmsg); nni_aio_set_packetid(&p->aio_send, pid); nni_aio_set_msg(&p->aio_send, rmsg); - debug_msg( + log_trace( "resending qos msg packetid: %d", pid); nni_pipe_send(p->pipe, &p->aio_send); nni_id_remove(npipe->nano_qos_db, pid); @@ -227,7 +227,7 @@ nano_keepalive(nano_pipe *p, void *arg) uint16_t interval; interval = conn_param_get_keepalive(p->conn_param); - debug_msg("KeepAlive: %d", interval); + log_trace("KeepAlive: %d", interval); //20% KeepAlive as buffer time for multi-threading nni_timer_schedule(&p->ka_timer, nni_clock() + NNI_SECOND * interval * 0.8); @@ -241,7 +241,7 @@ nano_ctx_close(void *arg) nano_sock *s = ctx->sock; nni_aio * aio; - debug_msg("nano_ctx_close"); + log_trace("nano_ctx_close"); nni_mtx_lock(&s->lk); if ((aio = ctx->saio) != NULL) { // nano_pipe *pipe = ctx->spipe; @@ -266,7 +266,7 @@ nano_ctx_fini(void *arg) nano_ctx_close(ctx); // timer - debug_msg("========= nano_ctx_fini ========="); + log_trace("========= nano_ctx_fini ========="); // nni_timer_cancel(&ctx->qos_timer); // nni_timer_fini(&ctx->qos_timer); } @@ -277,7 +277,7 @@ nano_ctx_init(void *carg, void *sarg) nano_sock *s = sarg; nano_ctx * ctx = carg; - debug_msg("&&&&&&&& nano_ctx_init %p &&&&&&&&&", ctx); + log_trace("&&&&&&&& nano_ctx_init %p &&&&&&&&&", ctx); NNI_LIST_NODE_INIT(&ctx->sqnode); NNI_LIST_NODE_INIT(&ctx->rqnode); @@ -293,7 +293,7 @@ nano_ctx_cancel_send(nni_aio *aio, void *arg, int rv) nano_ctx * ctx = arg; nano_sock *s = ctx->sock; - debug_msg("*********** nano_ctx_cancel_send ***********"); + log_trace("*********** nano_ctx_cancel_send ***********"); nni_mtx_lock(&s->lk); if (ctx->saio != aio) { nni_mtx_unlock(&s->lk); @@ -324,7 +324,7 @@ nano_ctx_send(void *arg, nni_aio *aio) return; } - debug_msg("#### nano_ctx_send with ctx %p msg type %x ####", + log_trace("#### nano_ctx_send with ctx %p msg type %x ####", ctx, nni_msg_cmd_type(msg)); if ((pipe = nni_msg_get_pipe(msg)) != 0) { @@ -339,7 +339,7 @@ nano_ctx_send(void *arg, nni_aio *aio) } nni_mtx_lock(&s->lk); - debug_msg(" ******** working with pipe id : %d ctx ********", pipe); + log_trace(" ******** working with pipe id : %d ctx ********", pipe); if ((p = nni_id_get(&s->pipes, pipe)) == NULL) { // Pipe is gone. Make this look like a good send to avoid // disrupting the state machine. We don't care if the peer @@ -348,7 +348,7 @@ nano_ctx_send(void *arg, nni_aio *aio) nni_aio_set_msg(aio, NULL); // TODO lastwill/SYS topic will trigger this (sub to the topic // that publish to by itself) - debug_syslog("ERROR: pipe is gone, pub failed"); + log_trace("ERROR: pipe is gone, pub failed"); nni_msg_free(msg); return; } @@ -370,13 +370,13 @@ nano_ctx_send(void *arg, nni_aio *aio) nni_mtx_unlock(&p->lk); return; } - debug_msg("WARNING: pipe %d occupied! resending in cb!", pipe); + log_trace("WARNING: pipe %d occupied! resending in cb!", pipe); if (nni_lmq_full(&p->rlmq)) { // Make space for the new message. TODO add max limit of msgq // len in conf if ((rv = nano_nni_lmq_resize( &p->rlmq, nni_lmq_cap(&p->rlmq) * 2)) != 0) { - debug_syslog("warning msg dropped!"); + log_trace("warning msg dropped!"); nni_msg *old; (void) nano_nni_lmq_getq(&p->rlmq, &old, NULL); nni_msg_free(old); @@ -424,7 +424,7 @@ nano_sock_init(void *arg, nni_sock *sock) (void) nano_ctx_init(&s->ctx, s); - debug_msg("************* nano_sock_init %p *************", s); + log_trace("************* nano_sock_init %p *************", s); // We start off without being either readable or writable. // Readability comes when there is something on the socket. nni_pollable_init(&s->writable); @@ -452,7 +452,7 @@ nano_pipe_stop(void *arg) { nano_pipe *p = arg; - debug_msg("##########nano_pipe_stop###############"); + log_trace("##########nano_pipe_stop###############"); nni_aio_stop(&p->aio_send); nni_aio_stop(&p->aio_timer); nni_aio_stop(&p->aio_recv); @@ -464,7 +464,7 @@ nano_pipe_fini(void *arg) nano_pipe * p = arg; nng_msg * msg; - debug_msg("########## nano_pipe_fini ###############"); + log_trace("########## nano_pipe_fini ###############"); if ((msg = nni_aio_get_msg(&p->aio_recv)) != NULL) { nni_aio_set_msg(&p->aio_recv, NULL); nni_msg_free(msg); @@ -495,7 +495,7 @@ nano_pipe_init(void *arg, nni_pipe *pipe, void *s) nano_pipe *p = arg; nano_sock *sock = s; - debug_msg("##########nano_pipe_init###############"); + log_trace("##########nano_pipe_init###############"); nni_mtx_init(&p->lk); nni_lmq_init(&p->rlmq, sock->conf->msq_len); @@ -530,7 +530,7 @@ nano_pipe_start(void *arg) nni_msg ** msgq = NULL; uint16_t pid = 0; - debug_msg("##########nano_pipe_start################"); + log_trace("##########nano_pipe_start################"); /* // TODO check peer protocol ver (websocket or tcp or quic??) if (nni_pipe_peer(p->pipe) != NNG_NANO_TCP_PEER) { @@ -548,7 +548,7 @@ nano_pipe_start(void *arg) rv = verify_connect(p->conn_param, s->conf); if (rv != 0) { // TODO disconnect client && send connack with reason code 0x05 - debug_syslog("Invalid auth info."); + log_trace("Invalid auth info."); *(reason + 1) = rv; // set return code } nni_mtx_unlock(&s->lk); @@ -611,7 +611,7 @@ nano_pipe_close(void *arg) char * clientid = NULL; uint32_t clientid_key = 0; - debug_msg("################# nano_pipe_close ##############"); + log_trace("################# nano_pipe_close ##############"); nni_mtx_lock(&s->lk); close_pipe(p); @@ -650,7 +650,7 @@ nano_pipe_close(void *arg) // no enough ctx, so cache to waitlmq if (nni_lmq_full(&s->waitlmq)) { if (nni_lmq_resize(&s->waitlmq, nni_lmq_cap(&s->waitlmq) * 2) != 0) { - debug_msg("wait lmq resize failed."); + log_trace("wait lmq resize failed."); } } nni_lmq_putq(&s->waitlmq, msg); @@ -664,7 +664,7 @@ nano_pipe_send_cb(void *arg) nano_pipe *p = arg; nni_msg * msg; - debug_msg("******** nano_pipe_send_cb %d ****", p->id); + log_trace("******** nano_pipe_send_cb %d ****", p->id); // retry here if (nni_aio_result(&p->aio_send) != 0) { nni_msg_free(nni_aio_get_msg(&p->aio_send)); @@ -678,7 +678,7 @@ nano_pipe_send_cb(void *arg) if (nni_lmq_getq(&p->rlmq, &msg) == 0) { // msg = NANO_NNI_LMQ_PACKED_MSG_QOS(msg, qos); nni_aio_set_msg(&p->aio_send, msg); - debug_msg("rlmq msg resending! %ld msgs left\n", nni_lmq_len(&p->rlmq)); + log_trace("rlmq msg resending! %ld msgs left\n", nni_lmq_len(&p->rlmq)); nni_pipe_send(p->pipe, &p->aio_send); nni_mtx_unlock(&p->lk); return; @@ -695,7 +695,7 @@ nano_cancel_recv(nni_aio *aio, void *arg, int rv) nano_ctx * ctx = arg; nano_sock *s = ctx->sock; - debug_msg("*********** nano_cancel_recv ***********"); + log_trace("*********** nano_cancel_recv ***********"); nni_mtx_lock(&s->lk); if (ctx->raio == aio) { nni_list_remove(&s->recvq, ctx); @@ -718,12 +718,12 @@ nano_ctx_recv(void *arg, nni_aio *aio) return; } - debug_msg("nano_ctx_recv start %p", ctx); + log_trace("nano_ctx_recv start %p", ctx); nni_mtx_lock(&s->lk); if (nni_lmq_getq(&s->waitlmq, &msg) == 0) { nni_mtx_unlock(&s->lk); - debug_msg("handle msg in waitlmq."); + log_trace("handle msg in waitlmq."); nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); return; @@ -740,7 +740,7 @@ nano_ctx_recv(void *arg, nni_aio *aio) // Cannot have a second receive operation pending. // This could be ESTATE, or we could cancel the first // with ECANCELED. We elect the former. - debug_msg("ERROR: former aio not finish yet"); + log_trace("ERROR: former aio not finish yet"); nni_mtx_unlock(&s->lk); nni_aio_finish_error(aio, NNG_ESTATE); return; @@ -764,7 +764,7 @@ nano_ctx_recv(void *arg, nni_aio *aio) // TODO MQTT 5 property ctx->pipe_id = nni_pipe_id(p->pipe); - debug_msg("nano_ctx_recv ends %p pipe: %p pipe_id: %d", ctx, p, + log_trace("nano_ctx_recv ends %p pipe: %p pipe_id: %d", ctx, p, ctx->pipe_id); nni_mtx_unlock(&s->lk); @@ -791,7 +791,7 @@ nano_pipe_recv_cb(void *arg) nni_pipe_close(p->pipe); return; } - debug_msg("######### nano_pipe_recv_cb ############"); + log_trace("######### nano_pipe_recv_cb ############"); p->ka_refresh = 0; msg = nni_aio_get_msg(&p->aio_recv); if (msg == NULL) { @@ -833,7 +833,7 @@ nano_pipe_recv_cb(void *arg) nni_id_remove(npipe->nano_qos_db, ackid); } else { // shouldn't get here BUG TODO - debug_syslog("qos msg not found!"); + log_trace("qos msg not found!"); } nni_mtx_unlock(&p->lk); case CMD_CONNECT: @@ -848,7 +848,7 @@ nano_pipe_recv_cb(void *arg) // If we are closed, then we can't return data. nni_aio_set_msg(&p->aio_recv, NULL); nni_msg_free(msg); - debug_msg("ERROR: pipe is closed abruptly!!"); + log_trace("ERROR: pipe is closed abruptly!!"); return; } @@ -858,7 +858,7 @@ nano_pipe_recv_cb(void *arg) nni_list_append(&s->recvpipes, p); nni_pollable_raise(&s->readable); nni_mtx_unlock(&s->lk); - debug_msg("ERROR: no ctx found!! create more ctxs!"); + log_trace("ERROR: no ctx found!! create more ctxs!"); // nni_println("ERROR: no ctx found!! create more ctxs!"); return; } @@ -875,13 +875,13 @@ nano_pipe_recv_cb(void *arg) nni_pipe_recv(p->pipe, &p->aio_recv); ctx->pipe_id = p->id; - debug_msg("currently processing pipe_id: %d", p->id); + log_trace("currently processing pipe_id: %d", p->id); nni_mtx_unlock(&s->lk); nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, nni_msg_len(msg)); - debug_msg("end of nano_pipe_recv_cb %p", ctx); + log_trace("end of nano_pipe_recv_cb %p", ctx); return; drop: @@ -889,7 +889,7 @@ nano_pipe_recv_cb(void *arg) end: nni_aio_set_msg(&p->aio_recv, NULL); nni_pipe_recv(p->pipe, &p->aio_recv); - debug_msg("Warning:dropping msg"); + log_trace("Warning:dropping msg"); return; } diff --git a/src/sp/transport/mqtt/broker_tcp.c b/src/sp/transport/mqtt/broker_tcp.c index b246a1e7a..6aeaf9689 100644 --- a/src/sp/transport/mqtt/broker_tcp.c +++ b/src/sp/transport/mqtt/broker_tcp.c @@ -9,7 +9,7 @@ #include "core/nng_impl.h" #include "core/sockimpl.h" -#include "nng/nng_debug.h" +#include "nng/nng_log.h" #include "nng/protocol/mqtt/mqtt.h" #include "nng/protocol/mqtt/mqtt_parser.h" @@ -123,7 +123,7 @@ tcptran_pipe_close(void *arg) nni_aio_close(p->negoaio); nng_stream_close(p->conn); - debug_syslog("tcptran_pipe_close\n"); + log_trace("tcptran_pipe_close\n"); } static void @@ -142,7 +142,7 @@ tcptran_pipe_stop(void *arg) static int tcptran_pipe_init(void *arg, nni_pipe *npipe) { - debug_msg("************tcptran_pipe_init************"); + log_trace("************tcptran_pipe_init************"); tcptran_pipe *p = arg; nni_pipe_set_conn_param(npipe, p->tcp_cparam); @@ -258,7 +258,7 @@ tcptran_pipe_nego_cb(void *arg) uint32_t len; int rv, len_of_varint = 0; - debug_msg("start tcptran_pipe_nego_cb max len %ld pipe_addr %p\n", + log_trace("start tcptran_pipe_nego_cb max len %ld pipe_addr %p\n", NANO_CONNECT_PACKET_LEN, p); nni_mtx_lock(&ep->mtx); @@ -283,7 +283,7 @@ tcptran_pipe_nego_cb(void *arg) } if (p->gotrxhead == NNI_NANO_MAX_HEADER_SIZE) { if (p->rxlen[0] != CMD_CONNECT) { - debug_msg("CMD TYPE %x", p->rxlen[0]); + log_trace("CMD TYPE %x", p->rxlen[0]); rv = NNG_EPROTO; goto error; } @@ -338,7 +338,7 @@ tcptran_pipe_nego_cb(void *arg) } nni_mtx_unlock(&ep->mtx); - debug_msg("^^^^^^^^^^end of tcptran_pipe_nego_cb^^^^^^^^^^\n"); + log_trace("^^^^^^^^^^end of tcptran_pipe_nego_cb^^^^^^^^^^\n"); return; error: @@ -357,7 +357,7 @@ tcptran_pipe_nego_cb(void *arg) } nni_mtx_unlock(&ep->mtx); tcptran_pipe_reap(p); - debug_msg("connect nego error rv: %d!", rv); + log_trace("connect nego error rv: %d!", rv); return; } @@ -376,7 +376,7 @@ tcptran_pipe_send_cb(void *arg) nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->sendq); - debug_msg("############### tcptran_pipe_send_cb ################"); + log_trace("############### tcptran_pipe_send_cb ################"); if ((rv = nni_aio_result(txaio)) != 0) { nni_pipe_bump_error(p->npipe, rv); @@ -388,7 +388,7 @@ tcptran_pipe_send_cb(void *arg) n = nni_aio_count(txaio); nni_aio_iov_advance(txaio, n); - debug_msg( + log_trace( "tcp socket sent %ld bytes iov %ld", n, nni_aio_iov_count(txaio)); if (nni_aio_iov_count(txaio) > 0) { @@ -441,13 +441,13 @@ tcptran_pipe_recv_cb(void *arg) nni_aio * rxaio = p->rxaio; conn_param * cparam; - debug_msg("tcptran_pipe_recv_cb %p\n", p); + log_trace("tcptran_pipe_recv_cb %p\n", p); nni_mtx_lock(&p->mtx); aio = nni_list_first(&p->recvq); if ((rv = nni_aio_result(rxaio)) != 0) { - debug_msg("nni aio error!! %d\n", rv); + log_trace("nni aio error!! %d\n", rv); goto recv_error; } @@ -457,12 +457,12 @@ tcptran_pipe_recv_cb(void *arg) nni_aio_iov_advance(rxaio, n); // not receive enough bytes, deal with remaining length len = get_var_integer(p->rxlen, &pos); - debug_msg("new %ld recevied %ld header %x %d pos: %d len : %d", n, + log_trace("new %ld recevied %ld header %x %d pos: %d len : %d", n, p->gotrxhead, p->rxlen[0], p->rxlen[1], pos, len); - debug_msg("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); + log_trace("still need byte count:%ld > 0\n", nni_aio_iov_count(rxaio)); if (nni_aio_iov_count(rxaio) > 0) { - debug_msg("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], + log_trace("got: %x %x, %ld!!\n", p->rxlen[0], p->rxlen[1], strlen((char *) p->rxlen)); nng_stream_recv(p->conn, rxaio); nni_mtx_unlock(&p->mtx); @@ -502,19 +502,19 @@ tcptran_pipe_recv_cb(void *arg) if (p->rxmsg == NULL) { // We should have gotten a message header. len -> remaining // length to define how many bytes left - debug_msg("pipe %p header got: %x %x %x %x %x, %ld!!\n", p, + log_trace("pipe %p header got: %x %x %x %x %x, %ld!!\n", p, p->rxlen[0], p->rxlen[1], p->rxlen[2], p->rxlen[3], p->rxlen[4], p->wantrxhead); // Make sure the message payload is not too big. If it is // the caller will shut down the pipe. if ((len > p->rcvmax) && (p->rcvmax > 0)) { - debug_msg("size error\n"); + log_trace("size error\n"); rv = NNG_EMSGSIZE; goto recv_error; } if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { - debug_syslog("mem error %ld\n", (size_t) len); + log_trace("mem error %ld\n", (size_t) len); goto recv_error; } @@ -546,12 +546,12 @@ tcptran_pipe_recv_cb(void *arg) // duplicated with fixed_header_adaptor nni_msg_set_remaining_len(msg, len); nni_msg_set_cmd_type(msg, type); - debug_msg("remain_len %d cparam %p clientid %s username %s proto %d\n", + log_trace("remain_len %d cparam %p clientid %s username %s proto %d\n", len, cparam, cparam->clientid.body, cparam->username.body, cparam->pro_ver); // set the payload pointer of msg according to packet_type - debug_msg("The type of msg is %x", type); + log_trace("The type of msg is %x", type); if (type == CMD_PUBLISH) { uint8_t qos_pac; uint16_t pid; @@ -602,7 +602,7 @@ tcptran_pipe_recv_cb(void *arg) nni_aio_set_msg(aio, msg); nni_aio_finish_sync(aio, 0, n); - debug_msg("end of tcptran_pipe_recv_cb: synch! %p\n", p); + log_trace("end of tcptran_pipe_recv_cb: synch! %p\n", p); return; recv_error: @@ -614,7 +614,7 @@ tcptran_pipe_recv_cb(void *arg) nni_msg_free(msg); nni_aio_finish_error(aio, rv); - debug_msg("tcptran_pipe_recv_cb: recv error rv: %d\n", rv); + log_trace("tcptran_pipe_recv_cb: recv error rv: %d\n", rv); return; notify: // nni_pipe_bump_rx(p->npipe, n); @@ -660,7 +660,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) nni_iov iov[4]; uint8_t qos; - debug_msg("########### tcptran_pipe_send_start ###########"); + log_trace("########### tcptran_pipe_send_start ###########"); if (p->closed) { while ((aio = nni_list_first(&p->sendq)) != NULL) { nni_list_remove(&p->sendq, aio); @@ -670,7 +670,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) } if ((aio = nni_list_first(&p->sendq)) == NULL) { - debug_msg("aio not functioning"); + log_trace("aio not functioning"); return; } @@ -708,7 +708,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) goto send; } - debug_msg("qos_pac %d sub %d\n", qos_pac, qos); + log_trace("qos_pac %d sub %d\n", qos_pac, qos); memcpy(fixheader, header, nni_msg_header_len(msg)); qos = qos_pac > qos ? qos : qos_pac; @@ -746,7 +746,7 @@ tcptran_pipe_send_start(tcptran_pipe *p) //first time send this msg pid = nni_pipe_inc_packetid(pipe); // store msg for qos retrying - debug_msg("* processing QoS pubmsg with pipe: %p *", p); + log_trace("* processing QoS pubmsg with pipe: %p *", p); nni_msg_clone(msg); if ((old = nni_id_get( pipe->nano_qos_db, pid)) != NULL) { @@ -821,7 +821,7 @@ tcptran_pipe_send(void *arg, nni_aio *aio) tcptran_pipe *p = arg; int rv; - debug_msg("####################tcptran_pipe_send###########"); + log_trace("####################tcptran_pipe_send###########"); if (nni_aio_begin(aio) != 0) { return; } @@ -911,7 +911,7 @@ tcptran_pipe_recv_start(tcptran_pipe *p) { nni_aio *rxaio; nni_iov iov; - debug_msg("*** tcptran_pipe_recv_start ***\n"); + log_trace("*** tcptran_pipe_recv_start ***\n"); NNI_ASSERT(p->rxmsg == NULL); if (p->closed) { @@ -949,7 +949,7 @@ tcptran_pipe_start(tcptran_pipe *p, nng_stream *conn, tcptran_ep *ep) p->ep = ep; // p->proto = ep->proto; - debug_msg("tcptran_pipe_start!"); + log_trace("tcptran_pipe_start!"); p->gotrxhead = 0; p->wantrxhead = NANO_CONNECT_PACKET_LEN; // packet type 1 + remaining // length 1 + protocal name 7 @@ -995,7 +995,7 @@ tcptran_ep_close(void *arg) nni_mtx_lock(&ep->mtx); - debug_syslog("tcptran_ep_close"); + log_trace("tcptran_ep_close"); ep->closed = true; nni_aio_close(ep->timeaio); if (ep->listener != NULL) { diff --git a/src/sp/transport/ws/nmq_websocket.c b/src/sp/transport/ws/nmq_websocket.c index 801b78857..58c4d71d4 100644 --- a/src/sp/transport/ws/nmq_websocket.c +++ b/src/sp/transport/ws/nmq_websocket.c @@ -20,7 +20,7 @@ #include #include -#include "nng/nng_debug.h" +#include "nng/nng_log.h" #include "nng/protocol/mqtt/mqtt.h" #include "nng/protocol/mqtt/mqtt_parser.h" @@ -110,12 +110,12 @@ wstran_pipe_recv_cb(void *arg) msg = nni_aio_get_msg(raio); ptr = nni_msg_body(msg); p->gotrxhead += nni_msg_len(msg); - debug_msg("#### wstran_pipe_recv_cb got %ld msg: %p %x %ld", + log_trace("#### wstran_pipe_recv_cb got %ld msg: %p %x %ld", p->gotrxhead, ptr, *ptr, nni_msg_len(msg)); // first we collect complete Fixheader if (p->tmp_msg == NULL && p->gotrxhead > 0) { if ((rv = nni_msg_alloc(&p->tmp_msg, 0)) != 0) { - debug_syslog("mem error %ld\n", (size_t) len); + log_trace("mem error %ld\n", (size_t) len); goto reset; } } @@ -380,7 +380,7 @@ wstran_pipe_send(void *arg, nni_aio *aio) // first time send this msg pid = nni_pipe_inc_packetid(pipe); // store msg for qos retrying - debug_msg( + log_trace( "* processing QoS pubmsg with pipe: %p *", p); nni_msg_clone(msg); @@ -445,7 +445,7 @@ wstran_pipe_stop(void *arg) static int wstran_pipe_init(void *arg, nni_pipe *pipe) { - debug_msg("************wstran_pipe_init************"); + log_trace("************wstran_pipe_init************"); ws_pipe *p = arg; nni_pipe_set_conn_param(pipe, p->ws_param); @@ -717,7 +717,7 @@ ws_pipe_start(ws_pipe *pipe, nng_stream *conn) { NNI_ARG_UNUSED(conn); ws_pipe *p = pipe; - debug_msg("ws_pipe_start!"); + log_trace("ws_pipe_start!"); nng_stream_recv(p->ws, p->rxaio); }