package com.it_jaros.networkScanner; import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.LockSupport; public class Scanner { private final Counter counter = new Counter(); private final ProgressBar progressBar = new ProgressBar(); private final Semaphore socketCap; private final int timeoutInMillis; public Scanner(int socketLimit, int timeoutInMillis) { this.timeoutInMillis = timeoutInMillis; socketCap = new Semaphore(socketLimit); } public Scanner() { this(1000, 1000); } public List scanPorts(ScanOptions target) { return scanPorts(target.targets(), target.delayInMillis(), new PortRange(target.ports())); } public List scanPorts(List targets, int delayInMillis, PortRange portsRange) { List results = new ArrayList<>(); long delayInNanos = TimeUnit.MILLISECONDS.toNanos(Math.max(0, delayInMillis)); try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();) { List hosts = new ArrayList<>(); for (String target : targets) { Progress progress = new Progress(target, portsRange.getTotal(), new AtomicInteger(), new AtomicInteger()); hosts.add(progress); results.add(scanTargetAsync(target, portsRange, delayInNanos, executor, progress)); } progressBar.start(hosts); } progressBar.stop(); System.out.println("Peak concurrent connects: " + counter.max()); return results; } private ScanResult scanTargetAsync(String target, PortRange portRange, long delayInNanos, ExecutorService executor, Progress p) { AtomicLong nextStartNanos = new AtomicLong(System.nanoTime()); Queue openPorts = new ConcurrentLinkedQueue<>(); while (portRange.hasNext()) { final int currentPort = portRange.next(); executor.submit(() -> { try { scanPortsAsync(target, delayInNanos, nextStartNanos, openPorts, currentPort); } finally { progressBar.onPortFinished(p); } }); } return new ScanResult(target, openPorts); } private void scanPortsAsync(String target, long delayInNanos, AtomicLong nextStartNanos, Queue openPorts, int currentPort) { if (delayInNanos > 0) { long mySlot = nextStartNanos.getAndAdd(delayInNanos); long wait = mySlot - System.nanoTime(); if (wait > 0) LockSupport.parkNanos(wait); } socketCap.acquireUninterruptibly(); counter.inc(); try (Socket socket = new Socket()) { socket.connect(new InetSocketAddress(target, currentPort), timeoutInMillis); openPorts.add(currentPort); } catch (ConnectException | SocketTimeoutException ignored) { } catch (IOException e) { System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage()); } finally { counter.dec(); socketCap.release(); } } }