Preserve main GNSS and volume behavior while porting verified TLS, receive fixes and full-handshake optimizations. Add MQTT connection diagnostics and route MQTT through banban.api.talkingq.com:1883. Include migration documentation and regression tools. Firmware builds and package checks passed; user confirmed new-board connectivity after switching the MQTT host to the domain.
108 lines
4.7 KiB
C
108 lines
4.7 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "mqtt_connect_diag.h"
|
|
#include "sockets.h"
|
|
|
|
/* Only installed during synchronous CONNECT. Never dump the CONNECT payload:
|
|
* it contains credentials. Keep only the first four incoming CONNACK bytes. */
|
|
static struct {
|
|
int (*read)(Network *, unsigned char *, int, int);
|
|
int (*write)(Network *, unsigned char *, int, int);
|
|
unsigned int read_calls, write_calls, received, sent;
|
|
unsigned char prefix[4];
|
|
unsigned int prefix_size;
|
|
} mqtt_diag;
|
|
|
|
static unsigned int mqtt_diag_elapsed(unsigned int start)
|
|
{
|
|
return (unsigned int)(ql_rtos_get_systicks() - start) * 5U;
|
|
}
|
|
|
|
static int mqtt_diag_read(Network *network, unsigned char *buffer, int size, int timeout)
|
|
{
|
|
unsigned int start = ql_rtos_get_systicks();
|
|
int result = mqtt_diag.read(network, buffer, size, timeout);
|
|
int socket_error = result <= 0 ? ql_get_soc_errno() : 0;
|
|
int i;
|
|
++mqtt_diag.read_calls;
|
|
if (result > 0) {
|
|
mqtt_diag.received += (unsigned int)result;
|
|
for (i = 0; i < result && i < size && mqtt_diag.prefix_size < sizeof(mqtt_diag.prefix); ++i)
|
|
mqtt_diag.prefix[mqtt_diag.prefix_size++] = buffer[i];
|
|
}
|
|
printf("[MQTT-DIAG] read request=%d rc=%d timeout_ms=%d elapsed_ms=%u errno_snapshot=%d\r\n",
|
|
size, result, timeout, mqtt_diag_elapsed(start), socket_error);
|
|
return result;
|
|
}
|
|
|
|
static int mqtt_diag_write(Network *network, unsigned char *buffer, int size, int timeout)
|
|
{
|
|
unsigned int start = ql_rtos_get_systicks();
|
|
int result = mqtt_diag.write(network, buffer, size, timeout);
|
|
int socket_error = result <= 0 ? ql_get_soc_errno() : 0;
|
|
++mqtt_diag.write_calls;
|
|
if (result > 0) mqtt_diag.sent += (unsigned int)result;
|
|
printf("[MQTT-DIAG] write request=%d rc=%d timeout_ms=%d elapsed_ms=%u errno_snapshot=%d\r\n",
|
|
size, result, timeout, mqtt_diag_elapsed(start), socket_error);
|
|
return result;
|
|
}
|
|
|
|
static const char *mqtt_diag_connack_reason(unsigned char code)
|
|
{
|
|
switch (code) {
|
|
case 0: return "accepted";
|
|
case 1: return "protocol_version_rejected";
|
|
case 2: return "client_id_rejected";
|
|
case 3: return "server_unavailable";
|
|
case 4: return "bad_username_or_password";
|
|
case 5: return "not_authorized";
|
|
default: return "reserved_code";
|
|
}
|
|
}
|
|
|
|
int talkingq_mqtt_connect_diagnosed(MQTTClient *client, MQTTPacket_connectData *options)
|
|
{
|
|
Network *network = client->ipstack;
|
|
MQTTConnackData connack = {255, 255};
|
|
unsigned int start;
|
|
int result;
|
|
int valid_connack;
|
|
memset(&mqtt_diag, 0, sizeof(mqtt_diag));
|
|
mqtt_diag.read = network->mqttread;
|
|
mqtt_diag.write = network->mqttwrite;
|
|
if (!mqtt_diag.read || !mqtt_diag.write) {
|
|
printf("[MQTT-DIAG] missing transport callbacks; calling SDK unchanged\r\n");
|
|
return MQTTConnectWithResults(client, options, &connack);
|
|
}
|
|
printf("[MQTT-DIAG] CONNECT begin version=%u clean=%u keepalive_s=%u timeout_ms=%u already_connected=%d\r\n",
|
|
(unsigned int)options->MQTTVersion, (unsigned int)options->cleansession,
|
|
(unsigned int)options->keepAliveInterval, client->command_timeout_ms, client->isconnected);
|
|
network->mqttread = mqtt_diag_read;
|
|
network->mqttwrite = mqtt_diag_write;
|
|
start = ql_rtos_get_systicks();
|
|
result = MQTTConnectWithResults(client, options, &connack);
|
|
network->mqttread = mqtt_diag.read;
|
|
network->mqttwrite = mqtt_diag.write;
|
|
printf("[MQTT-DIAG] CONNECT end rc=%d elapsed_ms=%u write_calls=%u tx_bytes=%u read_calls=%u rx_bytes=%u\r\n",
|
|
result, mqtt_diag_elapsed(start), mqtt_diag.write_calls, mqtt_diag.sent,
|
|
mqtt_diag.read_calls, mqtt_diag.received);
|
|
valid_connack = mqtt_diag.prefix_size == 4 && mqtt_diag.prefix[0] == 0x20 &&
|
|
mqtt_diag.prefix[1] == 2 && (mqtt_diag.prefix[2] & 0xfe) == 0 &&
|
|
mqtt_diag.prefix[3] <= 5 &&
|
|
(mqtt_diag.prefix[3] == 0 || mqtt_diag.prefix[2] == 0);
|
|
if (valid_connack) {
|
|
printf("[MQTT-DIAG] CONNACK code=%u reason=%s session_present=%u\r\n",
|
|
(unsigned int)mqtt_diag.prefix[3], mqtt_diag_connack_reason(mqtt_diag.prefix[3]),
|
|
(unsigned int)mqtt_diag.prefix[2]);
|
|
} else if (mqtt_diag.received) {
|
|
printf("[MQTT-DIAG] no valid initial CONNACK: received_prefix_bytes=%u\r\n", mqtt_diag.prefix_size);
|
|
} else {
|
|
printf("[MQTT-DIAG] no response bytes returned by SDK read\r\n");
|
|
}
|
|
if (result != 0 && !mqtt_diag.write_calls)
|
|
printf("[MQTT-DIAG] failed before transport write; inspect client state/CONNECT serialization\r\n");
|
|
/* SDK read maps both EOF and some socket errors to -1. The errno snapshot
|
|
* can be stale; do not claim a broker rejection without a valid CONNACK. */
|
|
return result;
|
|
}
|