Transport Interface
Introduction
coreMQTT and coreHTTP has no dependency on any particular TCP/IP stack. Therefore, in order to use either the coreMQTT or coreHTTP library, you'll need to provide a Transport Interface structure. An instance of the Transport Interface contains function pointers and context data required to send and receive data on a single network connection. The FreeRTOS distribution includes example implementations of the Transport Interface which you can use in your applications.
Custom Implementations
Applications can provide their own implementation of the Transport Interface if the example implementations don't match the underlying network or TLS stack. An implementation has two parts. The first is the definition of a network context data structure that wraps an underlying data stream, such as a socket handle or a TLS context. The second is a pair of functions that can send and receive data on that network context - these two functions just wrap whichever network send and receive functions you are already using within functions that have the prototype expected by the transport interface structure. There is a worked example below.
The Transport Interface structure is defined as follows:
struct NetworkContext;
typedef struct NetworkContext NetworkContext_t;
typedef int32_t ( * TransportRecv_t )( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv );
typedef int32_t ( * TransportSend_t )( NetworkContext_t * pNetworkContext,
const void * pBuffer,
size_t bytesToSend );
typedef struct TransportOutVector
{
const void * iov_base;
size_t iov_len;
} TransportOutVector_t;
typedef int32_t ( * TransportWritev_t )( NetworkContext_t * pNetworkContext,
TransportOutVector_t * pIoVec,
size_t ioVecCount );
typedef struct TransportInterface
{
TransportRecv_t recv; /* Receive function (see above) */
TransportSend_t send; /* Send function (see above) */
TransportWritev_t writev; /* Writev function (see above) */
NetworkContext_t * pNetworkContext; /* Network context (see above) */
} TransportInterface_t;
Transport Interface Structure
Worked Example
This example describes how to create a transport interface for the FreeRTOS-Plus-TCP stack
(this is for demonstration purposes only as the FreeRTOS source code download already contains a transport interface for FreeRTOS-Plus-TCP). For simplicity the example is using TCP without TLS or
other form of encryption. Production IoT devices should always use encrypted
connections and the FreeRTOS download includes transport interfaces that use
FreeRTOS-Plus-TCP with TLS stacks.
Starting point
It is recommended to ensure your application is able to successfully send and
receive from the network before creating a network transport interface - that
way the transport interface is just wrapping send and receive functions that are
already working.
Defining the NetworkContext structure
FreeRTOS-Plus-TCP sockets
are stored in variables of type Socket_t. So the NetworkContext structure
can be defined as:
struct NetworkContext
{
Socket_t tcpSocket;
};
Defining a NetworkContext structure that just contains a FreeRTOS-Plus-TCP socket.
Implementing the send and receive wrappers
Next, the FreeRTOS-Plus-TCP
send and
receive functions need to
be wrapped by functions that have the prototype expected by the transport interface's
send and receive functions. The example below also demonstrates how to obtain the socket used
by the send and receive functions from the NetworkContext parameter:
int32_t transport_recv( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv )
{
int32_t socketStatus = 1;
if( bytesToRecv == 1 )
{
socketStatus = ( int32_t ) FreeRTOS_recvcount( pPlaintextTransportParams->tcpSocket );
}
if( socketStatus > 0 )
{
socketStatus = FreeRTOS_recv( pNetworkContext->tcpSocket, pBuffer, bytesToRecv, 0 );
}
return socketStatus;
}
int32_t transport_send( NetworkContext_t * pNetworkContext,
const void * pBuffer,
size_t bytesToSend )
{
int32_t socketStatus;
socketStatus = FreeRTOS_send( pNetworkContext->tcpSocket, pBuffer, bytesToSend, 0 );
if( socketStatus == -pdFREERTOS_ERRNO_ENOSPC )
{
socketStatus = 0;
}
return socketStatus;
}
Implementing the transport send and receive functions for FreeRTOS-Plus-TCP
Populating the TransportInterface_t structure
Finally, the code below shows how to populate the transport interface structure
with the
NetworkContext structure, and
transport_send() and
transport_recv() functions defined above:
void init_transport_from_socket( Socket_t tcpSocket,
NetworkContext_t * pNetworkContext,
TransportInterface_t * pTransport )
{
pNetworkContext->tcpSocket = tcpSocket;
pTransport->recv = transport_recv;
pTransport->send = transport_send;
pTransport->writev = NULL;
pTransport->pNetworkContext = pNetworkContext;
}
Defines the NetworkContext declared in transport_interface.h
Example Implementations
Examples for both plain-text and TLS communication are included. We strongly recommend that production applications use TLS for communication. This provides a Transport Interface which is both authenticated and encrypted, as demonstrated in the MQTT TLS demo.
The transport interface implementations included in the FreeRTOS download are split into two files - a wrapper C file specific to the TCP stack, and a supplemental C file specific to using a TLS stack with the selected TCP stack. For example, to use FreeRTOS-Plus-TCP with mbedTLS, build sockets_wrapper.c from the network_transport/freertos_plus_tcp directory in the source code distribution, then build using_mbedtls.c from the using_mbedtls subdirectory.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.