使用 dbus-cpp 列出 WPA 请求者网络属性

Posted

技术标签:

【中文标题】使用 dbus-cpp 列出 WPA 请求者网络属性【英文标题】:List WPA supplicant network properties using dbus-cpp 【发布时间】:2017-10-15 15:55:06 【问题描述】:

当尝试列出网络属性 - https://w1.fi/wpa_supplicant/devel/dbus.html#dbus_network 使用 dbus-cpp 时,我收到了一些关于缺少 operator== for core::dbus::types::Variant 的错误

/usr/include/core/dbus/impl/object.h:185:17:   required from ‘std::shared_ptr<core::dbus::Property<PropertyDescription> > core::dbus::Object::get_property() [with PropertyDescription = fi::w1::wpa_supplicant1::Network::Properties::Propertiez]’ /home/martin/ClionProjects/ang-wifi-controller/src/wpasupplicantclient.cpp:149:118:   required from here /usr/include/c++/6/bits/stl_pair.h:364:51: error: no match for ‘operator==’ (operand types are ‘const core::dbus::types::Variant’ and ‘const core::dbus::types::Variant’)
  return __x.first == __y.first && __x.second == __y.second; 

我的代码基于 dbus-cpp 示例和 http://quaintous.com/2015/08/30/cpp11-dbus/,但它们仅提供有限的帮助。 表示Properties属性的代码如下:

namespace fi 
namespace w1 
struct wpa_supplicant1 
struct Network 
    struct Properties 
        struct Propertiez 
            inline static std::string name()  return "Properties"; ;
            typedef Network Interface;
            typedef std::map<std::string, core::dbus::types::Variant> ValueType;
            static const bool readable = true;
            static const bool writable = true;
        ;
    ;
;

.cpp 中的违规行是networkProxy-&gt;get_property&lt;fi::w1::wpa_supplicant1::Network::Properties::Propertiez&gt;();

我发现这个问题已经在https://answers.launchpad.net/ubuntu/+source/dbus-cpp/+question/593271 提出过,但没有人提供任何建议。通过apt-cache rdepends libdbus-cpp5 列出的包代码也没有产生任何结果。 我尝试弄乱ValueType,但这一切都导致了运行时错误,因为预期的结果可能真的是地图。老实说,这对我来说似乎是库中的一个错误,但由于这一定是一个明显的用例,我试图找出我使用库时的错误。那我做错了什么?

编辑:由于我没有收到任何回复,因此我包含了最少的样本。

#include <core/dbus/bus.h>
#include <core/dbus/object.h>
#include <core/dbus/property.h>
#include <core/dbus/service.h>
#include <core/dbus/result.h>
#include <core/dbus/asio/executor.h>
#include <core/dbus/interfaces/properties.h>
#include <core/dbus/types/stl/string.h>
#include <core/dbus/types/stl/tuple.h>
#include <core/dbus/types/stl/vector.h>
#include <core/dbus/types/struct.h>
#include <core/dbus/types/variant.h>

using namespace std::chrono_literals;
using DBusDict = std::map<std::string, core::dbus::types::Variant>;

namespace fi 
namespace w1 
struct wpa_supplicant1

    struct GetInterface 
        typedef wpa_supplicant1 Interface;
        static const std::string &name()
        
            static const std::string s("GetInterface");
            return s;
        
        inline static const std::chrono::milliseconds default_timeout()  return 1s; 
    ;
    struct Iface
    
        struct AddNetwork 
            typedef Iface Interface;
            static const std::string &name()
            
                static const std::string s("AddNetwork");
                return s;
            
            inline static const std::chrono::milliseconds default_timeout()  return 1s; 
        ;
        struct Properties
        
            struct Networks
            
                inline static std::string name()
                 return "Networks"; ;
                typedef Iface Interface;
                typedef std::vector<core::dbus::types::ObjectPath> ValueType;
                static const bool readable = true;
                static const bool writable = false;
            ;
        ;
    ;
    struct Network
    
        struct Properties
        
            struct Propertiez
            
                inline static std::string name()
                 return "Properties"; ;
                typedef Network Interface;
                typedef DBusDict ValueType;
                static const bool readable = true;
                static const bool writable = true;
            ;
        ;
    ;
;
;
;

namespace core 
namespace dbus 
namespace traits 
template <> struct Service<fi::w1::wpa_supplicant1> 
    inline static const std::string &interface_name()
    
        static const std::string s("fi.w1.wpa_supplicant1");
        return s;
    
;

template <> struct Service<fi::w1::wpa_supplicant1::Iface> 
    inline static const std::string &interface_name()
    
        static const std::string s("fi.w1.wpa_supplicant1.Interface");
        return s;
    
;
template <> struct Service<fi::w1::wpa_supplicant1::Network> 
    inline static const std::string &interface_name()
    
        static const std::string s("fi.w1.wpa_supplicant1.Network");
        return s;
    
;




int main()

    //bus
    auto systemBus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::system);
    systemBus->install_executor(core::dbus::asio::make_executor(systemBus));
    auto busThread = std::thread(std::bind(&core::dbus::Bus::run, systemBus));

    //service
    auto wpaService = core::dbus::Service::use_service<fi::w1::wpa_supplicant1>(systemBus);
    auto wpaObjectPath = core::dbus::types::ObjectPath("/fi/w1/wpa_supplicant1");
    auto wpaRootProxy = wpaService->object_for_path(wpaObjectPath);

    //iface
    auto ifacePath = wpaRootProxy->transact_method<fi::w1::wpa_supplicant1::GetInterface,
                                             core::dbus::types::ObjectPath,
                                             std::string>("wlan0"); //change this to your own wireless interface
    auto wpaIfaceProxy = wpaService->object_for_path(ifacePath.value());
    auto networkPaths = wpaIfaceProxy->get_property<fi::w1::wpa_supplicant1::Iface::Properties::Networks>();

    //network
    std::string ssid("network");
    std::string password("password");
    DBusDict args = 
        "ssid", core::dbus::types::Variant::encode(ssid),
        "psk", core::dbus::types::Variant::encode(password),
    ;

    auto networkPath = wpaIfaceProxy->transact_method<fi::w1::wpa_supplicant1::Iface::AddNetwork,
                                                        core::dbus::types::ObjectPath,
                                                        DBusDict>(args);
    auto networkProxy = wpaService->object_for_path(networkPath.value());

    //get properties - uncomment line below to get compiler errors
    //auto netProps = networkProxy->get_property<fi::w1::wpa_supplicant1::Network::Properties::Propertiez>();

    while (true) 
        continue;
    

编译使用:g++ $(pkg-config --cflags dbus-1 dbus-cpp) ./main.cpp $(pkg-config --libs dbus-1 dbus-cpp) -lpthread

【问题讨论】:

+1 提示使用 apt-cache rdepends libdbus-cpp5。我一直在考虑使用这个 d-bus 绑定,但似乎支持很少。我想使用 Introspectable 接口,但那家伙甚至没有开箱即用地编译。 FWIW,我在 Ubuntu 14.04 上工作并尝试过:apt-cache rdepends libdbus-cpp2,它提供了几个服务。我现在正在研究其中的一些来源(例如 libubuntu-location-service-dev)。 【参考方案1】:

更新:

dbus-cpp 实现了 org.freedesktop.DBus.Properties.Get 方法。

获取:

auto resultVariant = dbus_object->invoke_method_synchronously
/*Method*/          <dbus::interfaces::Properties::Get, 
/*Output Type*/      dbus::types::Variant, 
/*Input Types*/      std::string, std::string>
                    ("fi.w1.wpa_supplicant1.Network","Properties").value();
auto props = resultVariant.as<std::map<std::string, dbus::types::Variant>>();

遗憾的是,Set 方法虽然也已实现,但似乎不适用于其中包含嵌套变体的任何 ArgumentType。所以:

asv : std::map&lt;std::string, core::dbus::types::Variant&gt; av : std::vector&lt;core::dbus::types::Variant&gt;

在Set方法调用实际上会导致程序崩溃。 (没有测试更多)



旧帖:

我今天遇到了同样的错误,并找到了至少获取属性值的解决方法。

而不是使用

auto prop = dbus_object->get_property<fi::w1::wpa_supplicant1::Network::Properties::Propertiez>();

试试

//returns std::map<std::string, core::dbus::types::Variant>>
auto props = dbus_object->get_all_properties<fi::w1::wpa_supplicant1::Network>();

auto prop = props["Properties"];
auto prop_value = prop.as<std::map<std::string, core::dbus::types::Variant>>();

据我所知,dbus-cpp 利用 org.freedesktop.DBus.Properties 接口 来读取属性。

因此 dbus_object->get_property() 尝试调用 org.freedesktop.DBus.Properties.Get 并且由于缺少 ==operator 实现而无法编译。 (我猜它需要转换特定的 ValueType)

dbus_object->get_all_properties() 调用不需要特定 ValueType 的 org.freedesktop.DBus.Properties.GetAll,因此它可以工作。


当然,这只是获取属性的一种解决方法,因为设置属性值与获取属性值绑定到相同的 shared_pointer。

【讨论】:

【参考方案2】:

正如 fi.w1.wpa_supplicant1.Network.Properties.Properties 的文档所说:

[...] 所有值都是字符串类型,例如,频率是“2437”,而不是 2437。

所以尝试如下定义 DBusDict:

using DBusDict = std::map<std::string, std::string>;

【讨论】:

这显然是错误的。文档明确指出属性签名是“Properties - asv - (read/write)”。变体的内部无关紧要。我的意思是,它可以编译,但它会在运行时抛出org.freedesktop.DBus.Error.UnknownMethod: Method "Get" with signature "ss" on interface "org.freedesktop.DBus.Properties" doesn't exist

以上是关于使用 dbus-cpp 列出 WPA 请求者网络属性的主要内容,如果未能解决你的问题,请参考以下文章

i.MX6ULL应用移植 | 移植wpa_supplicant到Linux开发板(2.7版本)

i.MX6ULL应用移植 | 移植wpa_supplicant到Linux开发板(2.7版本)

ini 使用带有此.conf文件的wpa_supplicant连接到WPA2企业网络。我用这个连接到我大学的无线网络。

新唐NUC980使用记录:使用wpa_supplicant访问无线网络

如何捕获所有无线网络流量wireshark和wpa2?

linux 无线网络配置工具wpa_supplicant与wireless-tools