diff --git a/pom.xml b/pom.xml index 7825112..79b4913 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ scanner-core - 6.2.4-SNAPSHOT + 6.2.3 Scanner Core A generic scanner framework which can execute a set of probes and combine the results into a report. diff --git a/src/main/java/de/rub/nds/scanner/core/execution/ProbeProgressCallback.java b/src/main/java/de/rub/nds/scanner/core/execution/ProbeProgressCallback.java new file mode 100644 index 0000000..ef9f9be --- /dev/null +++ b/src/main/java/de/rub/nds/scanner/core/execution/ProbeProgressCallback.java @@ -0,0 +1,52 @@ +/* + * Scanner Core - A Modular Framework for Probe Definition, Execution, and Result Analysis. + * + * Copyright 2017-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH + * + * Licensed under Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + */ +package de.rub.nds.scanner.core.execution; + +import de.rub.nds.scanner.core.probe.ScannerProbe; +import de.rub.nds.scanner.core.report.ScanReport; + +/** + * Callback interface for receiving probe execution progress updates. This interface allows external + * components to be notified when individual probes complete during a scan, enabling real-time + * progress monitoring and streaming of partial results. + * + * @param the type of scan report + * @param the type of state object used by probes + */ +@FunctionalInterface +public interface ProbeProgressCallback { + + /** + * Called when a probe has completed execution and merged its results into the report. + * + * @param probe the probe that completed execution + * @param report the scan report with the probe's results merged in + * @param completedProbes the number of probes that have completed so far + * @param totalProbes the total number of probes scheduled for this scan + */ + void onProbeCompleted( + ScannerProbe probe, + ReportT report, + int completedProbes, + int totalProbes); + + /** + * Creates a no-op callback that does nothing when probes complete. Useful as a default when no + * progress tracking is needed. + * + * @param the type of scan report + * @param the type of state object + * @return a callback that performs no operations + */ + static ProbeProgressCallback noOp() { + return (probe, report, completedProbes, totalProbes) -> { + // No operation + }; + } +} diff --git a/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java b/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java index 3222639..1aa896c 100644 --- a/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java +++ b/src/main/java/de/rub/nds/scanner/core/execution/Scanner.java @@ -49,6 +49,9 @@ public abstract class Scanner< private final List afterList; private final boolean fillProbeListsAtScanStart; + // Optional callback for probe progress updates + private ProbeProgressCallback progressCallback = ProbeProgressCallback.noOp(); + /** * Creates a new scanner instance. * @@ -131,6 +134,18 @@ protected List getGuidelines() { return List.of(); } + /** + * Sets the progress callback to be invoked when probes complete during scanning. This allows + * external components to receive real-time updates about scan progress and partial results. + * + * @param progressCallback the callback to invoke on probe completion, or null to disable + * callbacks + */ + public void setProgressCallback(ProbeProgressCallback progressCallback) { + this.progressCallback = + progressCallback != null ? progressCallback : ProbeProgressCallback.noOp(); + } + /** * Performs the scan. It will take care of all the necessary steps to perform a scan, including * filling the probe list by calling {@link #fillProbeLists}, checking the scan prerequisites by @@ -166,6 +181,8 @@ public ReportT scan() { scanJob, executorConfig.getParallelProbes(), "ScannerProbeExecutor " + report.getRemoteName())) { + // Set the progress callback on the executor + scanJobExecutor.setProgressCallback(progressCallback); ProgressSpinner.startSpinnerTask("Executing:"); report.setScanStartTime(System.currentTimeMillis()); scanJobExecutor.execute(report); diff --git a/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java b/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java index a27e2fa..17abfc5 100644 --- a/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java +++ b/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java @@ -60,6 +60,9 @@ public class ThreadedScanJobExecutor< private volatile int probeCount; private final AtomicInteger finishedProbes = new AtomicInteger(0); + // Callback for probe progress updates (optional) + private ProbeProgressCallback progressCallback = ProbeProgressCallback.noOp(); + /** * Creates a new ThreadedScanJobExecutor with a custom thread pool. * @@ -103,6 +106,18 @@ public ThreadedScanJobExecutor( this.futureResults = new LinkedList<>(); } + /** + * Sets the progress callback to be invoked when probes complete. This allows external + * components to receive real-time updates about scan progress. + * + * @param progressCallback the callback to invoke on probe completion, or null to disable + * callbacks + */ + public void setProgressCallback(ProbeProgressCallback progressCallback) { + this.progressCallback = + progressCallback != null ? progressCallback : ProbeProgressCallback.noOp(); + } + /** * Executes the scan job by running probes concurrently and populating the report with results. * This method manages probe dependencies and ensures probes are executed in the correct order. @@ -146,7 +161,8 @@ private void executeProbesTillNoneCanBeExecuted(ReportT report) throws Interrupt try { probeResult = result.get(); LOGGER.info( - "[{}/{}] {} probe executed", + "[{}] [{}/{}] {} probe executed", + report.getRemoteName(), String.format("%2d", currentFinishedProbes), String.format("%2d", probeCount), probeResult.getType().getName()); @@ -157,6 +173,14 @@ private void executeProbesTillNoneCanBeExecuted(ReportT report) throws Interrupt finishedFutures.add(result); probeResult.merge(report); report.markProbeAsExecuted(probeResult); + + // Notify progress callback + try { + progressCallback.onProbeCompleted( + probeResult, report, currentFinishedProbes, probeCount); + } catch (Exception e) { + LOGGER.warn("Progress callback threw exception, continuing scan", e); + } } } futureResults.removeAll(finishedFutures);