├── images └── API.jpg ├── src ├── decpcap │ ├── compile.sh │ ├── decpcap.h │ ├── pcapTest.cpp │ └── decpcap.cpp ├── logger │ ├── loggerTest.cpp │ └── logger.hpp ├── CMakeLists.txt ├── sourceMonitor.cpp ├── sourceMonitor.hpp ├── netIoMonitorType.hpp ├── netIoMonitor.hpp ├── netIoMonitorPcap.hpp ├── monitorImpl.hpp ├── netIoMonitor.cpp ├── netIoMonitorPcap.cpp └── monitorImpl.cpp ├── CMakeLists.txt ├── example ├── compile.sh └── example.cpp └── README.md /images/API.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzpp3377/SourceMonitor/HEAD/images/API.jpg -------------------------------------------------------------------------------- /src/decpcap/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | g++ -std=c++11 -o pcapTest pcapTest.cpp decpcap.c -lpcap 3 | 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required (VERSION 2.6) 3 | project (sourceMonitor) 4 | ADD_SUBDIRECTORY(src) 5 | -------------------------------------------------------------------------------- /example/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | g++ -std=c++11 -o example example.cpp -lSrcMntr -pthread #compile using dynamic library 3 | #g++ -std=c++11 -o example example.cpp /usr/lib/libSrcMntr.a /usr/lib/x86_64-linux-gnu/libpcap.a -pthread #compile using static library -------------------------------------------------------------------------------- /src/logger/loggerTest.cpp: -------------------------------------------------------------------------------- 1 | #include "logger.hpp" 2 | 3 | // static LogLevel logLevel=LOG_LEVEL_DEBUG; 4 | 5 | int main(){ 6 | log_fatal(logLevel,"log_fatal"); 7 | log_err(logLevel,"log_err"); 8 | log_warn(logLevel,"log_warn"); 9 | log_info(logLevel,"log_info"); 10 | log_debug(logLevel,"log_debug"); 11 | } -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ADD_COMPILE_OPTIONS( -std=c++11 ) 2 | #ADD_COMPILE_OPTIONS( -fPIC ) 3 | SET(LIB_SRCMNTR_SRC sourceMonitor.cpp netIoMonitorPcap.cpp netIoMonitor.cpp monitorImpl.cpp decpcap/decpcap.cpp) 4 | ADD_LIBRARY(SrcMntr SHARED ${LIB_SRCMNTR_SRC}) 5 | ADD_LIBRARY(SrcMntrStatic STATIC ${LIB_SRCMNTR_SRC}) 6 | SET_TARGET_PROPERTIES(SrcMntrStatic PROPERTIES OUTPUT_NAME "SrcMntr") 7 | SET_TARGET_PROPERTIES(SrcMntrStatic PROPERTIES CLEAN_DIRECT_OUTPUT 1) 8 | SET_TARGET_PROPERTIES(SrcMntr PROPERTIES CLEAN_DIRECT_OUTPUT 1) 9 | 10 | LINK_DIRECTORIES("/usr/lib/x86_64-linux-gnu") 11 | TARGET_LINK_LIBRARIES(SrcMntr libpcap.so) 12 | TARGET_LINK_LIBRARIES(SrcMntrStatic libpcap.a) 13 | #ADD_DEFINITIONS(-std=c++11 -fPIC) 14 | 15 | INSTALL(TARGETS SrcMntr SrcMntrStatic 16 | LIBRARY DESTINATION /usr/lib 17 | ARCHIVE DESTINATION /usr/lib 18 | ) 19 | INSTALL(FILES sourceMonitor.hpp DESTINATION /usr/include ) 20 | 21 | SET_TARGET_PROPERTIES(SrcMntr PROPERTIES VERSION 0.1 SOVERSION 0.1) -------------------------------------------------------------------------------- /src/sourceMonitor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * sourceMonitor.cpp 3 | * 4 | * Copyright (c) 2019 Zhang Peng 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | 23 | 24 | #include "sourceMonitor.hpp" 25 | #include "monitorImpl.hpp" 26 | 27 | SourceMonitor::SourceMonitor(){ 28 | monitorImpl=new MonitorImpl(); 29 | } 30 | 31 | SourceMonitor::~SourceMonitor(){ 32 | delete monitorImpl; 33 | } 34 | 35 | bool SourceMonitor::registerStatistic(StatisticT statistic){ 36 | monitorImpl->registerStatistic(statistic); 37 | } 38 | bool SourceMonitor::registerPid(unsigned int pid){ 39 | monitorImpl->registerPid(pid); 40 | } 41 | bool SourceMonitor::init(){ 42 | return monitorImpl->init(); 43 | } 44 | void SourceMonitor::update(){ 45 | monitorImpl->update(); 46 | } 47 | double SourceMonitor::getStatistic(unsigned int pid,StatisticT statistic){ 48 | monitorImpl->getStatistic(pid,statistic); 49 | } 50 | -------------------------------------------------------------------------------- /src/sourceMonitor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * sourceMonitor.hpp 3 | * 4 | * Copyright (c) 2019 Zhang Peng 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | #ifndef SOURCE_MONITOR_HPP 23 | #define SOURCE_MONITOR_HPP 24 | 25 | typedef enum StatisticType{ 26 | CpuRatio=0, 27 | CpuUsrRatio, 28 | CpuSysRatio, 29 | CpuGstRatio, 30 | CpuWaitRatio, 31 | CpuIndex, 32 | 33 | MemRatio=1000, 34 | MemRss, 35 | MemVsz, 36 | MemMinfltRate, 37 | MemMajfltRate, 38 | 39 | IoRdRate=2000, 40 | IoWrRate, 41 | IoCcwrRate, 42 | IoDelay, 43 | 44 | NetSdRate=3000, 45 | NetRcRate 46 | } StatisticT; 47 | 48 | 49 | 50 | class MonitorImpl; 51 | class SourceMonitor{ 52 | public: 53 | SourceMonitor(); 54 | bool registerStatistic(StatisticT statistic); 55 | bool registerPid(unsigned int pid); 56 | bool init(); 57 | void update(); 58 | double getStatistic(unsigned int pid,StatisticT statistic); 59 | ~SourceMonitor(); 60 | private: 61 | MonitorImpl * monitorImpl; 62 | }; 63 | 64 | #endif -------------------------------------------------------------------------------- /src/netIoMonitorType.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * netIoMonitorType.cpp 3 | * 4 | * Copyright (c) 2019 Zhang Peng 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | 23 | #ifndef NETIOMONITORTYPE_HPP 24 | #define NETIOMONITORTYPE_HPP 25 | 26 | class NetStatus{ 27 | public: 28 | //net 29 | unsigned long long netSd_bytes=0; 30 | unsigned long long netRc_bytes=0; 31 | }; 32 | 33 | class TcpInfo{ 34 | public: 35 | friend bool operator<(const TcpInfo& tcp1, const TcpInfo& tcp2); 36 | TcpInfo(unsigned int ip,unsigned int port):ip(ip),port(port){}; 37 | TcpInfo(){ 38 | TcpInfo(0,0); 39 | } 40 | public: 41 | unsigned int ip; // ipv4 42 | unsigned int port; 43 | }; 44 | inline bool operator<(const TcpInfo& tcp1, const TcpInfo& tcp2){ 45 | return tcp1.port 28 | #include 29 | #include 30 | 31 | #include "netIoMonitorType.hpp" 32 | #include "netIoMonitorPcap.hpp" 33 | 34 | #define FL_TCPINFO "/proc/net/tcp" 35 | #define FL_UDPINFO "/proc/net/udp" 36 | #define FL_PID_FD "/proc/%u/fd/" 37 | 38 | 39 | 40 | class NetIoMonitor{ 41 | public: 42 | NetIoMonitor():netIoMonitorPcap(80,1){;} //magic number snapLen=80,timeout_ms=1 43 | bool registerPid(unsigned int pid); 44 | bool init(); //init new thread 45 | void update(); 46 | std::map getNetStatus(); 47 | ~NetIoMonitor(){;} 48 | protected: 49 | void getIPDeviceInfo(); 50 | void getInodeInfo(); 51 | void pid2TcpUdp(); 52 | void generFilter(){};//todo 53 | protected: 54 | 55 | std::map tcp2Pid; 56 | std::map udp2Pid; 57 | std::set devices; 58 | 59 | std::set ipSet; 60 | std::map ip2Device; 61 | std::map inode2Tcp; 62 | std::map inode2Udp; 63 | 64 | 65 | std::string filter; 66 | 67 | std::set registeredPids; 68 | 69 | NetIoMonitorPcap netIoMonitorPcap; 70 | }; 71 | 72 | 73 | 74 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SourceMonitor 2 | ### 1、简介 3 |   SourceMonitor是一个linux平台资源监控库,可以用来监控CPU、内存、存储IO、网络IO等资源的使用情况。该库最突出的特点是以进程为单位对资源进行监控,而且该库提供了简单易用的接口。 4 |   我们之所以提供一个资源监控库而非资源监控工具,主要是考虑到使用的灵活性。用户可以根据自己的需求,借助SourceMonitor库方便的搭建资源监控工具。 5 | ### 2、API介绍 6 | SourceMonitor的工作流程如下图所示: 7 |   ![image](https://github.com/zzpp3377/SourceMonitor/blob/master/images/API.jpg) 8 | (1)注册监控参数:registerStatistic(StatisticT statistic) 9 |   StatisticT是枚举类型,定义了SourceMonitor支持的监控参数。 10 | (2)注册被监控进程:registerPid(unsigned int pid) 11 |   pid是被监控进程的进程号。 12 | (3)初始化:init() 13 |   初始化并开始监控。 14 | (4)更新:update() 15 |   将监控参数记录到一张表中。 16 | (5)读取监控数据:getStatistic(unsigned int pid,StatisticT statistic) 17 |   读取进程pid的监控参数statistic。 18 | ### 3、支持的监控参数 19 | 监控参数 | 作用 20 | ----|---- 21 | CpuRatio | cpu利用率(进程占用cpu时间/墙上时间) 22 | CpuUsrRatio | 用户态cpu利用率(进程用户态占用cpu时间/墙上时间) 23 | CpuSysRatio | 内核态cpu利用率(进程内核态占用cpu时间/墙上时间) 24 | CpuGstRatio | 虚拟cpu利用率(Guest time of the process) 25 | CpuWaitRatio | 进程等待运行的时间开销(等待时间/墙上时间) 26 | CpuIndex | 当前运行进程的cup号 27 | MemRatio | 进程内存使用率(进程物理内存占用/总物理内存) 28 | MemRss | 进程物理内存占用 29 | MemVsz | 进程虚拟内存占用 30 | MemMinfltRate | 进程发生minor faults 的频率 31 | MemMajfltRate | 进程发生major faults 的频率 32 | IoRdRate | 进程硬盘读速率 33 | IoWrRate | 进程硬盘写速率 34 | IoCcwrRate | 进程cancelled write的速率 35 | IoDelay | 进程的block I/O延时 36 | NetSdRate | 进程网络发送速率(包括TCP、UDP)(要求root权限) 37 | NetRcRate | 进程网络接收速率(包括TCP、UDP)(要求root权限) 38 | ### 4、安装 39 | ubuntu: 40 | (1)安装SourceMonitor依赖。 41 | 42 | sudo apt-get install build-essential libpcap-dev cmake 43 | 44 | (2)下载SourceMonitor 45 | 46 | git clone https://github.com/zzpp3377/SourceMonitor.git 47 | 48 | (3)编译 49 | 50 | cd SourceMonitor && mkdir build && cd build 51 | cmake .. 52 | make 53 | sudo make install 54 | 55 |   编译生成一个动态链接库(libSrcMntr.so)和静态链接库(libSrcMntr.a),然后安装到了/usr/lib/下。 56 | 57 | ### 5、示例 58 |   完成安装后,可以进入SourceMonitor/example编译运行示例。 59 |   如示例中所展示的,使用SourceMonitor仅需要#include “sourceMonitor.hpp”,然后按照API介绍中描述的方法使用接口即可。 60 |   编译脚本SourceMonitor/example/compile.sh分别提供了SourceMonitor动态链接库和静态链接库的编译方法。 61 | 62 | ### 6、其他资源监控工具 63 |   sysstat: https://github.com/sysstat/sysstat.git 64 |   nethogs: https://github.com/raboof/nethogs.git 65 | -------------------------------------------------------------------------------- /src/decpcap/decpcap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * decpcap.h 3 | * 4 | * Copyright (c) 2004-2006,2011 Arnout Engelen 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | #ifndef __DECPCAP_H 23 | #define __DECPCAP_H 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #define DP_ERRBUF_SIZE PCAP_ERRBUF_SIZE 31 | extern bool catchall; 32 | /* definitions */ 33 | 34 | enum dp_packet_type { 35 | dp_packet_ethernet, 36 | dp_packet_ppp, 37 | dp_packet_sll, 38 | dp_packet_ip, 39 | dp_packet_ip6, 40 | dp_packet_tcp, 41 | dp_packet_udp, 42 | dp_n_packet_types 43 | }; 44 | 45 | /*enum dp_link_type { 46 | dp_link_ethernet, 47 | dp_link_ppp, 48 | dp_n_link_types 49 | };*/ 50 | 51 | /*struct dp_header { 52 | * pcap 53 | };*/ 54 | typedef struct pcap_pkthdr dp_header; 55 | 56 | typedef int (*dp_callback)(u_char *, const dp_header *, const u_char *); 57 | 58 | struct dp_handle { 59 | pcap_t *pcap_handle; 60 | dp_callback callback[dp_n_packet_types]; 61 | int linktype; 62 | u_char *userdata; 63 | int userdata_size; 64 | }; 65 | 66 | /* functions to set up a handle (which is basically just a pcap handle) */ 67 | 68 | struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc, 69 | int to_ms, char *filter, char *errbuf); 70 | struct dp_handle *dp_open_offline(char *fname, char *ebuf); 71 | 72 | /* functions to add callbacks */ 73 | 74 | void dp_addcb(struct dp_handle *handle, enum dp_packet_type type, 75 | dp_callback callback); 76 | 77 | /* functions to parse payloads */ 78 | 79 | void dp_parse(enum dp_packet_type type, void *packet); 80 | 81 | /* functions to start monitoring */ 82 | 83 | int dp_dispatch(struct dp_handle *handler, int count, u_char *user, int size); 84 | 85 | /* functions that simply call libpcap */ 86 | 87 | int dp_datalink(struct dp_handle *handle); 88 | 89 | int dp_setnonblock(struct dp_handle *handle, int i, char *errbuf); 90 | 91 | char *dp_geterr(struct dp_handle *handle); 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/netIoMonitorPcap.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * netIoMonitorPcap.hpp 3 | * 4 | * Copyright (c) 2019 Zhang Peng 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | #ifndef NETIOMONITORPCAP_HPP 23 | #define NETIOMONITORPCAP_HPP 24 | #include "netIoMonitorType.hpp" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "decpcap/decpcap.h" 32 | 33 | class NetIoMonitorPcap{ 34 | public: 35 | NetIoMonitorPcap(){;} 36 | NetIoMonitorPcap(int snaplen,int timeOut_ms):snaplen(snaplen),timeOut_ms(timeOut_ms){} 37 | void setFilter(std::string filter); 38 | void setPidNetStatus(std::map pidNetStatus); 39 | bool setDevices(std::set devices); 40 | bool setTcp2Pid(std::map tcp2Pid); 41 | bool setUdp2Pid(std::map udp2Pid); 42 | std::map getNetStatus(); 43 | void netIoMonitorPcapLoop(); 44 | ~NetIoMonitorPcap(){;} 45 | 46 | public: 47 | friend int process_tcp(u_char *userdata, const dp_header *header,const u_char *m_packet); 48 | friend int process_udp(u_char *userdata, const dp_header *header, const u_char *m_packet); 49 | friend int process_ip(u_char *userdata, const dp_header * header , const u_char *m_packet); 50 | friend int process_ip6(u_char *userdata, const dp_header * /* header */,const u_char *m_packet); 51 | protected: 52 | std::string device; 53 | int snaplen; 54 | int timeOut_ms; 55 | std::string filter; 56 | 57 | std::mutex mtxTcp2Pid; 58 | std::map tcp2Pid; 59 | std::mutex mtxUdp2Pid; 60 | std::map udp2Pid; 61 | std::mutex mtxStatus; 62 | std::map pidNetStatus; 63 | }; 64 | 65 | struct dpargs { 66 | const char *device; 67 | int sa_family; 68 | struct in_addr ip_src; 69 | struct in_addr ip_dst; 70 | struct in6_addr ip6_src; 71 | struct in6_addr ip6_dst; 72 | NetIoMonitorPcap * monitorPtr; 73 | }; 74 | 75 | #endif -------------------------------------------------------------------------------- /src/logger/logger.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * logger.hpp 4 | * 5 | * Copyright (c) 2019 Zhang Peng 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 20 | *USA. 21 | * 22 | */ 23 | 24 | #ifndef LOGGER_H 25 | #define LOGGER_H 26 | #include 27 | 28 | #define __DEBUG //日志模块总开关,注释掉将关闭日志输出 29 | 30 | #define DEBUG(format, ...) printf (format, ##__VA_ARGS__) 31 | 32 | //定义日志级别 33 | typedef enum LOG_LEVEL { 34 | LOG_LEVEL_OFF=0, 35 | LOG_LEVEL_FATAL, 36 | LOG_LEVEL_ERR, 37 | LOG_LEVEL_WARN, 38 | LOG_LEVEL_INFO, 39 | LOG_LEVEL_DEBUG, 40 | } LogLevel; 41 | 42 | #ifdef __DEBUG 43 | #define log_fatal(level,format, ...) \ 44 | do { \ 45 | if(level>=LOG_LEVEL_FATAL)\ 46 | DEBUG( "=>FATAL FUNC:%s FILE:%s LINE:%d \t" format "\n" ,\ 47 | __func__, __FILE__, __LINE__, ##__VA_ARGS__ );\ 48 | } while (0) 49 | #else 50 | #define log_fatal(level,format, ...) 51 | #endif 52 | 53 | #ifdef __DEBUG 54 | #define log_err(level,format, ...) \ 55 | do { \ 56 | if(level>=LOG_LEVEL_ERR)\ 57 | DEBUG( "=>ERR FUNC:%s FILE:%s LINE:%d \t" format "\n" ,\ 58 | __func__, __FILE__, __LINE__, ##__VA_ARGS__ );\ 59 | } while (0) 60 | #else 61 | #define log_err(level,format, ...) 62 | #endif 63 | 64 | #ifdef __DEBUG 65 | #define log_warn(level,format, ...) \ 66 | do { \ 67 | if(level>=LOG_LEVEL_WARN)\ 68 | DEBUG( "=>WARN FUNC:%s \t" format "\n" ,__func__, ##__VA_ARGS__ );\ 69 | } while (0) 70 | #else 71 | #define log_warn(level,format, ...) 72 | #endif 73 | 74 | #ifdef __DEBUG 75 | #define log_info(level,format, ...) \ 76 | do { \ 77 | if(level>=LOG_LEVEL_INFO)\ 78 | DEBUG( "=>INFO FUNC:%s \t" format "\n" ,__func__,##__VA_ARGS__ );\ 79 | } while (0) 80 | #else 81 | #define log_info(level,format, ...) 82 | #endif 83 | 84 | #ifdef __DEBUG 85 | #define log_debug(level,format, ...) \ 86 | do { \ 87 | if(level>=LOG_LEVEL_DEBUG)\ 88 | DEBUG( "=>DEBUG FUNC:%s \t" format "\n" ,__func__,##__VA_ARGS__ );\ 89 | } while (0) 90 | #else 91 | #define log_debug(level,format, ...) 92 | #endif 93 | 94 | 95 | #endif -------------------------------------------------------------------------------- /src/monitorImpl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * monitorImpl.hpp 3 | * 4 | * Copyright (c) 2019 Zhang Peng 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | 23 | #ifndef MONITOR_IMPL_HPP 24 | #define MONITOR_IMPL_HPP 25 | 26 | #include "sourceMonitor.hpp" 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "netIoMonitor.hpp" 33 | 34 | //read file flag 35 | #define RD_PID_STAT_FLG 0x01 36 | #define RD_PID_SCHEDSTAT_FLG 0x02 37 | #define RD_UPTIME_FLG 0x04 38 | #define RD_MEMINFO_FLG 0x08 39 | #define RD_PID_IO_FLG 0x10 40 | #define RD_NET_IO_FLG 0x20 41 | 42 | 43 | 44 | 45 | //file name 46 | #define FL_PID_STAT "/proc/%u/stat" 47 | #define FL_PID_IO "/proc/%u/io" 48 | #define FL_PID_SCHED "/proc/%u/schedstat" 49 | #define FL_MEMINFO "/proc/meminfo" 50 | #define FL_UPTIME "/proc/uptime" 51 | 52 | 53 | /* Number of bit shifts to convert pages to kB */ 54 | extern unsigned int kb_shift; 55 | #define PG_TO_KB(k) ((k) << kb_shift) 56 | 57 | #define B_TO_KB(k) ( (k) / 1024.0 ) 58 | 59 | class Status{ 60 | public: 61 | //cpu 62 | unsigned long long utime=0; 63 | unsigned long long stime=0; 64 | unsigned long long gtime=0; 65 | unsigned long long wtime=0; 66 | unsigned int processor=0; 67 | unsigned long long uptime=0; 68 | 69 | //mem 70 | unsigned long long minflt=0; 71 | unsigned long long majflt=0; 72 | unsigned long long vsz=0; 73 | unsigned long long rss=0; 74 | unsigned long long tlmkb=0; 75 | 76 | //io 77 | unsigned long long read_bytes=0; 78 | unsigned long long write_bytes=0; 79 | unsigned long long cancelled_write_bytes=0; 80 | unsigned long long blkio_swapin_delays=0; 81 | 82 | //net 83 | unsigned long long netSd_bytes=0; 84 | unsigned long long netRc_bytes=0; 85 | 86 | }; 87 | 88 | class MonitorImpl{ 89 | public: 90 | MonitorImpl(){}; 91 | bool registerStatistic(StatisticT statistic); 92 | bool registerPid(unsigned int pid); 93 | bool init(); 94 | void update(); 95 | double getStatistic(unsigned int pid,StatisticT statistic); 96 | ~MonitorImpl(){}; 97 | private: 98 | void readProcPidStat(); //cpu and mem and io:blkio_swapin_delays 99 | void readProcPidSchedstat(); //cpu:processor 100 | void readProcUptime(); //cpu:uptime 101 | void readProcMeminfo(); //mem:tlmkb 102 | void readProcPidIo(); //io 103 | void readNetIo();//net io 104 | public: 105 | //cpu 106 | double getCpuRatio(unsigned int pid); 107 | double getCpuUsrRatio(unsigned int pid); 108 | double getCpuSysRatio(unsigned int pid); 109 | double getCpuGstRatio(unsigned int pid); 110 | double getCpuWaitRatio(unsigned int pid); 111 | double getCpuIndex(unsigned int pid); 112 | //mem 113 | double getMemRatio(unsigned int pid); 114 | double getMemRss(unsigned int pid); 115 | double getMemVsz(unsigned int pid); 116 | double getMemMinfltRate(unsigned int pid); 117 | double getMemMajfltRate(unsigned int pid); 118 | //io 119 | double getIoRdRate(unsigned int pid); 120 | double getIoWrRate(unsigned int pid); 121 | double getIoCcwrRate(unsigned int pid); 122 | double getIoDelay(unsigned int pid); 123 | //net io 124 | double getNetSdRate(unsigned int pid); 125 | double getNetRcRate(unsigned int pid); 126 | 127 | private: 128 | int cur=0; 129 | unsigned int rdFlg=0; 130 | std::map> handlers; 131 | std::map> pidStatus; 132 | std::set registeredPids; 133 | NetIoMonitor netIoMonitor; 134 | }; 135 | 136 | 137 | 138 | 139 | 140 | #endif -------------------------------------------------------------------------------- /src/decpcap/pcapTest.cpp: -------------------------------------------------------------------------------- 1 | #include "decpcap.h" 2 | #include //in_addr inet_aton 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include //struct ip 10 | #include //struct ip6 11 | 12 | #include // signal SIGINT 13 | 14 | char localAddrStr1[20]="10.18.133.10"; 15 | struct in_addr localAddr1; 16 | char localAddrStr2[20]="10.18.134.10"; 17 | struct in_addr localAddr2; 18 | 19 | 20 | int sentBytes=0; 21 | int rcvBytes=0; 22 | 23 | void getLocalAddr(){ 24 | if(!inet_aton(localAddrStr1,&localAddr1)||!inet_aton(localAddrStr2,&localAddr2) ) 25 | printf("get local address error!!!\n"); 26 | printf("local addr1:%s\tlocal addr2:%s",inet_ntoa(localAddr1),inet_ntoa(localAddr2)); 27 | } 28 | 29 | void quit_cb(int iSignNo/* i */) { 30 | printf("Capture sign no:%d\n",iSignNo); 31 | exit(0); 32 | } 33 | 34 | bool wait_for_next_trigger() { 35 | std::this_thread::sleep_for (std::chrono::microseconds(1)); 36 | return true; 37 | } 38 | 39 | 40 | struct dpargs { 41 | const char *device; 42 | int sa_family; 43 | in_addr ip_src; 44 | in_addr ip_dst; 45 | in6_addr ip6_src; 46 | in6_addr ip6_dst; 47 | }; 48 | 49 | 50 | int process_tcp(u_char *userdata, const dp_header *header,const u_char *m_packet) { 51 | struct dpargs *args = (struct dpargs *)userdata; 52 | struct tcphdr *tcp = (struct tcphdr *)m_packet; 53 | 54 | /* get info from userdata, then call getPacket */ 55 | switch (args->sa_family) { 56 | case AF_INET: 57 | break; 58 | case AF_INET6: 59 | break; 60 | default: 61 | std::cerr << "Invalid address family for TCP packet: " << args->sa_family << std::endl; 62 | return true; 63 | } 64 | 65 | /* we're done now. */ 66 | return true; 67 | } 68 | 69 | int process_udp(u_char *userdata, const dp_header *header, const u_char *m_packet) { 70 | struct dpargs *args = (struct dpargs *)userdata; 71 | struct udphdr *udp = (struct udphdr *)m_packet; 72 | 73 | switch (args->sa_family) { 74 | case AF_INET: 75 | break; 76 | case AF_INET6: 77 | break; 78 | default: 79 | std::cerr << "Invalid address family for UDP packet: " << args->sa_family 80 | << std::endl; 81 | return true; 82 | } 83 | 84 | /* we're done now. */ 85 | return true; 86 | } 87 | 88 | int process_ip(u_char *userdata, const dp_header * header , const u_char *m_packet) { 89 | struct dpargs *args = (struct dpargs *)userdata; 90 | struct ip *ip = (struct ip *)m_packet; 91 | args->sa_family = AF_INET; 92 | args->ip_src = ip->ip_src; 93 | args->ip_dst = ip->ip_dst; 94 | 95 | if(args->ip_src.s_addr==localAddr1.s_addr||args->ip_src.s_addr==localAddr2.s_addr){ 96 | sentBytes+=header->len; 97 | }else if(args->ip_dst.s_addr==localAddr1.s_addr||args->ip_dst.s_addr==localAddr2.s_addr){ 98 | // }else{ 99 | rcvBytes+=header->len; 100 | } 101 | // char src[100]={0}; 102 | // char dst[100]={0}; 103 | // printf(); 104 | 105 | /* we're not done yet - also parse tcp :) */ 106 | return false; 107 | } 108 | 109 | int process_ip6(u_char *userdata, const dp_header * /* header */,const u_char *m_packet) { 110 | struct dpargs *args = (struct dpargs *)userdata; 111 | const struct ip6_hdr *ip6 = (struct ip6_hdr *)m_packet; 112 | args->sa_family = AF_INET6; 113 | args->ip6_src = ip6->ip6_src; 114 | args->ip6_dst = ip6->ip6_dst; 115 | 116 | /* we're not done yet - also parse tcp :) */ 117 | return false; 118 | } 119 | 120 | 121 | int main(int argc, char **argv) { 122 | 123 | int promisc = 0; 124 | char *filter = NULL; 125 | char errbuf[PCAP_ERRBUF_SIZE]; 126 | char devName[100]="eth1"; 127 | 128 | getLocalAddr(); 129 | 130 | dp_handle *newhandle = dp_open_live(devName, BUFSIZ, promisc, 100, filter, errbuf); 131 | if (newhandle != NULL) { 132 | dp_addcb(newhandle, dp_packet_ip, process_ip); 133 | dp_addcb(newhandle, dp_packet_ip6, process_ip6); 134 | dp_addcb(newhandle, dp_packet_tcp, process_tcp); 135 | dp_addcb(newhandle, dp_packet_udp, process_udp); 136 | 137 | /* The following code solves sf.net bug 1019381, but is only available 138 | * in newer versions (from 0.8 it seems) of libpcap 139 | * 140 | * update: version 0.7.2, which is in debian stable now, should be ok 141 | * also. 142 | */ 143 | if (dp_setnonblock(newhandle, 1, errbuf) == -1) { 144 | fprintf(stderr, "Error putting libpcap in nonblocking mode\n"); 145 | } 146 | // handles = new handle(newhandle, current_dev->name, handles); 147 | 148 | } else { 149 | fprintf(stderr, "Error opening handler for device %s\n",devName); 150 | } 151 | 152 | signal(SIGINT, &quit_cb); 153 | 154 | struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs)); 155 | 156 | int count=0; 157 | // Main loop: 158 | while (1) { 159 | bool packets_read = false; 160 | 161 | userdata->device = devName; 162 | userdata->sa_family = AF_UNSPEC; 163 | int retval = dp_dispatch(newhandle, -1, (u_char *)userdata,sizeof(struct dpargs)); 164 | if (retval == -1) 165 | std::cerr << "Error dispatching for device " << devName <<": " << dp_geterr(newhandle) << std::endl; 166 | else if (retval < 0) 167 | std::cerr << "Error dispatching for device " << devName <<": " << retval << std::endl; 168 | else if (retval != 0) 169 | packets_read = true; 170 | 171 | if(count%1000==0){ 172 | printf("send----receive:\t%d----%d\n",sentBytes,rcvBytes); 173 | } 174 | count++; 175 | 176 | // if not packets, do a select() until next packet 177 | if (!packets_read) 178 | if (!wait_for_next_trigger()) 179 | // Shutdown requested - exit the loop 180 | break; 181 | } 182 | 183 | // clean_up(); 184 | } 185 | 186 | -------------------------------------------------------------------------------- /example/example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * example.cpp 3 | * 4 | * Copyright (c) 2019 Zhang Peng 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | 23 | #include "sourceMonitor.hpp" 24 | #include "stdio.h" 25 | #include "stdlib.h" 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | void test1(int count, int interval, int pid){ 33 | SourceMonitor sourceMonitor; 34 | sourceMonitor.registerStatistic(CpuRatio); 35 | sourceMonitor.registerStatistic(MemRss); 36 | sourceMonitor.registerStatistic(MemVsz); 37 | 38 | sourceMonitor.registerPid(pid); 39 | sourceMonitor.init(); 40 | printf("cpuRatio\trss\tvsz\n"); 41 | for(int i=0;i 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | #include "logger/logger.hpp" 39 | static LogLevel logLevel=LOG_LEVEL_WARN; 40 | 41 | bool NetIoMonitor::registerPid(unsigned int pid){ 42 | if(registeredPids.count(pid)!=0)return false; 43 | registeredPids.emplace(pid); 44 | return true; 45 | } 46 | 47 | bool NetIoMonitor::init(){ 48 | //init infomation from main-thread to net-io-thread 49 | getIPDeviceInfo(); 50 | getInodeInfo(); 51 | pid2TcpUdp(); 52 | //init information from net-io-thread to main-thread 53 | std::map pidNetStatus; 54 | for(auto& pid: registeredPids){ 55 | pidNetStatus[pid]=NetStatus(); 56 | log_debug(logLevel,"pid: %d",pid); 57 | } 58 | //generate filter 59 | generFilter(); 60 | //start net-io-thread 61 | netIoMonitorPcap.setFilter(filter); 62 | netIoMonitorPcap.setPidNetStatus(pidNetStatus); 63 | netIoMonitorPcap.setDevices(devices); 64 | netIoMonitorPcap.setTcp2Pid(tcp2Pid); 65 | netIoMonitorPcap.setUdp2Pid(udp2Pid); 66 | std::thread netIoThread(&NetIoMonitorPcap::netIoMonitorPcapLoop,&netIoMonitorPcap); 67 | netIoThread.detach(); 68 | return true; 69 | } 70 | 71 | void NetIoMonitor::update(){ 72 | getIPDeviceInfo(); 73 | getInodeInfo(); 74 | pid2TcpUdp(); 75 | netIoMonitorPcap.setDevices(devices); 76 | netIoMonitorPcap.setTcp2Pid(tcp2Pid); 77 | netIoMonitorPcap.setUdp2Pid(udp2Pid); 78 | } 79 | 80 | std::map NetIoMonitor::getNetStatus(){ 81 | return netIoMonitorPcap.getNetStatus(); 82 | } 83 | 84 | void NetIoMonitor::getIPDeviceInfo(){ 85 | struct ifaddrs * ifaddr, *ifa; 86 | struct sockaddr_in * addr; 87 | if (getifaddrs(&ifaddr) == -1) { 88 | log_err(logLevel,"getifaddrs error"); 89 | return; 90 | } 91 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { 92 | if (ifa->ifa_addr == NULL)continue; 93 | if (ifa->ifa_addr->sa_family!=AF_INET)continue; 94 | addr=(struct sockaddr_in *)(ifa->ifa_addr); 95 | if(ipSet.count(addr->sin_addr.s_addr)==0){ 96 | ipSet.emplace(addr->sin_addr.s_addr); 97 | log_debug(logLevel,"ip2Device--addr: %x dev: %s",addr->sin_addr.s_addr,ifa->ifa_name); 98 | } 99 | if(ip2Device.count(addr->sin_addr.s_addr)==0){ 100 | ip2Device[addr->sin_addr.s_addr]=ifa->ifa_name; 101 | } 102 | } 103 | freeifaddrs(ifaddr); 104 | } 105 | 106 | // /proc/net/tcp /proc/net/udp 107 | void NetIoMonitor::getInodeInfo(){ 108 | unsigned int ip; 109 | unsigned int port; 110 | unsigned int inode; 111 | char tempC; 112 | unsigned int tempInt; 113 | 114 | std::fstream fs; 115 | char line[256]={0}; //magic number 256, line max length 116 | 117 | fs.open(FL_TCPINFO,std::fstream::in); 118 | fs.getline(line,256); 119 | while(fs.getline(line,256)){ 120 | unsigned int ip=0; 121 | unsigned int port=0; 122 | unsigned int inode=0; 123 | std::stringstream stst; 124 | stst.str(std::string(line)); 125 | stst.ignore(256,':'); 126 | stst>>std::hex>>ip>>std::dec; 127 | stst>>tempC; 128 | stst>>std::hex>>port>>std::dec; 129 | stst.ignore(256,':'); 130 | stst.ignore(256,':'); 131 | stst.ignore(256,':'); 132 | stst>>std::hex>>tempInt>>std::dec; 133 | log_debug(logLevel,"tempInt1: %x",tempInt); 134 | stst>>std::hex>>tempInt>>std::dec; 135 | log_debug(logLevel,"tempInt2: %x",tempInt); 136 | stst>>tempInt; 137 | log_debug(logLevel,"tempInt3: %x",tempInt); 138 | stst>>tempInt; 139 | log_debug(logLevel,"tempInt4: %x",tempInt); 140 | stst>>inode; 141 | log_debug(logLevel,"inode2Tcp--read--inode: %d ip: %x port: %d",inode,ip,port); 142 | if(inode2Tcp.count(inode)==0)inode2Tcp[inode]=TcpInfo(ip,port); 143 | } 144 | fs.close(); 145 | 146 | fs.open(FL_UDPINFO,std::fstream::in); 147 | fs.getline(line,256); 148 | while(fs.getline(line,256)){ 149 | std::stringstream stst; 150 | stst.str(std::string(line)); 151 | stst.ignore(256,':'); 152 | stst>>std::hex>>ip>>std::dec; 153 | stst>>tempC; 154 | stst>>std::hex>>port>>std::dec; 155 | stst.ignore(256,':'); 156 | stst.ignore(256,':'); 157 | stst.ignore(256,':'); 158 | stst>>std::hex>>tempInt>>std::dec; 159 | stst>>std::hex>>tempInt>>std::dec; 160 | stst>>tempInt; 161 | stst>>tempInt; 162 | stst>>inode; 163 | if(inode2Udp.count(inode)==0)inode2Udp[inode]=UdpInfo(ip,port); 164 | } 165 | fs.close(); 166 | for(auto ite:inode2Tcp){ 167 | log_debug(logLevel,"inode2Tcp--inode: %d ip: %x port: %d",ite.first,ite.second.ip,ite.second.port); 168 | } 169 | for(auto ite:inode2Udp){ 170 | log_debug(logLevel,"inode2Udp--inode: %d ip: %x port: %d",ite.first,ite.second.ip,ite.second.port); 171 | } 172 | } 173 | 174 | 175 | // /proc/pid/fd 176 | void NetIoMonitor::pid2TcpUdp(){ 177 | DIR *dp; 178 | struct dirent *entry; 179 | char link[256]={};//magic number 256, max path name 180 | int linkLen; 181 | unsigned int inode; 182 | 183 | for(auto pid: registeredPids){ 184 | log_debug(logLevel,"pid: %d",pid); 185 | } 186 | 187 | for(auto pid: registeredPids){ 188 | char dirName[100]={0}; 189 | sprintf(dirName,FL_PID_FD,pid); 190 | if((dp=opendir(dirName))==NULL){ 191 | log_err(logLevel,"Can`t open directory %s",dirName); 192 | return; 193 | } 194 | std::string path(dirName); 195 | while((entry=readdir(dp))!=NULL){ 196 | std::string file(entry->d_name); 197 | file=path+file; 198 | if((linkLen=readlink(file.c_str(),link,256))<0){ 199 | log_info(logLevel,"entry->d_name: %s linkLen: %d",file.c_str(),linkLen); 200 | continue; 201 | } 202 | std::string linkStr(link,linkLen); 203 | 204 | log_debug(logLevel,"linkStr: %s",linkStr.c_str()); 205 | 206 | if(linkStr.find("socket")==std::string::npos) continue; //magic string socket 207 | sscanf(linkStr.c_str(),"socket:[%u]",&inode); 208 | 209 | log_debug(logLevel,"inode: %d",inode); 210 | 211 | if(inode2Tcp.count(inode)!=0){ 212 | if(inode2Tcp[inode].ip!=0){ 213 | tcp2Pid[inode2Tcp[inode]]=pid; 214 | devices.emplace(ip2Device[inode2Tcp[inode].ip]); 215 | }else{ 216 | for(auto &ip: ipSet){ 217 | TcpInfo tempTcp(ip,inode2Tcp[inode].port); 218 | tcp2Pid[tempTcp]=pid; 219 | devices.emplace(ip2Device[ip]); 220 | } 221 | } 222 | }else if(inode2Udp.count(inode)!=0){ 223 | if(inode2Udp[inode].ip!=0){ 224 | udp2Pid[inode2Udp[inode]]=pid; 225 | devices.emplace(ip2Device[inode2Udp[inode].ip]); 226 | }else{ 227 | for(auto &ip: ipSet){ 228 | UdpInfo tempUdp(ip,inode2Udp[inode].port); 229 | udp2Pid[tempUdp]=pid; 230 | devices.emplace(ip2Device[ip]); 231 | } 232 | } 233 | } 234 | } 235 | } 236 | } -------------------------------------------------------------------------------- /src/netIoMonitorPcap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * netIoMonitorPcap.cpp 3 | * 4 | * Copyright (c) 2019 Zhang Peng 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | 23 | #ifndef NETIOMONITOR_HPP 24 | #define NETIOMONITOR_HPP 25 | #include "netIoMonitorType.hpp" 26 | #include "netIoMonitorPcap.hpp" 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "logger/logger.hpp" 36 | 37 | // static LogLevel logLevel=LOG_LEVEL_DEBUG; 38 | static LogLevel logLevel=LOG_LEVEL_WARN; 39 | 40 | int process_tcp(u_char *userdata, const dp_header *header,const u_char *m_packet) { 41 | struct dpargs *args = (struct dpargs *)userdata; 42 | struct tcphdr *tcp = (struct tcphdr *)m_packet; 43 | NetIoMonitorPcap * monitorPtr = args->monitorPtr; 44 | 45 | /* get info from userdata, then call getPacket */ 46 | switch (args->sa_family) { 47 | case AF_INET:{ 48 | TcpInfo tcpInfoSrc(args->ip_src.s_addr,ntohs(tcp->th_sport)); 49 | TcpInfo tcpInfoDst(args->ip_dst.s_addr,ntohs(tcp->th_dport)); 50 | log_debug(logLevel,"tcpInfoSrc ip: %x port: %d",args->ip_src.s_addr,ntohs(tcp->th_sport)); 51 | log_debug(logLevel,"tcpInfoDst ip: %x port: %d",args->ip_dst.s_addr,ntohs(tcp->th_dport)); 52 | int judge=0; //0--don't match,1--send,2--receive 53 | monitorPtr->mtxTcp2Pid.lock(); 54 | if(monitorPtr->tcp2Pid.count(tcpInfoSrc)!=0){ 55 | judge=1; 56 | }else if(monitorPtr->tcp2Pid.count(tcpInfoDst)!=0){ 57 | judge=2; 58 | } 59 | monitorPtr->mtxTcp2Pid.unlock(); 60 | monitorPtr->mtxStatus.lock(); 61 | if(judge==1){ 62 | monitorPtr->pidNetStatus[monitorPtr->tcp2Pid[tcpInfoSrc]].netSd_bytes+= header->len; 63 | log_debug(logLevel,"pidNetStatus[%d].netSd_bytes: %llu",monitorPtr->tcp2Pid[tcpInfoSrc],monitorPtr->pidNetStatus[monitorPtr->tcp2Pid[tcpInfoSrc]].netSd_bytes); 64 | }else if(judge==2){ 65 | monitorPtr->pidNetStatus[monitorPtr->tcp2Pid[tcpInfoDst]].netRc_bytes+= header->len; 66 | log_debug(logLevel,"pidNetStatus[%d].netRc_bytes: %llu",monitorPtr->tcp2Pid[tcpInfoDst],monitorPtr->pidNetStatus[monitorPtr->tcp2Pid[tcpInfoDst]].netRc_bytes); 67 | } 68 | monitorPtr->mtxStatus.unlock(); 69 | break; 70 | } 71 | case AF_INET6: 72 | break; 73 | default: 74 | log_err(logLevel,"Invalid address family for TCP packet: %d",args->sa_family); 75 | return true; 76 | } 77 | 78 | /* we're done now. */ 79 | return true; 80 | } 81 | 82 | int process_udp(u_char *userdata, const dp_header *header, const u_char *m_packet) { 83 | struct dpargs *args = (struct dpargs *)userdata; 84 | struct udphdr *udp = (struct udphdr *)m_packet; 85 | NetIoMonitorPcap * monitorPtr = args->monitorPtr; 86 | log_debug(logLevel,"into process_udp"); 87 | 88 | switch (args->sa_family) { 89 | case AF_INET:{ 90 | UdpInfo udpInfoSrc(args->ip_src.s_addr,ntohs(udp->uh_sport)); 91 | UdpInfo udpInfoDst(args->ip_dst.s_addr,ntohs(udp->uh_dport)); 92 | log_debug(logLevel,"udpInfoSrc ip: %x port: %d",args->ip_src.s_addr,ntohs(udp->uh_sport)); 93 | log_debug(logLevel,"udpInfoDst ip: %x port: %d",args->ip_dst.s_addr,ntohs(udp->uh_dport)); 94 | int judge=0; //0--don't match,1--send,2--receive 95 | monitorPtr->mtxUdp2Pid.lock(); 96 | if(monitorPtr->udp2Pid.count(udpInfoSrc)!=0){ 97 | judge=1; 98 | }else if(monitorPtr->udp2Pid.count(udpInfoDst)!=0){ 99 | judge=2; 100 | } 101 | monitorPtr->mtxUdp2Pid.unlock(); 102 | monitorPtr->mtxStatus.lock(); 103 | if(judge==1){ 104 | monitorPtr->pidNetStatus[monitorPtr->udp2Pid[udpInfoSrc]].netSd_bytes+= header->len; 105 | log_debug(logLevel,"pidNetStatus[%d].netSd_bytes: %llu",monitorPtr->udp2Pid[udpInfoSrc],monitorPtr->pidNetStatus[monitorPtr->udp2Pid[udpInfoSrc]].netSd_bytes); 106 | }else if(judge==2){ 107 | monitorPtr->pidNetStatus[monitorPtr->udp2Pid[udpInfoDst]].netRc_bytes+= header->len; 108 | log_debug(logLevel,"pidNetStatus[%d].netRc_bytes: %llu",monitorPtr->udp2Pid[udpInfoDst],monitorPtr->pidNetStatus[monitorPtr->udp2Pid[udpInfoDst]].netRc_bytes); 109 | } 110 | monitorPtr->mtxStatus.unlock(); 111 | break; 112 | } 113 | case AF_INET6: 114 | break; 115 | default: 116 | log_err(logLevel,"Invalid address family for UDP packet: %d",args->sa_family); 117 | return true; 118 | } 119 | 120 | /* we're done now. */ 121 | return true; 122 | } 123 | 124 | int process_ip(u_char *userdata, const dp_header * header , const u_char *m_packet) { 125 | struct dpargs *args = (struct dpargs *)userdata; 126 | struct ip *ip = (struct ip *)m_packet; 127 | args->sa_family = AF_INET; 128 | args->ip_src = ip->ip_src; 129 | args->ip_dst = ip->ip_dst; 130 | 131 | // if(args->ip_src.s_addr==localAddr1.s_addr||args->ip_src.s_addr==localAddr2.s_addr){ 132 | // sentBytes+=header->len; 133 | // }else if(args->ip_dst.s_addr==localAddr1.s_addr||args->ip_dst.s_addr==localAddr2.s_addr){ 134 | // rcvBytes+=header->len; 135 | // } 136 | 137 | /* we're not done yet - also parse tcp :) */ 138 | return false; 139 | } 140 | 141 | int process_ip6(u_char *userdata, const dp_header * /* header */,const u_char *m_packet) { 142 | struct dpargs *args = (struct dpargs *)userdata; 143 | const struct ip6_hdr *ip6 = (struct ip6_hdr *)m_packet; 144 | args->sa_family = AF_INET6; 145 | args->ip6_src = ip6->ip6_src; 146 | args->ip6_dst = ip6->ip6_dst; 147 | 148 | /* we're not done yet - also parse tcp :) */ 149 | return false; 150 | } 151 | 152 | bool NetIoMonitorPcap::setDevices(std::set devices){ 153 | // if(devices.size()==0)return false; 154 | // if(devices.size()==1)device=*(devices.begin()); 155 | // if(devices.size()>1)device="any"; //magic string according to libpcap 156 | device="any"; 157 | return true; 158 | } 159 | 160 | bool NetIoMonitorPcap::setTcp2Pid(std::map tcp2Pid){ 161 | mtxTcp2Pid.lock(); 162 | this->tcp2Pid=tcp2Pid; 163 | mtxTcp2Pid.unlock(); 164 | log_debug(logLevel,"tcp2Pid size: %lu",tcp2Pid.size()); 165 | for(auto ite: tcp2Pid){ 166 | log_debug(logLevel,"tcp--ip: %x port: %d pid: %d",ite.first.ip,ite.first.port,ite.second); 167 | } 168 | return true; 169 | } 170 | 171 | bool NetIoMonitorPcap::setUdp2Pid(std::map udp2Pid){ 172 | mtxUdp2Pid.lock(); 173 | this->udp2Pid=udp2Pid; 174 | mtxUdp2Pid.unlock(); 175 | log_debug(logLevel,"udp2Pid size: %lu",udp2Pid.size()); 176 | for(auto ite: udp2Pid){ 177 | log_debug(logLevel,"udp--ip: %x port: %d pid: %d",ite.first.ip,ite.first.port,ite.second); 178 | } 179 | return true; 180 | } 181 | 182 | void NetIoMonitorPcap::setFilter(std::string filter){ 183 | this->filter=filter; 184 | } 185 | 186 | void NetIoMonitorPcap::setPidNetStatus(std::map pidNetStatus){ 187 | this->pidNetStatus=pidNetStatus; 188 | for(auto ite: pidNetStatus){ 189 | log_debug(logLevel,"pidstatus--pid: %d",ite.first); 190 | } 191 | } 192 | 193 | std::map NetIoMonitorPcap::getNetStatus(){ 194 | mtxStatus.lock(); 195 | std::map result=pidNetStatus; 196 | mtxStatus.unlock(); 197 | for(auto ite: pidNetStatus){ 198 | log_debug(logLevel,"pidstatus--pid: %d netSd_bytes: %llu netRc_bytes: %llu",ite.first,ite.second.netSd_bytes,ite.second.netRc_bytes); 199 | } 200 | return result; 201 | } 202 | 203 | void NetIoMonitorPcap::netIoMonitorPcapLoop(){ 204 | char errbuf[PCAP_ERRBUF_SIZE]; 205 | char * filterC = new char [filter.length()+1]; 206 | std::strcpy (filterC, filter.c_str()); 207 | dp_handle *newhandle = dp_open_live(device.c_str(), snaplen, 0, timeOut_ms, filterC, errbuf); // magic number 0--not promisc, 208 | delete filterC; 209 | if (newhandle != NULL) { 210 | dp_addcb(newhandle, dp_packet_ip, process_ip); 211 | dp_addcb(newhandle, dp_packet_ip6, process_ip6); 212 | dp_addcb(newhandle, dp_packet_tcp, process_tcp); 213 | dp_addcb(newhandle, dp_packet_udp, process_udp); 214 | } else { 215 | log_err(logLevel,"Error opening handler for device %s",device.c_str()); 216 | return; 217 | } 218 | struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs)); 219 | while(1){ 220 | char * deviceC=new char [device.length()+1]; 221 | std::strcpy (deviceC, device.c_str()); 222 | userdata->device = deviceC; 223 | userdata->sa_family = AF_UNSPEC; 224 | userdata->monitorPtr = this; 225 | int retval = dp_dispatch(newhandle, -1, (u_char *)userdata,sizeof(struct dpargs));// magic number -1--cnt,according to libpcap 226 | delete userdata->device; 227 | if(retval<0){ 228 | log_err(logLevel,"Error dispatching for device %s : %d",device.c_str(),retval); 229 | return ; 230 | } 231 | } 232 | } 233 | 234 | 235 | 236 | #endif -------------------------------------------------------------------------------- /src/decpcap/decpcap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * decpcap.c 3 | * 4 | * Copyright (c) 2004-2006,2011 Arnout Engelen 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include // for memcpy 31 | #include 32 | #include "decpcap.h" 33 | 34 | #define DP_DEBUG 0 35 | // bool catchall = false; 36 | bool catchall = true; 37 | /* functions to set up a handle (which is basically just a pcap handle) */ 38 | 39 | struct dp_handle *dp_fillhandle(pcap_t *phandle) { 40 | struct dp_handle *retval = 41 | (struct dp_handle *)malloc(sizeof(struct dp_handle)); 42 | int i; 43 | retval->pcap_handle = phandle; 44 | 45 | for (i = 0; i < dp_n_packet_types; i++) { 46 | retval->callback[i] = NULL; 47 | } 48 | 49 | retval->linktype = pcap_datalink(retval->pcap_handle); 50 | 51 | switch (retval->linktype) { 52 | case (DLT_EN10MB): 53 | fprintf(stdout, "Ethernet link detected\n"); 54 | break; 55 | case (DLT_PPP): 56 | fprintf(stdout, "PPP link detected\n"); 57 | break; 58 | case (DLT_LINUX_SLL): 59 | fprintf(stdout, "Linux Cooked Socket link detected\n"); 60 | break; 61 | default: 62 | fprintf(stdout, "No PPP or Ethernet link: %d\n", retval->linktype); 63 | // TODO maybe error? or 'other' callback? 64 | break; 65 | } 66 | 67 | return retval; 68 | } 69 | 70 | struct dp_handle *dp_open_offline(char *fname, char *ebuf) { 71 | pcap_t *temp = pcap_open_offline(fname, ebuf); 72 | 73 | if (temp == NULL) { 74 | return NULL; 75 | } 76 | 77 | return dp_fillhandle(temp); 78 | } 79 | 80 | struct dp_handle *dp_open_live(const char *device, int snaplen, int promisc, 81 | int to_ms, char *filter, char *errbuf) { 82 | struct bpf_program fp; // compiled filter program 83 | bpf_u_int32 maskp; // subnet mask 84 | bpf_u_int32 netp; // interface IP 85 | 86 | pcap_t *temp = pcap_open_live(device, snaplen, promisc, to_ms, errbuf); 87 | 88 | if (temp == NULL) { 89 | return NULL; 90 | } 91 | 92 | if (filter != NULL) { 93 | pcap_lookupnet(device, &netp, &maskp, errbuf); 94 | 95 | /* Compile the filter */ 96 | if(pcap_compile(temp, &fp, filter, 1, netp) == -1) { 97 | fprintf( 98 | stderr, 99 | "Error calling pcap_compile for filter on device %s: %s\n", 100 | device, pcap_geterr(temp) 101 | ); 102 | return NULL; 103 | } 104 | 105 | /* set the filter */ 106 | if(pcap_setfilter(temp, &fp) == -1) { 107 | fprintf( 108 | stderr, 109 | "Error setting capture filter on device %s: %s\n", 110 | device, pcap_geterr(temp) 111 | ); 112 | return NULL; 113 | } 114 | 115 | } 116 | 117 | return dp_fillhandle(temp); 118 | } 119 | 120 | /* functions to add callbacks */ 121 | 122 | void dp_addcb(struct dp_handle *handle, enum dp_packet_type type, 123 | dp_callback callback) { 124 | handle->callback[type] = callback; 125 | } 126 | 127 | /* functions for parsing the payloads */ 128 | 129 | void dp_parse_tcp(struct dp_handle *handle, const dp_header *header, 130 | const u_char *packet) { 131 | // const struct tcphdr * tcp = (struct tcphdr *) packet; 132 | // u_char * payload = (u_char *) packet + sizeof (struct tcphdr); 133 | 134 | if (handle->callback[dp_packet_tcp] != NULL) { 135 | int done = 136 | (handle->callback[dp_packet_tcp])(handle->userdata, header, packet); 137 | if (done) 138 | return; 139 | } 140 | // TODO: maybe `pass on' payload to lower-level protocol parsing 141 | } 142 | 143 | void dp_parse_udp(struct dp_handle *handle, const dp_header *header, 144 | const u_char *packet) { 145 | 146 | if (handle->callback[dp_packet_udp] != NULL) { 147 | int done = 148 | (handle->callback[dp_packet_udp])(handle->userdata, header, packet); 149 | if (done) 150 | return; 151 | } 152 | // TODO: maybe `pass on' payload to lower-level protocol parsing 153 | } 154 | 155 | void dp_parse_ip(struct dp_handle *handle, const dp_header *header, 156 | const u_char *packet) { 157 | const struct ip *ip = (struct ip *)packet; 158 | if (DP_DEBUG) { 159 | fprintf(stdout, "Looking at packet with length %ud\n", header->len); 160 | } 161 | u_char *payload = (u_char *)packet + sizeof(struct ip); 162 | 163 | if (handle->callback[dp_packet_ip] != NULL) { 164 | int done = 165 | (handle->callback[dp_packet_ip])(handle->userdata, header, packet); 166 | if (done) 167 | return; 168 | } 169 | switch (ip->ip_p) { 170 | case IPPROTO_TCP: 171 | dp_parse_tcp(handle, header, payload); 172 | break; 173 | case IPPROTO_UDP: 174 | if(catchall) 175 | dp_parse_udp(handle, header, payload); 176 | break; 177 | default: 178 | // TODO: maybe support for non-tcp IP packets 179 | break; 180 | } 181 | } 182 | 183 | void dp_parse_ip6(struct dp_handle *handle, const dp_header *header, 184 | const u_char *packet) { 185 | const struct ip6_hdr *ip6 = (struct ip6_hdr *)packet; 186 | u_char *payload = (u_char *)packet + sizeof(struct ip6_hdr); 187 | 188 | if (handle->callback[dp_packet_ip6] != NULL) { 189 | int done = 190 | (handle->callback[dp_packet_ip6])(handle->userdata, header, packet); 191 | if (done) 192 | return; 193 | } 194 | switch ((ip6->ip6_ctlun).ip6_un1.ip6_un1_nxt) { 195 | case IPPROTO_TCP: 196 | dp_parse_tcp(handle, header, payload); 197 | break; 198 | case IPPROTO_UDP: 199 | if(catchall) 200 | dp_parse_udp(handle, header, payload); 201 | break; 202 | default: 203 | // TODO: maybe support for non-tcp ipv6 packets 204 | break; 205 | } 206 | } 207 | 208 | void dp_parse_ethernet(struct dp_handle *handle, const dp_header *header, 209 | const u_char *packet) { 210 | const struct ether_header *ethernet = (struct ether_header *)packet; 211 | u_char *payload = (u_char *)packet + sizeof(struct ether_header); 212 | u_int16_t protocol = 0; 213 | 214 | /* call handle if it exists */ 215 | if (handle->callback[dp_packet_ethernet] != NULL) { 216 | int done = (handle->callback[dp_packet_ethernet])(handle->userdata, header, 217 | packet); 218 | 219 | /* return if handle decides we're done */ 220 | if (done) 221 | return; 222 | } 223 | 224 | /* parse payload */ 225 | protocol = ntohs(ethernet->ether_type); 226 | switch (protocol) { 227 | case ETHERTYPE_IP: 228 | dp_parse_ip(handle, header, payload); 229 | break; 230 | case ETHERTYPE_IPV6: 231 | dp_parse_ip6(handle, header, payload); 232 | break; 233 | default: 234 | // TODO: maybe support for other protocols apart from IPv4 and IPv6 235 | break; 236 | } 237 | } 238 | 239 | /* ppp header, i hope ;) */ 240 | /* glanced from ethereal, it's 16 bytes, and the payload packet type is 241 | * in the last 2 bytes... */ 242 | struct ppp_header { 243 | u_int16_t dummy1; 244 | u_int16_t dummy2; 245 | u_int16_t dummy3; 246 | u_int16_t dummy4; 247 | u_int16_t dummy5; 248 | u_int16_t dummy6; 249 | u_int16_t dummy7; 250 | 251 | u_int16_t packettype; 252 | }; 253 | 254 | void dp_parse_ppp(struct dp_handle *handle, const dp_header *header, 255 | const u_char *packet) { 256 | const struct ppp_header *ppp = (struct ppp_header *)packet; 257 | u_char *payload = (u_char *)packet + sizeof(struct ppp_header); 258 | u_int16_t protocol = 0; 259 | 260 | /* call handle if it exists */ 261 | if (handle->callback[dp_packet_ppp] != NULL) { 262 | int done = 263 | (handle->callback[dp_packet_ppp])(handle->userdata, header, packet); 264 | 265 | /* return if handle decides we're done */ 266 | if (done) 267 | return; 268 | } 269 | 270 | /* parse payload */ 271 | protocol = ntohs(ppp->packettype); 272 | switch (protocol) { 273 | case ETHERTYPE_IP: 274 | dp_parse_ip(handle, header, payload); 275 | break; 276 | case ETHERTYPE_IPV6: 277 | dp_parse_ip6(handle, header, payload); 278 | break; 279 | default: 280 | // TODO: support for other than IPv4 and IPv6 281 | break; 282 | } 283 | } 284 | 285 | /* linux cooked header, i hope ;) */ 286 | /* glanced from libpcap/ssl.h */ 287 | #define SLL_ADDRLEN 8 /* length of address field */ 288 | struct sll_header { 289 | u_int16_t sll_pkttype; /* packet type */ 290 | u_int16_t sll_hatype; /* link-layer address type */ 291 | u_int16_t sll_halen; /* link-layer address length */ 292 | u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ 293 | u_int16_t sll_protocol; /* protocol */ 294 | }; 295 | 296 | void dp_parse_linux_cooked(struct dp_handle *handle, const dp_header *header, 297 | const u_char *packet) { 298 | const struct sll_header *sll = (struct sll_header *)packet; 299 | u_char *payload = (u_char *)packet + sizeof(struct sll_header); 300 | u_int16_t protocol = 0; 301 | 302 | /* call handle if it exists */ 303 | if (handle->callback[dp_packet_sll] != NULL) { 304 | int done = 305 | (handle->callback[dp_packet_sll])(handle->userdata, header, packet); 306 | 307 | /* return if handle decides we're done */ 308 | if (done) 309 | return; 310 | } 311 | 312 | /* parse payload */ 313 | protocol = ntohs(sll->sll_protocol); 314 | switch (protocol) { 315 | case ETHERTYPE_IP: 316 | dp_parse_ip(handle, header, payload); 317 | break; 318 | case ETHERTYPE_IPV6: 319 | dp_parse_ip6(handle, header, payload); 320 | break; 321 | default: 322 | // TODO: support for other than IPv4 / IPv6 323 | break; 324 | } 325 | } 326 | 327 | /* functions to do the monitoring */ 328 | void dp_pcap_callback(u_char *u_handle, const struct pcap_pkthdr *header, 329 | const u_char *packet) { 330 | struct dp_handle *handle = (struct dp_handle *)u_handle; 331 | struct dp_header; 332 | 333 | /* make a copy of the userdata for every packet */ 334 | u_char *userdata_copy = (u_char *)malloc(handle->userdata_size); 335 | memcpy(userdata_copy, handle->userdata, handle->userdata_size); 336 | 337 | switch (handle->linktype) { 338 | case (DLT_EN10MB): 339 | dp_parse_ethernet(handle, header, packet); 340 | break; 341 | case (DLT_PPP): 342 | dp_parse_ppp(handle, header, packet); 343 | break; 344 | case (DLT_LINUX_SLL): 345 | dp_parse_linux_cooked(handle, header, packet); 346 | break; 347 | case (DLT_RAW): 348 | case (DLT_NULL): 349 | // hope for the best 350 | dp_parse_ip(handle, header, packet); 351 | break; 352 | default: 353 | fprintf(stdout, "Unknown linktype %d", handle->linktype); 354 | break; 355 | } 356 | free(userdata_copy); 357 | } 358 | 359 | int dp_dispatch(struct dp_handle *handle, int count, u_char *user, int size) { 360 | handle->userdata = user; 361 | handle->userdata_size = size; 362 | return pcap_dispatch(handle->pcap_handle, count, dp_pcap_callback, 363 | (u_char *)handle); 364 | } 365 | 366 | int dp_setnonblock(struct dp_handle *handle, int i, char *errbuf) { 367 | return pcap_setnonblock(handle->pcap_handle, i, errbuf); 368 | } 369 | 370 | char *dp_geterr(struct dp_handle *handle) { 371 | return pcap_geterr(handle->pcap_handle); 372 | } 373 | -------------------------------------------------------------------------------- /src/monitorImpl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * monitorImpl.cpp 3 | * 4 | * Copyright (c) 2019 Zhang Peng 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19 | *USA. 20 | * 21 | */ 22 | 23 | 24 | 25 | #include "monitorImpl.hpp" 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include "logger/logger.hpp" 33 | 34 | unsigned int kb_shift; 35 | 36 | static LogLevel logLevel=LOG_LEVEL_WARN; 37 | 38 | //map from statistic to file flag 39 | std::map sttt2file={ 40 | //cpu 41 | {CpuRatio, (RD_UPTIME_FLG|RD_PID_STAT_FLG)}, 42 | {CpuUsrRatio, (RD_UPTIME_FLG|RD_PID_STAT_FLG)}, 43 | {CpuSysRatio, (RD_UPTIME_FLG|RD_PID_STAT_FLG)}, 44 | {CpuGstRatio, (RD_UPTIME_FLG|RD_PID_STAT_FLG)}, 45 | {CpuWaitRatio, (RD_UPTIME_FLG|RD_PID_SCHEDSTAT_FLG)}, 46 | {CpuIndex, RD_PID_STAT_FLG}, 47 | //mem 48 | {MemRatio, (RD_PID_STAT_FLG|RD_MEMINFO_FLG)}, 49 | {MemRss, RD_PID_STAT_FLG}, 50 | {MemVsz, RD_PID_STAT_FLG}, 51 | {MemMinfltRate, (RD_PID_STAT_FLG|RD_UPTIME_FLG)}, 52 | {MemMajfltRate, (RD_PID_STAT_FLG|RD_UPTIME_FLG)}, 53 | //io 54 | {IoRdRate, (RD_PID_IO_FLG|RD_UPTIME_FLG)}, 55 | {IoWrRate, (RD_PID_IO_FLG|RD_UPTIME_FLG)}, 56 | {IoCcwrRate, (RD_PID_IO_FLG|RD_UPTIME_FLG)}, 57 | {IoDelay, RD_PID_STAT_FLG}, 58 | //net 59 | {NetSdRate, (RD_NET_IO_FLG|RD_UPTIME_FLG)}, 60 | {NetRcRate, (RD_NET_IO_FLG|RD_UPTIME_FLG)} 61 | }; 62 | 63 | //map from statistic to method 64 | std::map> sttt2method={ 65 | //cpu 66 | {CpuRatio, &MonitorImpl::getCpuRatio}, 67 | {CpuUsrRatio, &MonitorImpl::getCpuUsrRatio}, 68 | {CpuSysRatio, &MonitorImpl::getCpuSysRatio}, 69 | {CpuGstRatio, &MonitorImpl::getCpuGstRatio}, 70 | {CpuWaitRatio, &MonitorImpl::getCpuWaitRatio}, 71 | {CpuIndex, &MonitorImpl::getCpuIndex}, 72 | //mem 73 | {MemRatio, &MonitorImpl::getMemRatio}, 74 | {MemRss, &MonitorImpl::getMemRss}, 75 | {MemVsz, &MonitorImpl::getMemVsz}, 76 | {MemMinfltRate, &MonitorImpl::getMemMinfltRate}, 77 | {MemMajfltRate, &MonitorImpl::getMemMajfltRate}, 78 | //io 79 | {IoRdRate, &MonitorImpl::getIoRdRate}, 80 | {IoWrRate, &MonitorImpl::getIoWrRate}, 81 | {IoCcwrRate, &MonitorImpl::getIoCcwrRate}, 82 | {IoDelay, &MonitorImpl::getIoDelay}, 83 | //net 84 | {NetSdRate, &MonitorImpl::getNetSdRate}, 85 | {NetRcRate, &MonitorImpl::getNetRcRate} 86 | }; 87 | 88 | 89 | bool MonitorImpl::registerStatistic(StatisticT statistic){ 90 | if(!sttt2file.count(statistic))return false; //add log 91 | rdFlg=rdFlg|sttt2file[statistic]; 92 | handlers[statistic]=sttt2method[statistic]; 93 | return true; 94 | } 95 | 96 | bool MonitorImpl::registerPid(unsigned int pid){ 97 | if(registeredPids.count(pid))return false; 98 | log_debug(logLevel,"pid: %u",pid); 99 | pidStatus[pid]=std::vector(2); 100 | registeredPids.emplace(pid); 101 | netIoMonitor.registerPid(pid); 102 | return true; 103 | } 104 | 105 | bool MonitorImpl::init(){ 106 | //init kb_shift 107 | int size=0; 108 | int shift=0; 109 | if ((size = sysconf(_SC_PAGESIZE)) == -1) return false; 110 | size >>= 10; /* Assume that a page has a minimum size of 1 kB */ 111 | while (size > 1) { 112 | shift++; 113 | size >>= 1; 114 | } 115 | kb_shift = (unsigned int) shift; 116 | 117 | // init the first pidStatus[pid][cur] 118 | if(rdFlg&RD_MEMINFO_FLG){ 119 | readProcMeminfo(); 120 | } 121 | //init the netIoMonitor 122 | if(rdFlg&RD_NET_IO_FLG)netIoMonitor.init(); 123 | update(); 124 | } 125 | 126 | void MonitorImpl::update(){ 127 | if(rdFlg&RD_PID_STAT_FLG){ 128 | readProcPidStat(); 129 | } 130 | if(rdFlg&RD_PID_SCHEDSTAT_FLG){ 131 | readProcPidSchedstat(); 132 | } 133 | if(rdFlg&RD_UPTIME_FLG){ 134 | readProcUptime(); 135 | } 136 | if(rdFlg&RD_PID_IO_FLG){ 137 | readProcPidIo(); 138 | } 139 | if(rdFlg&RD_NET_IO_FLG){ 140 | readNetIo(); 141 | netIoMonitor.update(); 142 | } 143 | cur=!cur; 144 | } 145 | 146 | double MonitorImpl::getStatistic(unsigned int pid,StatisticT statistic){ 147 | if(!sttt2method.count(statistic)) return -2; 148 | return handlers[statistic](this,pid); 149 | } 150 | 151 | void MonitorImpl::readProcMeminfo(){ 152 | unsigned long long totalMem; 153 | std::fstream fs; 154 | fs.open(FL_MEMINFO,std::fstream::in); 155 | fs.ignore(10,':'); 156 | fs>>totalMem; 157 | fs.close(); 158 | for(auto &pid: registeredPids){ 159 | for(auto &status: pidStatus[pid]){ 160 | status.tlmkb=totalMem; 161 | } 162 | } 163 | } 164 | void MonitorImpl::readProcPidStat(){ 165 | for(auto &pid: registeredPids){ 166 | char fileName[100]={0}; 167 | sprintf(fileName,FL_PID_STAT,pid); 168 | std::fstream fs; 169 | fs.open(fileName,std::fstream::in); 170 | fs.ignore(1024,')'); 171 | 172 | char temp1; 173 | unsigned long long int temp2; 174 | fs>>temp1; 175 | for(int i=4;i<10;i++){ 176 | fs>>temp2; 177 | } 178 | fs>>pidStatus[pid][cur].minflt; 179 | fs>>temp2; 180 | fs>>pidStatus[pid][cur].majflt; 181 | fs>>temp2; 182 | fs>>pidStatus[pid][cur].utime; 183 | fs>>pidStatus[pid][cur].stime; 184 | for(int i=16;i<23;i++){ 185 | fs>>temp2; 186 | } 187 | fs>>pidStatus[pid][cur].vsz; 188 | pidStatus[pid][cur].vsz=pidStatus[pid][cur].vsz; 189 | fs>>pidStatus[pid][cur].rss; 190 | pidStatus[pid][cur].rss=pidStatus[pid][cur].rss; 191 | for(int i=25;i<39;i++){ 192 | fs>>temp2; 193 | } 194 | printf("\n"); 195 | fs>>pidStatus[pid][cur].processor; 196 | for(int i=40;i<42;i++){ 197 | fs>>temp2; 198 | } 199 | fs>>pidStatus[pid][cur].blkio_swapin_delays; 200 | fs>>pidStatus[pid][cur].gtime; 201 | fs.close(); 202 | } 203 | } 204 | 205 | void MonitorImpl::readProcPidSchedstat(){ 206 | for(auto &pid: registeredPids){ 207 | char fileName[100]={0}; 208 | sprintf(fileName,FL_PID_SCHED,pid); 209 | std::fstream fs; 210 | fs.open(fileName,std::fstream::in); 211 | long int temp; 212 | fs>>temp; 213 | fs>>pidStatus[pid][cur].wtime; 214 | fs.close(); 215 | } 216 | } 217 | void MonitorImpl::readProcUptime(){ 218 | std::fstream fs; 219 | fs.open(FL_UPTIME,std::fstream::in); 220 | double uptime; 221 | fs>>uptime; 222 | fs.close(); 223 | for(auto &pid: registeredPids){ 224 | pidStatus[pid][cur].uptime=(unsigned long long)(uptime*100); //magic number 100 from sysconf(_SC_CLK_TCK) 225 | } 226 | } 227 | 228 | void MonitorImpl::readProcPidIo(){ 229 | for(auto &pid: registeredPids){ 230 | char fileName[100]={0}; 231 | sprintf(fileName,FL_PID_IO,pid); 232 | std::fstream fs; 233 | fs.open(fileName,std::fstream::in); 234 | std::string str; 235 | while(fs>>str){ 236 | if(str=="read_bytes:")fs>>pidStatus[pid][cur].read_bytes; 237 | if(str=="write_bytes:")fs>>pidStatus[pid][cur].write_bytes; 238 | if(str=="cancelled_write_bytes:")fs>>pidStatus[pid][cur].cancelled_write_bytes; 239 | } 240 | fs.close(); 241 | } 242 | } 243 | 244 | void MonitorImpl::readNetIo(){ 245 | std::map netStatus=netIoMonitor.getNetStatus(); 246 | for(auto &pid: registeredPids){ 247 | pidStatus[pid][cur].netSd_bytes=netStatus[pid].netSd_bytes; 248 | pidStatus[pid][cur].netRc_bytes=netStatus[pid].netRc_bytes; 249 | } 250 | } 251 | 252 | double MonitorImpl::getCpuRatio(unsigned int pid){ 253 | int cur_last=!cur; 254 | int pre_last=cur; 255 | double cpuTime=static_cast((pidStatus[pid][cur_last].utime+pidStatus[pid][cur_last].stime)-(pidStatus[pid][pre_last].utime+pidStatus[pid][pre_last].stime)); 256 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 257 | return cpuTime/wallTime; 258 | } 259 | double MonitorImpl::getCpuUsrRatio(unsigned int pid){ 260 | int cur_last=!cur; 261 | int pre_last=cur; 262 | double cpuTime=static_cast(pidStatus[pid][cur_last].utime-pidStatus[pid][pre_last].utime); 263 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 264 | return cpuTime/wallTime; 265 | } 266 | double MonitorImpl::getCpuSysRatio(unsigned int pid){ 267 | int cur_last=!cur; 268 | int pre_last=cur; 269 | double cpuTime=static_cast(pidStatus[pid][cur_last].stime-pidStatus[pid][pre_last].stime); 270 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 271 | return cpuTime/wallTime; 272 | } 273 | double MonitorImpl::getCpuGstRatio(unsigned int pid){ 274 | int cur_last=!cur; 275 | int pre_last=cur; 276 | double cpuTime=static_cast(pidStatus[pid][cur_last].gtime-pidStatus[pid][pre_last].gtime); 277 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 278 | return cpuTime/wallTime; 279 | } 280 | double MonitorImpl::getCpuWaitRatio(unsigned int pid){ 281 | int cur_last=!cur; 282 | int pre_last=cur; 283 | double cpuTime=static_cast(pidStatus[pid][cur_last].wtime-pidStatus[pid][pre_last].wtime); 284 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 285 | return cpuTime/wallTime; 286 | } 287 | double MonitorImpl::getCpuIndex(unsigned int pid){ 288 | int cur_last=!cur; 289 | return pidStatus[pid][cur_last].processor; 290 | } 291 | 292 | double MonitorImpl::getMemRatio(unsigned int pid){ 293 | int cur_last=!cur; 294 | double rss=static_cast(PG_TO_KB(pidStatus[pid][cur_last].rss)); 295 | double totalMem=static_cast(pidStatus[pid][cur_last].tlmkb); 296 | return rss/totalMem; 297 | } 298 | double MonitorImpl::getMemRss(unsigned int pid){ 299 | int cur_last=!cur; 300 | return static_cast(PG_TO_KB(pidStatus[pid][cur_last].rss)); 301 | } 302 | double MonitorImpl::getMemVsz(unsigned int pid){ 303 | int cur_last=!cur; 304 | return static_cast(B_TO_KB(pidStatus[pid][cur_last].vsz)); 305 | } 306 | double MonitorImpl::getMemMinfltRate(unsigned int pid){ 307 | int cur_last=!cur; 308 | int pre_last=cur; 309 | double minflt=static_cast(pidStatus[pid][cur_last].minflt-pidStatus[pid][pre_last].minflt)*100; //magic number 100 from sysconf(_SC_CLK_TCK) 310 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 311 | return minflt/wallTime; 312 | } 313 | double MonitorImpl::getMemMajfltRate(unsigned int pid){ 314 | int cur_last=!cur; 315 | int pre_last=cur; 316 | double majflt=static_cast(pidStatus[pid][cur_last].majflt-pidStatus[pid][pre_last].majflt)*100; //magic number 100 from sysconf(_SC_CLK_TCK) 317 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 318 | return majflt/wallTime; 319 | } 320 | 321 | double MonitorImpl::getIoRdRate(unsigned int pid){ 322 | int cur_last=!cur; 323 | int pre_last=cur; 324 | double read_bytes=static_cast(B_TO_KB(pidStatus[pid][cur_last].read_bytes-pidStatus[pid][pre_last].read_bytes))*100; //magic number 100 from sysconf(_SC_CLK_TCK) 325 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 326 | return read_bytes/wallTime; 327 | } 328 | double MonitorImpl::getIoWrRate(unsigned int pid){ 329 | int cur_last=!cur; 330 | int pre_last=cur; 331 | double write_bytes=static_cast(B_TO_KB(pidStatus[pid][cur_last].write_bytes-pidStatus[pid][pre_last].write_bytes))*100; //magic number 100 from sysconf(_SC_CLK_TCK) 332 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 333 | return write_bytes/wallTime; 334 | } 335 | double MonitorImpl::getIoCcwrRate(unsigned int pid){ 336 | int cur_last=!cur; 337 | int pre_last=cur; 338 | double cancelled_write_bytes=static_cast(B_TO_KB(pidStatus[pid][cur_last].cancelled_write_bytes-pidStatus[pid][pre_last].cancelled_write_bytes))*100; //magic number 100 from sysconf(_SC_CLK_TCK) 339 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime); 340 | return cancelled_write_bytes/wallTime; 341 | } 342 | double MonitorImpl::getIoDelay(unsigned int pid){ 343 | int cur_last=!cur; 344 | int pre_last=cur; 345 | return static_cast(pidStatus[pid][cur_last].blkio_swapin_delays-pidStatus[pid][pre_last].blkio_swapin_delays)/100.0; //magic number 100 from sysconf(_SC_CLK_TCK) 346 | } 347 | 348 | double MonitorImpl::getNetSdRate(unsigned int pid){ 349 | int cur_last=!cur; 350 | int pre_last=cur; 351 | double netSdByte=static_cast(pidStatus[pid][cur_last].netSd_bytes-pidStatus[pid][pre_last].netSd_bytes)/1000; 352 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime)/100; 353 | return netSdByte/wallTime; 354 | } 355 | double MonitorImpl::getNetRcRate(unsigned int pid){ 356 | int cur_last=!cur; 357 | int pre_last=cur; 358 | double netRcByte=static_cast(pidStatus[pid][cur_last].netRc_bytes-pidStatus[pid][pre_last].netRc_bytes)/1000; //kB 359 | double wallTime=static_cast(pidStatus[pid][cur_last].uptime-pidStatus[pid][pre_last].uptime)/100; // s 360 | return netRcByte/wallTime; 361 | } --------------------------------------------------------------------------------