/*******************************************************************************
* 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.jna;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import org.opennms.core.utils.LogUtils;
import org.opennms.jicmp.ip.ICMPEchoPacket;
import org.opennms.jicmp.ip.ICMPPacket;
import org.opennms.jicmp.ip.IPPacket;
import org.opennms.jicmp.ip.ICMPPacket.Type;
import org.opennms.jicmp.jna.NativeDatagramPacket;
import org.opennms.jicmp.jna.NativeDatagramSocket;
import com.sun.jna.Platform;
/**
* PingListener
*
* @author brozow
*/
public class V4Pinger extends AbstractPinger<Inet4Address> {
public V4Pinger(final int pingerId) throws Exception {
super(pingerId, NativeDatagramSocket.create(NativeDatagramSocket.PF_INET, Platform.isMac() ? NativeDatagramSocket.SOCK_DGRAM : NativeDatagramSocket.SOCK_RAW, NativeDatagramSocket.IPPROTO_ICMP));
// Windows requires at least one packet sent before a receive call can be made without error
// so we send a packet here to make sure... This one should not match the normal ping requests
// since it does not contain the cookie so it won't interface.
if (Platform.isWindows()) {
final ICMPEchoPacket packet = new ICMPEchoPacket(64);
packet.setCode(0);
packet.setType(Type.EchoRequest);
packet.getContentBuffer().putLong(System.nanoTime());
packet.getContentBuffer().putLong(System.nanoTime());
getPingSocket().send(packet.toDatagramPacket(InetAddress.getLocalHost()));
}
}
public void run() {
try {
final int pingerId = getPingerId();
final NativeDatagramPacket datagram = new NativeDatagramPacket(65535);
while (!isFinished()) {
getPingSocket().receive(datagram);
final long received = System.nanoTime();
final ICMPPacket icmpPacket = new ICMPPacket(getIPPayload(datagram));
final V4PingReply echoReply = icmpPacket.getType() == Type.EchoReply ? new V4PingReply(icmpPacket, received) : null;
if (echoReply != null && echoReply.getIdentifier() == pingerId && echoReply.isValid()) {
notifyPingListeners(datagram.getAddress(), echoReply);
}
}
} catch(final Throwable t) {
setThrowable(t);
LogUtils.debugf(this, t, "Error caught while processing ping packets: %s", t.getMessage());
}
}
private ByteBuffer getIPPayload(final NativeDatagramPacket datagram) {
return new IPPacket(datagram.getContent()).getPayload();
}
public void ping(final Inet4Address addr, final int identifier, final int sequenceNumber, final long threadId, final long count, final long interval, final int packetSize) throws InterruptedException {
final NativeDatagramSocket socket = getPingSocket();
for(int i = sequenceNumber; i < sequenceNumber + count; i++) {
final V4PingRequest request = new V4PingRequest(identifier, i, threadId,packetSize);
request.send(socket, addr);
Thread.sleep(interval);
}
}
}