All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hivemq.client.internal.mqtt.handler.ping.MqttPingHandler Maven / Gradle / Ivy

Go to download

HiveMQ MQTT Client is an MQTT 5.0 and MQTT 3.1.1 compatible and feature-rich high-performance Java client library with different API flavours and backpressure support

The newest version!
/*
 * Copyright 2018-present HiveMQ and the HiveMQ Community
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hivemq.client.internal.mqtt.handler.ping;

import com.hivemq.client.internal.mqtt.handler.MqttConnectionAwareHandler;
import com.hivemq.client.internal.mqtt.handler.disconnect.MqttDisconnectEvent;
import com.hivemq.client.internal.mqtt.handler.disconnect.MqttDisconnectUtil;
import com.hivemq.client.internal.mqtt.ioc.ConnectionScope;
import com.hivemq.client.internal.mqtt.message.ping.MqttPingReq;
import com.hivemq.client.internal.mqtt.message.ping.MqttPingResp;
import com.hivemq.client.internal.netty.DefaultChannelOutboundHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.ScheduledFuture;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.concurrent.TimeUnit;

/**
 * MQTT Keep Alive Handling.
 * 
    *
  • Sends a PINGREQ message when no write has been performed for the Keep Alive interval.
  • *
  • Disconnects or closes the channel if the PINGRESP message is not received in the timeout.
  • *
* * @author Silvio Giebl */ @ConnectionScope public class MqttPingHandler extends MqttConnectionAwareHandler implements DefaultChannelOutboundHandler, Runnable, ChannelFutureListener { public static final @NotNull String NAME = "ping"; private static final boolean PINGRESP_REQUIRED = false; // TODO configurable private final long keepAliveNanos; private long lastFlushTimeNanos; private long lastReadTimeNanos; private boolean pingReqWritten; private boolean pingReqFlushed; private boolean messageRead; private @Nullable ScheduledFuture timeoutFuture; public MqttPingHandler(final int keepAlive, final long lastFlushTimeNanos, final long lastReadTimeNanos) { keepAliveNanos = TimeUnit.SECONDS.toNanos(keepAlive) - TimeUnit.MILLISECONDS.toNanos(100); this.lastFlushTimeNanos = lastFlushTimeNanos; this.lastReadTimeNanos = lastReadTimeNanos; } @Override public void handlerAdded(final @NotNull ChannelHandlerContext ctx) { super.handlerAdded(ctx); schedule(ctx, nextDelay(System.nanoTime())); } @Override public void flush(final @NotNull ChannelHandlerContext ctx) { lastFlushTimeNanos = System.nanoTime(); ctx.flush(); } @Override public void channelRead(final @NotNull ChannelHandlerContext ctx, final @NotNull Object msg) { lastReadTimeNanos = System.nanoTime(); if (msg instanceof MqttPingResp) { messageRead = true; } else { messageRead = !PINGRESP_REQUIRED; ctx.fireChannelRead(msg); } } private void schedule(final @NotNull ChannelHandlerContext ctx, final long delayNanos) { timeoutFuture = ctx.executor().schedule(this, delayNanos, TimeUnit.NANOSECONDS); } private long nextDelay(final long timeNanos) { return keepAliveNanos - (timeNanos - Math.min(lastReadTimeNanos, lastFlushTimeNanos)); } @Override public void run() { if (ctx == null) { return; } if (pingReqWritten) { if (!pingReqFlushed) { MqttDisconnectUtil.close(ctx.channel(), "Timeout while writing PINGREQ"); return; } if (!messageRead) { MqttDisconnectUtil.close(ctx.channel(), "Timeout while waiting for PINGRESP"); return; } } pingReqFlushed = false; messageRead = false; final long timeNanos = System.nanoTime(); final long nextDelayNanos = nextDelay(timeNanos); if (nextDelayNanos > 1_000) { pingReqWritten = false; schedule(ctx, nextDelayNanos); } else { pingReqWritten = true; schedule(ctx, keepAliveNanos); lastFlushTimeNanos = timeNanos; ctx.writeAndFlush(MqttPingReq.INSTANCE).addListener(this); } } @Override public void operationComplete(final @NotNull ChannelFuture future) { if (future.isSuccess()) { pingReqFlushed = true; } } @Override protected void onDisconnectEvent( final @NotNull ChannelHandlerContext ctx, final @NotNull MqttDisconnectEvent disconnectEvent) { if (timeoutFuture != null) { timeoutFuture.cancel(false); timeoutFuture = null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy