/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you 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 network.thunder.core.communication.nio.handler.low; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; import network.thunder.core.communication.objects.messages.impl.message.etc.Ping; import network.thunder.core.communication.objects.messages.impl.message.etc.Pong; import java.util.Random; public class PingHandler extends ChannelDuplexHandler { static final long PING_INTERVAL = 10 * 1000; static final long TIMEOUT = 30 * 1000; long lastMessageSent = System.currentTimeMillis(); long lastMessageReceived = System.currentTimeMillis(); long lastPing = System.currentTimeMillis(); long lastPong = System.currentTimeMillis(); boolean connectionClosed = false; ChannelHandlerContext ctx; Random random = new Random(); @Override public void channelActive (ChannelHandlerContext ctx) throws Exception { this.ctx = ctx; ctx.fireChannelActive(); new Thread(() -> { while (true) { if (connectionClosed) { return; } else { if (lastPing - lastPong > TIMEOUT) { ctx.disconnect(); } else if (System.currentTimeMillis() - lastPing > PING_INTERVAL) { sendPing(); } } try { Thread.sleep(random.nextInt(1000)); } catch (InterruptedException e) { return; } } }).start(); } @Override public void channelRead (ChannelHandlerContext ctx, Object msg) throws Exception { lastMessageReceived = System.currentTimeMillis(); if (msg instanceof Ping) { lastPing = System.currentTimeMillis(); sendPong(); } else if (msg instanceof Pong) { lastPong = System.currentTimeMillis(); } else { ctx.fireChannelRead(msg); } } private void sendPong () { lastPong = System.currentTimeMillis(); ctx.writeAndFlush(new Pong()); } private void sendPing () { lastPing = System.currentTimeMillis(); ctx.writeAndFlush(new Ping()); } @Override public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } @Override public void write (ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { lastMessageSent = System.currentTimeMillis(); ctx.writeAndFlush(msg, promise); } @Override public void channelUnregistered (ChannelHandlerContext ctx) throws Exception { super.channelUnregistered(ctx); connectionClosed = true; } }