/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.icmp.jni6;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.Inet6Address;
import java.util.Queue;
import org.opennms.core.utils.LogUtils;
import org.opennms.protocols.icmp6.ICMPv6EchoReply;
import org.opennms.protocols.icmp6.ICMPv6Packet;
import org.opennms.protocols.icmp6.ICMPv6Packet.Type;
import org.opennms.protocols.icmp6.ICMPv6Socket;
import org.opennms.protocols.rt.Messenger;
/**
* JniIcmpMessenger
*
* @author brozow
* @version $Id: $
*/
public class Jni6IcmpMessenger implements Messenger<Jni6PingRequest, Jni6PingResponse> {
private int m_pingerId;
private ICMPv6Socket m_socket;
/**
* <p>Constructor for JniIcmpMessenger.</p>
* @param pingerId
*
* @throws java.io.IOException if any.
*/
public Jni6IcmpMessenger(int pingerId) throws IOException {
m_pingerId = pingerId;
m_socket = new ICMPv6Socket();
}
void processPackets(Queue<Jni6PingResponse> pendingReplies) {
while (true) {
try {
DatagramPacket packet = m_socket.receive();
Jni6PingResponse reply = Jni6IcmpMessenger.createPingResponse(packet);
if (reply != null && reply.getIdentifier() == m_pingerId) {
pendingReplies.offer(reply);
}
} catch (IOException e) {
LogUtils.errorf(this, e, "I/O Error occurred reading from ICMP Socket");
} catch (IllegalArgumentException e) {
// this is not an EchoReply so ignore it
} catch (IndexOutOfBoundsException e) {
// this packet is not a valid EchoReply ignore it
} catch (Throwable e) {
LogUtils.errorf(this, e, "Unexpected Exception processing reply packet!");
}
}
}
/**
* <p>sendRequest</p>
*
* @param request a {@link org.opennms.netmgt.icmp.jni6.Jni6PingRequest} object.
*/
@Override
public void sendRequest(Jni6PingRequest request) {
request.send(m_socket);
}
/** {@inheritDoc} */
@Override
public void start(final Queue<Jni6PingResponse> responseQueue) {
Thread socketReader = new Thread("JNI-ICMP-"+m_pingerId+"-Socket-Reader") {
public void run() {
try {
processPackets(responseQueue);
} catch (Throwable t) {
LogUtils.errorf(this, t, "Unexpected exception on Thread %s!", this);
}
}
};
socketReader.setDaemon(true);
socketReader.start();
}
/**
* <p>
* Creates a new instance of the class using the passed datagram as the data
* source. The address and ping packet are extracted from the datagram and
* returned as a new instance of the class. In addition to extracting the
* packet, the packet's received time is updated to the current time.
* </p>
*
* <p>
* If the received datagram is not an echo reply or an incorrect length then
* an exception is generated to alert the caller.
* </p>
*
* @param packet
* The packet with the ICMP datagram.
* @throws java.lang.IllegalArgumentException
* Throw if the datagram is not the correct length or type.
* @throws java.lang.IndexOutOfBoundsException
* Thrown if the datagram does not contain sufficient data.
* @return a {@link org.opennms.netmgt.icmp.spi.PingReply} object.
*/
public static Jni6PingResponse createPingResponse(DatagramPacket packet) {
ICMPv6Packet icmpPacket = new ICMPv6Packet(packet.getData(), packet.getOffset(), packet.getLength());
if (icmpPacket.getType() != Type.EchoReply) return null;
ICMPv6EchoReply echoReply = new ICMPv6EchoReply(icmpPacket);
if (!echoReply.isEchoReply() || !echoReply.isValid()) return null;
Inet6Address address = (Inet6Address) packet.getAddress();
return new Jni6PingResponse(address, echoReply);
}
}