Skip to content

Commit

Permalink
Merge pull request #173 from osociety/dev
Browse files Browse the repository at this point in the history
Dev -> Main
  • Loading branch information
git-elliot authored Jan 28, 2024
2 parents 3f31f10 + 2453ce2 commit 6e08f17
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 46 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Change Log

## 4.0.3
1. scanPortsForSingleDevice and customDiscover supports async mode now.

## 4.0.2
1. Separated logs for example and library

Expand Down
8 changes: 6 additions & 2 deletions lib/src/host_scanner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ class HostScanner {
final Duration? time = response.time;
if (time != null) {
log.fine("Pingable device found: $host");
tempSendableActivateHost = SendableActiveHost(host, pingData);
tempSendableActivateHost =
SendableActiveHost(host, pingData: pingData);
} else {
log.fine("Non pingable device found: $host");
}
Expand All @@ -126,12 +127,15 @@ class HostScanner {

if (data != null) {
log.fine("Successfully fetched arp entry for $host as $data");
tempSendableActivateHost = SendableActiveHost(host, pingData);
tempSendableActivateHost =
SendableActiveHost(host, pingData: pingData);
} else {
log.fine("Problem in fetching arp entry for $host");
}
}

if (tempSendableActivateHost != null) {
log.fine("Successfully added to result $host");
activeHostsController.add(tempSendableActivateHost);
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/models/active_host.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class ActiveHost {
}
return ActiveHost(
internetAddress: internetAddressTemp,
openPorts: [],
openPorts: sendableActiveHost.openPorts,
pingData: sendableActiveHost.pingData,
mdnsInfoVar: mdnsInfo,
);
Expand Down
11 changes: 9 additions & 2 deletions lib/src/models/sendable_active_host.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import 'package:dart_ping/dart_ping.dart';

import 'package:network_tools/network_tools.dart';

class SendableActiveHost {
SendableActiveHost(this.address, this.pingData);
SendableActiveHost(
this.address, {
this.pingData,
this.openPorts = const [],
});
final String address;
final PingData pingData;
final PingData? pingData;
List<OpenPort> openPorts;
}
136 changes: 123 additions & 13 deletions lib/src/port_scanner.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:isolate';
import 'dart:math';

import 'package:network_tools/src/models/active_host.dart';
import 'package:network_tools/src/models/callbacks.dart';
import 'package:network_tools/src/models/open_port.dart';
import 'package:network_tools/network_tools.dart';
import 'package:universal_io/io.dart';

/// Scans open port for a target Address or domain.
Expand Down Expand Up @@ -73,19 +73,104 @@ class PortScanner {
ProgressCallback? progressCallback,
Duration timeout = const Duration(milliseconds: 2000),
bool resultsInAddressAscendingOrder = true,
bool async = false,
}) async* {
if (async) {
yield* _customDiscover<ActiveHost>(
target,
portList: portList,
progressCallback: progressCallback,
timeout: timeout,
resultsInAddressAscendingOrder: resultsInAddressAscendingOrder,
);
} else {
const int scanRangeForIsolate = 1000;
for (int i = 0; i <= portList.length; i += scanRangeForIsolate + 1) {
final limit = min(i + scanRangeForIsolate, portList.length);
final receivePort = ReceivePort();
final isolate =
await Isolate.spawn(_startSearchingPorts, receivePort.sendPort);

await for (final message in receivePort) {
if (message is SendPort) {
message.send(
<dynamic>[
target,
portList.sublist(i, limit),
timeout,
resultsInAddressAscendingOrder.toString(),
dbDirectory,
enableDebugging.toString(),
],
);
} else if (message is SendableActiveHost) {
progressCallback?.call(i * 100 / (portList.length));
final activeHostFound =
ActiveHost.fromSendableActiveHost(sendableActiveHost: message);
await activeHostFound.resolveInfo();
yield activeHostFound;
} else if (message is String && message == 'Done') {
isolate.kill();
break;
}
}
}
}
}

/// Will search devices in the network inside new isolate
@pragma('vm:entry-point')
static Future<void> _startSearchingPorts(SendPort sendPort) async {
final port = ReceivePort();
sendPort.send(port.sendPort);

await for (final message in port) {
if (message is List<dynamic>) {
final String target = message[0] as String;
final List<int> portList = message[1] as List<int>;
final Duration timeout = message[2] as Duration;
final bool resultsInAddressAscendingOrder = message[3] == "true";
final String dbDirectory = message[4] as String;
final bool enableDebugging = message[5] == "true";
// configure again
await configureNetworkTools(
dbDirectory,
enableDebugging: enableDebugging,
);
final openPortsForTarget = _customDiscover<SendableActiveHost>(
target,
portList: portList,
timeout: timeout,
resultsInAddressAscendingOrder: resultsInAddressAscendingOrder,
);

await for (final SendableActiveHost activeHostFound
in openPortsForTarget) {
sendPort.send(activeHostFound);
}
sendPort.send('Done');
}
}
}

static Stream<T> _customDiscover<T>(
String target, {
List<int> portList = commonPorts,
ProgressCallback? progressCallback,
Duration timeout = const Duration(milliseconds: 2000),
bool resultsInAddressAscendingOrder = true,
}) async* {
final List<InternetAddress> address =
await InternetAddress.lookup(target, type: InternetAddressType.IPv4);
if (address.isNotEmpty) {
final String hostAddress = address[0].address;
final List<Future<ActiveHost?>> openPortList = [];
final StreamController<ActiveHost> activeHostsController =
StreamController<ActiveHost>();
final List<Future<T?>> openPortList = [];
final StreamController<T> activeHostsController = StreamController<T>();

for (int k = 0; k < portList.length; k++) {
if (portList[k] >= 0 && portList[k] <= 65535) {
openPortList.add(
connectToPort(
_connectToPort<T>(
address: hostAddress,
port: portList[k],
timeout: timeout,
Expand All @@ -101,8 +186,8 @@ class PortScanner {

int counter = 0;

for (final Future<ActiveHost?> openPortFuture in openPortList) {
final ActiveHost? openPort = await openPortFuture;
for (final Future<T?> openPortFuture in openPortList) {
final T? openPort = await openPortFuture;
if (openPort == null) {
continue;
}
Expand All @@ -125,6 +210,7 @@ class PortScanner {
ProgressCallback? progressCallback,
Duration timeout = const Duration(milliseconds: 2000),
bool resultsInAddressAscendingOrder = true,
bool async = false,
}) async* {
if (startPort < 0 ||
endPort < 0 ||
Expand All @@ -147,6 +233,7 @@ class PortScanner {
progressCallback: progressCallback,
timeout: timeout,
resultsInAddressAscendingOrder: resultsInAddressAscendingOrder,
async: async,
);
}

Expand All @@ -156,17 +243,40 @@ class PortScanner {
required Duration timeout,
required StreamController<ActiveHost> activeHostsController,
int recursionCount = 0,
}) async {
return _connectToPort<ActiveHost>(
address: address,
port: port,
timeout: timeout,
activeHostsController: activeHostsController,
);
}

static Future<T?> _connectToPort<T>({
required String address,
required int port,
required Duration timeout,
required StreamController<T> activeHostsController,
int recursionCount = 0,
}) async {
try {
final Socket s = await Socket.connect(address, port, timeout: timeout);
s.destroy();

if (T == SendableActiveHost) {
final SendableActiveHost sendableActiveHost = SendableActiveHost(
address,
openPorts: [OpenPort(port)],
);
activeHostsController.add(sendableActiveHost as T);
return sendableActiveHost as T;
}
final ActiveHost activeHost = ActiveHost.buildWithAddress(
address: address,
openPorts: [OpenPort(port)],
);
activeHostsController.add(activeHost);

return activeHost;
activeHostsController.add(activeHost as T);
return activeHost as T;
} catch (e) {
if (e is! SocketException) {
rethrow;
Expand All @@ -187,7 +297,7 @@ class PortScanner {

await Future.delayed(timeout + const Duration(milliseconds: 250));

return connectToPort(
return _connectToPort<T>(
address: address,
port: port,
timeout: timeout,
Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: network_tools
description: Networking Tools library which can help you discover open ports, devices on subnet and many other things.
version: 4.0.2
version: 4.0.3
issue_tracker: https://github.com/osociety/network_tools/issues
repository: https://github.com/osociety/network_tools

Expand Down Expand Up @@ -38,7 +38,7 @@ dependencies:
# A comprehensive, cross-platform path manipulation library for Dart.
path: ^1.8.3
# Process run helpers
process_run: ^0.13.3+1
process_run: ">=0.13.3+1 <0.15.0"
# Yet another NoSQL persistent store database solution for single process io apps.
sembast: ^3.5.0+1
# Cross-platform 'dart:io' that works in all platforms.
Expand Down
Loading

0 comments on commit 6e08f17

Please sign in to comment.