Quality RTOS & Embedded Software

LIBRARIES

Transport Interface

Introduction

coreMQTT has no dependency on any particular TCP/IP stack. Therefore, in order to use the coreMQTT 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 default 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:


/*

* The NetworkContext is an incomplete type. An implementation of this

* interface must define struct NetworkContext for the system’s requirements.

* For example, a plain-text implemention of the NetworkContext type might

* include a socket, and a TLS implementation might add a TLS context. This

* context is passed into the network interface send() and recv() functions.

*/

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 TransportInterface
{
TransportRecv_t recv; /* Receive function (see above) */
TransportSend_t send; /* Send 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+TCP stack (this is for demonstration purposes only as the RTOS source code download already contains a transport interface for FreeRTOS+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+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+TCP sockets are stored in variables of type Socket_t. So the NetworkContext structure can be defined as:

/* The network context just contains the FreeRTOS+TCP socket (production

systems should use TLS, not just the underlying socket, so could use the

TLS context here instead of the socket) */

struct NetworkContext
{
Socket_t tcpSocket;
};
Defining a NetworkContext structure that just contains a FreeRTOS+TCP socket.

Implementing the send and receive wrappers

Next, the FreeRTOS+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:

/* The prototypes of the following send and receive functions match that

expected by the transport interface’s function pointers. These simple

implementations show how to use the network context structure defined

above. */



int32_t transport_recv( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRecv )
{
int32_t 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 = 0;
socketStatus = FreeRTOS_send( pNetworkContext->tcpSocket, pBuffer, bytesToSend, 0 );
return socketStatus;
}
Implementing the transport send and receive functions for FreeRTOS+TCP


Populating the TransportInterface_t structure

Finally, the code below shows how to populate the network transport interface structure with the NetworkContext, transport_send() and transport_recv() structure and functions defined above:

/* Populating the TransportInterface_t structure with the definitions 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->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 interfaces 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+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.