/******************************************************************************* * 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.jni; import java.io.IOException; import java.net.DatagramPacket; import java.util.Queue; import org.opennms.core.utils.LogUtils; import org.opennms.protocols.icmp.ICMPEchoPacket; import org.opennms.protocols.icmp.IcmpSocket; import org.opennms.protocols.rt.Messenger; /** * JniIcmpMessenger * * @author brozow * @version $Id: $ */ public class JniIcmpMessenger implements Messenger<JniPingRequest, JniPingResponse> { private int m_pingerId; private IcmpSocket m_socket; /** * <p>Constructor for JniIcmpMessenger.</p> * @param pingerId * * @throws java.io.IOException if any. */ public JniIcmpMessenger(int pingerId) throws IOException { m_pingerId = pingerId; m_socket = new IcmpSocket(); } void processPackets(Queue<JniPingResponse> pendingReplies) { final int pingerId = m_pingerId; while (true) { try { DatagramPacket packet = m_socket.receive(); JniPingResponse reply = JniIcmpMessenger.createPingResponse(packet); if (reply.isEchoReply() && reply.getIdentifier() == pingerId) { // Remove this so we don't send a lot of time in this method when we should be processing packets // LogUtils.debugf(this, "Found an echo packet addr = %s, port = %d, length = %d, created reply %s", packet.getAddress(), packet.getPort(), packet.getLength(), reply); 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.jni.JniPingRequest} object. */ @Override public void sendRequest(JniPingRequest request) { request.send(m_socket); } /** {@inheritDoc} */ @Override public void start(final Queue<JniPingResponse> 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 JniPingResponse createPingResponse(DatagramPacket packet) { // Check the packet length // if (packet.getData().length != ICMPEchoPacket.getNetworkSize()) { throw new IllegalArgumentException("The packet is not the correct network size"); } // Construct a new packet // ICMPEchoPacket pkt = new ICMPEchoPacket(packet.getData()); if (pkt.getReceivedTime() == 0) pkt.setReceivedTime(); // Construct and return the new reply // return new JniPingResponse(packet.getAddress(), pkt); } }