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:
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 -> {