Fix MQTT client ID collision on ARM 32-bit userland with 64-bit kernel

The MQTT client ID was generated using sprintf with %ld and time(nullptr).
On platforms with 32-bit userland but 64-bit kernel (such as Raspberry Pi OS
and some custom Alpine Linux builds), time_t is a 64-bit long long but %ld
only reads 32 bits. Since the upper 32 bits of the current Unix timestamp
are zero, this always produces a client ID ending in .0, causing collisions
when multiple instances or restarts occur.

Replace time()-based client IDs with PID-based IDs using getpid(), which is
always a portable 32-bit value and unique per process. Platform-guarded for
Windows (_getpid) and POSIX (getpid).
This commit is contained in:
Andy Taylor 2026-03-08 12:51:36 +00:00
parent 32c3d7360e
commit 50a3567335

View file

@ -21,7 +21,12 @@
#include <cassert>
#include <cstdio>
#include <cstring>
#include <ctime>
#if defined(_WIN32) || defined(_WIN64)
#include <process.h>
#else
#include <unistd.h>
#endif
CMQTTConnection::CMQTTConnection(const std::string& host, unsigned short port, const std::string& name, const bool authEnabled, const std::string& username, const std::string& password, const std::vector<std::pair<std::string, void (*)(const unsigned char*, unsigned int)>>& subs, unsigned int keepalive, MQTT_QOS qos) :
m_host(host),
@ -52,7 +57,11 @@ CMQTTConnection::~CMQTTConnection()
bool CMQTTConnection::open()
{
char name[50U];
::sprintf(name, "DMRGateway.%ld", ::time(nullptr));
#if defined(_WIN32) || defined(_WIN64)
::sprintf(name, "DMRGateway.%u", (unsigned)::_getpid());
#else
::sprintf(name, "DMRGateway.%u", (unsigned)::getpid());
#endif
::fprintf(stdout, "DMRGateway (%s) connecting to MQTT as %s\n", m_name.c_str(), name);