diff --git a/ext/winping/jni/Makefile b/ext/winping/jni/Makefile new file mode 100755 index 00000000..c77c3aaa --- /dev/null +++ b/ext/winping/jni/Makefile @@ -0,0 +1,31 @@ +# +# Windows JNI pinger using Microsoft's ICMP.DLL +# +# Copyright 2007 Anton Keks +# + +JAVA_INCDIR = $(JDK_HOME)\include +JAVA_INCDIR_PLAF = $(JAVA_INCDIR)\win32 + +CC = cl +CFLAGS = -TC +CPPFLAGS = -I$(JAVA_INCDIR) -I$(JAVA_INCDIR_PLAF) + +SRC = WindowsPinger.c +OBJ = $(SRC:.c=.obj) + +LIBNAME = winping +LIBEXTENSION = dll +LIBWINPING = $(LIBNAME).$(LIBEXTENSION) +CLEAN_EXTENSIONS = *.obj *.$(LIBEXTENSION) *.lib *.exp + +all: $(LIBWINPING) + +.c.obj: + $(CC) -nologo $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +$(LIBWINPING): $(OBJ) + $(CC) -nologo -MD -LD -o $@ $** + +clean: + del $(CLEAN_EXTENSIONS) diff --git a/ext/winping/jni/WindowsPinger.c b/ext/winping/jni/WindowsPinger.c new file mode 100755 index 00000000..80f7eaea --- /dev/null +++ b/ext/winping/jni/WindowsPinger.c @@ -0,0 +1,93 @@ +/* + * Copyright 2007 Anton Keks + */ + +#include + +#include "WindowsPinger.h" + +FARPROC IcmpCreateFile; + +typedef BOOL (FAR WINAPI *TIcmpCloseHandle)(HANDLE IcmpHandle); +TIcmpCloseHandle IcmpCloseHandle; + +typedef DWORD (FAR WINAPI *TIcmpSendEcho)( + HANDLE IcmpHandle, /* handle returned from IcmpCreateFile() */ + u_long DestAddress, /* destination IP address (in network order) */ + LPVOID RequestData, /* pointer to buffer to send */ + WORD RequestSize, /* length of data in buffer */ + LPIPINFO RequestOptns, /* see Note 2 */ + LPVOID ReplyBuffer, /* see Note 1 */ + DWORD ReplySize, /* length of reply (must allow at least 1 reply) */ + DWORD Timeout /* time in milliseconds to wait for reply */ +); +TIcmpSendEcho IcmpSendEcho; + +/* + * Class: net_azib_ipscan_core_net_WindowsPinger + * Method: nativeIcmpCreateFile + */ +JNIEXPORT jint JNICALL +Java_net_azib_ipscan_core_net_WindowsPinger_nativeIcmpCreateFile +(JNIEnv *env, jclass cls) +{ + HMODULE hICMP = LoadLibrary("icmp.dll"); + if (!hICMP) { + // newer versions of Windows should include this one instead + hICMP = LoadLibrary("iphlpapi.dll"); + } + if (!hICMP) { + return -1; + } + IcmpCreateFile = (FARPROC)GetProcAddress(hICMP, "IcmpCreateFile"); + IcmpCloseHandle = (TIcmpCloseHandle)GetProcAddress(hICMP, "IcmpCloseHandle"); + IcmpSendEcho = (TIcmpSendEcho)GetProcAddress(hICMP, "IcmpSendEcho"); + + return IcmpCreateFile(); +} + +/* + * Class: net_azib_ipscan_core_net_WindowsPinger + * Method: nativeIcmpCloseHandle + */ +JNIEXPORT jint JNICALL +Java_net_azib_ipscan_core_net_WindowsPinger_nativeIcmpCloseHandle +(JNIEnv *env, jclass cls, jint handle) +{ + return IcmpCloseHandle(handle); +} + +/* + * Class: net_azib_ipscan_core_net_WindowsPinger + * Method: nativeIcmpSendEcho + */ +JNIEXPORT jint JNICALL +Java_net_azib_ipscan_core_net_WindowsPinger_nativeIcmpSendEcho +(JNIEnv *env, jclass cls, jint handle, + jbyteArray address, jbyteArray pingData, jbyteArray replyData, jint timeout) +{ + DWORD replyCount; + IPINFO IPInfo; + jbyte *addrBuf, *pingDataBuf, replyDataBuf; + jclass replyClass; + jfieldID fid; + + IPInfo.Ttl = 128; + IPInfo.Tos = 0; + IPInfo.Flags = 0; + IPInfo.OptionsSize = 0; + IPInfo.OptionsData = NULL; + + addrBuf = env->GetByteArrayElements(env, address, NULL); + pingDataBuf = env->GetByteArrayElements(env, pingData, NULL); + replyDataBuf = env->GetByteArrayElements(env, replyData, NULL); + + replyCount = IcmpSendEcho(handle, (DWORD)*addrBuf, pingDataBuf, env->GetArrayLength(pingData) * sizeof(jbyte), + &IPInfo, replyDataBuf, env->GetArrayLength(replyData), timeout); + + env->ReleaseByteArrayElements(env, address, addrBuf, JNI_ABORT); + env->ReleaseByteArrayElements(env, pingData, pingDataBuf, JNI_ABORT); + env->ReleaseByteArrayElements(env, replyData, replyDataBuf, NULL); + + return replyCount; +} diff --git a/ext/winping/jni/WindowsPinger.h b/ext/winping/jni/WindowsPinger.h new file mode 100644 index 00000000..a920f8af --- /dev/null +++ b/ext/winping/jni/WindowsPinger.h @@ -0,0 +1,36 @@ +#include +/* Header for class net_azib_ipscan_core_net_WindowsPinger */ + +#ifndef _Included_net_azib_ipscan_core_net_WindowsPinger +#define _Included_net_azib_ipscan_core_net_WindowsPinger +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: net_azib_ipscan_core_net_WindowsPinger + * Method: nativeIcmpCreateFile + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_net_azib_ipscan_core_net_WindowsPinger_nativeIcmpCreateFile + (JNIEnv *, jclass); + +/* + * Class: net_azib_ipscan_core_net_WindowsPinger + * Method: nativeIcmpSendEcho + * Signature: (I[B[B[BI)I + */ +JNIEXPORT jint JNICALL Java_net_azib_ipscan_core_net_WindowsPinger_nativeIcmpSendEcho + (JNIEnv *, jclass, jint, jbyteArray, jbyteArray, jbyteArray, jint); + +/* + * Class: net_azib_ipscan_core_net_WindowsPinger + * Method: nativeIcmpCloseHandle + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_net_azib_ipscan_core_net_WindowsPinger_nativeIcmpCloseHandle + (JNIEnv *, jclass, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/net/azib/ipscan/core/net/WindowsPinger.java b/src/net/azib/ipscan/core/net/WindowsPinger.java new file mode 100644 index 00000000..d2de107a --- /dev/null +++ b/src/net/azib/ipscan/core/net/WindowsPinger.java @@ -0,0 +1,61 @@ +/** + * This file is a part of Angry IP Scanner source code, + * see http://www.azib.net/ for more information. + * Licensed under GPLv2. + */ +package net.azib.ipscan.core.net; + +import java.io.IOException; +import java.net.InetAddress; + +/** + * Windows-only pinger that uses Microsoft's ICMP.DLL for its job. + * This pinger exists to provide adequate pinging to Windows users, + * because Microsoft has removed raw socket support from consumer + * versions of Windows since XP SP2. + * + * @author Anton Keks + */ +public class WindowsPinger implements Pinger { + + private int timeout; + + public WindowsPinger(int timeout) { + this.timeout = timeout; + } + + public void close() throws IOException { + } + + public PingResult ping(InetAddress address, int count) throws IOException { + + PingResult result = new PingResult(address); + byte[] pingData = new byte[56]; + byte[] replyData = new byte[56 + 100]; + + int handle = nativeIcmpCreateFile(); + try { + + // send a bunch of packets + for (int i = 1; i <= count; i++) { + if (nativeIcmpSendEcho(handle, address.getAddress(), pingData, replyData, timeout) > 0) { + /*if (replyData.status == 11000) { + result.addReply(replyData.roundTripTime); + result.setTTL(replyData.ttl); + }*/ + } + } + } + finally { + nativeIcmpCloseHandle(handle); + } + + return result; + } + + private native static int nativeIcmpCreateFile(); + + private native static int nativeIcmpSendEcho(int handle, byte[] address, byte[] pingData, byte[] replyData, int timeout); + + private native static void nativeIcmpCloseHandle(int handle); +}