jscanner

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit fbe0a40f421acc7b488c32d0536dfec1702cb071
parent ab71c5ad14512f2a33e1c91f510c4c00c8026ff7
Author: Matthias Jaros <jaros@mailbox.org>
Date:   Fri,  3 Jul 2026 16:38:12 +0200

Added ability to read from stdin using Streams
Replaced useless counters with already existing hasNext() methods

Diffstat:
Msrc/main/java/com/it_jaros/jscanner/Scan.java | 51++++++++++++++++++++++++++++++++++++---------------
Msrc/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 @@ -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<String> hosts; + private final Stream<String> hosts; private final ScanState state; private final String ports; private final Counter counter; private final ProgressBar progressBar; - private Scan(List<String> hosts, String ports, ScanState state, boolean quiet) { + private Scan(Stream<String> 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<String> 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<String> lines, String ports, boolean quiet) { + return new Scan(lines, ports, new ScanState(), quiet); } public static Scan create(List<String> hostsArgv, String ports, boolean quiet) { - return new Scan(hostsArgv, ports, new ScanState(), quiet); + return new Scan(hostsArgv.stream(), ports, new ScanState(), quiet); } - public List<String> getHosts() { + public Stream<String> 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 @@ -61,19 +61,18 @@ public class Scanner implements AutoCloseable { scan.start(); CompletionService<ScanResult> completionService = new ExecutorCompletionService<>(executor); - Queue<String> hostsInQueue = new ArrayDeque<>(scan.getHosts()); - int hostsToProcess = hostsInQueue.size(); + Iterator<String> 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<Throwable> 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 -> {