diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..91f2fbf --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "host scan", + "program": "${workspaceFolder}/example/lib/scan/host_scan.dart", + "request": "launch", + "type": "dart" + }, + { + "name": "mdns scan", + "program": "${workspaceFolder}/example/lib/scan/mdns_scan.dart", + "request": "launch", + "type": "dart" + }, + { + "name": "port scan", + "program": "${workspaceFolder}/example/lib/scan/port_scan.dart", + "request": "launch", + "type": "dart" + }, + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5edb075..1951585 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## 4.0.5 +1. Added hostIds list parameter to restrict scan to only these ids. + ## 4.0.4 1. Bug fix for sync runs when async flag is true diff --git a/analysis_options.yaml b/analysis_options.yaml index 8394ed6..3a07972 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -22,7 +22,6 @@ analyzer: - "**/*.pbjson.dart" - "**/*.gr.dart" - "**/*.md" - - "example/**" linter: rules: diff --git a/example/lib/main.dart b/example/lib/main.dart index dc0756a..5121780 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,5 +1,8 @@ void main() { + // ignore: avoid_print print("Run host scan : 'dart example/lib/scan/host_scan.dart'"); + // ignore: avoid_print print("Run port scan : 'dart example/lib/scan/port_scan.dart'"); + // ignore: avoid_print print("Run mdns scan : 'dart example/lib/scan/mdns_scan.dart'"); } diff --git a/example/lib/scan/host_scan.dart b/example/lib/scan/host_scan.dart index 7d6088d..9d80a90 100644 --- a/example/lib/scan/host_scan.dart +++ b/example/lib/scan/host_scan.dart @@ -1,12 +1,12 @@ -import 'package:logging/logging.dart'; import 'package:network_tools/network_tools.dart'; + import '../example_utils.dart'; Future main() async { enableExampleLogging(); await configureNetworkTools('build'); - String subnet = '192.168.0'; //Default network id for home networks + String subnet = '192.168.1'; //Default network id for home networks final interface = await NetInterface.localInterface(); final netId = interface?.networkId; @@ -20,7 +20,7 @@ Future main() async { // You can set [firstHostId] and scan will start from this host in the network. // Similarly set [lastHostId] and scan will end at this host in the network. - final stream = HostScanner.getAllPingableDevicesAsync( + final stream = HostScannerService.instance.getAllPingableDevicesAsync( subnet, // firstHostId: 1, // lastHostId: 254, @@ -30,7 +30,7 @@ Future main() async { ); stream.listen( - (final host) async { + (host) async { //Same host can be emitted multiple times //Use Set instead of List examplesLog.fine('Found device: ${await host.toStringFull()}'); diff --git a/example/lib/scan/mdns_scan.dart b/example/lib/scan/mdns_scan.dart index 53d5466..5b93e96 100644 --- a/example/lib/scan/mdns_scan.dart +++ b/example/lib/scan/mdns_scan.dart @@ -4,7 +4,8 @@ import '../example_utils.dart'; Future main() async { enableExampleLogging(); await configureNetworkTools('build'); - for (final ActiveHost activeHost in await MdnsScanner.searchMdnsDevices()) { + for (final ActiveHost activeHost + in await MdnsScannerService.instance.searchMdnsDevices()) { final MdnsInfo? mdnsInfo = await activeHost.mdnsInfo; examplesLog.fine( 'Address: ${activeHost.address}, Port: ${mdnsInfo!.mdnsPort}, ServiceType: ${mdnsInfo.mdnsServiceType}, MdnsName: ${mdnsInfo.getOnlyTheStartOfMdnsName()}, Mdns Device Name: ${mdnsInfo.mdnsSrvTarget}\n', diff --git a/example/lib/scan/port_scan.dart b/example/lib/scan/port_scan.dart index 54d494c..faf11db 100644 --- a/example/lib/scan/port_scan.dart +++ b/example/lib/scan/port_scan.dart @@ -1,5 +1,5 @@ -import 'package:logging/logging.dart'; import 'package:network_tools/network_tools.dart'; + import '../example_utils.dart'; Future main() async { @@ -18,7 +18,7 @@ Future main() async { // [New] Scan for a single open port in a subnet // You can set [firstHostId] and scan will start from this host in the network. // Similarly set [lastHostId] and scan will end at this host in the network. - final stream2 = HostScanner.scanDevicesForSinglePort( + final stream2 = HostScannerService.instance.scanDevicesForSinglePort( subnet, 53, progressCallback: (progress) { @@ -27,9 +27,9 @@ Future main() async { ); stream2.listen( - (activeHost) { - examplesLog.fine( - '[scanDevicesForSinglePort]: Found device : ${activeHost.toString()}'); + (ActiveHost activeHost) { + examplesLog + .fine('[scanDevicesForSinglePort]: Found device : $activeHost'); final OpenPort deviceWithOpenPort = activeHost.openPorts[0]; if (deviceWithOpenPort.isOpen) { examplesLog.fine( @@ -49,7 +49,7 @@ Future main() async { examplesLog.fine("Target is $target"); } - PortScanner.scanPortsForSingleDevice( + PortScannerService.instance.scanPortsForSingleDevice( target, // Scan will start from this port. // startPort: 1, @@ -63,7 +63,8 @@ Future main() async { if (deviceWithOpenPort.isOpen) { examplesLog.fine( - 'Found open port: ${deviceWithOpenPort.port} on device $target'); + 'Found open port: ${deviceWithOpenPort.port} on device $target', + ); } }, onDone: () { diff --git a/lib/injectable.dart b/lib/injectable.dart deleted file mode 100644 index 4be767e..0000000 --- a/lib/injectable.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:get_it/get_it.dart'; -import 'package:injectable/injectable.dart'; -import 'package:network_tools/injectable.config.dart'; - -final getIt = GetIt.instance; - -@InjectableInit( - initializerName: 'init', // default - preferRelativeImports: true, // default - asExtension: true, // default -) -void configureDependencies() => getIt.init(); diff --git a/lib/network_tools.dart b/lib/network_tools.dart index 27eb944..9bf7605 100644 --- a/lib/network_tools.dart +++ b/lib/network_tools.dart @@ -1,18 +1,10 @@ /// Network tools base library library network_tools; -import 'package:get_it/get_it.dart'; -import 'package:logging/logging.dart'; -import 'package:network_tools/injectable.dart'; -import 'package:network_tools/src/device_info/vendor_table.dart'; -import 'package:network_tools/src/network_tools_utils.dart'; -import 'package:network_tools/src/services/arp_service.dart'; - +export 'src/configure_dart_native.dart'; export 'src/device_info/net_interface.dart'; export 'src/device_info/vendor_table.dart'; -export 'src/host_scanner.dart'; export 'src/mdns_scanner/list_of_srv_records.dart'; -export 'src/mdns_scanner/mdns_scanner.dart'; export 'src/models/active_host.dart'; export 'src/models/arp_data.dart'; export 'src/models/callbacks.dart'; @@ -20,35 +12,10 @@ export 'src/models/mdns_info.dart'; export 'src/models/open_port.dart'; export 'src/models/sendable_active_host.dart'; export 'src/models/vendor.dart'; -export 'src/port_scanner.dart'; - -final _getIt = GetIt.instance; -late bool _enableDebugging; - -late String _dbDirectory; +export 'src/services/host_scanner_service.dart'; +export 'src/services/mdns_scanner_service.dart'; +export 'src/services/port_scanner_service.dart'; -String get dbDirectory => _dbDirectory; -bool get enableDebugging => _enableDebugging; +late bool enableDebugging; -Future configureNetworkTools( - String dbDirectory, { - bool enableDebugging = false, -}) async { - _enableDebugging = enableDebugging; - _dbDirectory = dbDirectory; - if (enableDebugging) { - Logger.root.level = Level.FINE; - Logger.root.onRecord.listen((record) { - if (record.loggerName == log.name) { - // ignore: avoid_print - print( - '${record.time.toLocal()}: ${record.level.name}: ${record.loggerName}: ${record.message}', - ); - } - }); - } - configureDependencies(); - final arpService = await _getIt().open(); - await arpService.buildTable(); - await VendorTable.createVendorTableMap(); -} +late String dbDirectory; diff --git a/lib/src/configure_dart_native.dart b/lib/src/configure_dart_native.dart new file mode 100644 index 0000000..12e61d6 --- /dev/null +++ b/lib/src/configure_dart_native.dart @@ -0,0 +1,38 @@ +import 'package:logging/logging.dart'; +import 'package:network_tools/network_tools.dart' as pacakges_page; +import 'package:network_tools/src/network_tools_utils.dart'; +import 'package:network_tools/src/services/arp_service.dart'; +import 'package:network_tools/src/services/impls/arp_service_sembast_impl.dart'; +import 'package:network_tools/src/services/impls/host_scanner_service_impl.dart'; +import 'package:network_tools/src/services/impls/mdns_scanner_service_impl.dart'; +import 'package:network_tools/src/services/impls/port_scanner_service_impl.dart'; + +Future configureNetworkTools( + String dbDirectory, { + bool enableDebugging = false, +}) async { + pacakges_page.enableDebugging = enableDebugging; + pacakges_page.dbDirectory = dbDirectory; + + if (pacakges_page.enableDebugging) { + Logger.root.level = Level.FINE; + Logger.root.onRecord.listen((record) { + if (record.loggerName == log.name) { + // ignore: avoid_print + print( + '${record.time.toLocal()}: ${record.level.name}: ${record.loggerName}: ${record.message}', + ); + } + }); + } + + /// Setting dart native classes implementations + ARPServiceSembastImpl(); + HostScannerServiceImpl(); + PortScannerServiceImpl(); + MdnsScannerServiceImpl(); + + final arpService = await ARPService.instance.open(); + await arpService.buildTable(); + await pacakges_page.VendorTable.createVendorTableMap(); +} diff --git a/lib/src/device_info/vendor_table.dart b/lib/src/device_info/vendor_table.dart index e908e54..3cffff5 100644 --- a/lib/src/device_info/vendor_table.dart +++ b/lib/src/device_info/vendor_table.dart @@ -16,8 +16,11 @@ class VendorTable { if (arpData.notNullMacAddress) { await createVendorTableMap(); final pattern = arpData.macAddress.contains(':') ? ':' : '-'; - return _vendorTableMap[ - arpData.macAddress.split(pattern).sublist(0, 3).join()] as Vendor?; + return _vendorTableMap[arpData.macAddress + .split(pattern) + .sublist(0, 3) + .join() + .toUpperCase()] as Vendor?; } } return null; diff --git a/lib/src/mdns_scanner/list_of_srv_records.dart b/lib/src/mdns_scanner/list_of_srv_records.dart index 51a3eb1..4cf194c 100644 --- a/lib/src/mdns_scanner/list_of_srv_records.dart +++ b/lib/src/mdns_scanner/list_of_srv_records.dart @@ -1,35 +1,46 @@ /// Service record list that is including the protocol, mostly _tcp, _udp may /// not work List tcpSrvRecordsList = [ + '_autodiscover._tcp', + '_http._tcp', // "domain": "bosch_shc", "name": "bosch shc*" + '_http-alt._tcp', + '_googlecast._tcp', // Is there a ChromeCast-capable device in this network "domain": "cast" + '_androidtvremote2._tcp', + '_smartview._tcp', // Samsung tv's + '_spotify-connect._tcp', // "domain": "spotify" + '_nanoleafapi._tcp', // "domain": "nanoleaf" + '_nanoleafms._tcp', // "domain": "nanoleaf" + '_esphomelib._tcp', // [ { "domain": "esphome" }, { "domain": "zha", "name": "tube*" } ] + '_ewelink._tcp', // Ewelink devices + '_hue._tcp', // "domain": "hue" + '_mqtt._tcp', + '_hap._tcp', // [ { "domain": "homekit_controller" }, { "domain": "zwave_me", "name": "*z.wave-me*" } ] + '_homekit._tcp', // "domain": "homekit" + '_hscp._tcp', // "domain": "apple_tv" + '_appletv-v2._tcp', // "domain": "apple_tv" + '_airplay._tcp', // Any Apple AirPlay-capable video displays here_ipps // [ { "domain": "apple_tv", "properties": { "model": "appletv*" } }, { "domain": "apple_tv", "properties": { "model": "audioaccessory*" } }, { "domain": "apple_tv", "properties": { "am": "airport*" } }, { "domain": "samsungtv", "properties": { "manufacturer": "samsung*" } } ] + '_raop._tcp', // Any Apple AirPlay-capable audio devices [ { "domain": "apple_tv", "properties": { "am": "appletv*" } }, { "domain": "apple_tv", "properties": { "am": "audioaccessory*" } }, { "domain": "apple_tv", "properties": { "am": "airport*" } } ], + '_airport._tcp', // Any Apple AirPort WiFi APs // "domain": "apple_tv" + '_touch-able._tcp', // "domain": "apple_tv" + '_mediaremotetv._tcp', // "domain": "apple_tv" '_uscan._tcp', // Any HP-compatible network scanners '_uscans._tcp', // Any SSL/TLS-capable HP-compatible network scanners '_privet._tcp', // Any Google CloudPrint-capable printers or print services - '_http-alt._tcp', '_scanner._tcp', // Are there any Bonjour-capable scanners - '_home-assistant._tcp', '_pdl-datastream._tcp', // Any HP JetDirect-style network printers '_ipp._tcp', // Are there any printers using the IPP protocol // "domain": "ipp" '_ipps._tcp', // Any SSL/TLS capable IPP printers // "domain": "ipp" - '_http._tcp', // "domain": "bosch_shc", "name": "bosch shc*" - '_ldap._tcp', - '_gc._tcp', - '_kerberos._tcp', - '_kpasswd._tcp', - '_airplay._tcp', // Any Apple AirPlay-capable video displays here_ipps // [ { "domain": "apple_tv", "properties": { "model": "appletv*" } }, { "domain": "apple_tv", "properties": { "model": "audioaccessory*" } }, { "domain": "apple_tv", "properties": { "am": "airport*" } }, { "domain": "samsungtv", "properties": { "manufacturer": "samsung*" } } ] - '_raop._tcp', // Any Apple AirPlay-capable audio devices [ { "domain": "apple_tv", "properties": { "am": "appletv*" } }, { "domain": "apple_tv", "properties": { "am": "audioaccessory*" } }, { "domain": "apple_tv", "properties": { "am": "airport*" } } ], '_ippusb._tcp', // Are there any shared printers that are using the IPP-over-USB protocol, i.e. USB-connected printers shared by a Mac '_printer._tcp', // Any kinds of shared printers at all "domain": "brother", "name": "brother*" '_ptp._tcp', // Any devices supporting the Picture Transfer Protocol over this network - '_googlecast._tcp', // Is there a ChromeCast-capable device in this network "domain": "cast" - '_airport._tcp', // Any Apple AirPort WiFi APs // "domain": "apple_tv" - '_esphomelib._tcp', // [ { "domain": "esphome" }, { "domain": "zha", "name": "tube*" } ] - '_mqtt._tcp', - '_autodiscover._tcp', + '_kpasswd._tcp', + '_ldap._tcp', + '_gc._tcp', + '_kerberos._tcp', '_sip._tcp', '_minecraft._tcp', '_Volumio._tcp', // "domain": "volumio" '_api._tcp', // [ { "domain": "baf", "properties": { "model": "haiku*" } }, { "domain": "baf", "properties": { "model": "i6*" } } ] - '_appletv-v2._tcp', // "domain": "apple_tv" '_axis-video._tcp', // [ { "domain": "axis", "properties": { "macaddress": "00408c*" } }, { "domain": "axis", "properties": { "macaddress": "accc8e*" } }, { "domain": "axis", "properties": { "macaddress": "b8a44f*" } }, { "domain": "doorbird", "properties": { "macaddress": "1ccae3*"} } ], '_bond._tcp', // "domain": "bond" '_companion-link._tcp', // "domain": "apple_tv" @@ -40,17 +51,10 @@ List tcpSrvRecordsList = [ '_elg._tcp', // "domain": "elgato" '_enphase-envoy._tcp', // "domain": "enphase_envoy" '_fbx-api._tcp', // "domain": "freebox" - '_hap._tcp', // [ { "domain": "homekit_controller" }, { "domain": "zwave_me", "name": "*z.wave-me*" } ] - '_homekit._tcp', // "domain": "homekit" - '_hscp._tcp', // "domain": "apple_tv" - '_hue._tcp', // "domain": "hue" '_hwenergy._tcp', // "domain": "homewizard", '_kizbox._tcp', // "domain": "overkiz", "name": "gateway*" '_leap._tcp', // "domain": "lutron_caseta" '_lookin._tcp', // "domain": "lookin" - '_mediaremotetv._tcp', // "domain": "apple_tv" - '_nanoleafapi._tcp', // "domain": "nanoleaf" - '_nanoleafms._tcp', // "domain": "nanoleaf" '_nut._tcp', // "domain": "nut" '_octoprint._tcp', // "domain": "octoprint" '_plexmediasvr._tcp', // "domain": "plex" @@ -59,20 +63,16 @@ List tcpSrvRecordsList = [ '_sideplay._tcp', // { "domain": "ecobee", "properties": { "mdl": "eb-*" } }, { "domain": "ecobee", "properties": { "mdl": "ecobee*" } } '_sonos._tcp', // "domain": "sonos" '_soundtouch._tcp', // "domain": "soundtouch" - '_spotify-connect', // "domain": "spotify" '_ssh._tcp', // { "domain": "smappee", "name": "smappee1*" }, { "domain": "smappee", "name": "smappee2*" }, { "domain": "smappee", "name": "smappee50*" } '_system-bridge._tcp', // "domain": "system_bridge" - '_touch-able._tcp', // "domain": "apple_tv" '_viziocast._tcp', // "domain": "vizio" '_wled._tcp', // "domain": "wled" '_xbmc-jsonrpc-h._tcp', // "domain": "kodi" + '_home-assistant._tcp', '_zigate-zigbee-gateway._tcp', // "domain": "zha", "name": "*zigate*" '_zwave-js-server._tcp', // "domain": "zwave_js" '_axis-video._tcp', // "properties": { "macaddress": "00408c*" } "properties": { "macaddress": "accc8e*" } "properties": { "macaddress": "b8a44f*" } - '_androidtvremote2._tcp', - '_ewelink._tcp', // Ewelink devices '_nvstream_dbd._tcp', - '_smartview._tcp', // Samsung tv's ]; List udpSrvRecordsList = [ @@ -81,4 +81,5 @@ List udpSrvRecordsList = [ '_miio._udp', // [ { "domain": "xiaomi_aqara" }, { "domain": "xiaomi_miio" }, { "domain": "yeelight", "name": "yeelink-*" } ] '_sleep-proxy._udp', // "domain": "apple_tv" '_system-bridge._udp', + '_kdeconnect._udp', ]; diff --git a/lib/src/models/active_host.dart b/lib/src/models/active_host.dart index e3a1a02..30fd92c 100644 --- a/lib/src/models/active_host.dart +++ b/lib/src/models/active_host.dart @@ -1,12 +1,9 @@ import 'package:dart_ping/dart_ping.dart'; -import 'package:get_it/get_it.dart'; import 'package:network_tools/network_tools.dart'; import 'package:network_tools/src/network_tools_utils.dart'; import 'package:network_tools/src/services/arp_service.dart'; import 'package:universal_io/io.dart'; -final _getIt = GetIt.instance; - /// ActiveHost which implements comparable /// By default sort by hostId ascending class ActiveHost { @@ -91,7 +88,6 @@ class ActiveHost { } static const generic = 'Generic Device'; - static final arpService = _getIt(); InternetAddress internetAddress; @@ -183,8 +179,8 @@ class ActiveHost { } Future setARPData() async { - await arpService.open(); - return arpService.entryFor(address); + await ARPService.instance.open(); + return ARPService.instance.entryFor(address); } Future setVendor() async { diff --git a/lib/src/models/mdns_info.dart b/lib/src/models/mdns_info.dart index 5ca5946..f2b65f6 100644 --- a/lib/src/models/mdns_info.dart +++ b/lib/src/models/mdns_info.dart @@ -35,6 +35,9 @@ class MdnsInfo { /// mDNS name without the ._tcp.local String getOnlyTheStartOfMdnsName() { - return mdnsName.substring(0, mdnsName.indexOf('.')); + if (mdnsName.contains('.')) { + return mdnsName.substring(0, mdnsName.indexOf('.')); + } + return mdnsName; } } diff --git a/lib/src/services/arp_service.dart b/lib/src/services/arp_service.dart index 911c8be..de29cdd 100644 --- a/lib/src/services/arp_service.dart +++ b/lib/src/services/arp_service.dart @@ -1,6 +1,14 @@ import 'package:network_tools/src/models/arp_data.dart'; abstract class ARPService { + ARPService() { + _instance = this; + } + + static late ARPService _instance; + + static ARPService get instance => _instance; + Future open(); Future?> entries(); Future entryFor(String address); diff --git a/lib/src/services/host_scanner_service.dart b/lib/src/services/host_scanner_service.dart new file mode 100644 index 0000000..ff023ba --- /dev/null +++ b/lib/src/services/host_scanner_service.dart @@ -0,0 +1,66 @@ +import 'package:network_tools/src/models/active_host.dart'; +import 'package:network_tools/src/models/callbacks.dart'; +import 'package:network_tools/src/models/sendable_active_host.dart'; + +/// Scans for all hosts in a subnet. +abstract class HostScannerService { + HostScannerService() { + _instance = this; + } + + static late HostScannerService _instance; + + static HostScannerService get instance => _instance; + + /// Devices scan will start from this integer Id + static const int defaultFirstHostId = 1; + + /// Devices scan will stop at this integer id + static const int defaultLastHostId = 254; + + Stream getAllPingableDevices( + String subnet, { + int firstHostId = defaultFirstHostId, + int lastHostId = defaultLastHostId, + List hostIds = const [], + int timeoutInSeconds = 1, + ProgressCallback? progressCallback, + bool resultsInAddressAscendingOrder = true, + }); + + Stream getAllSendablePingableDevices( + String subnet, { + int firstHostId = defaultFirstHostId, + int lastHostId = defaultLastHostId, + List hostIds = const [], + int timeoutInSeconds = 1, + ProgressCallback? progressCallback, + bool resultsInAddressAscendingOrder = true, + }); + + int validateAndGetLastValidSubnet( + String subnet, + int firstHostId, + int lastHostId, + ); + + Stream getAllPingableDevicesAsync( + String subnet, { + int firstHostId = defaultFirstHostId, + int lastHostId = defaultLastHostId, + List hostIds = const [], + int timeoutInSeconds = 1, + ProgressCallback? progressCallback, + bool resultsInAddressAscendingOrder = true, + }); + + Stream scanDevicesForSinglePort( + String subnet, + int port, { + int firstHostId = defaultFirstHostId, + int lastHostId = defaultLastHostId, + Duration timeout = const Duration(milliseconds: 2000), + ProgressCallback? progressCallback, + bool resultsInAddressAscendingOrder = true, + }); +} diff --git a/lib/src/services/impls/arp_service_sembast_impl.dart b/lib/src/services/impls/arp_service_sembast_impl.dart index 2e7ef1a..59656b6 100644 --- a/lib/src/services/impls/arp_service_sembast_impl.dart +++ b/lib/src/services/impls/arp_service_sembast_impl.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:injectable/injectable.dart'; import 'package:network_tools/network_tools.dart'; import 'package:network_tools/src/device_info/arp_table_helper.dart'; import 'package:network_tools/src/services/arp_service.dart'; @@ -8,10 +7,9 @@ import 'package:path/path.dart' as p; import 'package:sembast/sembast.dart'; import 'package:sembast/sembast_io.dart'; -@Injectable(as: ARPService) class ARPServiceSembastImpl extends ARPService { - static Database? _db; - static final _store = stringMapStoreFactory.store('arpstore'); + Database? _db; + final _store = stringMapStoreFactory.store('arpstore'); @override Future buildTable() async { diff --git a/lib/src/host_scanner.dart b/lib/src/services/impls/host_scanner_service_impl.dart similarity index 80% rename from lib/src/host_scanner.dart rename to lib/src/services/impls/host_scanner_service_impl.dart index 490bf0f..12d04fa 100644 --- a/lib/src/host_scanner.dart +++ b/lib/src/services/impls/host_scanner_service_impl.dart @@ -3,33 +3,27 @@ import 'dart:isolate'; import 'dart:math'; import 'package:dart_ping/dart_ping.dart'; -import 'package:get_it/get_it.dart'; import 'package:network_tools/network_tools.dart'; import 'package:network_tools/src/network_tools_utils.dart'; import 'package:network_tools/src/services/arp_service.dart'; -final _getIt = GetIt.instance; - /// Scans for all hosts in a subnet. -class HostScanner { - static final arpServiceFuture = _getIt().open(); - - /// Devices scan will start from this integer Id - static const int defaultFirstHostId = 1; - - /// Devices scan will stop at this integer id - static const int defaultLastHostId = 254; +class HostScannerServiceImpl extends HostScannerService { + final arpServiceFuture = ARPService.instance.open(); /// Scans for all hosts in a particular subnet (e.g., 192.168.1.0/24) /// Set maxHost to higher value if you are not getting results. /// It won't firstHostId again unless previous scan is completed due to heavy /// resource consumption. + /// Use hostIds to limit subnet scan to hosts given. /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream getAllPingableDevices( + @override + Stream getAllPingableDevices( String subnet, { - int firstHostId = defaultFirstHostId, - int lastHostId = defaultLastHostId, + int firstHostId = HostScannerService.defaultFirstHostId, + int lastHostId = HostScannerService.defaultLastHostId, + List hostIds = const [], int timeoutInSeconds = 1, ProgressCallback? progressCallback, bool resultsInAddressAscendingOrder = true, @@ -38,6 +32,7 @@ class HostScanner { subnet, firstHostId: firstHostId, lastHostId: lastHostId, + hostIds: hostIds, timeoutInSeconds: timeoutInSeconds, progressCallback: progressCallback, resultsInAddressAscendingOrder: resultsInAddressAscendingOrder, @@ -54,10 +49,12 @@ class HostScanner { } /// Same as [getAllPingableDevices] but can be called or run inside isolate. - static Stream getAllSendablePingableDevices( + @override + Stream getAllSendablePingableDevices( String subnet, { - int firstHostId = defaultFirstHostId, - int lastHostId = defaultLastHostId, + int firstHostId = HostScannerService.defaultFirstHostId, + int lastHostId = HostScannerService.defaultLastHostId, + List hostIds = const [], int timeoutInSeconds = 1, ProgressCallback? progressCallback, bool resultsInAddressAscendingOrder = true, @@ -68,14 +65,18 @@ class HostScanner { final StreamController activeHostsController = StreamController(); + final List pinged = []; for (int i = firstHostId; i <= lastValidSubnet; i++) { - activeHostsFuture.add( - _getHostFromPing( - activeHostsController: activeHostsController, - host: '$subnet.$i', - timeoutInSeconds: timeoutInSeconds, - ), - ); + if (hostIds.isEmpty || hostIds.contains(i)) { + pinged.add(i); + activeHostsFuture.add( + getHostFromPing( + activeHostsController: activeHostsController, + host: '$subnet.$i', + timeoutInSeconds: timeoutInSeconds, + ), + ); + } } if (!resultsInAddressAscendingOrder) { @@ -87,8 +88,9 @@ class HostScanner { i++; final SendableActiveHost? tempHost = await host; - progressCallback - ?.call((i - firstHostId) * 100 / (lastValidSubnet - firstHostId)); + progressCallback?.call( + (pinged[i] - firstHostId) * 100 / (lastValidSubnet - firstHostId), + ); if (tempHost == null) { continue; @@ -97,7 +99,7 @@ class HostScanner { } } - static Future _getHostFromPing({ + Future getHostFromPing({ required String host, required StreamController activeHostsController, int timeoutInSeconds = 1, @@ -143,15 +145,16 @@ class HostScanner { return tempSendableActivateHost; } - static int validateAndGetLastValidSubnet( + @override + int validateAndGetLastValidSubnet( String subnet, int firstHostId, int lastHostId, ) { final int maxEnd = maxHost; if (firstHostId > lastHostId || - firstHostId < defaultFirstHostId || - lastHostId < defaultFirstHostId || + firstHostId < HostScannerService.defaultFirstHostId || + lastHostId < HostScannerService.defaultFirstHostId || firstHostId > maxEnd || lastHostId > maxEnd) { throw 'Invalid subnet range or firstHostId < lastHostId is not true'; @@ -161,10 +164,12 @@ class HostScanner { /// Works same as [getAllPingableDevices] but does everything inside /// isolate out of the box. - static Stream getAllPingableDevicesAsync( + @override + Stream getAllPingableDevicesAsync( String subnet, { - int firstHostId = defaultFirstHostId, - int lastHostId = defaultLastHostId, + int firstHostId = HostScannerService.defaultFirstHostId, + int lastHostId = HostScannerService.defaultLastHostId, + List hostIds = const [], int timeoutInSeconds = 1, ProgressCallback? progressCallback, bool resultsInAddressAscendingOrder = true, @@ -193,15 +198,16 @@ class HostScanner { resultsInAddressAscendingOrder.toString(), dbDirectory, enableDebugging.toString(), + hostIds.join(','), ], ); } else if (message is SendableActiveHost) { - progressCallback - ?.call((i - firstHostId) * 100 / (lastValidSubnet - firstHostId)); - // print('Address ${message.address}'); final activeHostFound = ActiveHost.fromSendableActiveHost(sendableActiveHost: message); await activeHostFound.resolveInfo(); + final j = int.tryParse(activeHostFound.hostId) ?? i; + progressCallback + ?.call((j - firstHostId) * 100 / (lastValidSubnet - firstHostId)); yield activeHostFound; } else if (message is String && message == 'Done') { isolate.kill(); @@ -226,6 +232,11 @@ class HostScanner { final bool resultsInAddressAscendingOrder = message[4] == "true"; final String dbDirectory = message[5]; final bool enableDebugging = message[6] == "true"; + final List hostIds = message[7] + .split(',') + .where((e) => e.isNotEmpty) + .map(int.parse) + .toList(); // configure again await configureNetworkTools( dbDirectory, @@ -235,10 +246,11 @@ class HostScanner { /// Will contain all the hosts that got discovered in the network, will /// be use inorder to cancel on dispose of the page. final Stream hostsDiscoveredInNetwork = - HostScanner.getAllSendablePingableDevices( + HostScannerService.instance.getAllSendablePingableDevices( subnetIsolate, firstHostId: firstSubnetIsolate, lastHostId: lastSubnetIsolate, + hostIds: hostIds, timeoutInSeconds: timeoutInSeconds, resultsInAddressAscendingOrder: resultsInAddressAscendingOrder, ); @@ -255,11 +267,12 @@ class HostScanner { /// Scans for all hosts that have the specific port that was given. /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream scanDevicesForSinglePort( + @override + Stream scanDevicesForSinglePort( String subnet, int port, { - int firstHostId = defaultFirstHostId, - int lastHostId = defaultLastHostId, + int firstHostId = HostScannerService.defaultFirstHostId, + int lastHostId = HostScannerService.defaultLastHostId, Duration timeout = const Duration(milliseconds: 2000), ProgressCallback? progressCallback, bool resultsInAddressAscendingOrder = true, @@ -273,7 +286,7 @@ class HostScanner { for (int i = firstHostId; i <= lastValidSubnet; i++) { final host = '$subnet.$i'; activeHostOpenPortList.add( - PortScanner.connectToPort( + PortScannerService.instance.connectToPort( address: host, port: port, timeout: timeout, @@ -301,25 +314,25 @@ class HostScanner { } /// Defines total number of subnets in class A network - static const classASubnets = 16777216; + final classASubnets = 16777216; /// Defines total number of subnets in class B network - static const classBSubnets = 65536; + final classBSubnets = 65536; /// Defines total number of subnets in class C network - static const classCSubnets = 256; + final classCSubnets = 256; /// Minimum value of first octet in IPv4 address used by getMaxHost - static const int minNetworkId = 1; + final int minNetworkId = 1; /// Maximum value of first octect in IPv4 address used by getMaxHost - static const int maxNetworkId = 223; + final int maxNetworkId = 223; /// returns the max number of hosts a subnet can have excluding network Id and broadcast Id @Deprecated( "Implementation is wrong, since we only append in last octet, max host can only be 254. Use maxHost getter", ) - static int getMaxHost(String subnet) { + int getMaxHost(String subnet) { if (subnet.isEmpty) { throw ArgumentError('Invalid subnet address, address can not be empty.'); } @@ -349,5 +362,5 @@ class HostScanner { ); } - static int get maxHost => defaultLastHostId; + int get maxHost => HostScannerService.defaultLastHostId; } diff --git a/lib/src/mdns_scanner/mdns_scanner.dart b/lib/src/services/impls/mdns_scanner_service_impl.dart similarity index 90% rename from lib/src/mdns_scanner/mdns_scanner.dart rename to lib/src/services/impls/mdns_scanner_service_impl.dart index 1bc4eba..43ef5bc 100644 --- a/lib/src/mdns_scanner/mdns_scanner.dart +++ b/lib/src/services/impls/mdns_scanner_service_impl.dart @@ -4,7 +4,7 @@ import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list.dart' import 'package:network_tools/src/network_tools_utils.dart'; import 'package:universal_io/io.dart'; -class MdnsScanner { +class MdnsScannerServiceImpl extends MdnsScannerService { /// This method searching for all the mdns devices in the network. /// TODO: The implementation is **Lacking!** and will not find all the /// TODO: results that actual exist in the network!, only some of them. @@ -13,7 +13,8 @@ class MdnsScanner { /// TODO: In some cases we resolve this missing functionality using /// TODO: specific os tools. - static Future> searchMdnsDevices({ + @override + Future> searchMdnsDevices({ bool forceUseOfSavedSrvRecordList = false, }) async { List srvRecordListToSearchIn; @@ -47,7 +48,8 @@ class MdnsScanner { return activeHostList; } - static Future> findingMdnsWithAddress( + @override + Future> findingMdnsWithAddress( String serviceType, ) async { final MDnsClient client = MDnsClient( @@ -79,7 +81,7 @@ class MdnsScanner { )) { listOfActiveHost.addAll( await findAllActiveHostForSrv( - addressType: AddressType.ipv4, + addressType: InternetAddress.anyIPv4, client: client, ptr: ptr, srv: srv, @@ -87,7 +89,7 @@ class MdnsScanner { ); listOfActiveHost.addAll( await findAllActiveHostForSrv( - addressType: AddressType.ipv6, + addressType: InternetAddress.anyIPv6, client: client, ptr: ptr, srv: srv, @@ -100,8 +102,9 @@ class MdnsScanner { return listOfActiveHost; } - static Future> findAllActiveHostForSrv({ - required AddressType addressType, + @override + Future> findAllActiveHostForSrv({ + required InternetAddress addressType, required MDnsClient client, required PtrResourceRecord ptr, required SrvResourceRecord srv, @@ -110,7 +113,7 @@ class MdnsScanner { try { Stream iPAddressResourceRecordStream; - if (addressType == AddressType.ipv4) { + if (addressType == InternetAddress.anyIPv4) { iPAddressResourceRecordStream = client.lookup( ResourceRecordQuery.addressIPv4(srv.target), ); @@ -143,7 +146,8 @@ class MdnsScanner { return listOfActiveHost; } - static ActiveHost convertSrvToHostName({ + @override + ActiveHost convertSrvToHostName({ required InternetAddress internetAddress, required PtrResourceRecord ptr, required SrvResourceRecord srv, @@ -158,5 +162,3 @@ class MdnsScanner { ); } } - -enum AddressType { ipv4, ipv6 } diff --git a/lib/src/port_scanner.dart b/lib/src/services/impls/port_scanner_service_impl.dart similarity index 90% rename from lib/src/port_scanner.dart rename to lib/src/services/impls/port_scanner_service_impl.dart index de7a466..b80d504 100644 --- a/lib/src/port_scanner.dart +++ b/lib/src/services/impls/port_scanner_service_impl.dart @@ -6,39 +6,10 @@ import 'package:network_tools/network_tools.dart'; import 'package:universal_io/io.dart'; /// Scans open port for a target Address or domain. -class PortScanner { - static const int defaultStartPort = 1; - static const int defaultEndPort = 1024; - static const List commonPorts = [ - 20, - 21, - 22, - 23, - 25, - 50, - 51, - 53, - 67, - 68, - 69, - 80, - 110, - 119, - 123, - 135, - 139, - 143, - 161, - 162, - 389, - 443, - 989, - 990, - 3389, - ]; - +class PortScannerServiceImpl extends PortScannerService { /// Checks if the single [port] is open or not for the [target]. - static Future isOpen( + @override + Future isOpen( String target, int port, { Duration timeout = const Duration(milliseconds: 2000), @@ -67,9 +38,10 @@ class PortScanner { /// Tries connecting ports before until [timeout] reached. /// [resultsInAddressAscendingOrder] = false will return results faster but not in /// ascending order and without [progressCallback]. - static Stream customDiscover( + @override + Stream customDiscover( String target, { - List portList = commonPorts, + List portList = PortScannerService.commonPorts, ProgressCallback? progressCallback, Duration timeout = const Duration(milliseconds: 2000), bool resultsInAddressAscendingOrder = true, @@ -121,7 +93,7 @@ class PortScanner { /// Will search devices in the network inside new isolate @pragma('vm:entry-point') - static Future _startSearchingPorts(SendPort sendPort) async { + Future _startSearchingPorts(SendPort sendPort) async { final port = ReceivePort(); sendPort.send(port.sendPort); @@ -154,9 +126,9 @@ class PortScanner { } } - static Stream _customDiscover( + Stream _customDiscover( String target, { - List portList = commonPorts, + List portList = PortScannerService.commonPorts, ProgressCallback? progressCallback, Duration timeout = const Duration(milliseconds: 2000), bool resultsInAddressAscendingOrder = true, @@ -204,10 +176,11 @@ class PortScanner { /// Scans port from [startPort] to [endPort] of [target]. Progress can be /// retrieved by [progressCallback] /// Tries connecting ports before until [timeout] reached. - static Stream scanPortsForSingleDevice( + @override + Stream scanPortsForSingleDevice( String target, { - int startPort = defaultStartPort, - int endPort = defaultEndPort, + int startPort = PortScannerService.defaultStartPort, + int endPort = PortScannerService.defaultEndPort, ProgressCallback? progressCallback, Duration timeout = const Duration(milliseconds: 2000), bool resultsInAddressAscendingOrder = true, @@ -238,7 +211,8 @@ class PortScanner { ); } - static Future connectToPort({ + @override + Future connectToPort({ required String address, required int port, required Duration timeout, @@ -253,7 +227,7 @@ class PortScanner { ); } - static Future _connectToPort({ + Future _connectToPort({ required String address, required int port, required Duration timeout, @@ -311,5 +285,5 @@ class PortScanner { } } - static final _errorCodes = [13, 49, 61, 64, 65, 101, 111, 113]; + final _errorCodes = [13, 49, 61, 64, 65, 101, 111, 113]; } diff --git a/lib/src/services/mdns_scanner_service.dart b/lib/src/services/mdns_scanner_service.dart new file mode 100644 index 0000000..1337cdc --- /dev/null +++ b/lib/src/services/mdns_scanner_service.dart @@ -0,0 +1,35 @@ +import 'package:multicast_dns/multicast_dns.dart'; +import 'package:network_tools/network_tools.dart'; +import 'package:universal_io/io.dart'; + +abstract class MdnsScannerService { + MdnsScannerService() { + _instance = this; + } + + static late MdnsScannerService _instance; + + static MdnsScannerService get instance => _instance; + + /// This method searching for all the mdns devices in the network. + Future> searchMdnsDevices({ + bool forceUseOfSavedSrvRecordList = false, + }); + + Future> findingMdnsWithAddress( + String serviceType, + ); + + Future> findAllActiveHostForSrv({ + required InternetAddress addressType, + required MDnsClient client, + required PtrResourceRecord ptr, + required SrvResourceRecord srv, + }); + + ActiveHost convertSrvToHostName({ + required InternetAddress internetAddress, + required PtrResourceRecord ptr, + required SrvResourceRecord srv, + }); +} diff --git a/lib/src/services/port_scanner_service.dart b/lib/src/services/port_scanner_service.dart new file mode 100644 index 0000000..f2875aa --- /dev/null +++ b/lib/src/services/port_scanner_service.dart @@ -0,0 +1,87 @@ +import 'dart:async'; + +import 'package:network_tools/network_tools.dart'; + +/// Scans open port for a target Address or domain. +abstract class PortScannerService { + PortScannerService() { + _instance = this; + } + + static late PortScannerService _instance; + + static PortScannerService get instance => _instance; + + static const int defaultStartPort = 1; + static const int defaultEndPort = 1024; + + static const List commonPorts = [ + 20, + 21, + 22, + 23, + 25, + 50, + 51, + 53, + 67, + 68, + 69, + 80, + 110, + 119, + 123, + 135, + 139, + 143, + 161, + 162, + 389, + 443, + 989, + 990, + 3389, + ]; + + /// Checks if the single [port] is open or not for the [target]. + Future isOpen( + String target, + int port, { + Duration timeout = const Duration(milliseconds: 2000), + }); + + /// Scans ports only listed in [portList] for a [target]. Progress can be + /// retrieved by [progressCallback] + /// Tries connecting ports before until [timeout] reached. + /// [resultsInAddressAscendingOrder] = false will return results faster but not in + /// ascending order and without [progressCallback]. + Stream customDiscover( + String target, { + List portList = commonPorts, + ProgressCallback? progressCallback, + Duration timeout = const Duration(milliseconds: 2000), + bool resultsInAddressAscendingOrder = true, + bool async = false, + }); + + /// Scans port from [startPort] to [endPort] of [target]. Progress can be + /// retrieved by [progressCallback] + /// Tries connecting ports before until [timeout] reached. + Stream scanPortsForSingleDevice( + String target, { + int startPort = defaultStartPort, + int endPort = defaultEndPort, + ProgressCallback? progressCallback, + Duration timeout = const Duration(milliseconds: 2000), + bool resultsInAddressAscendingOrder = true, + bool async = false, + }); + + Future connectToPort({ + required String address, + required int port, + required Duration timeout, + required StreamController activeHostsController, + int recursionCount = 0, + }); +} diff --git a/pubspec.yaml b/pubspec.yaml index 8f114d3..b35addc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.4 +version: 4.0.5 issue_tracker: https://github.com/osociety/network_tools/issues repository: https://github.com/osociety/network_tools @@ -20,15 +20,11 @@ funding: dependencies: # A dart csv to list converter. - csv: ^5.1.1 + csv: ">=5.1.1 <7.0.0" # Multi-platform network ping utility. dart_ping: ^9.0.1 - # Defines the annotations used by json_serializable - get_it: ^7.6.4 # A composable, Future-based library for making HTTP requests. http: ^1.1.2 - # Injectable is a convenient code generator for get_it. - injectable: ^2.3.2 # Defines the annotations used by json_serializable. json_annotation: ^4.8.1 # Debugging and error logging. diff --git a/test/network_tools_test.dart b/test/network_tools_test.dart index 53748f3..2bb0028 100644 --- a/test/network_tools_test.dart +++ b/test/network_tools_test.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:network_tools/network_tools.dart'; import 'package:network_tools/src/network_tools_utils.dart'; import 'package:test/test.dart'; @@ -6,6 +7,7 @@ import 'package:universal_io/io.dart'; void main() { int port = 0; + int hostId = 0; int firstHostId = 0; int lastHostId = 0; String myOwnHost = "0.0.0.0"; @@ -26,14 +28,14 @@ void main() { final interface = await NetInterface.localInterface(); if (interface != null) { - final hostId = interface.hostId; + hostId = interface.hostId; interfaceIp = interface.networkId; myOwnHost = interface.ipAddress; // Better to restrict to scan from hostId - 1 to hostId + 1 to prevent GHA timeouts firstHostId = hostId <= 1 ? hostId : hostId - 1; lastHostId = hostId >= 254 ? hostId : hostId + 1; - await for (final host - in HostScanner.scanDevicesForSinglePort(interfaceIp, port)) { + await for (final host in HostScannerService.instance + .scanDevicesForSinglePort(interfaceIp, port)) { hostsWithOpenPort.add(host); for (final tempOpenPort in host.openPorts) { if (tempOpenPort.port == port) { @@ -69,17 +71,39 @@ void main() { () { expectLater( //There should be at least one device pingable in network - HostScanner.getAllPingableDevices( + HostScannerService.instance.getAllPingableDevices( + interfaceIp, + timeoutInSeconds: 3, + firstHostId: firstHostId, + lastHostId: lastHostId, + ), + emits(isA()), + ); + expectLater( + //There should be at least one device pingable in network when limiting to own hostId + HostScannerService.instance.getAllPingableDevices( interfaceIp, timeoutInSeconds: 3, + hostIds: [hostId], firstHostId: firstHostId, lastHostId: lastHostId, ), emits(isA()), ); + expectLater( + //There should be at least one device pingable in network when limiting to hostId other than own + HostScannerService.instance.getAllPingableDevices( + interfaceIp, + timeoutInSeconds: 3, + hostIds: [0], + firstHostId: firstHostId, + lastHostId: lastHostId, + ), + neverEmits(isA()), + ); expectLater( //Should emit at least our own local machine when pinging all hosts. - HostScanner.getAllPingableDevices( + HostScannerService.instance.getAllPingableDevices( interfaceIp, timeoutInSeconds: 3, firstHostId: firstHostId, @@ -99,7 +123,7 @@ void main() { () { expectLater( //There should be at least one device pingable in network - HostScanner.getAllPingableDevicesAsync( + HostScannerService.instance.getAllPingableDevicesAsync( interfaceIp, timeoutInSeconds: 3, firstHostId: firstHostId, @@ -109,7 +133,7 @@ void main() { ); expectLater( //Should emit at least our own local machine when pinging all hosts. - HostScanner.getAllPingableDevicesAsync( + HostScannerService.instance.getAllPingableDevicesAsync( interfaceIp, timeoutInSeconds: 3, firstHostId: firstHostId, @@ -121,12 +145,34 @@ void main() { ), ), ); + expectLater( + //There should be at least one device pingable in network when limiting to own hostId + HostScannerService.instance.getAllPingableDevicesAsync( + interfaceIp, + timeoutInSeconds: 3, + hostIds: [hostId], + firstHostId: firstHostId, + lastHostId: lastHostId, + ), + emits(isA()), + ); + expectLater( + //There should be at least one device pingable in network when limiting to hostId other than own + HostScannerService.instance.getAllPingableDevicesAsync( + interfaceIp, + timeoutInSeconds: 3, + hostIds: [0], + firstHostId: firstHostId, + lastHostId: lastHostId, + ), + neverEmits(isA()), + ); }, ); test('Running scanDevicesForSinglePort tests', () async* { expectLater( - HostScanner.scanDevicesForSinglePort( + HostScannerService.instance.scanDevicesForSinglePort( interfaceIp, port, firstHostId: firstHostId, @@ -142,7 +188,7 @@ void main() { for (final activeHost in hostsWithOpenPort) { final port = activeHost.openPorts.elementAt(0).port; expectLater( - PortScanner.scanPortsForSingleDevice( + PortScannerService.instance.scanPortsForSingleDevice( activeHost.address, startPort: port - 1, endPort: port, @@ -162,7 +208,7 @@ void main() { for (final activeHost in hostsWithOpenPort) { final port = activeHost.openPorts.elementAt(0).port; expectLater( - PortScanner.scanPortsForSingleDevice( + PortScannerService.instance.scanPortsForSingleDevice( activeHost.address, startPort: port - 1, endPort: port, @@ -182,7 +228,7 @@ void main() { test('Running customDiscover tests', () { for (final activeHost in hostsWithOpenPort) { expectLater( - PortScanner.customDiscover( + PortScannerService.instance.customDiscover( activeHost.address, portList: [port], ), @@ -194,7 +240,7 @@ void main() { test('Running customDiscover Async tests', () { for (final activeHost in hostsWithOpenPort) { expectLater( - PortScanner.customDiscover( + PortScannerService.instance.customDiscover( activeHost.address, portList: [port], async: true, @@ -207,7 +253,7 @@ void main() { test('Running connectToPort tests', () { for (final activeHost in hostsWithOpenPort) { expectLater( - PortScanner.connectToPort( + PortScannerService.instance.connectToPort( address: activeHost.address, port: port, timeout: const Duration(seconds: 5), @@ -227,7 +273,7 @@ void main() { test('Running isOpen tests', () { for (final activeHost in hostsWithOpenPort) { expectLater( - PortScanner.isOpen(activeHost.address, port), + PortScannerService.instance.isOpen(activeHost.address, port), completion( isA().having( (p0) => p0.openPorts.contains(OpenPort(port)), @@ -242,7 +288,7 @@ void main() { group("Testing mdns scanner group", () { test('Running searchMdnsDevices tests', () async { - final mdnsDevices = await MdnsScanner.searchMdnsDevices(); + final mdnsDevices = await MdnsScannerService.instance.searchMdnsDevices(); expectLater( mdnsDevices, isA>(),