Hello all,
I have a question related to the max-keep-alive we have set that is not respected.
We have the setting as this:
<!-- Disallow keep-alive of more than 60s because load balancer drops connections after 90s (should be 1.5x keep-alive) -->
<keep-alive>
<max-keep-alive>60</max-keep-alive>
<allow-unlimited>false</allow-unlimited>
</keep-alive>
However, when I run this test:
@Test
void tooLongKeepAliveWillNotWork() {
String clientId = randomAlphabetic(10);
when(authenticationProxyService.isAuthenticated(eq(clientId), eq("test-password")))
.thenAnswer(i -> AuthenticatedResponse.authenticated("test"));
{
Mqtt5BlockingClient client = Mqtt5Client.builder()
.identifier(clientId)
.serverPort(hivemqProperties.getPortNumber())
.simpleAuth(new MqttSimpleAuth(MqttUtf8StringImpl.of("test"),
ByteBuffer.wrap("test-password".getBytes(StandardCharsets.UTF_8))))
.buildBlocking();
Mqtt5ConnAck send = client.connectWith().keepAlive(5000).send();
OptionalInt serverKeepAlive = send.getServerKeepAlive();
assertThat(serverKeepAlive.orElseThrow(), is(equalTo(60)));
int keepAlive = client.getConfig().getConnectionConfig().orElseThrow().getKeepAlive();
assertThat(keepAlive, is(equalTo(60))); // works
}
{
Mqtt3BlockingClient client = Mqtt3Client.builder()
.identifier(clientId)
.serverPort(hivemqProperties.getPortNumber())
.simpleAuth(Mqtt3SimpleAuth.builder()
.username(MqttUtf8StringImpl.of("test"))
.password(ByteBuffer.wrap("test-password".getBytes(StandardCharsets.UTF_8)))
.build())
.buildBlocking();
Mqtt3ConnAck send = client.connectWith().keepAlive(5000).send();
Mqtt3ConnAckReturnCode returnCode = send.getReturnCode();
assertThat(returnCode, is(not(equalTo(Mqtt3ConnAckReturnCode.SUCCESS))));
int keepAlive = client.getConfig().getConnectionConfig().orElseThrow().getKeepAlive();
assertThat(keepAlive, is(equalTo(60))); // also doesn't pass
}
}
It does not pass the bottom 2 assertions. This seems very weird to me as the setting clearly says:
The max-keep-alive value refers to the maximum value of the keepAlive field in the CONNECT packet of the client that will be accepted by the broker. If a client sends a CONNECT with a keepAlive value that exceeds this value, the broker will not accept the connection.
Am I missing something or is this a bug? When using Mqtt V5, it does seem to work, but in the ConnAck tells you to what the server keep-alive is (which also doesn’t match the text close to the config). Is this just inherent to Mqtt V3 that you cannot have this? And how could I simulate such a thing? Do a check in the authenticator and don’t authenticate it if its V3 and the keep-alive is too long?
I also did some tests regarding the maximum clientId size, and that one seems to work.
Can somebody shed some light on this?
Many thanks,
Bram
FYI: I’m using hiveMq 2023.9 Community Edition
EDIT: If I look at this code (in the ConnectHandler):
if (ProtocolVersion.MQTTv5.equals(msg.getProtocolVersion()) &&
((msg.getKeepAlive() == 0 && !allowZeroKeepAlive) || (msg.getKeepAlive() > serverKeepAliveMaximum))) {
if (log.isTraceEnabled()) {
log.trace("Client {} used keepAlive {} which is invalid, using server maximum of {}",
msg.getClientIdentifier(),
msg.getKeepAlive(),
serverKeepAliveMaximum);
}
keepAlive = serverKeepAliveMaximum;
} else {
keepAlive = msg.getKeepAlive();
}
It looks like this is done on only Mqtt V5, is this an oversight? Or just a consequence of Mqtt 3, I’m not super familiar with the spec and implementation details.