0

我在编译以下代码时遇到错误,关键是我知道 nl_socket_alloc 的声明存在一些错误,但我看不出我到底在哪里搞砸了。

当我初始化 .cpp 中的套接字时,编译器会抱怨,所以我猜测它们可能被错误地声明了。

提前致谢

#include "ibrcommon/net/NetLink3Manager.h"
#include "ibrcommon/net/vsocket.h"
#include "ibrcommon/Logger.h"

#include <netlink/netlink.h>
#include <netlink/route/link.h>
#include <netlink/route/addr.h>
#include <netlink/route/rtnl.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
//#include <net/if.h>
#include <string.h>

namespace ibrcommon
{
    static int nl3_callback(struct nl_msg *msg, void *arg)
    {
        NetLink3Manager *m = static_cast<NetLink3Manager *>(arg);
        NetLink3ManagerEvent evt(msg);
        m->callback(evt);
        return 0;
    }

    void add_addr_to_list(struct nl_object *obj, void *data)
    {
        char buf[INET6_ADDRSTRLEN+5];
        std::list<vaddress> *list = static_cast<std::list<vaddress>*>(data);

        struct nl_addr *naddr = rtnl_addr_get_local((struct rtnl_addr *) obj);
        int ifindex = 0;
        int scope = rtnl_addr_get_scope((struct rtnl_addr *) obj);

        if (scope == rtnl_str2scope("link"))
            ifindex = rtnl_addr_get_ifindex((struct rtnl_addr *) obj);

        if (naddr)
        {
            int family = nl_addr_get_family(naddr);
            nl_addr2str( naddr, buf, sizeof( buf ) );
            vaddress vaddr(vaddress::Family(family), vaddress::strip_netmask(std::string(buf)), ifindex, false);
            list->push_back( vaddr );
        }

        struct nl_addr *baddr = rtnl_addr_get_broadcast((struct rtnl_addr *) obj);

        if (baddr)
        {
            int family = nl_addr_get_family(baddr);
            nl_addr2str( baddr, buf, sizeof( buf ) );
            vaddress vaddr(vaddress::Family(family), vaddress::strip_netmask(std::string(buf)), ifindex, true);
            list->push_back( vaddr );
        }
    }

    NetLink3Manager::NetLink3Manager()
     : _refresh_cache(false), _running(true), _sock(NULL)
    {
        // initialize the sockets
        _nl_notify_sock = nl_socket_alloc();//=>First error
        _nl_query_sock = nl_socket_alloc();//=>Second error

        // disable seq check for notify socket
        nl_socket_disable_seq_check(_nl_notify_sock);

        // define callback method
        nl_socket_modify_cb(_nl_notify_sock, NL_CB_VALID, NL_CB_CUSTOM, nl3_callback, this);

        // connect to routing netlink protocol
        nl_connect(_nl_notify_sock, NETLINK_ROUTE);
        nl_connect(_nl_query_sock, NETLINK_ROUTE);

        // init route messages
        nl_socket_add_memberships(_nl_notify_sock, RTNLGRP_IPV4_IFADDR);

//      IPv6 requires further support in the parsing procedures!
//      nl_socket_add_membership(_nl_notify_sock, RTNLGRP_IPV6_IFADDR);
        nl_socket_add_memberships(_nl_notify_sock, RTNLGRP_LINK);

        // create a cache for the links
        if (rtnl_link_alloc_cache(_nl_query_sock, AF_UNSPEC, &_link_cache) < 0)
        {
            nl_socket_free(_nl_notify_sock);
            nl_socket_free(_nl_query_sock);
            // error
            throw ibrcommon::vsocket_exception("netlink cache allocation failed");
        }

        // create a cache for addresses
        if (rtnl_addr_alloc_cache(_nl_query_sock, &_addr_cache) < 0)
        {
            nl_socket_free(_nl_notify_sock);
            nl_socket_free(_nl_query_sock);
            // error
            nl_cache_free(_link_cache);
            _link_cache = NULL;
            throw ibrcommon::vsocket_exception("netlink cache allocation failed");
        }

        // create a new socket for the netlink interface
        _sock = new ibrcommon::vsocket();
    }

    NetLink3Manager::~NetLink3Manager()
    {
        stop();
        join();

        // destroy the socket for the netlink interface
        delete _sock;

        nl_cache_free(_addr_cache);
        nl_cache_free(_link_cache);

        nl_socket_free(_nl_notify_sock);
        nl_socket_free(_nl_query_sock);
    }

    const std::string NetLink3Manager::getInterface(int index) const
    {
        char buf[256];
        rtnl_link_i2name(_link_cache, index, (char*)&buf, sizeof buf);
        return std::string((char*)&buf);
    }

    const std::list<vaddress> NetLink3Manager::getAddressList(const vinterface &iface, const vaddress::Family f)
    {
        ibrcommon::MutexLock l(_call_mutex);

        if (_refresh_cache)
        {
            nl_cache_free(_addr_cache);
            nl_cache_free(_link_cache);

            // create a cache for the links
            if (rtnl_link_alloc_cache(_nl_query_sock, AF_UNSPEC, &_link_cache) < 0)
            {
                // error
                throw ibrcommon::vsocket_exception("netlink cache allocation failed");
            }

            // create a cache for addresses
            if (rtnl_addr_alloc_cache(_nl_query_sock, &_addr_cache) < 0)
            {
                // error
                nl_cache_free(_link_cache);
                _link_cache = NULL;
                throw ibrcommon::vsocket_exception("netlink cache allocation failed");
            }

            // mark the cache as refreshed
            _refresh_cache = false;
        }

        std::list<vaddress> addresses;

        struct rtnl_addr *filter = rtnl_addr_alloc();
        const std::string i = iface.toString();
        rtnl_addr_set_ifindex(filter, rtnl_link_name2i(_link_cache, i.c_str()));

        if (f == vaddress::VADDRESS_UNSPEC)
        {
            rtnl_addr_set_family(filter, AF_INET6);
            nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
                                    add_addr_to_list, &addresses);

            rtnl_addr_set_family(filter, AF_INET);
            nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
                                    add_addr_to_list, &addresses);
        }
        else
        {
            rtnl_addr_set_family(filter, f);
            nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
                                    add_addr_to_list, &addresses);
        }

        rtnl_addr_put(filter);

        return addresses;
    }

    void NetLink3Manager::callback(const NetLink3ManagerEvent &lme)
    {
        // ignore if the event is unknown
        if (lme.getType() == LinkManagerEvent::EVENT_UNKOWN) return;

        // ignore if this is an wireless extension event
        if (lme.isWirelessExtension()) return;

        // need to refresh the cache
        {
            ibrcommon::MutexLock l(_call_mutex);
            _refresh_cache = true;
        }

        // print out some debugging
        IBRCOMMON_LOGGER_DEBUG(10) << lme.toString() << IBRCOMMON_LOGGER_ENDL;

        // notify all subscribers about this event
        raiseEvent(lme);
    }

    void NetLink3Manager::run()
    {
        // add netlink fd to vsocket
        _sock->add(nl_socket_get_fd(_nl_notify_sock));

        try {
            while (_running)
            {
                std::list<int> fds;
                _sock->select(fds, NULL);

                nl_recvmsgs_default(_nl_notify_sock);
            }
        } catch (const vsocket_exception&) {
            // stopped / interrupted
            IBRCOMMON_LOGGER(error) << "NetLink connection stopped" << IBRCOMMON_LOGGER_ENDL;
        }
    }

    void NetLink3Manager::__cancellation()
    {
        _running = false;
        _sock->close();
    }

    /** read a netlink message from the socket and create a new netlink event object **/
    NetLink3ManagerEvent::NetLink3ManagerEvent(struct nl_msg *msg)
     : _type(EVENT_UNKOWN), _state(0), _wireless(false)
    {
        int attrlen, nlmsg_len, rta_len, rtl;
        struct rtattr *attr;
        struct rtattr *rth;
        struct ifaddrmsg *ifa;
        struct ifinfomsg *ifi;
        struct nlmsghdr *nlh;

        // cast netlink message
        nlh = nlmsg_hdr(msg);

        switch (nlh->nlmsg_type)
        {
            case RTM_BASE:
            {
                ifi = (struct ifinfomsg *) NLMSG_DATA(nlh);

                nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
                attrlen = nlh->nlmsg_len - nlmsg_len;

                if (attrlen < 0) break;

                attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);

                rta_len = RTA_ALIGN(sizeof(struct rtattr));
                while (RTA_OK(attr, attrlen))
                {
                    size_t rta_length = RTA_PAYLOAD(attr);

                    switch (attr->rta_type)
                    {
                    case IFLA_IFNAME:
                        _interface = ibrcommon::vinterface( std::string((char*)RTA_DATA(attr), rta_length) );
                        _type = EVENT_LINK_STATE;
                        break;

                    case IFLA_OPERSTATE:
                    {
                        char s;
                        ::memcpy(&s, (char*)RTA_DATA(attr), 1);
                        _state = s;
                        break;
                    }

                    case IFLA_WIRELESS:
                        _wireless = true;
                        break;

                    default:
                        _attributes[attr->rta_type] = std::string((char*)RTA_DATA(attr), rta_length);
                        break;
                    }

                    attr = RTA_NEXT(attr, attrlen);
                }
                break;
            }

            case RTM_NEWADDR:
            {
                ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
                rth = IFA_RTA(ifa);
                rtl = IFA_PAYLOAD(nlh);

                // parse all attributes
                while (rtl && RTA_OK(rth, rtl))
                {
                    switch (rth->rta_type)
                    {
                        // local address
                        case IFA_LOCAL:
                        {
                            char address[256];

                            uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
                            sprintf(address, "%d.%d.%d.%d", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);

                            _address = ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, std::string(address));
                            _type = EVENT_ADDRESS_ADDED;
                            break;
                        }

                        // interface name
                        case IFA_LABEL:
                        {
                            //char name[IFNAMSIZ];
                            char *name = (char *)RTA_DATA(rth);
                            _interface = ibrcommon::vinterface(name);
                            break;
                        }
                    }
                    rth = RTA_NEXT(rth, rtl);
                }
                break;
            }

            case RTM_DELADDR:
            {
                ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
                rth = IFA_RTA(ifa);
                rtl = IFA_PAYLOAD(nlh);

                // parse all attributes
                while (rtl && RTA_OK(rth, rtl))
                {
                    switch (rth->rta_type)
                    {
                        // local address
                        case IFA_LOCAL:
                        {
                            char address[256];

                            uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
                            sprintf(address, "%d.%d.%d.%d", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);

                            _address = ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, std::string(address));
                            _type = EVENT_ADDRESS_REMOVED;
                            break;
                        }

                        // interface name
                        case IFA_LABEL:
                        {
                            //char name[IFNAMSIZ];
                            char *name = (char *)RTA_DATA(rth);
                            _interface = ibrcommon::vinterface(name);
                            break;
                        }
                    }
                    rth = RTA_NEXT(rth, rtl);
                }
                break;
            }

            default:
                IBRCOMMON_LOGGER_DEBUG(10) << "unknown netlink type received: " << nlh->nlmsg_type << IBRCOMMON_LOGGER_ENDL;
                break;
        }
    }

    NetLink3ManagerEvent::~NetLink3ManagerEvent()
    {
    }

    const ibrcommon::vinterface& NetLink3ManagerEvent::getInterface() const
    {
        return _interface;
    }

    const ibrcommon::vaddress& NetLink3ManagerEvent::getAddress() const
    {
        return _address;
    }

    unsigned int NetLink3ManagerEvent::getState() const
    {
        return _state;
    }

    bool NetLink3ManagerEvent::isWirelessExtension() const
    {
        return _wireless;
    }

    LinkManagerEvent::EventType NetLink3ManagerEvent::getType() const
    {
        return _type;
    }

    const std::string NetLink3ManagerEvent::toString() const
    {
        std::stringstream ss;
        ss << "NetLinkManagerEvent on " << getInterface().toString() << "; Type: " << getType();

        switch (getType())
        {
        case EVENT_LINK_STATE:
            ss << "; State: " << getState();
            break;

        case EVENT_ADDRESS_ADDED:
            ss << "; Address added: " << getAddress().toString();
            break;

        case EVENT_ADDRESS_REMOVED:
            ss << "; Address removed: " << getAddress().toString();
            break;

        default:
            break;
        };

        return ss.str();
    }

    void NetLink3ManagerEvent::debug() const
    {
//      for (std::map<int, std::string>::const_iterator iter = attr.begin(); iter != attr.end(); iter++)
//      {
//          std::stringstream ss;
//          const std::string &value = (*iter).second;
//
//          for (std::string::const_iterator si = value.begin(); si != value.end(); si++)
//          {
//              const char &c = (*si);
//              ss << std::hex << "0x" << (int)c << " ";
//          }
//
//          IBRCOMMON_LOGGER_DEBUG(10) << (*iter).first << ": " << ss.str() << IBRCOMMON_LOGGER_ENDL;
//      }
    }
} /* namespace ibrcommon */

日食输出:

./ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:66:37: error: ‘nl_socket_alloc’ was not declared in this scope
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:70:46: error: ‘nl_socket_disable_seq_check’ was not declared in this scope
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:73:85: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘int nl_socket_modify_cb(nl_handle*, nl_cb_type, nl_cb_kind, nl_recvmsg_msg_cb_t, void*)’
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:76:44: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘int nl_connect(nl_handle*, int)’
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:77:43: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘int nl_connect(nl_handle*, int)’
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:80:65: error: ‘nl_socket_add_memberships’ was not declared in this scope
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:87:68: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘nl_cache* rtnl_link_alloc_cache(nl_handle*)’
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:89:34: error: ‘nl_socket_free’ was not declared in this scope
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:96:57: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘nl_cache* rtnl_addr_alloc_cache(nl_handle*)’
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:98:34: error: ‘nl_socket_free’ was not declared in this scope
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp: In destructor ‘virtual ibrcommon::NetLink3Manager::~NetLink3Manager()’:
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:121:33: error: ‘nl_socket_free’ was not declared in this scope
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp: In member function ‘virtual const std::list<ibrcommon::vaddress> ibrcommon::NetLink3Manager::getAddressList(const ibrcommon::vinterface&, ibrcommon::vaddress::Family)’:
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:142:69: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘nl_cache* rtnl_link_alloc_cache(nl_handle*)’
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:149:58: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘nl_cache* rtnl_addr_alloc_cache(nl_handle*)’
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp: In member function ‘virtual void ibrcommon::NetLink3Manager::run()’:
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:213:46: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘int nl_socket_get_fd(nl_handle*)’
../ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.cpp:221:40: error: cannot convert ‘ibrcommon::nl_sock*’ to ‘nl_handle*’ for argument ‘1’ to ‘int nl_recvmsgs_default(nl_handle*)’
make: *** [ibrcommon-0.8.0/ibrcommon/net/NetLink3Manager.o] Error 1

那里有函数 NetLink3Manager.h 的标题

#ifndef NETLINK3MANAGER_H_
#define NETLINK3MANAGER_H_

#include "ibrcommon/net/LinkManager.h"
#include "ibrcommon/thread/Mutex.h"
#include "ibrcommon/thread/Thread.h"
#include "ibrcommon/net/vsocket.h"

#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/route/link.h>
#include <netlink/msg.h>

namespace ibrcommon
{
    class NetLink3ManagerEvent : public LinkManagerEvent
    {
    public:
        NetLink3ManagerEvent(struct nl_msg *msg);
        virtual ~NetLink3ManagerEvent();

        virtual const ibrcommon::vinterface& getInterface() const;
        virtual const ibrcommon::vaddress& getAddress() const;
        virtual unsigned int getState() const;
        virtual EventType getType() const;

        virtual bool isWirelessExtension() const;

        void debug() const;
        const std::string toString() const;

    private:
        EventType _type;
        unsigned int _state;
        bool _wireless;
        ibrcommon::vinterface _interface;
        ibrcommon::vaddress _address;
        std::map<int, std::string> _attributes;
    };

    class NetLink3Manager : public ibrcommon::LinkManager, public ibrcommon::JoinableThread
    {
        friend class LinkManager;

    public:
        virtual ~NetLink3Manager();

        const std::string getInterface(int index) const;
        const std::list<vaddress> getAddressList(const vinterface &iface, const vaddress::Family f);

        class parse_exception : public Exception
        {
        public:
            parse_exception(string error) : Exception(error)
            {};
        };

        void callback(const NetLink3ManagerEvent &evt);

    protected:
        void run();
        void __cancellation();

    private:
        NetLink3Manager();

        struct nl_sock *_nl_notify_sock;
        struct nl_sock *_nl_query_sock;

        // local link cache
        struct nl_cache *_link_cache;
        struct nl_cache *_addr_cache;

        // mutex for the link cache
        ibrcommon::Mutex _call_mutex;

        bool _refresh_cache;
        bool _running;

        ibrcommon::vsocket *_sock;
    };
} /* namespace ibrcommon */
#endif /* NETLINK3MANAGER_H_ */
4

2 回答 2

1

不知何故死灵 - 但我只是偶然发现了同样的问题 - 所以也许这可以帮助某人。

首先:您需要安装 libnetlink 开发头文件。在我古老的 Debian 8 盒子上

> sudo apt-get install libnl-3-dev

成功了。

netlink 库的文档包含有关库结构的部分。在这一部分中,您可以找到有关所需标头以及如何链接到库的所有信息。它基本上归结为包括netlink/netlink.h。但有时(如在我的 Debian 机器上)安装了 devel 包,但包含头文件的目录不是默认搜索路径的一部分。您可以在整个文件系统上运行 find 以查找 netlink.h - 这可能会给您一个错误的方向(当然 - 如果您使用 find 挖掘某些内容,您总是会检查两次以包含正确的文件)。但是有一种更系统的方法可用......

如果您使用 Debian 打包系统运行一个盒子,您可以检查安装了哪些 netlink 库:

> dpkg --list libnl*
...
ii  libnl-3-200:amd64               3.2.24-2             amd64                library for dealing with netlink sockets
ii  libnl-3-dev                     3.2.24-2             amd64                development library and headers for libnl-3
un  libnl-dev                       <none>               <none>               (no description available)
ii  libnl-genl-3-200:amd64          3.2.24-2             amd64                library for dealing with netlink sockets - generic netlink
ii  libnl-route-3-200:amd64         3.2.24-2             amd64                library for dealing with netlink sockets - route interface
un  libnl2-dev                      <none>               <none>               (no description available)
un  libnl3-dev                      <none>               <none>               (no description available)

ii 开头的那些是相关的。现在使用 dpkg 获取软件包提供的文件列表(并过滤所需的文件):

> dpkg  -L  libnl-3-dev | grep  "netlink\.h"

/usr/include/libnl3/netlink/netlink.h

由于/usr/include/是默认包含路径的一部分(您可以使用此处给出的答案检查 gcc 使用的路径),您需要将前缀libnl3添加到包含语句中。为了避免在库版本更改时更改包含,只需将/usr/include/libnl3添加到包含路径即可。对于 gcc,这可以使用标志来完成

-I /usr/include/libnl3

对于基于 cmake 的构建系统,只需添加一个include_diretories()指令:

include_directories("/usr/include/libnl3")
于 2017-07-07T11:19:37.393 回答
0

从第一个错误开始,然后一路向下。首先,nl_socket_alloc()您是否在任何头文件中声明了该函数#include?找出这一点的方法是通过这些头文件(它们将在您的系统上的某个位置)进行 grep,查找该符号,并确保您找到它的文件是显式的#include-ed。

将此策略应用于其他缺失的符号。

如果您已包含该文件,则该函数nl_socket_alloc可能会在全局命名空间中声明,在这种情况下,您可以选择将其称为::nl_socket_alloc(因为您要定义一个非全局命名空间。

希望这些建议能为您指明正确的方向。

于 2013-04-11T19:46:27.497 回答