LCOV - code coverage report
Current view: top level - lib/third_party/nm/src - network_manager_client.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 129 0.0 %
Date: 2024-02-26 20:09:01 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : import 'dart:io';
       3             : 
       4             : import 'package:dbus/dbus.dart';
       5             : 
       6             : /// D-Bus interface names
       7             : const _managerInterfaceName = 'org.freedesktop.NetworkManager';
       8             : 
       9             : /// Overall networking states.
      10             : enum NetworkManagerState {
      11             :   unknown,
      12             :   asleep,
      13             :   disconnected,
      14             :   disconnecting,
      15             :   connecting,
      16             :   connectedLocal,
      17             :   connectedSite,
      18             :   connectedGlobal,
      19             : }
      20             : 
      21           0 : NetworkManagerState _decodeState(int value) {
      22             :   switch (value) {
      23           0 :     case 10:
      24             :       return NetworkManagerState.asleep;
      25           0 :     case 20:
      26             :       return NetworkManagerState.disconnected;
      27           0 :     case 30:
      28             :       return NetworkManagerState.disconnecting;
      29           0 :     case 40:
      30             :       return NetworkManagerState.connecting;
      31           0 :     case 50:
      32             :       return NetworkManagerState.connectedLocal;
      33           0 :     case 60:
      34             :       return NetworkManagerState.connectedSite;
      35           0 :     case 70:
      36             :       return NetworkManagerState.connectedGlobal;
      37             :     default:
      38             :       return NetworkManagerState.unknown;
      39             :   }
      40             : }
      41             : 
      42             : /// Internet connectivity states.
      43             : enum NetworkManagerConnectivityState { unknown, none, portal, limited, full }
      44             : 
      45           0 : NetworkManagerConnectivityState _decodeConnectivityState(int value) {
      46             :   switch (value) {
      47           0 :     case 1:
      48             :       return NetworkManagerConnectivityState.none;
      49           0 :     case 2:
      50             :       return NetworkManagerConnectivityState.portal;
      51           0 :     case 3:
      52             :       return NetworkManagerConnectivityState.limited;
      53           0 :     case 4:
      54             :       return NetworkManagerConnectivityState.full;
      55             :     default:
      56             :       return NetworkManagerConnectivityState.unknown;
      57             :   }
      58             : }
      59             : 
      60             : class _NetworkManagerInterface {
      61             :   final Map<String, DBusValue> properties;
      62             :   final propertiesChangedStreamController = StreamController<List<String>>.broadcast();
      63             : 
      64             :   /// Stream of property names as their values change.
      65           0 :   Stream<List<String>> get propertiesChanged => propertiesChangedStreamController.stream;
      66             : 
      67           0 :   _NetworkManagerInterface(this.properties);
      68             : 
      69           0 :   void updateProperties(Map<String, DBusValue> changedProperties) {
      70           0 :     properties.addAll(changedProperties);
      71           0 :     propertiesChangedStreamController.add(changedProperties.keys.toList());
      72             :   }
      73             : }
      74             : 
      75             : class _NetworkManagerObject extends DBusRemoteObject {
      76             :   final interfaces = <String, _NetworkManagerInterface>{};
      77             : 
      78           0 :   void updateInterfaces(Map<String, Map<String, DBusValue>> interfacesAndProperties) {
      79           0 :     interfacesAndProperties.forEach((interfaceName, properties) {
      80           0 :       interfaces[interfaceName] = _NetworkManagerInterface(properties);
      81             :     });
      82             :   }
      83             : 
      84             :   /// Returns true if removing [interfaceNames] would remove all interfaces on this object.
      85           0 :   bool wouldRemoveAllInterfaces(List<String> interfaceNames) {
      86           0 :     for (var interface in interfaces.keys) {
      87           0 :       if (!interfaceNames.contains(interface)) {
      88             :         return false;
      89             :       }
      90             :     }
      91             :     return true;
      92             :   }
      93             : 
      94           0 :   void removeInterfaces(List<String> interfaceNames) {
      95           0 :     for (var interfaceName in interfaceNames) {
      96           0 :       interfaces.remove(interfaceName);
      97             :     }
      98             :   }
      99             : 
     100           0 :   void updateProperties(String interfaceName, Map<String, DBusValue> changedProperties) {
     101           0 :     var interface = interfaces[interfaceName];
     102             :     if (interface != null) {
     103           0 :       interface.updateProperties(changedProperties);
     104             :     }
     105             :   }
     106             : 
     107             :   /// Gets a cached property.
     108           0 :   DBusValue? getCachedProperty(String interfaceName, String name) {
     109           0 :     var interface = interfaces[interfaceName];
     110             :     if (interface == null) {
     111             :       return null;
     112             :     }
     113           0 :     return interface.properties[name];
     114             :   }
     115             : 
     116             :   /// Gets a cached boolean property, or returns null if not present or not the correct type.
     117           0 :   bool? getBooleanProperty(String interface, String name) {
     118           0 :     var value = getCachedProperty(interface, name);
     119             :     if (value == null) {
     120             :       return null;
     121             :     }
     122           0 :     if (value.signature != DBusSignature('b')) {
     123             :       return null;
     124             :     }
     125           0 :     return (value as DBusBoolean).value;
     126             :   }
     127             : 
     128             :   /// Gets a cached unsigned 8 bit integer property, or returns null if not present or not the correct type.
     129           0 :   int? getByteProperty(String interface, String name) {
     130           0 :     var value = getCachedProperty(interface, name);
     131             :     if (value == null) {
     132             :       return null;
     133             :     }
     134           0 :     if (value.signature != DBusSignature('y')) {
     135             :       return null;
     136             :     }
     137           0 :     return (value as DBusByte).value;
     138             :   }
     139             : 
     140             :   /// Gets a cached signed 32 bit integer property, or returns null if not present or not the correct type.
     141           0 :   int? getInt32Property(String interface, String name) {
     142           0 :     var value = getCachedProperty(interface, name);
     143             :     if (value == null) {
     144             :       return null;
     145             :     }
     146           0 :     if (value.signature != DBusSignature('i')) {
     147             :       return null;
     148             :     }
     149           0 :     return (value as DBusInt32).value;
     150             :   }
     151             : 
     152             :   /// Gets a cached unsigned 32 bit integer property, or returns null if not present or not the correct type.
     153           0 :   int? getUint32Property(String interface, String name) {
     154           0 :     var value = getCachedProperty(interface, name);
     155             :     if (value == null) {
     156             :       return null;
     157             :     }
     158           0 :     if (value.signature != DBusSignature('u')) {
     159             :       return null;
     160             :     }
     161           0 :     return (value as DBusUint32).value;
     162             :   }
     163             : 
     164             :   /// Gets a cached signed 64 bit integer property, or returns null if not present or not the correct type.
     165           0 :   int? getInt64Property(String interface, String name) {
     166           0 :     var value = getCachedProperty(interface, name);
     167             :     if (value == null) {
     168             :       return null;
     169             :     }
     170           0 :     if (value.signature != DBusSignature('x')) {
     171             :       return null;
     172             :     }
     173           0 :     return (value as DBusInt64).value;
     174             :   }
     175             : 
     176             :   /// Gets a cached unsigned 64 bit integer property, or returns null if not present or not the correct type.
     177           0 :   int? getUint64Property(String interface, String name) {
     178           0 :     var value = getCachedProperty(interface, name);
     179             :     if (value == null) {
     180             :       return null;
     181             :     }
     182           0 :     if (value.signature != DBusSignature('t')) {
     183             :       return null;
     184             :     }
     185           0 :     return (value as DBusUint64).value;
     186             :   }
     187             : 
     188             :   /// Gets a cached string property, or returns null if not present or not the correct type.
     189           0 :   String? getStringProperty(String interface, String name) {
     190           0 :     var value = getCachedProperty(interface, name);
     191             :     if (value == null) {
     192             :       return null;
     193             :     }
     194           0 :     if (value.signature != DBusSignature('s')) {
     195             :       return null;
     196             :     }
     197           0 :     return (value as DBusString).value;
     198             :   }
     199             : 
     200             :   /// Gets a cached string array property, or returns null if not present or not the correct type.
     201           0 :   List<String>? getStringArrayProperty(String interface, String name) {
     202           0 :     var value = getCachedProperty(interface, name);
     203             :     if (value == null) {
     204             :       return null;
     205             :     }
     206           0 :     if (value.signature != DBusSignature('as')) {
     207             :       return null;
     208             :     }
     209           0 :     return (value as DBusArray).children.map((e) => (e as DBusString).value).toList();
     210             :   }
     211             : 
     212             :   /// Gets a cached object path property, or returns null if not present or not the correct type.
     213           0 :   DBusObjectPath? getObjectPathProperty(String interface, String name) {
     214           0 :     var value = getCachedProperty(interface, name);
     215             :     if (value == null) {
     216             :       return null;
     217             :     }
     218           0 :     if (value.signature != DBusSignature('o')) {
     219             :       return null;
     220             :     }
     221             :     return (value as DBusObjectPath);
     222             :   }
     223             : 
     224             :   /// Gets a cached object path array property, or returns null if not present or not the correct type.
     225           0 :   List<DBusObjectPath>? getObjectPathArrayProperty(String interface, String name) {
     226           0 :     var value = getCachedProperty(interface, name);
     227             :     if (value == null) {
     228             :       return null;
     229             :     }
     230           0 :     if (value.signature != DBusSignature('ao')) {
     231             :       return null;
     232             :     }
     233           0 :     return (value as DBusArray).children.map((e) => (e as DBusObjectPath)).toList();
     234             :   }
     235             : 
     236             :   /// Gets a cached list of data property, or returns null if not present or not the correct type.
     237           0 :   List<Map<String, dynamic>>? getDataListProperty(String interface, String name) {
     238           0 :     var value = getCachedProperty(interface, name);
     239             :     if (value == null) {
     240             :       return null;
     241             :     }
     242           0 :     if (value.signature != DBusSignature('aa{sv}')) {
     243             :       return null;
     244             :     }
     245           0 :     Map<String, dynamic> convertData(DBusValue value) {
     246           0 :       return (value as DBusDict).children.map((key, value) => MapEntry(
     247           0 :             (key as DBusString).value,
     248           0 :             (value as DBusVariant).value.toNative(),
     249             :           ));
     250             :     }
     251             : 
     252           0 :     return (value as DBusArray).children.map((value) => convertData(value)).toList();
     253             :   }
     254             : 
     255           0 :   _NetworkManagerObject(DBusClient client, DBusObjectPath path, Map<String, Map<String, DBusValue>> interfacesAndProperties) : super(client, name: 'org.freedesktop.NetworkManager', path: path) {
     256           0 :     updateInterfaces(interfacesAndProperties);
     257             :   }
     258             : }
     259             : 
     260             : /// A client that connects to NetworkManager.
     261             : class NetworkManagerClient {
     262             :   /// The bus this client is connected to.
     263             :   final DBusClient _bus;
     264             :   final bool _closeBus;
     265             : 
     266             :   /// The root D-Bus NetworkManager object at path '/org/freedesktop'.
     267             :   late final DBusRemoteObjectManager _root;
     268             : 
     269             :   // Objects exported on the bus.
     270             :   final _objects = <DBusObjectPath, _NetworkManagerObject>{};
     271             : 
     272             :   // Subscription to object manager signals.
     273             :   StreamSubscription? _objectManagerSubscription;
     274             : 
     275             :   /// Creates a new NetworkManager client connected to the system D-Bus.
     276           0 :   NetworkManagerClient({DBusClient? bus})
     277           0 :       : _bus = bus ?? DBusClient.system(),
     278             :         _closeBus = bus == null {
     279           0 :     _root = DBusRemoteObjectManager(
     280           0 :       _bus,
     281             :       name: 'org.freedesktop.NetworkManager',
     282           0 :       path: DBusObjectPath('/org/freedesktop'),
     283             :     );
     284             :   }
     285             : 
     286             :   /// Stream of property names as their values change.
     287           0 :   Stream<List<String>> get propertiesChanged => _manager?.interfaces[_managerInterfaceName]?.propertiesChangedStreamController.stream ?? Stream<List<String>>.empty();
     288             : 
     289             :   /// Connects to the NetworkManager D-Bus objects.
     290             :   /// Must be called before accessing methods and properties.
     291           0 :   Future<void> connect() async {
     292             :     // Already connected
     293           0 :     if (_objectManagerSubscription != null) {
     294             :       return;
     295             :     }
     296             : 
     297             :     // Big old grody Hack
     298             :     // DBus/nm doesnt seem to offer a way to deter ine if dbus is available on system
     299             :     // worse the first connections get triggered in dbus_client onListen an isn't a catchable exception so crashes the app
     300             :     // this is a hacky way to force an exception on thread if dbus isn't available and bail with out crashing
     301             :     try {
     302           0 :       await _root.client.getNameOwner(_root.name);
     303           0 :     } on SocketException catch (e) {
     304           0 :       print("nm dbus connect/emit test threw exception, dbus likely unavailable on system, aborting connect: $e");
     305             :       return;
     306             :     }
     307             : 
     308             :     // Subscribe to changes
     309           0 :     _objectManagerSubscription = _root.signals.listen((signal) {
     310           0 :       if (signal is DBusObjectManagerInterfacesAddedSignal) {
     311           0 :         var object = _objects[signal.changedPath];
     312             :         if (object != null) {
     313           0 :           object.updateInterfaces(signal.interfacesAndProperties);
     314             :         } else {
     315           0 :           object = _NetworkManagerObject(_bus, signal.changedPath, signal.interfacesAndProperties);
     316           0 :           _objects[signal.changedPath] = object;
     317             :         }
     318           0 :       } else if (signal is DBusObjectManagerInterfacesRemovedSignal) {
     319           0 :         var object = _objects[signal.changedPath];
     320             :         if (object != null) {
     321             :           // If all the interface are removed, then this object has been removed.
     322             :           // Keep the previous values around for the client to use.
     323           0 :           if (object.wouldRemoveAllInterfaces(signal.interfaces)) {
     324           0 :             _objects.remove(signal.changedPath);
     325             :           } else {
     326           0 :             object.removeInterfaces(signal.interfaces);
     327             :           }
     328             :         }
     329           0 :       } else if (signal is DBusPropertiesChangedSignal) {
     330           0 :         var object = _objects[signal.path];
     331             :         if (object != null) {
     332           0 :           object.updateProperties(signal.propertiesInterface, signal.changedProperties);
     333             :         }
     334             :       }
     335             :     });
     336             : 
     337             :     // Find all the objects exported.
     338           0 :     var objects = await _root.getManagedObjects();
     339           0 :     objects.forEach((objectPath, interfacesAndProperties) {
     340           0 :       _objects[objectPath] = _NetworkManagerObject(_bus, objectPath, interfacesAndProperties);
     341             :     });
     342             :   }
     343             : 
     344             :   /// The type of connection being used to access the network.
     345           0 :   String get primaryConnectionType {
     346           0 :     return _manager?.getStringProperty(
     347             :           _managerInterfaceName,
     348             :           'PrimaryConnectionType',
     349             :         ) ??
     350             :         '';
     351             :   }
     352             : 
     353             :   /// True is NetworkManager is still starting up.
     354           0 :   bool get startup {
     355           0 :     return _manager?.getBooleanProperty(_managerInterfaceName, 'Startup') ?? false;
     356             :   }
     357             : 
     358             :   /// The version of NetworkManager running.
     359           0 :   String get version {
     360           0 :     return _manager?.getStringProperty(_managerInterfaceName, 'Version') ?? '';
     361             :   }
     362             : 
     363             :   /// The result of the last connectivity check.
     364           0 :   NetworkManagerConnectivityState get connectivity {
     365           0 :     var value = _manager?.getUint32Property(_managerInterfaceName, 'Connectivity') ?? 0;
     366           0 :     return _decodeConnectivityState(value);
     367             :   }
     368             : 
     369             :   /// The overall networking state.
     370           0 :   NetworkManagerState get state {
     371           0 :     var value = _manager?.getUint32Property(_managerInterfaceName, 'State') ?? 0;
     372           0 :     return _decodeState(value);
     373             :   }
     374             : 
     375           0 :   _NetworkManagerObject? get _manager => _objects[DBusObjectPath('/org/freedesktop/NetworkManager')];
     376             : 
     377             :   /// Terminates all active connections. If a client remains unclosed, the Dart process may not terminate.
     378           0 :   Future<void> close() async {
     379           0 :     if (_objectManagerSubscription != null) {
     380           0 :       await _objectManagerSubscription!.cancel();
     381           0 :       _objectManagerSubscription = null;
     382             :     }
     383           0 :     if (_closeBus) {
     384           0 :       await _bus.close();
     385             :     }
     386             :   }
     387             : }

Generated by: LCOV version 1.14