commit c7e87c2e43a569e7a4fb72178ac3c5b5c7d13216
parent cedba0f485d95cca854ab1b3b83d020a4aa10181
Author: Matthias Jaros <jaros@mailbox.org>
Date: Thu, 2 Jul 2026 12:45:18 +0200
Changed scanstate to class that now owns completetly the Result List and
does not allow modifications outside of defined methods. -> thread safe
Diffstat:
2 files changed, 42 insertions(+), 10 deletions(-)
diff --git a/src/main/java/com/it_jaros/jscanner/ScanState.java b/src/main/java/com/it_jaros/jscanner/ScanState.java
@@ -1,5 +1,37 @@
package com.it_jaros.jscanner;
+import java.util.ArrayList;
import java.util.List;
-public record ScanState(Counter counter, ProgressBar progressBar, List<ScanResult> scanResult) {}
+public class ScanState {
+ private final Counter counter;
+ private final ProgressBar progressBar;
+ private final List<ScanResult> scanResult;
+
+ public ScanState(Counter counter, ProgressBar progressBar) {
+ this.counter = counter;
+ this.progressBar = progressBar;
+ // scanResult can not be given from outside because this class controls full access to it
+ this.scanResult = new ArrayList<>();
+ }
+
+ public Counter getCounter() {
+ return counter;
+ }
+
+ public ProgressBar getProgressBar() {
+ return progressBar;
+ }
+
+ public void addScanResult(ScanResult newResult) {
+ synchronized (this.scanResult) {
+ this.scanResult.add(newResult);
+ }
+ }
+
+ public List<ScanResult> getSnapshotOfScanResults() {
+ synchronized (scanResult) {
+ return List.copyOf(scanResult);
+ }
+ }
+}
diff --git a/src/main/java/com/it_jaros/jscanner/Scanner.java b/src/main/java/com/it_jaros/jscanner/Scanner.java
@@ -86,8 +86,8 @@ public class Scanner implements AutoCloseable {
}
public List<ScanResult> scanHosts(Stream<String> hosts, String ports) throws IOException {
- ScanState scanState = new ScanState(new Counter(), new ProgressBar(quiet), new ArrayList<>());
- scanState.progressBar().start();
+ ScanState scanState = new ScanState(new Counter(), new ProgressBar(quiet));
+ scanState.getProgressBar().start();
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
CompletionService<ScanResult> completionService = new ExecutorCompletionService<>(executor);
Queue<String> hostsInQueue = hosts.collect(Collectors.toCollection(ArrayDeque::new));
@@ -109,7 +109,7 @@ public class Scanner implements AutoCloseable {
}
activeHostWorkers--;
hostsToProcess--;
- scanState.scanResult().add(finishedHost.get());
+ scanState.addScanResult(finishedHost.get());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
@@ -122,13 +122,13 @@ public class Scanner implements AutoCloseable {
}
}
- scanState.progressBar().stop();
+ scanState.getProgressBar().stop();
System.out.println("--------------------");
System.out.println("Finished scan!");
System.out.println("Stats:");
- System.out.println("Peak concurrent connects: " + scanState.counter().max());
+ System.out.println("Peak concurrent connects: " + scanState.getCounter().max());
System.out.println("--------------------");
- return scanState.scanResult();
+ return scanState.getSnapshotOfScanResults();
}
private ScanResult scanHost(String host, String ports, ScanState scanState) {
@@ -140,7 +140,7 @@ public class Scanner implements AutoCloseable {
// Give progressbar the current progress object which is then updated in the sub virtual threads
Progress progress = new Progress(host, portRange.getTotal(), new AtomicInteger(), new AtomicInteger(), new AtomicInteger());
- scanState.progressBar().submit(progress);
+ scanState.getProgressBar().submit(progress);
if (!disableOnlineCheck && !checkHostOnline(host)) {
// Visually show that this host is basically done
@@ -228,7 +228,7 @@ public class Scanner implements AutoCloseable {
// don't allow more sockets then specified
socketLimit.acquireUninterruptibly();
// count how many ports are concurrently checked
- scanState.counter().inc();
+ scanState.getCounter().inc();
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port), timeoutInMillis);
@@ -244,7 +244,7 @@ public class Scanner implements AutoCloseable {
// NoRouteToHostException: this can be safely ignored because the port is closed if a host is unreachable
// Will happen a lot when scanning for open ports, so not needed
} finally {
- scanState.counter().dec();
+ scanState.getCounter().dec();
socketLimit.release();
}