I am developing a C++ MQTT client to connect to the AWS IoT Core and I am using Paho MQTT CPP for that. My code is simply based on the ssl_publish which uses the async_client class and SSL for communicating with the broker. I have discovered that the only way to make the connection work and be able to publish a message to a topic on AWS IoT Core is to both
- Pass in the address of the broker to the async_client constructor as ssl://: format where the port is 8883 and the ip can be fetched using ping or nslookup on the AWS IoT Core endpoint.
- Add the AWS IoT Core endpoint endpoint to a vector and set it on the connection_options using the set_servers() method.
Anything else will fail with different TCP errors such as -1 and -11.
The question is when the async_client constructor is receiving the server address why do we need to sort of set it again on the connection options. Is it a bug on Paho CPP or is it the expected behavior by design. what am i missing in that case then?
The code that works looks like the below:
/**
* #includes
*/
const std::string DFLT_SERVER_ADDRESS { "ssl://xx.xxx.xxx.xxx:8883" };
const std::string DFLT_CLIENT_ID { "mytopic" };
/**
* Other properties like mqtt topic, cert paths and qos are here
*/
// This is the aws iot core end point
static const std::vector<std::string> URIsVec = {
"xxxxx.iot.eu-west-1.amazonaws.com",
};
const mqtt::const_string_collection_ptr URIs = std::make_shared<const mqtt::string_collection>(URIsVec);
/////////////////////////////////////////////////////////////////////////////
/**
* A callback class for use with the main MQTT client.
*/
class callback : public virtual mqtt::callback
{
/**
* implementation
*/
};
/////////////////////////////////////////////////////////////////////////////
using namespace std;
int main(int argc, char* argv[])
{
string address = (argc > 1) ? string(argv[1]) : DFLT_SERVER_ADDRESS,
clientID = (argc > 2) ? string(argv[2]) : DFLT_CLIENT_ID;
// Call to the async_client ctor
mqtt::async_client client(address, clientID);
callback cb;
client.set_callback(cb);
// Build the connect options, including SSL and a LWT message.
mqtt::ssl_options sslopts;
// details of setting the sslopts
mqtt::connect_options connopts;
// Removing this line will fail the connection even though the async_client already knows about the server address via its constructor
connopts.set_servers(URIs);
// details of setting the connopts
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(LWT_TOPIC, "Hello World!", QOS, true);
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;
}
My Environment:
- CMake, minimum_required: 3.5
- Paho project version: 1.2.0
- C++ version: 11 from Paho Project Cmake
Complementary Info:
I tested connection using the mosquitto_pub on the same topic and by using same certificates and it works with the AWS IoT Core domain name and the port, no need to set the ip address.