diff --git a/manifest.yml b/manifest.yml
index 9d693767..c0655ed9 100644
--- a/manifest.yml
+++ b/manifest.yml
@@ -1,5 +1,5 @@
name : "coreMQTT"
-version: "v2.3.1+"
+version: "v5.0.0+"
description: |
- "Client implementation of the MQTT 3.1.1 specification for embedded devices.\n"
+ "Client implementation of the MQTT 3.1.1 and MQTT 5.0 specifications for embedded devices.\n"
license: "MIT"
diff --git a/source/core_mqtt_serializer.c b/source/core_mqtt_serializer.c
index 458e9c77..a635c8e8 100644
--- a/source/core_mqtt_serializer.c
+++ b/source/core_mqtt_serializer.c
@@ -39,6 +39,11 @@
*/
#define MQTT_VERSION_3_1_1 ( ( uint8_t ) 4U )
+/**
+ * @brief MQTT protocol version 5.0.
+ */
+#define MQTT_VERSION_5_0 ( ( uint8_t ) 5U )
+
/**
* @brief Size of the fixed and variable header of a CONNECT packet.
*/
diff --git a/source/include/core_mqtt_config_defaults.h b/source/include/core_mqtt_config_defaults.h
index 3fd79f97..7780922e 100644
--- a/source/include/core_mqtt_config_defaults.h
+++ b/source/include/core_mqtt_config_defaults.h
@@ -275,6 +275,18 @@
#define LogDebug( message )
#endif
+/**
+ * @brief Define this macro to enable MQTT v5.x support in the library.
+ *
+ * When this macro is defined, the library will include support for MQTT v5.x
+ * features such as properties, reason codes, and user properties.
+ *
+ * Default value: MQTT v5.x support is disabled.
+ */
+#ifndef MQTT_VERSION_5_ENABLED
+ #define MQTT_VERSION_5_ENABLED ( 0 )
+#endif
+
/* *INDENT-OFF* */
#ifdef __cplusplus
}
diff --git a/source/include/transport_interface.h b/source/include/transport_interface.h
new file mode 100644
index 00000000..b88a74fb
--- /dev/null
+++ b/source/include/transport_interface.h
@@ -0,0 +1,353 @@
+/*
+ * coreMQTT
+ * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file transport_interface.h
+ * @brief Transport interface definitions to send and receive data over the
+ * network.
+ */
+#ifndef TRANSPORT_INTERFACE_H_
+#define TRANSPORT_INTERFACE_H_
+
+#include
+#include
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+ extern "C" {
+#endif
+/* *INDENT-ON* */
+
+/**
+ * @transportpage
+ * @brief The transport interface definition.
+ *
+ * @transportsectionoverview
+ *
+ * The transport interface is a set of APIs that must be implemented using an
+ * external transport layer protocol. The transport interface is defined in
+ * @ref transport_interface.h. This interface allows protocols like MQTT and
+ * HTTP to send and receive data over the transport layer. This
+ * interface does not handle connection and disconnection to the server of
+ * interest. The connection, disconnection, and other transport settings, like
+ * timeout and TLS setup, must be handled in the user application.
+ *
+ *
+ * The functions that must be implemented are:
+ * - [Transport Receive](@ref TransportRecv_t)
+ * - [Transport Send](@ref TransportSend_t)
+ *
+ * Each of the functions above take in an opaque context @ref NetworkContext_t.
+ * The functions above and the context are also grouped together in the
+ * @ref TransportInterface_t structure:
+ * @snippet this define_transportinterface
+ *
+ *
+ * @transportsectionimplementation
+ *
+ * The following steps give guidance on implementing the transport interface:
+ *
+ * -# Implementing @ref NetworkContext_t
+ * @snippet this define_networkcontext
+ *
+ * @ref NetworkContext_t is the incomplete type struct NetworkContext.
+ * The implemented struct NetworkContext must contain all of the information
+ * that is needed to receive and send data with the @ref TransportRecv_t
+ * and the @ref TransportSend_t implementations.
+ * In the case of TLS over TCP, struct NetworkContext is typically implemented
+ * with the TCP socket context and a TLS context.
+ * Example code:
+ * @code{c}
+ * struct NetworkContext
+ * {
+ * struct MyTCPSocketContext tcpSocketContext;
+ * struct MyTLSContext tlsContext;
+ * };
+ * @endcode
+ *
+ * -# Implementing @ref TransportRecv_t
+ * @snippet this define_transportrecv
+ *
+ * This function is expected to populate a buffer, with bytes received from the
+ * transport, and return the number of bytes placed in the buffer.
+ * In the case of TLS over TCP, @ref TransportRecv_t is typically implemented by
+ * calling the TLS layer function to receive data. In case of plaintext TCP
+ * without TLS, it is typically implemented by calling the TCP layer receive
+ * function. @ref TransportRecv_t may be invoked multiple times by the protocol
+ * library, if fewer bytes than were requested to receive are returned.
+ *
+ * Example code:
+ * @code{c}
+ * int32_t myNetworkRecvImplementation( NetworkContext_t * pNetworkContext,
+ * void * pBuffer,
+ * size_t bytesToRecv )
+ * {
+ * int32_t bytesReceived = 0;
+ * bool callTlsRecvFunc = true;
+ *
+ * // For a single byte read request, check if data is available on the network.
+ * if( bytesToRecv == 1 )
+ * {
+ * // If no data is available on the network, do not call TLSRecv
+ * // to avoid blocking for socket timeout.
+ * if( TLSRecvCount( pNetworkContext->tlsContext ) == 0 )
+ * {
+ * callTlsRecvFunc = false;
+ * }
+ * }
+ *
+ * if( callTlsRecvFunc == true )
+ * {
+ * bytesReceived = TLSRecv( pNetworkContext->tlsContext,
+ * pBuffer,
+ * bytesToRecv,
+ * MY_SOCKET_TIMEOUT );
+ * if( bytesReceived < 0 )
+ * {
+ * // If the error code represents a timeout, then the return
+ * // code should be translated to zero so that the caller
+ * // can retry the read operation.
+ * if( bytesReceived == MY_SOCKET_ERROR_TIMEOUT )
+ * {
+ * bytesReceived = 0;
+ * }
+ * }
+ * // Handle other cases.
+ * }
+ * return bytesReceived;
+ * }
+ * @endcode
+ *
+ * -# Implementing @ref TransportSend_t
+ * @snippet this define_transportsend
+ *
+ * This function is expected to send the bytes, in the given buffer over the
+ * transport, and return the number of bytes sent.
+ * In the case of TLS over TCP, @ref TransportSend_t is typically implemented by
+ * calling the TLS layer function to send data. In case of plaintext TCP
+ * without TLS, it is typically implemented by calling the TCP layer send
+ * function. @ref TransportSend_t may be invoked multiple times by the protocol
+ * library, if fewer bytes than were requested to send are returned.
+ *
+ * Example code:
+ * @code{c}
+ * int32_t myNetworkSendImplementation( NetworkContext_t * pNetworkContext,
+ * const void * pBuffer,
+ * size_t bytesToSend )
+ * {
+ * int32_t bytesSent = 0;
+ * bytesSent = TLSSend( pNetworkContext->tlsContext,
+ * pBuffer,
+ * bytesToSend,
+ * MY_SOCKET_TIMEOUT );
+ *
+ * // If underlying TCP buffer is full, set the return value to zero
+ * // so that caller can retry the send operation.
+ * if( bytesSent == MY_SOCKET_ERROR_BUFFER_FULL )
+ * {
+ * bytesSent = 0;
+ * }
+ * else if( bytesSent < 0 )
+ * {
+ * // Handle socket error.
+ * }
+ * // Handle other cases.
+ *
+ * return bytesSent;
+ * }
+ * @endcode
+ *
+ * -# Implementing @ref TransportWritev_t
+ * @snippet this define_transportwritev
+ *
+ * This function is expected to send multiple buffers, in the given array of
+ * TransportOutVector_t structures over the transport, and return the number of
+ * bytes sent.
+ * In the case of TLS over TCP, @ref TransportWritev_t is typically implemented by
+ * calling the TLS layer function to send data. In case of plaintext TCP
+ * without TLS, it is typically implemented by calling the TCP layer send
+ * function. @ref TransportWritev_t may be invoked multiple times by the protocol
+ * library, if fewer bytes than were requested to send are returned.
+ *
+ * Example code:
+ * @code{c}
+ * int32_t myNetworkWritevImplementation( NetworkContext_t * pNetworkContext,
+ * const TransportOutVector_t * pIoVec,
+ * size_t ioVecCount )
+ * {
+ * int32_t bytesSent = 0;
+ * bytesSent = TLSWritev( pNetworkContext->tlsContext,
+ * pIoVec,
+ * ioVecCount,
+ * MY_SOCKET_TIMEOUT );
+ *
+ * // If underlying TCP buffer is full, set the return value to zero
+ * // so that caller can retry the send operation.
+ * if( bytesSent == MY_SOCKET_ERROR_BUFFER_FULL )
+ * {
+ * bytesSent = 0;
+ * }
+ * else if( bytesSent < 0 )
+ * {
+ * // Handle socket error.
+ * }
+ * // Handle other cases.
+ *
+ * return bytesSent;
+ * }
+ * @endcode
+ */
+
+/**
+ * @transportstruct
+ * @typedef NetworkContext_t
+ * @brief The NetworkContext is an incomplete type. An implementation of this
+ * interface must define struct NetworkContext for the system requirements.
+ * This context is passed into the network interface functions.
+ */
+/* @[define_networkcontext] */
+struct NetworkContext;
+typedef struct NetworkContext NetworkContext_t;
+/* @[define_networkcontext] */
+
+/**
+ * @transportcallback
+ * @brief Transport interface for receiving data on the network.
+ *
+ * @note It is HIGHLY RECOMMENDED that the transport receive
+ * implementation does NOT block.
+ * coreMQTT will continue to call the transport interface if it receives
+ * a partial packet until it accumulates enough data to get the complete
+ * MQTT packet.
+ *
+ * @param[in] pNetworkContext Implementation-defined network context.
+ * @param[in] pBuffer Buffer to receive the data into.
+ * @param[in] bytesToRecv Number of bytes requested from the network.
+ *
+ * @return The number of bytes received or a negative value to indicate
+ * error.
+ *
+ * @note If no data is available on the network to read and no error
+ * has occurred, zero MUST be the return value. A zero return value
+ * SHOULD represent that the read operation can be retried by calling
+ * the API function. Zero MUST NOT be returned if a network disconnection
+ * has occurred.
+ */
+/* @[define_transportrecv] */
+typedef int32_t ( * TransportRecv_t )( NetworkContext_t * pNetworkContext,
+ void * pBuffer,
+ size_t bytesToRecv );
+/* @[define_transportrecv] */
+
+/**
+ * @transportcallback
+ * @brief Transport interface for sending data over the network.
+ *
+ * @param[in] pNetworkContext Implementation-defined network context.
+ * @param[in] pBuffer Buffer containing the bytes to send over the network stack.
+ * @param[in] bytesToSend Number of bytes to send over the network.
+ *
+ * @return The number of bytes sent or a negative value to indicate error.
+ *
+ * @note If no data is transmitted over the network due to a full TX buffer and
+ * no network error has occurred, this MUST return zero as the return value.
+ * A zero return value SHOULD represent that the send operation can be retried
+ * by calling the API function. Zero MUST NOT be returned if a network disconnection
+ * has occurred.
+ */
+/* @[define_transportsend] */
+typedef int32_t ( * TransportSend_t )( NetworkContext_t * pNetworkContext,
+ const void * pBuffer,
+ size_t bytesToSend );
+/* @[define_transportsend] */
+
+/**
+ * @brief Transport vector structure for sending multiple messages.
+ */
+typedef struct TransportOutVector
+{
+ /**
+ * @brief Base address of data.
+ */
+ const void * iov_base;
+
+ /**
+ * @brief Length of data in buffer.
+ */
+ size_t iov_len;
+} TransportOutVector_t;
+
+/**
+ * @transportcallback
+ * @brief Transport interface function for "vectored" / scatter-gather based
+ * writes. This function is expected to iterate over the list of vectors pIoVec
+ * having ioVecCount entries containing portions of one MQTT message at a maximum.
+ * If the proper functionality is available, then the data in the list should be
+ * copied to the underlying TCP buffer before flushing the buffer. Implementing it
+ * in this fashion will lead to sending of fewer TCP packets for all the values
+ * in the list.
+ *
+ * @note If the proper write functionality is not present for a given device/IP-stack,
+ * then there is no strict requirement to implement write. Only the send and recv
+ * interfaces must be defined for the application to work properly.
+ *
+ * @param[in] pNetworkContext Implementation-defined network context.
+ * @param[in] pIoVec An array of TransportIoVector_t structs.
+ * @param[in] ioVecCount Number of TransportIoVector_t in pIoVec.
+ *
+ * @return The number of bytes written or a negative value to indicate error.
+ *
+ * @note If no data is written to the buffer due to the buffer being full this MUST
+ * return zero as the return value.
+ * A zero return value SHOULD represent that the write operation can be retried
+ * by calling the API function. Zero MUST NOT be returned if a network disconnection
+ * has occurred.
+ */
+/* @[define_transportwritev] */
+typedef int32_t ( * TransportWritev_t )( NetworkContext_t * pNetworkContext,
+ TransportOutVector_t * pIoVec,
+ size_t ioVecCount );
+/* @[define_transportwritev] */
+
+/**
+ * @transportstruct
+ * @brief The transport layer interface.
+ */
+/* @[define_transportinterface] */
+typedef struct TransportInterface
+{
+ TransportRecv_t recv; /**< Transport receive function pointer. */
+ TransportSend_t send; /**< Transport send function pointer. */
+ TransportWritev_t writev; /**< Transport writev function pointer. */
+ NetworkContext_t * pNetworkContext; /**< Implementation-defined network context. */
+} TransportInterface_t;
+/* @[define_transportinterface] */
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+ }
+#endif
+/* *INDENT-ON* */
+
+#endif /* ifndef TRANSPORT_INTERFACE_H_ */