/******************************************************************************* * Copyright (c) 2015 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.network.infrastructure.channel.ping; import jsettlers.network.NetworkConstants; import jsettlers.network.NetworkConstants.ENetworkKey; import jsettlers.network.infrastructure.channel.Channel; import jsettlers.network.infrastructure.channel.GenericDeserializer; import jsettlers.network.infrastructure.channel.listeners.PacketChannelListener; import jsettlers.network.infrastructure.log.Logger; import jsettlers.network.infrastructure.utils.AveragingBoundedBuffer; /** * {@link PacketChannelListener} to receive and send {@link PingPacket}s. * * @author Andreas Eberle * */ public class PingPacketListener extends PacketChannelListener<PingPacket> implements IRoundTripTimeSupplier { private static final int JITTER_AVERAGING_BUFFER = 7; private final Logger logger; private final Channel channel; private final AveragingBoundedBuffer avgJitter = new AveragingBoundedBuffer(JITTER_AVERAGING_BUFFER); private RoundTripTime currRtt = new RoundTripTime(System.currentTimeMillis(), 0, 0, 0); private IPingUpdateListener pingUpdateListener = null; public PingPacketListener(Logger logger, Channel channel) { super(NetworkConstants.ENetworkKey.PING, new GenericDeserializer<PingPacket>(PingPacket.class)); this.logger = logger; this.channel = channel; channel.registerListener(this); } @Override protected void receivePacket(ENetworkKey key, PingPacket receivedPing) { long now = System.currentTimeMillis(); int rtt = (int) (now - receivedPing.getReceiverTime()); int jitter = Math.abs(currRtt.getRtt() - rtt); avgJitter.insert(jitter); currRtt = new RoundTripTime(now, rtt, jitter, avgJitter.getAverage()); if (rtt > NetworkConstants.RTT_LOGGING_THRESHOLD || jitter > NetworkConstants.JITTER_LOGGING_THRESHOLD) { logger.info(String.format("rtt: %5d jitter: %3d avgJitter: %3d", rtt, jitter, avgJitter.getAverage())); } sendPing(receivedPing.getSenderTime()); if (pingUpdateListener != null) pingUpdateListener.pingUpdated(currRtt); } private void sendPing(long receiverTime) { channel.sendPacket(NetworkConstants.ENetworkKey.PING, new PingPacket(System.currentTimeMillis(), receiverTime)); } /** * Gets the round trip time of this {@link Channel}. * * @return Returns the current {@link RoundTripTime}. */ @Override public RoundTripTime getRoundTripTime() { return currRtt; } /** * Initialize the pinging by sending a first {@link PingPacket}. */ public void initPinging() { sendPing(0); } /** * Sets the {@link IPingUpdateListener} that will be informed on ping updates. Set null to deregister a listener.<br> * Note: Only one listener at a time can be set! * * @param pingUpdateListener */ public void setPingUpdateListener(IPingUpdateListener pingUpdateListener) { this.pingUpdateListener = pingUpdateListener; } }