GrabBag/Module/EthMonitor/Src/VrEthMonitor.cpp

223 lines
5.2 KiB
C++

#include "VrEthMonitor.h"
#include "IVrUtils.h"
#include <thread>
#ifndef _WIN32
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <asm/types.h>
#include <arpa/inet.h>
#include <linux/route.h>
#include <unistd.h>
#include <linux/if.h>
#include <linux/rtnetlink.h>
#include <stdio.h>
#include <mutex>
#include <ifaddrs.h>
#endif
CVrEthMonitor::CVrEthMonitor()
: m_fNotify(nullptr)
, m_pParam(nullptr)
, m_bRunning(false)
{
}
CVrEthMonitor::~CVrEthMonitor()
{
}
/// @brief
/// 开始监控
/// @return 成功返回TRUE
int CVrEthMonitor::StartMonitor(NetNotify func, void* pParam)
{
m_bRunning = true;
std::thread runMonitor(std::bind(&CVrEthMonitor::_MonitorTask, this));
runMonitor.detach();
m_fNotify = func;
m_pParam = pParam;
return SUCCESS;
}
/// @brief
/// 停止监控
void CVrEthMonitor::StopMonitor()
{
m_bRunning = false;
}
void CVrEthMonitor::_MonitorTask()
{
#ifndef _WIN32
int socket_fd;
int err = 0;
int read_r;
struct sockaddr_nl sa;
struct nlmsghdr *nh;
const int len = 2048;
char buff[len];
// signal(SIGINT, intHandler);
/*打开NetLink Socket*/
socket_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
setsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
/*设定接收类型并绑定Socket*/
bzero(&sa, sizeof(sa));
sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
bind(socket_fd, (struct sockaddr *) &sa, sizeof(sa));
while (m_bRunning)
{
fd_set readFD;
FD_SET(socket_fd, &readFD);
struct timeval waitTime = { 5, 0 };
int nCount = select(socket_fd + 1, &readFD, nullptr, nullptr, &waitTime);
if (nCount > 0)
{
read_r = read(socket_fd, buff, sizeof(buff));
for (nh = (struct nlmsghdr *) buff; NLMSG_OK(nh, read_r); nh = NLMSG_NEXT(nh, read_r))
{
switch (nh->nlmsg_type) {
default:
/*收到些奇怪的信息*/
break;
case NLMSG_DONE:
case NLMSG_ERROR:
break;
case RTM_NEWLINK:
case RTM_DELLINK:
_ifinfomsg(nh);
break;
case RTM_NEWADDR:
case RTM_DELADDR:
_ifaddrmsg(nh);
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
_rtmsg(nh);
break;
}
}
}
}
close(socket_fd);
#endif // !_WIN32
}
/// 解析RTA,并存入tb
void CVrEthMonitor::_parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len)
{
#ifndef _WIN32
for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
if (attr->rta_type <= max) {
tb[attr->rta_type] = attr;
}
}
#endif // !_WIN32
}
///显示连接信息
///当网卡变动的时候触发这个信息,例如插/拔网线,增/减网卡设备,启用/禁用接口等.
void CVrEthMonitor::_ifinfomsg(struct nlmsghdr *nh)
{
#ifndef _WIN32
int len;
struct rtattr *tb[IFLA_MAX + 1];
struct ifinfomsg *ifinfo;
bzero(tb, sizeof(tb));
ifinfo = (ifinfomsg *)NLMSG_DATA(nh);
len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifinfo), len);
//LOG_DEBUG("%s %s: %s \n", (char *)RTA_DATA(tb[IFLA_IFNAME]), (nh->nlmsg_type == RTM_NEWLINK) ? "NEWLINK" : "DELLINK", (ifinfo->ifi_flags & IFF_LOWER_UP) ? "up" : "down");
std::string sName = (char *)RTA_DATA(tb[IFLA_IFNAME]);
if (sName.find("eth") != std::string::npos)
{
if (ifinfo->ifi_flags & IFF_LOWER_UP)
{
m_fNotify(sName, NET_STATUS_UP, m_pParam);
}
else
{
m_fNotify(sName, NET_STATUS_DOWN, m_pParam);
}
}
#endif // !_WIN32
}
///显示地址信息
///当地址变动的时候触发这个信息,例如通过DHCP获取到地址后
void CVrEthMonitor::_ifaddrmsg(struct nlmsghdr *nh)
{
#ifndef _WIN32
int len;
struct rtattr *tb[IFA_MAX + 1];
struct ifaddrmsg *ifaddr;
char tmp[256];
bzero(tb, sizeof(tb));
ifaddr = (ifaddrmsg *)NLMSG_DATA(nh);
len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifaddr));
_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifaddr), len);
if (tb[IFA_LABEL] != NULL && tb[IFA_ADDRESS] != NULL && nh->nlmsg_type == RTM_NEWADDR)
{
inet_ntop(ifaddr->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), tmp, sizeof(tmp));
}
std::string sName = (char *)RTA_DATA(tb[IFLA_IFNAME]);
m_fNotify(sName, NET_STATUS_STATUS_CHANGE, m_pParam);
#endif
}
/**
* 显示路由信息
* 当路由变动的时候触发这个信息
*/
void CVrEthMonitor::_rtmsg(struct nlmsghdr *nh)
{
#ifndef _WIN32
int len;
struct rtattr *tb[RTA_MAX + 1];
struct rtmsg *rt;
char tmp[256];
bzero(tb, sizeof(tb));
rt = (rtmsg *)NLMSG_DATA(nh);
len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*rt));
_parse_rtattr(tb, RTA_MAX, RTM_RTA(rt), len);
if (tb[RTA_DST] != NULL) {
inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_DST]), tmp, sizeof(tmp));
}
if (tb[RTA_SRC] != NULL) {
inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_SRC]), tmp, sizeof(tmp));
}
if (tb[RTA_GATEWAY] != NULL) {
inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), tmp, sizeof(tmp));
if (nh->nlmsg_type == RTM_NEWROUTE) {
m_fNotify("", NET_STATUS_ROUTE_ADD, m_pParam);
} else {
m_fNotify("", NET_STATUS_ROUTE_DEL, m_pParam);
}
//system("ip rule add from all lookup main pref 0");
}
#endif // !_WIN32
}
bool VrCreateEthMonitor(IVrEthMonitor** ppEthMonitor)
{
CVrEthMonitor* pObj = new CVrEthMonitor;
*ppEthMonitor = pObj;
return true;
}