summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Matthias Jaros <jarlucmat@mailbox.org>2026-07-04 12:06:49 +0200
committerGravatar Matthias Jaros <jarlucmat@mailbox.org>2026-07-09 09:59:28 +0200
commit9606d80948057438a00892b845188f6ff154427e (patch)
tree337e203fd00f6a95e8ee20902e5afed97e54fbff /src
parent1a806d503c2a4be6b164b758d86e815c593b801a (diff)
Same producer pattern for ports as for hosts
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/it_jaros/jscanner/Scanner.java74
1 files changed, 44 insertions, 30 deletions
diff --git a/src/main/java/com/it_jaros/jscanner/Scanner.java b/src/main/java/com/it_jaros/jscanner/Scanner.java
index 9433841..bfb7ac6 100644
--- a/src/main/java/com/it_jaros/jscanner/Scanner.java
+++ b/src/main/java/com/it_jaros/jscanner/Scanner.java
@@ -138,45 +138,59 @@ public class Scanner implements AutoCloseable {
CompletionService<PortResult> completionService = new ExecutorCompletionService<>(executor);
List<Throwable> errors = new ArrayList<>();
- AtomicLong portSlotFactory = new AtomicLong(System.nanoTime());
- int activePerHostWorkers = 0;
- while ((portRange.hasNext() && !cancelled) || activePerHostWorkers > 0) {
- while (
- portRange.hasNext() // continue as long as we have ports
- && activePerHostWorkers < maxWorkersPerHost // and we have not reached our limit
- && !cancelled // and the scanner is not about to close
- ) {
- // Here we are filling the completion service
- // port <-> virtual thread
- final int currentPort = portRange.next();
- activePerHostWorkers++;
- completionService.submit(() -> {
- waitForSlot(portSlotFactory);
- return checkPort(host, currentPort, scan);
- });
+ final AtomicLong portSlotFactory = new AtomicLong(System.nanoTime());
+ final Semaphore activePerHostWorkers = new Semaphore(maxWorkersPerHost);
+ final AtomicInteger inPipeline = new AtomicInteger(0);
+
+ // producer thread
+ executor.submit(() -> {
+ try {
+ while (portRange.hasNext() && !cancelled) {
+ activePerHostWorkers.acquire();
+ // Here we are filling the completion service
+ // port <-> virtual thread
+ final int currentPort = portRange.next();
+ inPipeline.incrementAndGet();
+ completionService.submit(() -> {
+ waitForSlot(portSlotFactory);
+ return checkPort(host, currentPort, scan);
+ });
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
}
+ });
+ // consumer is the main thread
+ while ((portRange.hasNext() && !cancelled) || inPipeline.get() > 0) {
try {
Future<PortResult> portResultFuture = completionService.poll(10, TimeUnit.MILLISECONDS);
if (portResultFuture == null) {
continue;
}
- PortResult portResult = portResultFuture.get();
- activePerHostWorkers--;
- progress.done().incrementAndGet();
- switch (portResult.getState()) {
- case OPEN -> {
- // bitset is not thread-safe, so it is set
- // outside the other virtual threads that update progress
- openPorts.set(portResult.getPort());
- progress.open().incrementAndGet();
- serviceTypes.put(portResult.getPort(), ServiceDetector.detect(portResult.getBanner()));
- }
- case FILTERED -> {
- filteredPorts.set(portResult.getPort());
- progress.filtered().incrementAndGet();
+ try {
+ PortResult portResult = portResultFuture.get();
+ switch (portResult.getState()) {
+ case OPEN -> {
+ // bitset is not thread-safe, so it is set
+ // outside the other virtual threads that update progress
+ openPorts.set(portResult.getPort());
+ progress.open().incrementAndGet();
+ serviceTypes.put(portResult.getPort(), ServiceDetector.detect(portResult.getBanner()));
+ }
+ case FILTERED -> {
+ filteredPorts.set(portResult.getPort());
+ progress.filtered().incrementAndGet();
+ }
+ default -> {
+ // sonarcube glücklich machen
+ }
}
+ } finally {
+ activePerHostWorkers.release();
+ inPipeline.decrementAndGet();
+ progress.done().incrementAndGet();
}
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();