make it possible to terminate socket operations in progress (this is possible by calling socket.close() from another thread)

This commit is contained in:
Anton Keks 2012-12-16 17:17:56 +02:00
parent 74710d8d77
commit 21a202062b
7 changed files with 77 additions and 66 deletions

View File

@ -10,6 +10,9 @@ import net.azib.ipscan.core.values.NotScanned;
import net.azib.ipscan.fetchers.Fetcher;
import net.azib.ipscan.fetchers.FetcherRegistry;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Scanner functionality is encapsulated in this class.
* It uses a list of fetchers to perform the actual scanning.
@ -17,8 +20,8 @@ import net.azib.ipscan.fetchers.FetcherRegistry;
* @author Anton Keks
*/
public class Scanner {
private FetcherRegistry fetcherRegistry;
private Map<Long, Fetcher> currentFetchers = new ConcurrentHashMap<Long, Fetcher>();
public Scanner(FetcherRegistry fetcherRegistry) {
this.fetcherRegistry = fetcherRegistry;
@ -34,6 +37,7 @@ public class Scanner {
int fetcherIndex = 0;
boolean isScanningInterrupted = false;
for (Fetcher fetcher : fetcherRegistry.getSelectedFetchers()) {
currentFetchers.put(Thread.currentThread().getId(), fetcher);
Object value = NotScanned.VALUE;
if (!subject.isAddressAborted() && !isScanningInterrupted) {
// run the fetcher
@ -50,6 +54,11 @@ public class Scanner {
result.setType(subject.getResultType());
}
public void interrupt(Thread thread) {
Fetcher fetcher = currentFetchers.get(thread.getId());
if (fetcher != null) fetcher.cleanup();
}
/**
* Init everything needed for scanning, including Fetchers
@ -64,9 +73,9 @@ public class Scanner {
* Cleanup after a scan
*/
public void cleanup() {
currentFetchers.clear();
for (Fetcher fetcher : fetcherRegistry.getSelectedFetchers()) {
fetcher.cleanup();
}
}
}

View File

@ -158,11 +158,15 @@ public class ScannerDispatcherThread extends Thread implements ThreadFactory, St
*/
public Thread newThread(Runnable r) {
// create IP threads in the specified group
Thread thread = new Thread(threadGroup, r);
// IP threads must be daemons, not preventing the JVM to terminate
thread.setDaemon(true);
return thread;
return new Thread(threadGroup, r) {
// IP threads must be daemons, not preventing the JVM to terminate
{ setDaemon(true); }
@Override
public void interrupt() {
scanner.interrupt(this);
super.interrupt();
}
};
}
/**

View File

@ -6,16 +6,18 @@
package net.azib.ipscan.fetchers;
import net.azib.ipscan.config.LoggerFactory;
import net.azib.ipscan.config.ScannerConfig;
import net.azib.ipscan.core.ScanningSubject;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.azib.ipscan.config.ScannerConfig;
import net.azib.ipscan.config.LoggerFactory;
import net.azib.ipscan.core.ScanningSubject;
import static java.util.logging.Level.*;
import static net.azib.ipscan.util.IOUtils.*;
/**
* NetBIOSInfoFetcher - gathers NetBIOS info about Windows machines.
@ -84,13 +86,11 @@ public class NetBIOSInfoFetcher extends AbstractFetcher {
}
catch (Exception e) {
// bugs?
LOG.log(Level.WARNING, null, e);
LOG.log(WARNING, null, e);
return null;
}
finally {
if (socket != null) {
socket.close();
}
closeQuietly(socket);
}
}

View File

@ -18,6 +18,8 @@ import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static net.azib.ipscan.core.ScanningSubject.*;
/**
* PingFetcher is able to ping IP addresses.
* It returns the average round trip time of all pings sent.
@ -53,25 +55,21 @@ public class PingFetcher extends AbstractFetcher {
}
protected PingResult executePing(ScanningSubject subject) {
PingResult result = null;
if (subject.hasParameter(ScanningSubject.PARAMETER_PING_RESULT)) {
result = (PingResult) subject.getParameter(ScanningSubject.PARAMETER_PING_RESULT);
}
else {
try {
result = pinger.ping(subject, config.pingCount);
}
catch (IOException e) {
// if this is not a timeout
LOG.log(Level.WARNING, "Pinging failed", e);
// return an empty ping result
result = new PingResult(subject.getAddress());
}
// remember the result for other fetchers to use
subject.setParameter(ScanningSubject.PARAMETER_PING_RESULT, result);
}
if (subject.hasParameter(PARAMETER_PING_RESULT))
return (PingResult) subject.getParameter(PARAMETER_PING_RESULT);
PingResult result;
try {
result = pinger.ping(subject, config.pingCount);
}
catch (IOException e) {
// if this is not a timeout
LOG.log(Level.WARNING, "Pinging failed", e);
// return an empty ping result
result = new PingResult(subject.getAddress());
}
// remember the result for other fetchers to use
subject.setParameter(PARAMETER_PING_RESULT, result);
return result;
}

View File

@ -5,8 +5,8 @@
package net.azib.ipscan.fetchers;
import net.azib.ipscan.config.ScannerConfig;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.core.ScanningResult.ResultType;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.core.net.PingResult;
import net.azib.ipscan.core.net.PingerRegistry;
@ -29,6 +29,6 @@ public class PingTTLFetcher extends PingFetcher {
public Object scan(ScanningSubject subject) {
PingResult result = executePing(subject);
subject.setResultType(result.isAlive() ? ResultType.ALIVE : ResultType.DEAD);
return result.isAlive() && result.getTTL() > 0 ? new Integer(result.getTTL()) : null;
return result.isAlive() && result.getTTL() > 0 ? result.getTTL() : null;
}
}

View File

@ -5,6 +5,16 @@
*/
package net.azib.ipscan.fetchers;
import net.azib.ipscan.config.ScannerConfig;
import net.azib.ipscan.core.PortIterator;
import net.azib.ipscan.core.ScanningResult.ResultType;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.core.values.NotScanned;
import net.azib.ipscan.core.values.NumericRangeList;
import net.azib.ipscan.gui.fetchers.PortsFetcherPrefs;
import net.azib.ipscan.util.SequenceIterator;
import net.azib.ipscan.util.ThreadResourceBinder;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
@ -14,15 +24,6 @@ import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
import net.azib.ipscan.config.ScannerConfig;
import net.azib.ipscan.core.PortIterator;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.core.ScanningResult.ResultType;
import net.azib.ipscan.core.values.NotScanned;
import net.azib.ipscan.core.values.NumericRangeList;
import net.azib.ipscan.gui.fetchers.PortsFetcherPrefs;
import net.azib.ipscan.util.SequenceIterator;
/**
* PortsFetcher scans TCP ports.
* Port list is obtained using the {@link net.azib.ipscan.core.PortIterator}.
@ -37,6 +38,7 @@ public class PortsFetcher extends AbstractFetcher {
private static final String PARAMETER_FILTERED_PORTS = "filteredPorts";
private ScannerConfig config;
private ThreadResourceBinder<Socket> sockets = new ThreadResourceBinder<Socket>();
// initialize preferences for this scan
private PortIterator portIteratorPrototype;
@ -80,7 +82,6 @@ public class PortsFetcher extends AbstractFetcher {
int portTimeout = subject.getAdaptedPortTimeout();
Socket socket = null;
// clone port iterator for performance instead of creating for every thread
Iterator<Integer> portsIterator = portIteratorPrototype.copy();
if (config.useRequestedPorts && subject.isAnyPortRequested()) {
@ -91,11 +92,10 @@ public class PortsFetcher extends AbstractFetcher {
// no ports are configured for scanning
return false;
}
while (portsIterator.hasNext() && !Thread.currentThread().isInterrupted()) {
// TODO: UDP ports?
// TODO: reuse sockets?
socket = new Socket();
Socket socket = sockets.bind(new Socket());
int port = portsIterator.next();
try {
// set some optimization options
@ -108,9 +108,7 @@ public class PortsFetcher extends AbstractFetcher {
socket.setSendBufferSize(16);
socket.setTcpNoDelay(true);
if (socket.isConnected()) {
openPorts.add(port);
}
if (socket.isConnected()) openPorts.add(port);
}
catch (SocketTimeoutException e) {
filteredPorts.add(port);
@ -120,29 +118,18 @@ public class PortsFetcher extends AbstractFetcher {
assert e instanceof ConnectException : e;
}
finally {
try {
socket.close();
}
catch (IOException e) {}
sockets.closeAndUnbind(socket);
}
}
}
return true;
}
/**
* @param subject
* @return
*/
@SuppressWarnings("unchecked")
protected SortedSet<Integer> getFilteredPorts(ScanningSubject subject) {
return (SortedSet<Integer>) subject.getParameter(PARAMETER_FILTERED_PORTS);
}
/**
* @param subject
* @return
*/
@SuppressWarnings("unchecked")
protected SortedSet<Integer> getOpenPorts(ScanningSubject subject) {
return (SortedSet<Integer>) subject.getParameter(PARAMETER_OPEN_PORTS);
@ -169,4 +156,8 @@ public class PortsFetcher extends AbstractFetcher {
this.portIteratorPrototype = new PortIterator(config.portString);
}
@Override
public void cleanup() {
sockets.close();
}
}

View File

@ -1,13 +1,14 @@
package net.azib.ipscan.util;
import java.io.Closeable;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.Socket;
public class IOUtils {
public static void closeQuietly(Socket socket) {
try {
if (socket != null) socket.close();
if (socket != null) try {
socket.close();
}
catch (IOException ignore) {
}
@ -16,4 +17,12 @@ public class IOUtils {
public static void closeQuietly(DatagramSocket socket) {
if (socket != null) socket.close();
}
public static void closeQuietly(Closeable closeable) {
if (closeable != null) try {
closeable.close();
}
catch (IOException ignore) {
}
}
}