I made a post over at the ESP32 forum, but I’m not sure I’ll get a response there (as this seems to be more of a QEMU problem).
I’ve got a Docker container running ESP-IDF (for development) along with a Mosquitto server for testing MQTT messaging. I can successfully connect and pub/sub to the Mosquitto broker with open MQTT (non-TLS) in QEMU as well as on a physical device. My full application is here: course-iot-with-esp-idf/workspace/apps/mqtts_demo/main/main.c at main · ShawnHymel/course-iot-with-esp-idf · GitHub
Here is my code for connecting over TCP on my physical ESP32 device. The hostname is the IP address of my computer on my local network. This works:
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.hostname = "10.0.0.100",
.broker.address.transport = MQTT_TRANSPORT_OVER_TCP,
.broker.address.port = 1883,
.credentials.username = "iot",
.credentials.authentication.password = "mosquitto"
};
// Initialize MQTT client
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
// Register event handler
esp_ret = esp_mqtt_client_register_event(mqtt_client,
ESP_EVENT_ANY_ID,
mqtt_event_handler,
NULL);
if (esp_ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to register MQTT event handler (%d)", esp_ret);
ESP_ERROR_CHECK(esp_mqtt_client_destroy(mqtt_client));
abort();
}
// Start MQTT client
esp_ret = esp_mqtt_client_start(mqtt_client);
if (esp_ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to start MQTT client (%d)", esp_ret);
ESP_ERROR_CHECK(esp_mqtt_client_destroy(mqtt_client));
abort();
}
...
Here is the esp_mqtt config for connecting over TCP in QEMU. The hostname is the IP address of the host container from within QEMU. This works:
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.hostname = "10.0.2.2",
.broker.address.transport = MQTT_TRANSPORT_OVER_TCP,
.broker.address.port = 1883,
.credentials.username = "iot",
.credentials.authentication.password = "mosquitto"
};
Here is the esp_mqtt config for connecting over SSL/TLS on the physical ESP32. This works:
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.hostname = "10.0.0.100",
.broker.address.transport = MQTT_TRANSPORT_OVER_SSL,
.broker.address.port = 8883,
.broker.verification.use_global_ca_store = false,
.broker.verification.certificate = (const char *)mqtt_ca_cert_start,
.broker.verification.certificate_len = mqtt_ca_cert_end - mqtt_ca_cert_start,
.broker.verification.skip_cert_common_name_check = false,
.broker.verification.common_name = "localhost",
.credentials.username = "iot",
.credentials.authentication.password = "mosquitto",
};
Here is the esp_mqtt config for connecting over SSL/TLS in QEMU. This does NOT work:
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.hostname = "10.0.2.2",
.broker.address.transport = MQTT_TRANSPORT_OVER_SSL,
.broker.address.port = 8883,
.broker.verification.use_global_ca_store = false,
.broker.verification.certificate = (const char *)mqtt_ca_cert_start,
.broker.verification.certificate_len = mqtt_ca_cert_end - mqtt_ca_cert_start,
.broker.verification.skip_cert_common_name_check = false,
.broker.verification.common_name = "localhost",
.credentials.username = "iot",
.credentials.authentication.password = "mosquitto",
};
With mbedTLS logging on verbose, here is what I see in the terminal:
I (2245) mqtts_demo: Starting MQTT demo
I (2265) eth_qemu: Starting Ethernet...
I (2295) esp_eth.netif.netif_glue: 00:00:00:00:00:03
I (2295) esp_eth.netif.netif_glue: ethernet attached to netif
I (2395) network_wrapper: Waiting for WiFi to connect...
I (2395) eth_qemu: Ethernet started
I (2405) eth_qemu: Ethernet link up
I (2405) eth_qemu: Ethernet MAC address: 00:00:00:00:00:03
I (2405) network_wrapper: Connected to WiFi
I (2405) network_wrapper: Waiting for IP address...
I (3405) esp_netif_handlers: eth ip: 10.0.2.15, mask: 255.255.255.0, gw: 10.0.2.2
I (3405) eth_qemu: Ethernet IPv4 address obtained
I (3405) eth_qemu: IP address: 10.0.2.15
I (3405) eth_qemu: Netmask: 255.255.255.0
I (3405) eth_qemu: Gateway: 10.0.2.2
I (12405) network_wrapper: Connected to IPv4 network
I (12405) mqtts_demo: Connecting to MQTT broker...
I (12455) mbedtls: ssl_tls.c:4606 => handshake
I (12455) mbedtls: ssl_msg.c:2353 => flush output
I (12455) mbedtls: ssl_msg.c:2362 <= flush output
I (12465) mbedtls: ssl_tls.c:4525 client state: MBEDTLS_SSL_HELLO_REQUEST
I (12465) mbedtls: ssl_msg.c:2353 => flush output
I (12465) mbedtls: ssl_msg.c:2362 <= flush output
I (12465) mbedtls: ssl_tls.c:4525 client state: MBEDTLS_SSL_CLIENT_HELLO
I (12465) mbedtls: ssl_client.c:919 => write client hello
--- Error: read failed: socket disconnected
--- Waiting for the device to reconnect................................
Even though the handshake succeeds in the real device, it gets to “write client hello” and then disconnects for some reason in QEMU. Does anyone have any clue as to why this is happening?