PrevUpHomeNext

Establishing a network connection with different protocols

The MQTT protocol requires the underlying transport protocol that ensures orderly, lossless transmission of byte streams between the Client and Server in both directions.

The following examples demonstrate how to establish a network connection using suitable transport protocols such as TCP/IP, TLS/SSL, and WebSocket.

TCP/IP connection

To create a TCP/IP connection with a Broker, initialise mqtt_client with boost::asio::ip::tcp::socket as the StreamType.

#include <boost/asio/io_context.hpp>

#include <boost/asio/ip/tcp.hpp>

#include <async_mqtt5.hpp>

void tcp_setup() {
	boost::asio::io_context ioc;

	// Use boost::asio::ip::tcp::socket as the underlying stream.
	async_mqtt5::mqtt_client<boost::asio::ip::tcp::socket> client(ioc);
}

TLS/SSL connection

To establish a secure and encrypted connection using the TLS/SSL protocol, supply a context object that meets the TlsContext requirements. Additionally, initialise mqtt_client with an underlying stream that implements TLS/SSL protocol as the StreamType.

This example will demonstrate how to set up an SSL connection using boost::asio::ssl::context and boost::asio::ssl::stream<boost::asio::ip::tcp::socket>. To use SSL support in Boost.Asio, OpenSSL is required.

#include <boost/asio/io_context.hpp>
#include <boost/asio/ssl.hpp>

#include <boost/asio/ip/tcp.hpp>

#include <async_mqtt5.hpp>


// External customization point.
namespace async_mqtt5 {

template <typename StreamBase>
struct tls_handshake_type<asio::ssl::stream<StreamBase>> {
	static constexpr auto client = asio::ssl::stream_base::client;
	static constexpr auto server = asio::ssl::stream_base::server;
};

// This client uses this funcction to indicate which hostname it is
// attempting to connect to at the start of the handshaking process.
template <typename StreamBase>
void assign_tls_sni(
	const authority_path& ap,
	boost::asio::ssl::context& ctx,
	boost::asio::ssl::stream<StreamBase>& stream
) {
	SSL_set_tlsext_host_name(stream.native_handle(), ap.host.c_str());
}

} // end namespace async_mqtt5

// The certificate file in PEM format.
constexpr char certificate[] =
"-----BEGIN CERTIFICATE-----\n"
"...........................\n"
"-----END CERTIFICATE-----\n"
;

void ssl_setup() {
	boost::asio::io_context ioc;

	// Context satisfying TlsContext requirements that the underlying SSL stream will use.
	// The purpose of the context is to allow us to set up TLS/SSL-related options. 
	// See SSL for more information and options.
	boost::asio::ssl::context context(boost::asio::ssl::context::tls_client);

	async_mqtt5::error_code ec;

	// Add the trusted certificate authority for performing verification.
	context.add_certificate_authority(boost::asio::buffer(certificate), ec);

	// Set peer verification mode used by the context.
	// This will verify that the server's certificate is valid and signed by a trusted certificate authority.
	context.set_verify_mode(boost::asio::ssl::verify_peer, ec);

	// Use boost::asio::ssl::stream<boost::asio::ip::tcp::socket> as the StreamType with boost::asio::ssl::context as the TlsContext.
	async_mqtt5::mqtt_client<
		boost::asio::ssl::stream<boost::asio::ip::tcp::socket>,
		boost::asio::ssl::context
	> client(ioc, std::move(context));
}

WebSocket connection

The WebSocket connection can be established over an unencrypted TCP/IP connection or an encrypted TLS/SSL connection.

The following example will showcase setting up WebSocket over TCP/IP and WebSocket over TLS/SLL connection using boost::beast::websocket::stream<NextLayer>.

WebSocket over TCP/IP
#include <boost/asio/io_context.hpp>

#include <boost/asio/ip/tcp.hpp>

#include <boost/beast/websocket.hpp>

#include <async_mqtt5.hpp>

void websocket_tcp_setup() {
	boost::asio::io_context ioc;

	// Use boost::beast::websocket::stream<boost::asio::ip::tcp::socket> as the underlying stream.
	async_mqtt5::mqtt_client<
		boost::beast::websocket::stream<boost::asio::ip::tcp::socket>
	> client(ioc);
}
WebSocket over TLS/SSL
#include <boost/asio/io_context.hpp>
#include <boost/asio/ssl.hpp>

#include <boost/asio/ip/tcp.hpp>

#include <boost/beast/websocket.hpp>

#include <async_mqtt5.hpp>

constexpr char ca[] =
"-----BEGIN CERTIFICATE-----\n"
"...........................\n"
"-----END CERTIFICATE-----\n"
;

namespace boost::beast::websocket {

// boost::beast::boost::beast::websocket::async_teardown is a free function
// designed to initiate the asynchronous teardown of a connection.
// The specific behaviour of this function is based on the NextLayer type (Socket type) used to create the boost::beast::websocket::stream<NextLayer>.
// Boost.Beast library includes an implementation of this function for boost::asio::ip::tcp::socket.
// However, the callers are responsible for providing a suitable overload of this function for any other type,
// such as boost::asio::ssl::stream<boost::asio::ip::tcp::socket> as shown in this example.
template <typename TeardownHandler>
void async_teardown(
	boost::beast::role_type role,
	asio::ssl::stream<asio::ip::tcp::socket>& stream,
	TeardownHandler&& handler
) {
	return stream.async_shutdown(std::forward<TeardownHandler>(handler));
}

} // end namespace boost::beast::websocket

namespace async_mqtt5 {

template <typename StreamBase>
struct tls_handshake_type<asio::ssl::stream<StreamBase>> {
	static constexpr auto client = asio::ssl::stream_base::client;
	static constexpr auto server = asio::ssl::stream_base::server;
};

template <typename streambase>
void assign_tls_sni(
	const authority_path& ap,
	asio::ssl::context& ctx,
	asio::ssl::stream<streambase>& stream
) {
	ssl_set_tlsext_host_name(stream.native_handle(), ap.host.c_str());
}

} // end namespace async_mqtt5

void websocket_tls_setup() {
	boost::asio::io_context ioc;

	boost::asio::ssl::context context(boost::asio::ssl::context::tls_client);

	async_mqtt5::error_code ec;
	context.add_certificate_authority(boost::asio::buffer(ca), ec);
	context.set_verify_mode(boost::asio::ssl::verify_peer, ec);

	async_mqtt5::mqtt_client<
		boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>,
		boost::asio::ssl::context
	> client(ioc, std::move(context));
}

Once the mqtt_client has been initialised with a suitable StreamType, it is prepared for configuration and utilisation.


PrevUpHomeNext