#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 ð_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
Linux下根据网卡vid和pid查找网卡ip地址
最新推荐文章于 2021-06-06 00:04:10 发布