1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
// ssl_publish.cpp
//
// This is a Paho MQTT C++ client, sample application.
//
// It's an example of how to connect to an MQTT broker securely, and then
// send messages as an MQTT publisher using the C++ asynchronous client
// interface.
//
// The sample demonstrates:
// - Connecting to an MQTT server/broker securely
// - Setting SSL/TLS options
// - Last will and testament
// - Publishing messages
// - Using asynchronous tokens
// - Implementing callbacks and action listeners
//
// We can test this using mosquitto configured with certificates in the
// Paho C library. The C library has an SSL/TSL test suite, and we can use
// that to test:
// $ cd paho.mqtt.c
// $ mosquitto -c test/tls-testing/mosquitto.conf
//
// Then use the files "test-root-ca.crt" and "client.pem" from the
// test/ssl directory (paho.mqtt.c/test/ssl) for the trust store and
// key_store, respectively, for this program.
//
/*******************************************************************************
* Copyright (c) 2013-2023 Frank Pagliughi <fpagliughi@mindspring.com>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Frank Pagliughi - initial implementation and documentation
*******************************************************************************/
#include <chrono>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include "mqtt/async_client.h"
const std::string DFLT_SERVER_URI{"mqtts://localhost:18884"};
const std::string DFLT_CLIENT_ID{"ssl_publish_cpp"};
const std::string KEY_STORE{"client.pem"};
const std::string TRUST_STORE{"test-root-ca.crt"};
const std::string LWT_TOPIC{"events/disconnect"};
const std::string LWT_PAYLOAD{"Last will and testament."};
const int QOS = 1;
const auto TIMEOUT = std::chrono::seconds(10);
/////////////////////////////////////////////////////////////////////////////
/**
* A callback class for use with the main MQTT client.
*/
class callback : public virtual mqtt::callback
{
public:
void connection_lost(const std::string& cause) override
{
std::cout << "\nConnection lost" << std::endl;
if (!cause.empty())
std::cout << "\tcause: " << cause << std::endl;
}
void delivery_complete(mqtt::delivery_token_ptr tok) override
{
std::cout << "\tDelivery complete for token: " << (tok ? tok->get_message_id() : -1)
<< std::endl;
}
};
/////////////////////////////////////////////////////////////////////////////
using namespace std;
int main(int argc, char* argv[])
{
string serverURI = (argc > 1) ? string{argv[1]} : DFLT_SERVER_URI,
clientID = (argc > 2) ? string{argv[2]} : DFLT_CLIENT_ID;
// Note that we don't actually need to open the trust or key stores.
// We just need a quick, portable way to check that they exist.
{
ifstream tstore(TRUST_STORE);
if (!tstore) {
cerr << "The trust store file does not exist: " << TRUST_STORE << endl;
cerr << " Get a copy from \"paho.mqtt.c/test/ssl/test-root-ca.crt\"" << endl;
;
return 1;
}
ifstream kstore(KEY_STORE);
if (!kstore) {
cerr << "The key store file does not exist: " << KEY_STORE << endl;
cerr << " Get a copy from \"paho.mqtt.c/test/ssl/client.pem\"" << endl;
return 1;
}
}
cout << "Initializing for server '" << serverURI << "'..." << endl;
mqtt::async_client client(serverURI, clientID);
callback cb;
client.set_callback(cb);
// Build the connect options, including SSL and a LWT message.
auto sslopts = mqtt::ssl_options_builder()
.trust_store(TRUST_STORE)
.key_store(KEY_STORE)
.error_handler([](const std::string& msg) {
std::cerr << "SSL Error: " << msg << std::endl;
})
.finalize();
auto willmsg = mqtt::message(LWT_TOPIC, LWT_PAYLOAD, QOS, true);
auto connopts = mqtt::connect_options_builder()
.user_name("testuser")
.password("testpassword")
.will(std::move(willmsg))
.ssl(std::move(sslopts))
.finalize();
cout << " ...OK" << endl;
try {
// Connect using SSL/TLS
cout << "\nConnecting..." << endl;
mqtt::token_ptr conntok = client.connect(connopts);
cout << "Waiting for the connection..." << endl;
conntok->wait();
cout << " ...OK" << endl;
// Send a message
cout << "\nSending message..." << endl;
auto msg = mqtt::make_message("hello", "Hello secure C++ world!", QOS, false);
client.publish(msg)->wait_for(TIMEOUT);
cout << " ...OK" << endl;
// Disconnect
cout << "\nDisconnecting..." << endl;
client.disconnect()->wait();
cout << " ...OK" << endl;
}
catch (const mqtt::exception& exc) {
cerr << exc.what() << endl;
return 1;
}
return 0;
}
|