/* * coreMQTT v1.1.0 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. 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"), 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 /** * @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 */ /** * @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 RECOMMENDED that the transport receive implementation * does NOT block when requested to read a single byte. A single byte * read request can be made by the caller to check whether there is a * new frame available on the network for reading. * However, the receive implementation MAY block for a timeout period when * it is requested to read more than 1 byte. This is because once the caller * is aware that a new frame is available to read on the network, then * the likelihood of reading more than one byte over the network becomes high. * * @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] */ /** * @transportstruct * @brief The transport layer interface. */ /* @[define_transportinterface] */ typedef struct TransportInterface { TransportRecv_t recv; /**< Transport receive interface. */ TransportSend_t send; /**< Transport send interface. */ NetworkContext_t * pNetworkContext; /**< Implementation-defined network context. */ } TransportInterface_t; /* @[define_transportinterface] */ #endif /* ifndef TRANSPORT_INTERFACE_H_ */