LCOV - code coverage report
Current view: top level - lib/src/services/impls - mdns_scanner_service_impl.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 45.0 % 80 36
Test Date: 2026-06-11 16:54:34 Functions: - 0 0

            Line data    Source code
       1              : import 'dart:async';
       2              : import 'package:multicast_dns/multicast_dns.dart';
       3              : import 'package:network_tools/network_tools.dart';
       4              : import 'package:network_tools/src/mdns_scanner/get_srv_list_by_os/srv_list.dart';
       5              : import 'package:network_tools/src/network_tools_utils.dart';
       6              : import 'package:universal_io/io.dart';
       7              : 
       8              : /// Resolves the bind target for [RawDatagramSocket.bind].
       9              : ///
      10              : /// On Windows, binding with an [InternetAddress] whose hostname is empty fails
      11              : /// with errno 10049. Always use the numeric address string instead.
      12            1 : dynamic _mdnsDatagramBindHost(dynamic host) {
      13            1 :   if (host is InternetAddress) {
      14            0 :     return host.address;
      15              :   }
      16              :   return host;
      17              : }
      18              : 
      19            1 : Future<RawDatagramSocket> _mdnsRawDatagramSocketFactory(
      20              :   dynamic host,
      21              :   int port, {
      22              :   bool? reuseAddress,
      23              :   bool? reusePort,
      24              :   int? ttl,
      25              : }) {
      26            1 :   return RawDatagramSocket.bind(
      27            1 :     _mdnsDatagramBindHost(host),
      28              :     port,
      29              :     reuseAddress: reuseAddress ?? true,
      30              :     reusePort:
      31            2 :         !(Platform.isWindows || Platform.isAndroid) && (reusePort ?? true),
      32              :     ttl: ttl ?? 255,
      33              :   );
      34              : }
      35              : 
      36            1 : Future<Iterable<NetworkInterface>> _mdnsNetworkInterfacesFactory(
      37              :   InternetAddressType type,
      38              : ) {
      39            1 :   return NetworkInterface.list(
      40            1 :     includeLinkLocal: !Platform.isWindows,
      41              :     type: type,
      42              :   );
      43              : }
      44              : 
      45              : class MdnsScannerServiceImpl extends MdnsScannerService {
      46              :   /// This method searching for all the mdns devices in the network.
      47              :   /// TODO: The implementation is **Lacking!** and will not find all the
      48              :   /// TODO: results that actual exist in the network!, only some of them.
      49              :   /// TODO: This is because missing functionality in dart
      50              :   /// TODO: https://github.com/flutter/flutter/issues/97210
      51              :   /// TODO: In some cases we resolve this missing functionality using
      52              :   /// TODO: specific os tools.
      53              : 
      54            1 :   @override
      55              :   Future<List<ActiveHost>> searchMdnsDevices({
      56              :     bool forceUseOfSavedSrvRecordList = false,
      57              :   }) async {
      58              :     List<String> srvRecordListToSearchIn;
      59              : 
      60              :     if (forceUseOfSavedSrvRecordList) {
      61            1 :       srvRecordListToSearchIn = tcpSrvRecordsList;
      62            2 :       srvRecordListToSearchIn.addAll(udpSrvRecordsList);
      63              :     } else {
      64            1 :       final List<String>? srvRecordsFromOs = await SrvList.getSrvRecordList();
      65              : 
      66            1 :       if (srvRecordsFromOs == null || srvRecordsFromOs.isEmpty) {
      67            1 :         srvRecordListToSearchIn = tcpSrvRecordsList;
      68            2 :         srvRecordListToSearchIn.addAll(udpSrvRecordsList);
      69              :       } else {
      70              :         srvRecordListToSearchIn = srvRecordsFromOs;
      71              :       }
      72              :     }
      73              : 
      74            1 :     final List<Future<List<ActiveHost>>> activeHostListsFuture = [];
      75            2 :     for (final String srvRecord in srvRecordListToSearchIn) {
      76            2 :       activeHostListsFuture.add(findingMdnsWithAddress(srvRecord));
      77              :     }
      78              : 
      79            1 :     final List<ActiveHost> activeHostList = [];
      80              : 
      81              :     for (final Future<List<ActiveHost>> activeHostListFuture
      82            2 :         in activeHostListsFuture) {
      83            1 :       activeHostList.addAll(await activeHostListFuture);
      84              :     }
      85              : 
      86              :     return activeHostList;
      87              :   }
      88              : 
      89            1 :   @override
      90              :   Future<List<ActiveHost>> findingMdnsWithAddress(String serviceType) async {
      91            1 :     final MDnsClient client = MDnsClient(
      92              :       rawDatagramSocketFactory: _mdnsRawDatagramSocketFactory,
      93              :     );
      94              : 
      95            1 :     final List<ActiveHost> listOfActiveHost = [];
      96            1 :     final Completer<void> completer = Completer<void>();
      97              : 
      98            1 :     runZonedGuarded(
      99            1 :       () async {
     100              :         try {
     101            1 :           await client.start(
     102            1 :             listenAddress: InternetAddress.anyIPv4,
     103              :             interfacesFactory: _mdnsNetworkInterfacesFactory,
     104              :           );
     105              : 
     106            1 :           await for (final PtrResourceRecord ptr
     107            1 :               in client.lookup<PtrResourceRecord>(
     108            1 :                 ResourceRecordQuery.serverPointer(serviceType),
     109            0 :               )) {
     110            0 :             await for (final SrvResourceRecord srv
     111            0 :                 in client.lookup<SrvResourceRecord>(
     112            0 :                   ResourceRecordQuery.service(ptr.domainName),
     113            0 :                 )) {
     114            0 :               await for (final TxtResourceRecord txtRecords
     115            0 :                   in client.lookup<TxtResourceRecord>(
     116            0 :                     ResourceRecordQuery.text(ptr.domainName),
     117            0 :                   )) {
     118            0 :                 listOfActiveHost.addAll(
     119            0 :                   await findAllActiveHostForSrv(
     120            0 :                     addressType: InternetAddress.anyIPv4,
     121              :                     client: client,
     122              :                     ptr: ptr,
     123              :                     srv: srv,
     124              :                     txt: txtRecords,
     125              :                   ),
     126              :                 );
     127            0 :                 listOfActiveHost.addAll(
     128            0 :                   await findAllActiveHostForSrv(
     129            0 :                     addressType: InternetAddress.anyIPv6,
     130              :                     client: client,
     131              :                     ptr: ptr,
     132              :                     srv: srv,
     133              :                     txt: txtRecords,
     134              :                   ),
     135              :                 );
     136              :               }
     137              :             }
     138              :           }
     139              :         } catch (e) {
     140            0 :           logger.severe(
     141            0 :             'Error finding mdns devices for serviceType $serviceType: $e',
     142              :           );
     143              :         } finally {
     144            1 :           client.stop();
     145            2 :           if (!completer.isCompleted) completer.complete();
     146              :         }
     147              :       },
     148            0 :       (Object error, StackTrace stack) {
     149            0 :         logger.severe(
     150            0 :           'Unhandled async error in findingMdnsWithAddress for $serviceType: $error',
     151              :         );
     152            0 :         client.stop();
     153            0 :         if (!completer.isCompleted) completer.complete();
     154              :       },
     155              :     );
     156              : 
     157            1 :     await completer.future;
     158              :     return listOfActiveHost;
     159              :   }
     160              : 
     161            0 :   @override
     162              :   Future<List<ActiveHost>> findAllActiveHostForSrv({
     163              :     required InternetAddress addressType,
     164              :     required MDnsClient client,
     165              :     required PtrResourceRecord ptr,
     166              :     required SrvResourceRecord srv,
     167              :     required TxtResourceRecord txt,
     168              :   }) async {
     169            0 :     final List<ActiveHost> listOfActiveHost = [];
     170              :     try {
     171              :       Stream<IPAddressResourceRecord> iPAddressResourceRecordStream;
     172              : 
     173            0 :       if (addressType == InternetAddress.anyIPv4) {
     174            0 :         iPAddressResourceRecordStream = client.lookup<IPAddressResourceRecord>(
     175            0 :           ResourceRecordQuery.addressIPv4(srv.target),
     176              :         );
     177              :       } else {
     178            0 :         iPAddressResourceRecordStream = client.lookup<IPAddressResourceRecord>(
     179            0 :           ResourceRecordQuery.addressIPv6(srv.target),
     180              :         );
     181              :       }
     182            0 :       await for (final IPAddressResourceRecord ip
     183            0 :           in iPAddressResourceRecordStream) {
     184            0 :         final ActiveHost activeHost = convertSrvToHostName(
     185            0 :           internetAddress: InternetAddress.fromRawAddress(
     186            0 :             ip.address.rawAddress,
     187              :           ),
     188              :           ptr: ptr,
     189              :           srv: srv,
     190              :           txt: txt,
     191              :         );
     192              : 
     193            0 :         listOfActiveHost.add(activeHost);
     194              :       }
     195              :     } catch (e) {
     196            0 :       logger.severe(
     197            0 :         'Error finding ip of mdns record ${ptr.name} srv target ${srv.target}, will add it with ip 0.0.0.0\n$e',
     198              :       );
     199            0 :       final ActiveHost activeHost = convertSrvToHostName(
     200            0 :         internetAddress: InternetAddress('0.0.0.0'),
     201              :         srv: srv,
     202              :         ptr: ptr,
     203              :         txt: txt,
     204              :       );
     205            0 :       listOfActiveHost.add(activeHost);
     206              :     }
     207              :     return listOfActiveHost;
     208              :   }
     209              : 
     210            0 :   @override
     211              :   ActiveHost convertSrvToHostName({
     212              :     required InternetAddress internetAddress,
     213              :     required PtrResourceRecord ptr,
     214              :     required SrvResourceRecord srv,
     215              :     required TxtResourceRecord txt,
     216              :   }) {
     217            0 :     final MdnsInfo mdnsInfo = MdnsInfo(
     218              :       srvResourceRecord: srv,
     219              :       ptrResourceRecord: ptr,
     220              :       txtResourceRecord: txt,
     221              :     );
     222            0 :     return ActiveHost(internetAddress: internetAddress, mdnsInfoVar: mdnsInfo);
     223              :   }
     224              : }
        

Generated by: LCOV version 2.0-1