/**
* Copyright (C) 2010-2013 Eugen Feller, INRIA <eugen.feller@inria.fr>
*
* This file is part of Snooze, a scalable, autonomic, and
* energy-aware virtual machine (VM) management framework.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses>.
*/
package org.inria.myriads.snoozenode.heartbeat.receiver;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import org.inria.myriads.snoozecommon.communication.NetworkAddress;
import org.inria.myriads.snoozecommon.guard.Guard;
import org.inria.myriads.snoozenode.heartbeat.listener.HeartbeatListener;
import org.inria.myriads.snoozenode.heartbeat.message.HeartbeatMessage;
import org.inria.myriads.snoozenode.util.SerializationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Heartbeat multicast listener.
*
* @author Eugen Feller
*/
public final class HeartbeatMulticastReceiver
implements Runnable
{
/** Define the logger. */
private static final Logger log_ = LoggerFactory.getLogger(HeartbeatMulticastReceiver.class);
/** Size of buffer. */
private static final int BUFF_SIZE = 65535;
/** Multicast socket reference. */
private MulticastSocket mcastSocket_;
/** Heartbeat event holder. */
private HeartbeatListener heartbeatEvent_;
/** Timeout. */
private int timeout_;
/** Signals termination. */
private boolean isTerminated_;
/**
* Heartbeat multicast listener constructor.
*
* @param heartbeatAddress The heartbeat address
* @param timeout The timeout
* @param heartbeatEvent The heartbeat callback
* @throws IOException Exception
*/
public HeartbeatMulticastReceiver(NetworkAddress heartbeatAddress,
int timeout,
HeartbeatListener heartbeatEvent)
throws IOException
{
Guard.check(heartbeatAddress, timeout, heartbeatEvent);
log_.debug(String.format("Starting heartbeat listener on the group: %s, port: %d, and timeout: %d",
heartbeatAddress.getAddress(), heartbeatAddress.getPort(), timeout));
timeout_ = timeout;
heartbeatEvent_ = heartbeatEvent;
isTerminated_ = false;
joinMulticastGroup(heartbeatAddress);
}
/**
* Listen for group leader heartbeat multicast packets.
*/
public void run()
{
log_.debug("Heartbeat multicast listener waiting for packets");
while (!isTerminated_)
{
try
{
byte[] byteArray = receive();
HeartbeatMessage heartbeat = (HeartbeatMessage) SerializationUtils.deserializeObject(byteArray);
heartbeatEvent_.onHeartbeatArrival(heartbeat);
}
catch (IOException exception)
{
if (!isTerminated_)
{
heartbeatEvent_.onHeartbeatFailure();
}
}
catch (ClassNotFoundException exception)
{
log_.error(String.format("Class not found exception: %s", exception.getMessage()));
}
}
log_.debug("Heartbeat multicast listened is stopped!");
}
/**
* Join a multicast group.
*
* @param heartbeatAddress The heartbeat address
* @throws IOException The I/O exception
*/
private void joinMulticastGroup(NetworkAddress heartbeatAddress)
throws IOException
{
log_.debug(String.format("Joining multicast group: %d", heartbeatAddress.getPort()));
mcastSocket_ = new MulticastSocket(heartbeatAddress.getPort());
mcastSocket_.setSoTimeout(timeout_);
InetAddress address = InetAddress.getByName(heartbeatAddress.getAddress());
mcastSocket_.joinGroup(address);
}
/**
* Listen for multicast packets.
*
* @return The byte array
* @throws IOException The I/O exception
*/
private byte[] receive()
throws IOException
{
byte[] buffer = new byte[BUFF_SIZE];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
mcastSocket_.receive(packet);
packet.setLength(buffer.length);
return buffer;
}
/**
* Closes the socket.
*/
private void close()
{
if (mcastSocket_ != null)
{
mcastSocket_.close();
}
}
/**
* Terminates the listener.
*/
public synchronized void terminate()
{
log_.debug("Terminating the heartbeat multicast listener");
isTerminated_ = true;
close();
}
}