From 09035b78a2aa6f8f0702d40288ef44a76ef7a6ac Mon Sep 17 00:00:00 2001 From: Matthias Jaros Date: Fri, 3 Jul 2026 16:38:12 +0200 Subject: Added ability to read from stdin using Streams Replaced useless counters with already existing hasNext() methods --- src/main/java/com/it_jaros/jscanner/Scan.java | 51 +++++++++++++++++------- src/main/java/com/it_jaros/jscanner/Scanner.java | 14 +++---- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/it_jaros/jscanner/Scan.java b/src/main/java/com/it_jaros/jscanner/Scan.java index e9b1c72..75ed349 100644 --- a/src/main/java/com/it_jaros/jscanner/Scan.java +++ b/src/main/java/com/it_jaros/jscanner/Scan.java @@ -1,24 +1,24 @@ package com.it_jaros.jscanner; import java.io.BufferedReader; -import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.List; +import java.util.stream.Stream; /** * Object holder for stateful volatile data during scan */ public class Scan { - private final List hosts; + private final Stream hosts; private final ScanState state; private final String ports; private final Counter counter; private final ProgressBar progressBar; - private Scan(List hosts, String ports, ScanState state, boolean quiet) { + private Scan(Stream hosts, String ports, ScanState state, boolean quiet) { this.hosts = hosts; this.ports = ports; this.state = state; @@ -34,30 +34,50 @@ public class Scan { return counter.max(); } - public static Scan create(ScanOptions options) { + public static Scan create(ScanOptions options) throws IOException { if (options.hostsFile() != null) { return create(options.hostsFile(), options.ports(), options.quiet()); } return create(options.hostsArgv(), options.ports(), options.quiet()); } - public static Scan create(String sourceFile, String ports, boolean quiet) { - try (BufferedReader reader = Files.newBufferedReader(Path.of(sourceFile))) { - return create(reader.lines().toList(), ports, quiet); - } catch (FileNotFoundException | NoSuchFileException e) { - System.out.printf("Could not open file %s%n", sourceFile); - } catch (IOException e) { - System.out.printf("Error while trying to read hosts: %s -> %s %n", e.getClass().getSimpleName(), e.getMessage()); + /** + * Create Scan based on either a source file or stdin + * + * @param sourceFile + * @param ports + * @param quiet + * @return + * @throws IOException + */ + public static Scan create(String sourceFile, String ports, boolean quiet) throws IOException { + Stream hosts; + if ("-".equals(sourceFile)) { + BufferedReader stdinReader = new BufferedReader(new InputStreamReader(System.in)); + hosts = stdinReader.lines(); + } else { + BufferedReader reader = Files.newBufferedReader(Path.of(sourceFile)); + hosts = reader.lines().onClose(() -> { + try { + reader.close(); + } catch (IOException e) { + // ignored + } + }); } - return null; + return create(hosts, ports, quiet); + } + + private static Scan create(Stream lines, String ports, boolean quiet) { + return new Scan(lines, ports, new ScanState(), quiet); } public static Scan create(List hostsArgv, String ports, boolean quiet) { - return new Scan(hostsArgv, ports, new ScanState(), quiet); + return new Scan(hostsArgv.stream(), ports, new ScanState(), quiet); } - public List getHosts() { + public Stream getHosts() { return hosts; } @@ -71,6 +91,7 @@ public class Scan { public void stop() { progressBar.stop(); + hosts.close(); // close stream } public void addHostProgress(Progress progress) { diff --git a/src/main/java/com/it_jaros/jscanner/Scanner.java b/src/main/java/com/it_jaros/jscanner/Scanner.java index 8de423c..66ceb03 100644 --- a/src/main/java/com/it_jaros/jscanner/Scanner.java +++ b/src/main/java/com/it_jaros/jscanner/Scanner.java @@ -61,19 +61,18 @@ public class Scanner implements AutoCloseable { scan.start(); CompletionService completionService = new ExecutorCompletionService<>(executor); - Queue hostsInQueue = new ArrayDeque<>(scan.getHosts()); - int hostsToProcess = hostsInQueue.size(); + Iterator queue = scan.getHosts().iterator(); int activeHostWorkers = 0; - while ((hostsToProcess > 0 && !cancelled) || activeHostWorkers > 0) { + while ((queue.hasNext() && !cancelled) || activeHostWorkers > 0) { while ( - !hostsInQueue.isEmpty() // continue as long as we have hosts to process + queue.hasNext() // continue as long as we have hosts to process && activeHostWorkers < maxHostsLimit // limit is not reached && !cancelled // and scanner not closed ) { // here we are filling the completion service // host <-> virtual thread - final String host = hostsInQueue.poll(); + final String host = queue.next(); activeHostWorkers++; completionService.submit(() -> scanHostPorts(host, scan.getPorts(), scan)); } @@ -85,7 +84,6 @@ public class Scanner implements AutoCloseable { continue; } activeHostWorkers--; - hostsToProcess--; scan.addScanResult(finishedHost.get()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -118,8 +116,7 @@ public class Scanner implements AutoCloseable { List errors = new ArrayList<>(); AtomicLong portSlotFactory = new AtomicLong(System.nanoTime()); int activePerHostWorkers = 0; - int portsToProcess = portRange.getTotal(); - while ((portsToProcess > 0 && !cancelled) || 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 @@ -143,7 +140,6 @@ public class Scanner implements AutoCloseable { PortResult portResult = portResultFuture.get(); activePerHostWorkers--; - portsToProcess--; progress.done().incrementAndGet(); switch (portResult.getState()) { case OPEN -> { -- cgit v1.3.1