can't store sockets in fields because Pinger instances are reused between threads - ThreadResourceBinder introduced instead

This commit is contained in:
Anton Keks 2012-12-16 17:16:04 +02:00
parent d6c858137e
commit cafde6229f
3 changed files with 46 additions and 11 deletions

View File

@ -6,6 +6,7 @@
package net.azib.ipscan.core.net;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.util.ThreadResourceBinder;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -15,7 +16,6 @@ import java.net.SocketTimeoutException;
import java.util.logging.Logger;
import static java.util.logging.Level.*;
import static net.azib.ipscan.util.IOUtils.*;
/**
* TCP Pinger. Uses a TCP port to ping, doesn't require root privileges.
@ -28,7 +28,7 @@ public class TCPPinger implements Pinger {
// try different ports in sequence, starting with 80 (which is most probably not filtered)
private static final int[] PROBE_TCP_PORTS = {80, 80, 443, 8080, 22, 7};
private Socket socket;
private ThreadResourceBinder<Socket> sockets = new ThreadResourceBinder<Socket>();
private int timeout;
public TCPPinger(int timeout) {
@ -39,9 +39,10 @@ public class TCPPinger implements Pinger {
public PingResult ping(ScanningSubject subject, int count) throws IOException {
PingResult result = new PingResult(subject.getAddress());
int workingPort = -1;
Socket socket;
for (int i = 0; i < count && !Thread.currentThread().isInterrupted(); i++) {
socket = new Socket();
socket = sockets.bind(new Socket());
long startTime = System.currentTimeMillis();
try {
// cycle through different ports until a working one is found
@ -78,7 +79,7 @@ public class TCPPinger implements Pinger {
}
else
// this should result in NoRouteToHostException or ConnectException, but not all Java implementation respect that
if (msg.contains(/*No*/"route to host") || msg.contains(/*Host is*/"down") || msg.contains(/*Network*/"unreachable")) {
if (msg.contains(/*No*/"route to host") || msg.contains(/*Host is*/"down") || msg.contains(/*Network*/"unreachable") || msg.contains(/*Socket*/"closed")) {
// host is down
break;
}
@ -88,7 +89,7 @@ public class TCPPinger implements Pinger {
}
}
finally {
closeQuietly(socket);
sockets.closeAndUnbind(socket);
}
}
@ -102,6 +103,6 @@ public class TCPPinger implements Pinger {
}
public void close() throws IOException {
closeQuietly(socket);
sockets.close();
}
}

View File

@ -6,13 +6,13 @@
package net.azib.ipscan.core.net;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.util.ThreadResourceBinder;
import java.io.IOException;
import java.net.*;
import java.util.logging.Logger;
import static java.util.logging.Level.*;
import static net.azib.ipscan.util.IOUtils.*;
/**
* UDP Pinger. Uses an UDP port to ping, doesn't require root privileges.
@ -24,8 +24,8 @@ public class UDPPinger implements Pinger {
private static final int PROBE_UDP_PORT = 33381;
private DatagramSocket socket;
private int timeout;
private ThreadResourceBinder<DatagramSocket> sockets = new ThreadResourceBinder<DatagramSocket>();
public UDPPinger(int timeout) {
this.timeout = timeout;
@ -34,7 +34,7 @@ public class UDPPinger implements Pinger {
public PingResult ping(ScanningSubject subject, int count) throws IOException {
PingResult result = new PingResult(subject.getAddress());
socket = new DatagramSocket();
DatagramSocket socket = sockets.bind(new DatagramSocket());
socket.setSoTimeout(timeout);
socket.connect(subject.getAddress(), PROBE_UDP_PORT);
@ -68,6 +68,6 @@ public class UDPPinger implements Pinger {
}
public void close() throws IOException {
closeQuietly(socket);
sockets.close();
}
}

View File

@ -0,0 +1,34 @@
package net.azib.ipscan.util;
import java.io.Closeable;
import java.net.DatagramSocket;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static net.azib.ipscan.util.IOUtils.*;
public class ThreadResourceBinder<T> {
private Map<Long, T> resources = new ConcurrentHashMap<Long, T>(256);
public T bind(T resource) {
resources.put(Thread.currentThread().getId(), resource);
return resource;
}
public void close() {
for (T resource : resources.values()) close(resource);
resources.clear();
}
private void close(T resource) {
if (resource instanceof DatagramSocket) closeQuietly((DatagramSocket) resource);
else if (resource instanceof Socket) closeQuietly((Socket) resource);
else if (resource instanceof Closeable) closeQuietly((Closeable) resource);
}
public void closeAndUnbind(T resource) {
close(resource);
resources.remove(Thread.currentThread().getId());
}
}