Linux下根据网卡vid和pid查找网卡ip地址

#ifndef ETC_UTIL_H
#define ETC_UTIL_H

#include <string>
#include <memory>

namespace maxhub {

class EthUtil {
public:
    explicit EthUtil();
    ~EthUtil();

public:
    std::string GetIpv4ByVidPid(const std::string& vid,const std::string& pid);

private:
    class EthUtilImpl;
    std::unique_ptr<EthUtilImpl> pimpl_;
};

} //namespace maxhub


#endif // ETC_UTIL_H

#include "ethutillearn.h"
#include <cstdint>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <utility>
#include <net/if.h>
#include <sys/ioctl.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <libgen.h>
#include <algorithm>

namespace maxhub {

namespace  {
    const std::uint8_t kMaxRecursivecount = 9;
    const std::string kPciDirPath = "/sys/devices/pci0000:00";
}

class EthUtil::EthUtilImpl {
public:
    EthUtilImpl() : recursive_count_(0) {}

public:
    std::string GetIpv4(const std::string& vid_pid) {
        Refresh();
        if(eth_infos_.size() == 0) {
            return "";
        }

        for (auto eth : eth_infos_) {
            if(eth.eth_vid_pid == vid_pid) {
                return eth.eth_ipv4;
            }
        }
        return "";
    }

    std::string GetMacAddress(const std::string& vid_pid) {
        Refresh();
        if(eth_infos_.size() == 0) {
            return "";
        }

        for (auto eth : eth_infos_) {
            if(eth.eth_vid_pid == vid_pid) {
                return eth.eth_mac;
            }
        }
        return "";
    }

    std::string GetIpFromNetName(const std::string& net_name) {
        Refresh();
        if(eth_infos_.size() == 0) {
            return "";
        }

        for (auto eth : eth_infos_) {
            if(eth.eth_name == net_name) {
                return eth.eth_ipv4;
            }
        }
        return "";
    }

    std::string GetNetNameFromVidPid(const std::string& vid_pid) {
        Refresh();
        if(eth_infos_.size() == 0) {
            return "";
        }

        for (auto eth : eth_infos_) {
            if(eth.eth_vid_pid == vid_pid) {
                return eth.eth_name;
            }
        }
        return "";
    }

private:
    struct EthInfo{
        std::string eth_name;
        std::string eth_mac;
        std::string eth_vid_pid;
        std::string eth_ipv4;
        std::string eth_ipv6;
    };

private:
    void Refresh() {
        eth_infos_.clear();

        TraversingFileList(kPciDirPath);
        TraversingNet();
    }

    bool CheckDir(const std::string &path) {
        if((access(path.c_str(),F_OK)) == -1) {
            return false;
        }

        struct stat info;
        if(stat(path.c_str(), &info) != 0) {
            return false;
        }
        if(!S_ISDIR(info.st_mode)) {
            return false;
        }
        return true;
    }

    std::string GetNetPath(const std::string &source_path) {
        if(!CheckDir(source_path)) {
            return "";
        }

        std::string tmp;
        std::shared_ptr<char> path_tmp;
        auto dir_paths = GetAllDir(source_path);
        for (auto path : dir_paths) {
            path_tmp.reset(new char[path.length()+1]);
            std::strcpy(path_tmp.get(),path.c_str());
            tmp = basename(path_tmp.get());
            if(tmp == "net") {
                return source_path;
            }
        }

        std::string temp_path;
        std::vector<std::string> paths_tmp(10);
        while(dir_paths.size() != 0) {
            temp_path = dir_paths.back();
            dir_paths.pop_back();

            auto count = std::count(temp_path.begin(),temp_path.end(),'/');
            if(count > kMaxRecursivecount) {
                continue; //digui xianzhi
            }
            paths_tmp = GetAllDir(temp_path);

            for (auto path : paths_tmp) {
                path_tmp.reset(new char[path.length()+1]);
                std::strcpy(path_tmp.get(),path.c_str());
                tmp = basename(path_tmp.get());
                if(tmp == "net") {
                    return temp_path;
                } else {
                    dir_paths.insert(dir_paths.begin(),path);
                }
            }
        }

        return "";
    }

    std::vector<std::string> GetAllDir(const std::string &dir_path) {
        std::vector<std::string> dir_paths;
        if(!CheckDir(dir_path)) {
            return dir_paths;
        }

        DIR *dir;
        if ((dir=opendir(dir_path.c_str())) == nullptr) {
            return dir_paths;
        }

        std::string temp_path;
        struct dirent *ptr;
        while ((ptr=readdir(dir)) != nullptr) {
            if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) {
                continue;
            } else if(ptr->d_type == 4) {
                temp_path = dir_path + "/" + ptr->d_name;
                dir_paths.push_back(temp_path);
            }
        }
        closedir(dir);
        return dir_paths;
    }

    void TraversingFileList(const std::string &path) {
        DIR *dir;
        struct dirent *ptr;
        std::string temp_path;
        std::string vendor;
        std::string device_id;
        std::string net_path;
        std::string net_name;
        std::string vid_pid;
        std::string mac_address;
        EthInfo eth_info_tmp;

        if ((dir=opendir(path.c_str())) == nullptr) {
            return;
        }
        while ((ptr=readdir(dir)) != nullptr) {
            if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) { //current dir OR parrent dir
                continue;
            } else if (ptr->d_type == 4) {
                temp_path = path + "/" + ptr->d_name;
                recursive_count_ = 0;
                net_path = GetNetPath(temp_path);
                if(!net_path.empty()) {
                    vendor = GetVender(net_path);
                    device_id = GetDeviceId(net_path);
                    net_name = GetNetNameFromNetPath(net_path);
                    vid_pid = vendor+":"+device_id;
                    mac_address = GetMacAddressFromEthpath(net_path+"/net/"+net_name);
                    eth_info_tmp.eth_name = net_name;
                    eth_info_tmp.eth_vid_pid = vid_pid;
                    eth_info_tmp.eth_mac = mac_address;
                    eth_infos_.push_back(eth_info_tmp);
                }
            }
        }
        closedir(dir);
    }

    std::string ReadVendorOrDevice(const std::string &file_path) {
        if((access(file_path.c_str(),F_OK))==-1) {
            return "";
        }

        std::string str_result = "";
        FILE *fd = fopen(file_path.c_str(),"r");
        char result[256];
        memset(result,'\0',sizeof(result));

        if(fgets(result,256,fd)) {
           str_result.append(result,strlen(result)-1); //remove '/n'
           if(str_result[0] == '0' && str_result[1] == 'x') {
               str_result = str_result.substr(2);
           }
        }
        fclose(fd);
        return str_result;
    }

    std::string GetVender(const std::string &net_path) {
        if(net_path.empty()) {
            return "";
        }

        std::string vender_path = net_path+"/vendor";
        std::shared_ptr<char> path_tmp;
        if((access(vender_path.c_str(),F_OK))==-1) {
            path_tmp.reset(new char[net_path.length()+1]);
            std::strcpy(path_tmp.get(),net_path.c_str());
            std::string net_parent_dir_name = dirname(path_tmp.get());
            vender_path = net_parent_dir_name + "/idVendor";
        }
        return ReadVendorOrDevice(vender_path);
    }

    std::string GetDeviceId(const std::string &net_path) {
        if(net_path.empty()) {
            return "";
        }

        std::string device_path = net_path+"/device";
        std::shared_ptr<char> path_tmp;
        if((access(device_path.c_str(),F_OK))==-1) {
            path_tmp.reset(new char[net_path.length()+1]);
            std::strcpy(path_tmp.get(),net_path.c_str());
            std::string net_parent_dir_name = dirname(path_tmp.get());
            device_path = net_parent_dir_name + "/idProduct";
        }
        return ReadVendorOrDevice(device_path);
    }

    std::string GetNetNameFromNetPath(const std::string &net_path) {
        DIR *dir;
        struct dirent *ptr;
        std::string net_name;
        std::string net_dir = net_path + "/net";
        if ((dir=opendir(net_dir.c_str())) == nullptr) {
            return "";
        }

        while ((ptr=readdir(dir)) != nullptr) {

            if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) { //current dir OR parrent dir
                continue;
            } else if (ptr->d_type == 4) {
                net_name = ptr->d_name;
                break;
            }
        }
        closedir(dir);
        return net_name;
    }

    std::string GetMacAddressFromEthpath(const std::string &eth_path) {
        if(eth_path.empty()) {
            return "";
        }

        std::string address_path = eth_path+"/address";
        std::string str_address;
        if((access(address_path.c_str(),F_OK))!=-1) {
             FILE *fd = fopen(address_path.c_str(),"r");

             char result[256];
             memset(result,'\0',sizeof(result));

             if(fgets(result,256,fd)) {
                str_address.append(result,strlen(result)-1);
             }
             fclose(fd);
        }

        return str_address;
    }

    void TraversingNet() {
        struct ifaddrs * ifAddrStruct = nullptr;
        void * tmpAddrPtr = nullptr;

        getifaddrs(&ifAddrStruct);

        std::string str_mac;
        std::string net_name;
        std::string str_ipAddress;
        char addressBuffer[INET6_ADDRSTRLEN];
        EthInfo *eth_info = nullptr;
        while (ifAddrStruct != nullptr) {
            net_name = ifAddrStruct->ifa_name;
            str_mac = GetMacFromNetName(ifAddrStruct->ifa_name);
            eth_info = GetEthData(str_mac);
            if(!eth_info) {
                continue;
            }
            eth_info->eth_name = net_name;
            if(ifAddrStruct->ifa_addr->sa_family==AF_INET) { // check it is IP4
                // is a valid IP4 Address
                tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
                inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
                eth_info->eth_ipv4 = addressBuffer;
            } else if (ifAddrStruct->ifa_addr->sa_family==AF_INET6) { // check it is IP6
                // is a valid IP6 Address
                tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
                inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
                eth_info->eth_ipv6 = addressBuffer;
            }
            ifAddrStruct=ifAddrStruct->ifa_next;
        }
    }

    std::string GetMacFromNetName(std::string net_name) {
        int sock_mac;
        struct ifreq ifr_mac;
        char mac_addr[30];

        sock_mac = socket( AF_INET, SOCK_STREAM, 0 );
        if( sock_mac == -1)
        {
            return "";
        }

        memset(&ifr_mac,'\0',sizeof(ifr_mac));
        strncpy(ifr_mac.ifr_name, net_name.c_str(), sizeof(ifr_mac.ifr_name)-1);

        if((ioctl( sock_mac, SIOCGIFHWADDR, &ifr_mac)) < 0)
        {
            return "";
        }

        sprintf(mac_addr,"%02x:%02x:%02x:%02x:%02x:%02x",
               static_cast<unsigned char>(ifr_mac.ifr_hwaddr.sa_data[0]),
               static_cast<unsigned char>(ifr_mac.ifr_hwaddr.sa_data[1]),
               static_cast<unsigned char>(ifr_mac.ifr_hwaddr.sa_data[2]),
               static_cast<unsigned char>(ifr_mac.ifr_hwaddr.sa_data[3]),
               static_cast<unsigned char>(ifr_mac.ifr_hwaddr.sa_data[4]),
               static_cast<unsigned char>(ifr_mac.ifr_hwaddr.sa_data[5]));

        close( sock_mac );
        std::string str_mac(mac_addr,strlen(mac_addr));
        return mac_addr;
    }

    EthInfo *GetEthData(std::string str_mac) {
        EthInfo *info = nullptr;
        std::vector<EthInfo>::iterator iter;
        for (iter = eth_infos_.begin();iter != eth_infos_.end(); ++iter) {
            if(iter->eth_mac == str_mac) {
                info = iter.base();
                return info;
            }
        }

        EthInfo eth_info;
        if(iter == eth_infos_.end()) {
            eth_info.eth_mac = str_mac;
        }
        eth_infos_.push_back(eth_info);
        return GetEthData(str_mac);
    }
private:
    std::vector<EthInfo> eth_infos_;
    std::uint16_t recursive_count_;
};

EthUtil::EthUtil() {
    pimpl_.reset(new EthUtilImpl());
}

EthUtil::~EthUtil() = default;

std::string EthUtil::GetIpv4ByVidPid(const std::string &vid, const std::string &pid) {
    return pimpl_->GetIpv4(vid + ":" + pid);
}

} //namespace maxhub
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值