hypfvieh / dbus-java

Improved version of java DBus library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/)
https://hypfvieh.github.io/dbus-java/
MIT License
185 stars 73 forks source link

dbus-java and NetworkManager #25

Closed martinfluchmfmfmf closed 6 years ago

martinfluchmfmfmf commented 6 years ago

Hi,

since days I try to get dbus-java and and networkmanager up and running, without the final success. I hope that somebody of you can help me.

the task is simple: connect via dbus to the locally installed networkmanager, first list the devices, access detail information (here i fail), afterwards install signals handlers ..

my test script

public void dbustest()
    {
        DBusConnection conn; 
        Properties nmProp;
        NetworkManager na;

        try
        {
         conn = DBusConnection.getConnection(DBusConnection.SYSTEM);     
         for (int i=0;i<conn.getNames().length;i++)
         {
             log.info("name={}",conn.getNames()[i]);
         }

        na=(NetworkManager) conn.getRemoteObject("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager",NetworkManager.class);

        Map<String,String> myperm=na.GetPermissions();
        for (String s:myperm.keySet())
        {
            log.info("perm {}={}",s,myperm.get(s));
        }

        List<DBusInterface> devices=na.GetDevices();
        //List<Path> devices = na.GetDevices();
        log.info("devices={}",devices.size());

            ///List<DBusInterface> mydevices=na.GetDevices();
            //  List<Path> devList = na.GetDevices();
            //https://github.com/Paxle/Paxle/blob/master/bundles/Dbus/src/main/java/org/freedesktop/NetworkManager.java

            if (devices!=null)
            {
                for (DBusInterface i:devices)
                {
                    //Path p=new Path();        
                    //log.info("dbusinterface {}={}",i.toString(),d.hashCode());

                }
            }else
            {
                log.error("mydevices==null");
            }

        } catch (org.freedesktop.dbus.exceptions.DBusException e)
        {
            log.error("dbusException e={}",e);
        }
    }

my pom.xml

     <dependency>
          <groupId>com.github.hypfvieh</groupId>
        <artifactId>dbus-java</artifactId>
        <version>2.7.5</version>
        </dependency>

My Challenges / and the most recent ways i tried to fix them

Task1: Generation of the Java Interfaces I installed the latest NetworkManager Source to get the introspection.xml files I generated the neccesary Classes

/home/mf/dbus/hypf/dbus-java/target/classes/CreateInterface.sh -f /home/mf/dbus/NetworkManager/introspection/org.freedesktop.NetworkManager.xml
WARNING: Ignoring property
WARNING: Ignoring property
WARNING: Ignoring property
WARNING: Ignoring property
...
/home/mf/dbus/hypf/dbus-java/target/classes/CreateInterface.sh -f /home/mf/dbus/NetworkManager/introspection/org.freedesktop.NetworkManager.Device.Wired.xml
WARNING: Ignoring property
WARNING: Ignoring property
...

Question 1: Why do I get the Ignoring Property ? Any Relevance for me? Question 2: Obviously the Source Generator uses ident PackageNames and ClassName which leads to the fllowing Comiliation Error - how can I overcome this beahviour?

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project quattro: Compilation failure: Compilation failure:
[ERROR] /home/mf/jooby/quattro/src/main/java/org/freedesktop/NetworkManager/Device/Wired.java:[1,1] package org.freedesktop.NetworkManager clashes with class of same name
[ERROR] /home/mf/jooby/quattro/src/main/java/org/freedesktop/NetworkManager.java:[12,8] interface org.freedesktop.NetworkManager clashes with package of same name

To solve this issue I moved the Wired (and the other classes which I generated but not listed here) to the top Level Package (for testing issues).

The good News I can compile and run the program, Connection to Dbus works

[2018-08-15 09:09:10,127]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - networkmanagermodule start
[2018-08-15 09:09:10,219]-[Sender] INFO  org.freedesktop.dbus.MessageWriter - <= MethodCall(0,1) { Path=>/org/freedesktop/DBus, Interface=>org.freedesktop.DBus, Member=>Hello, Destination=>org.freedesktop.DBus } { }
[2018-08-15 09:09:10,225]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - name=:1.156
[2018-08-15 09:09:10,239]-[Sender] INFO  org.freedesktop.dbus.MessageWriter - <= MethodCall(0,3) { Path=>/org/freedesktop/NetworkManager, Interface=>org.freedesktop.NetworkManager, Member=>GetPermissions, Destination=>org.freedesktop.NetworkManager } { }
[2018-08-15 09:09:10,261]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.enable-disable-network=no
[2018-08-15 09:09:10,261]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.enable-disable-wifi=no
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.enable-disable-wimax=no
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.enable-disable-wwan=no
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.network-control=no
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.settings.modify.hostname=auth
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.settings.modify.own=auth
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.settings.modify.system=auth
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.sleep-wake=no
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.wifi.share.open=no
[2018-08-15 09:09:10,262]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - perm org.freedesktop.NetworkManager.wifi.share.protected=no
[2018-08-15 09:09:10,263]-[Sender] INFO  org.freedesktop.dbus.MessageWriter - <= MethodCall(0,4) { Path=>/org/freedesktop/NetworkManager, Interface=>org.freedesktop.NetworkManager, Member=>GetDevices, Destination=>org.freedesktop.NetworkManager } { }
[2018-08-15 09:09:10,267]-[Sender] INFO  org.freedesktop.dbus.MessageWriter - <= MethodCall(0,5) { Path=>/org/freedesktop/NetworkManager/Devices/0, Interface=>org.freedesktop.DBus.Introspectable, Member=>Introspect, Destination=>:1.50 } { }
[2018-08-15 09:09:10,284]-[Sender] INFO  org.freedesktop.dbus.MessageWriter - <= MethodCall(0,6) { Path=>/org/freedesktop/NetworkManager/Devices/1, Interface=>org.freedesktop.DBus.Introspectable, Member=>Introspect, Destination=>:1.50 } { }
[2018-08-15 09:09:10,289]-[Hotswap] INFO  quattro.networkmanager.NetworkmanagerModule - devices=2

Task2: Accessing Detail Information per Interface

As listed above the System seems to get the Information but only if I call

    List<DBusInterface> devices=na.GetDevices();

and DBusInterface has no properties or Methods to get Details. After Goolge Recherche I Found that the GetDevices (in some Implementations) returns List but thats not the case in my installation. Even a Cast to (eg. Device.Wired) does not work

Question3: What is the proposed way to access the Details in the resolved DbusInterface?

Thanks

Martin

hypfvieh commented 6 years ago

First of all, the CreateInterface class is just a helper to create a basic java interface class from a XML definition. Not everything in the generated code can or will be correct nor be complete.

After generating the required classes some manual work is always needed. Also reading the XML by yourself will also help to understand what methods should be used or should be avoided due to deprecation.

The generated package names may also be invalid. Like in this case, package names contains Uppercase characters which is not forbidden, but the java code recommendations are: you should only use lowercase characters for package names. So the error or warning you will see, is that the package name contain parts which are identical to a class. The correct way to fix this, is to use the correct java naming scheme and annotate the interface with DBusInterface-Annotation which provides the name in the way DBus would expect it.

The usage of the tool "d-feet" is also always worth a shot, and will definitely help to create proper java interfaces.

Warnings about ignored properties are the regular case, as all properties provided by a certain object is specified in the introspection XML. Nevertheless, the generated code will not contain any properties, as all properties will be gathered by using the default DBus Properties-Interface.

The methods you use will only return pathes to the objects which contain the information you may want to have. That is correct and the expected behavior.

After getting the pathes, you have to query DBus on the proper interface with the given path to get e.g. IP-Addresses, interface name or whatever from NetworkManager.

Before I start explain everything as text, it may be more useful to take a look at my sample code: https://github.com/hypfvieh/sandbox/blob/master/src/main/java/org/github/hypfvieh/sandbox/dbus/NetworkManagerExample.java

martinfluchmfmfmf commented 6 years ago

first of all thanks, the example helped a lot. for my understanding the interface creator is more a problem than a solution. i got everything up and running with one exception: the extraction of the interface ip.

your sample code

List<Map<String, Variant<?>>> addressArrV4 = ipv4Config.Get("org.freedesktop.NetworkManager.IP4Config", "AddressData");

fires an exception that the property does not exist.

i changed the code the get clarity to

Map<String,Variant<?>> addressArrV4 = ipv4Config.GetAll("org.freedesktop.NetworkManager.IP4Config");
                       for (String key: addressArrV4.keySet())
                       {
                           log.info("key: {}",key);

                       }

and get

NetworkmanagerModule - key: Addresses
NetworkmanagerModule - key: Domains
NetworkmanagerModule - key: Gateway
NetworkmanagerModule - key: Nameservers
NetworkmanagerModule - key: Routes
NetworkmanagerModule - key: Searches
NetworkmanagerModule - key: WinsServers

Don't know why?, maybe because of the fact that my networkmanager installation is not "managing" any interface? can you give me a hint were i find a quick start to implement signal handling in java? any samples you can refer me to?

martin

hypfvieh commented 6 years ago

I don't think the interface creator is useless, it does the basic stuff and will help you save some time.

According to the XML definition, Addresses is deprecated and one should use AddressData to get the IP. Using "AddressData" may fail, if you use an old NetworkManager version (< 1.2) I use Ubuntu 16.04 which provides a NetworkManager in version 1.2.6, so it works for me.

For me, listing all keys in the ipv4Config-Properties, will return this:

key: AddressData
key: Addresses
key: DnsOptions
key: DnsPriority
key: Domains
key: Gateway
key: Nameservers
key: RouteData
key: Routes
key: Searches
key: WinsServers

Maybe it is failing because it does not manage any device. But I'm not really sure. Usually at least 'lo' loopback device should be available.

Nonetheless, if you cannot be sure if the value is available or if NetworkManager version is suitable, then you have to handle that problem in your code.

SignalHandling in DBus is similar to requesting any value from DBus. First you need an interface which extends DBusSignal and provides the signatures of every method for that very signal. Then you have to create a class which implements the new interface and provides implementations for all the methods required for the signal you want to implement. After that, you have to register your class as signal handler on the DBus connection.

You may take a look in the TestAll-Unittest at line 125 (testSignalHandlers). This test method provides some different flavours of implementing and registering signals.

martinfluchmfmfmf commented 6 years ago

Thanks, up to the point everything works. I don't know why but when I think that the last steps are straight forward I have to learn that I'm wrong...

Case1: Add a Connection / Remove a Connection Adding works Remove not - any hint why?

   public Connection getConnection(String name) throws DBusException
            {
              settings=dbusConn.getRemoteObject("org.freedesktop.NetworkManager","/org/freedesktop/NetworkManager/Settings",Settings.class);
              List<DBusInterface> connections=settings.ListConnections();
                for (DBusInterface i:connections)
                {
                    Connection mf=dbusConn.getRemoteObject("org.freedesktop.NetworkManager", i.getObjectPath(),Connection.class);
                    Map<String,Map<String,Variant>> settings=mf.GetSettings();
                    Map<String,Variant> connectionsettings=settings.get("connection");
                    String foundname=null;
                    if (connectionsettings!=null&&connectionsettings.get("id")!=null) foundname=connectionsettings.get("id").toString().replaceAll("\\[|\\]", "");
                    log.info("found name: {} search name: {}",foundname,name);
                    if (foundname.equalsIgnoreCase(name)) return mf;

                }
                return null; 
            }

          public void removeConnection(String connectionName) throws Exception
          {
              Connection c=getConnection(connectionName);
              if (c==null) 
                  {
                    log.error("connection not found");
                    throw new Exception("Connection not found");
                  }
              c.Delete();
          }

          public void createLanConnection(String connectionName,boolean autoconnect) throws DBusException
          {
              settings=dbusConn.getRemoteObject("org.freedesktop.NetworkManager","/org/freedesktop/NetworkManager/Settings",Settings.class);

                Map<String, Variant> connectionMap = new HashMap<String, Variant>();

                connectionMap.put("id", new Variant<String>(connectionName));
                connectionMap.put("type", new Variant<String>("802-3-ethernet"));
                connectionMap.put("autoconnect", new Variant<Boolean>(autoconnect));
                UUID uuid = UUID.randomUUID();
                connectionMap.put("uuid", new Variant<String>(uuid.toString()));

                Map<String, Variant> ipv4Map = new HashMap<String, Variant>();
                ipv4Map.put("method", new Variant<String>("auto"));

                Map<String, Map<String,Variant> > newConnection = new HashMap<String, Map<String,Variant> >();              
                newConnection.put("connection", connectionMap);

                newConnection.put("ipv4", ipv4Map);

                settings.AddConnection(newConnection);

          }

Case2: Trigger a preconfigured OPEN Vpn Connection


          public void activateConnection(String connectionname,String interfacename) throws DBusException
          {
              Connection c=this.getConnection(connectionname);

              if (c==null)
              {log.error("connection {} not found",connectionname);
              return; 
              }

              Active d=this.getActiveConnection(interfacename);
              if (d==null)
              {
                  log.error("device {} not found",interfacename);
                  return; 
              }

              log.info("found connection={}",c.getObjectPath());
              log.info("found active connection={}",d.getObjectPath()); 

                 DBusInterface active=nm.ActivateConnection(c,d,d );
                  //nm.ActivateConnection(c.GetSettings(), device, setting);

          }

To prevent issue due to missconfiguration I used the gnome networkmanager applet to configure the openvpn connection, it works.

[2018-08-24 19:51:32,366]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -  Connection Details for interface /org/freedesktop/NetworkManager/Settings/2
[2018-08-24 19:51:32,370]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -   key: connection
[2018-08-24 19:51:32,370]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     autoconnect=[false]
[2018-08-24 19:51:32,370]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     id=[home]
[2018-08-24 19:51:32,370]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     permissions=[[]]
[2018-08-24 19:51:32,371]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     timestamp=[1535120059]
[2018-08-24 19:51:32,371]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     type=[vpn]
[2018-08-24 19:51:32,371]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     uuid=[a3ff0a14-fdec-4aac-a30a-b7173c0d5fbc]
[2018-08-24 19:51:32,371]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -   key: ipv4
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     address-data=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     addresses=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     dns=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     dns-search=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     method=[auto]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     route-data=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     routes=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -   key: ipv6
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     address-data=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     addresses=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     dns=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     dns-search=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     ip6-privacy=[0]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     method=[auto]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     route-data=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     routes=[[]]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -   key: proxy
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -   key: vpn
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     data=[{ ta-dir => 1,connection-type => tls,auth => SHA512,remote => xxxxxxxxxx:1194,cipher => AES-256-CBC,comp-lzo => yes,cert-pass-flags => 0,dev-type => tun,remote-cert-tls => server,ca => /root/.cert/nm-openvpn/home-ca.pem,dev => tun,key => /root/.cert/nm-openvpn/home-key.pem,cert => /root/.cert/nm-openvpn/home-cert.pem,ta => /root/.cert/nm-openvpn/home-tls-auth.pem }]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -     service-type=[org.freedesktop.NetworkManager.openvpn]
[2018-08-24 19:51:32,372]-[pool-3-thread-1] INFO  networkmanager.MFDBusBridge -  end of connection /org/freedesktop/NetworkManager/Settings/2 *************************

Leads to org.freedesktop.dbus.exceptions.DBusExecutionException: Device not found

even tough the NetworkManager.xml clarifies that i have to have a valid connection path,the second object is ignored for vpn and the last one should be the base active connection

 <!--
        ActivateConnection:
        @connection: The connection to activate. If "/" is given, a valid device path must be given, and NetworkManager picks the best connection to activate for the given device. VPN connections must always pass a valid connection path.
        @device: The object path of device to be activated for physical connections. This parameter is ignored for VPN connections, because the specific_object (if provided) specifies the device to use.
        @specific_object: The path of a connection-type-specific object this activation should use. This parameter is currently ignored for wired and mobile broadband connections, and the value of "/" should be used (ie, no specific object). For WiFi connections, pass the object path of a specific AP from the card's scan list, or "/" to pick an AP automatically. For VPN connections, pass the object path of an ActiveConnection object that should serve as the "base" connection (to which the VPN connections lifetime will be tied), or pass "/" and NM will automatically use the current default device.
        @active_connection: The path of the active connection object representing this active connection.

        Activate a connection using the supplied device.
    -->

my parameters:

[2018-08-24 20:00:59,762]-[netty task-4-2] INFO  MFDBusBridge - found connection=/org/freedesktop/NetworkManager/Settings/2
[2018-08-24 20:00:59,763]-[netty task-4-2] INFO  MFDBusBridge - found active connection=/org/freedesktop/NetworkManager/ActiveConnection/3

only to clarify

Greets Martin

hypfvieh commented 6 years ago

No I can't and I won't help any longer. I don't have the correct setup to do so - and anyways, this is not an issue of dbus-java but of understanding how DBus and dbus-java works.

For example, your issue with deleting connections. I don't know how you structured your code, but for me it looks like you were using the wrong interface. NetworkManager has:

org.freedesktop.NetworkManager.Settings and org.freedesktop.NetworkManager.Settings.Connection

The first one only has some properties and signals, and does not know any 'Delete' call. The second one does. From your source it looks like you were using the first interface, which is wrong.

Also you should really improve your code style. Reading your source, without reformatting is really a pain.

There are missing generics, missing spaces. You are not using the diamond operator where possible (which will shorten some calls). Using 'if' statements in one line is not really good style if the line gets too long. Also some collection usages should be improved by using containsKey()/contains() instead of get() == null. Your indenting-style is also somehow weird.

I'll close this ticket - there is no bug. This is a issue tracker and not a 'how do I achieve this, I need copy&paste code'-stackoverflow-board.