接触snmp有3个星期左右了吧,现在来总结下子自己在这期间做了些什么,老板给我的任务有以下几项:
1:aggen.cpp与globaltime版本对齐,就是个个文件是对应的,都保证是相互兼容的,不一定都是最新的。
2:写一个gpd的驱动,他主要是用于电源的管理,用来查询和通知snmp电源现在的状况。
3:系统的一些状态。例如cpu利用率,内存利用率。
4:代理端发送trap时使用162端口,这样做有利于防火墙的规范
大体上是这多,以下对以上4点做详细的介绍.
对齐问题:
在aggen.cpp里有一个读取硬件寄存器的一段,这是针对x86构架的:
//读取电源状态
{
int nVal;
ioperm(0x2f1,1,1);
nVal = inb(0x2f1); //读取键盘
nVal >>= 6;
ioperm(0x2f1,1,0);
//报警
if(g_nPowerStatus != nVal && nVal != 0 && nVal != 3)
{
//printf("val = %d/n",nVal);
g_nPowerStatus = nVal;
g_lpSnmpData->SendAllTrapType(oidTrapMsgPowerErr);
}
}*/
全部屏蔽掉,因为我们是用在arm上的。
signal (SIGTERM, sig);
signal (SIGINT, sig);
signal (SIGSEGV, sig);
signal (SIGALRM,sig);
是对这4个信号的处理,至于这4个信号在我的另一片博客上有讲到。
保证mib树的值是对的,#define oidSysMsgReBoot "1.3.6.1.4.1.2354.1.2.1.0"
#define oidSysMsgLocalTime "1.3.6.1.4.1.2354.1.2.2.0"
#define oidSysMsgLocalDate "1.3.6.1.4.1.2354.1.2.3.0"
#define oidSysMsgTimeSource "1.3.6.1.4.1.2354.1.2.4.0"
#define oidSysMsgSetTrapAddress "1.3.6.1.4.1.2354.1.2.5.0"
#define oidSysMsgpower1status "1.3.6.1.4.1.2354.1.2.6.0"
#define oidSysMsgpower2status "1.3.6.1.4.1.2354.1.2.7.0"
#define oidSysMsgcpustatus "1.3.6.1.4.1.2354.1.2.8.0"
#define oidSysMsgmemorystatus "1.3.6.1.4.1.2354.1.2.9.0"
#define oidTrapMsgColdStart "1.3.6.1.4.1.2354.1.3.1"
#define oidTrapMsgNtpAlarm "1.3.6.1.4.1.2354.1.3.2"
#define oidTrapMsgGpsUnlocked "1.3.6.1.4.1.2354.1.3.4"
#define oidTrapMsgNewSyncType "1.3.6.1.4.1.2354.1.3.5"
#define oidTrapMsgPowerErr "1.3.6.1.4.1.2354.1.3.7"
#define oidTrapMsgRootDlay "1.3.6.1.4.1.2354.1.3.8"
#define oidTrapWorkStatusChange "1.3.6.1.4.1.2354.1.3.9"
//2007-3-13 17:59添加错误时间源trap
#define oidTrapErrorTimeSource "1.3.6.1.4.1.2354.1.3.10"
//2007-5-27 11:13添加主备机切换,0表示当前状态为备机,1表示为主机
#define oidTrappulsechange "1.3.6.1.4.1.2354.1.3.11"
#define oidTrapcpualarm "1.3.6.1.4.1.2354.1.3.12"
#define oidNtpSysHostMode "1.3.6.1.4.1.2354.1.4.6.0"
#define oidNtpSysStratum "1.3.6.1.4.1.2354.1.4.7.0"
#define oidNtpSysPoll "1.3.6.1.4.1.2354.1.4.8.0"
#define oidNtpSysPrecision "1.3.6.1.4.1.2354.1.4.9.0"
#define oidNtpSysRootDelay "1.3.6.1.4.1.2354.1.4.10.0"
#define oidNtpSysRootDisp "1.3.6.1.4.1.2354.1.4.11.0"
#define oidNtpSysRefClockIdent "1.3.6.1.4.1.2354.1.4.12.0"
#define oidNtpSysRunTime "1.3.6.1.4.1.2354.1.4.13.0"
#define oidNtpDeviceDiscrible "1.3.6.1.4.1.2354.1.4.14.0"
#define oidNtpSysWorkStatus "1.3.6.1.4.1.2354.1.4.15.0"
//2007-5-27 11:14,表示查询当前的机器为主备机状态
#define oidNtpSysPulseStatus "1.3.6.1.4.1.2354.1.4.16.0"
#define oidTest "1.3.6.1.4.1.2354.1.4.17.0"
#define oidGpsGroupValid "1.3.6.1.4.1.2354.1.5.1.0"
#define oidGpsNumTrackSats "1.3.6.1.4.1.2354.1.5.2.0"
#define oidGpsLongitude "1.3.6.1.4.1.2354.1.5.4.0"
#define oidGpsLatitude "1.3.6.1.4.1.2354.1.5.5.0"
#define oidGpsHeight "1.3.6.1.4.1.2354.1.5.6.0"
//电源的状态
#define oidpower1status "1.3.6.1.4.1.2354.1.6.1.0"
#define oidpower2status "1.3.6.1.4.1.2354.1.6.2.0"
#define oidcpu "1.3.6.1.4.1.2354.1.6.3.0"
#define oidmemory "1.3.6.1.4.1.2354.1.6.4.0"
//手工添加的TRAP数据包参数OID定义
#define oidImuParamMsgDesc "1.3.6.1.4.1.2354.1.7.1"
#define oidImuParamServerName "1.3.6.1.4.1.2354.1.7.2"
#define oidImuParamServerIPAddress "1.3.6.1.4.1.2354.1.7.1.3"
#define oidImuParamWarnningTime "1.3.6.1.4.1.2354.1.7.1.4"
#define oidImuParamActData "1.3.6.1.4.1.2354.1.7.1.5"
//#define oidGloblEnterprise "1.3.6.1.4.1.2011.2.105.1.1"
#define oidGlobalTimeEnterprise "1.3.6.1.4.1.2354.1"
//表示trap的值
#define oidTrapDataValue "1.3.6.1.4.1.2354.1.7.3"
这些值是和globaltime_mib.txt对应的--iso OBJECT IDENTIFIER ::= { 1 }
--org OBJECT IDENTIFIER ::= { iso 3 }
--dod OBJECT IDENTIFIER ::= { org 6 }
--internet OBJECT IDENTIFIER ::= { dod 1 }
--private OBJECT IDENTIFIER ::= { internet 4 }
--enterprises OBJECT IDENTIFIER ::= { private 1 }
--globalTimeCom OBJECT IDENTIFIER ::= { enterprises 2354 }
gttMIB MODULE-IDENTITY
LAST-UPDATED "200602230000Z"
ORGANIZATION "Shanghai GLOBALTIME CO. Ltd."
CONTACT-INFO "[email protected]"
DESCRIPTION "NTP Server MIB File"
::= { gtt 1 }
globalTimeEnt OBJECT IDENTIFIER ::= { enterprises 2354 }
gtt OBJECT IDENTIFIER ::= { globalTimeEnt 1 }
--gttMIB OBJECT IDENTIFIER ::= { gtt 1 }
sysMsg OBJECT IDENTIFIER ::= { gtt 2 }
trapMsg OBJECT IDENTIFIER ::= { gtt 3 }
ntp OBJECT IDENTIFIER ::= { gtt 4 }
gps OBJECT IDENTIFIER ::= { gtt 5 }
gttMIBConformance OBJECT IDENTIFIER ::= { gttMIB 1 }
gttMIBCompliances OBJECT IDENTIFIER ::= { gttMIBConformance 1 }
gttMIBGroups OBJECT IDENTIFIER ::= { gttMIBConformance 2 }
gttMIBCompliance MODULE-COMPLIANCE
STATUS current
DESCRIPTION "compliance statements."
MODULE -- this module
MANDATORY-GROUPS
{
-- trapMsgGroup,
sysMsgGroup,
ntpGroup,
gpsGroup
sysstatusGroup
}
::= { gttMIBCompliances 1 }
gttNotificationsGroup NOTIFICATION-GROUP
NOTIFICATIONS
{
trapMsgColdStart,
trapMsgNtpAlarm,
trapMsgGpsUnlocked,
trapClientTimeErr,
trapMsgNewSyncType,
trapMsgPower1Err,
trapMsgRootDlay,
trapMsgWorkStatusChange,
trapErrorTimeSource,
Trappulsechange,
Trapcpualarm
}
STATUS current
DESCRIPTION
"units of conformance"
::= { gttMIBGroups 4 }
sysMsgGroup OBJECT-GROUP
OBJECTS
{
sysMsgReBoot,
sysMsgLocalTime,
sysMsgLocalDate,
sysMsgTimeSource,
SysMsgSetTrapAddress,
SysMsgpower1status,
SysMsgpower2status,
SysMsgcpu,
SysMsgmemory
}
STATUS current
DESCRIPTION
"units of conformance"
::= { gttMIBGroups 1 }
ntpGroup OBJECT-GROUP
OBJECTS
{
ntpSysHostMode,
ntpSysStratum,
ntpSysPoll,
ntpSysPrecision,
ntpSysRootDelay,
ntpSysRootDisp,
ntpSysRefClockIdent,
ntpSysRunTime,
ntpNtpDeviceDiscrible,
ntpSysWorkStatus,
ntpSysPulseStatus
}
STATUS current
DESCRIPTION "units of conformance"
::= { gttMIBGroups 2 }
gpsGroup OBJECT-GROUP
OBJECTS
{
gpsGroupValid,
gpsNumTrackSats,
gpsLongitude,
gpsLatitude,
gpsHeight
}
STATUS current
DESCRIPTION
"units of conformance"
::= { gttMIBGroups 3 }
还有就是globaltime_mib.txt里有的globaltime.h没有,这时就要相互添加了,怎么添加就是照葫芦画瓢,
class Trapcpualarm : public NotificationOriginator {
public:
Trapcpualarm ();
virtual ~Trapcpualarm ();
virtual void generate(Vbx*, int, const OctetStr&);
};
这就是照上一个类写出来的。
public NotificationOriginator 这是所有trap类都必须包含的子类,因为你的trap是于他来发送的
class globaltime: public MibGroup 这是mibgrop的一个分支,与他来产生树的。
class power1status: public MibLeaf 返回值是整型的
class gpsLongitude: public SnmpDisplayString 返回值是字符串的
对齐就讲到这吧。
现在现在讲讲电源的问题。我们用GPD14,GPD15来接受2路电源,在snmp中我们要知道2路电源的情况,谁有电谁没电,当有一路断电时会自动发trap,恩,电源基本上就是这些问题。
为了获取GPD14,GPD15的值,我们必须写驱动,因为这读取的是硬件寄存器的值,应用层不能直接访问。
驱动程序如下:
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#define DEVICE_NAME "power" //定义设备名
#define POWER_MAJOR 232 //手动定义主设备号
//定义要操作的设备,把每一个led作为结构体的一个成员
static unsigned long power_table[] = {
S3C2410_GPD14,
S3C2410_GPD15,
};
//对设备进行设置,结构体的每一个成员是对对应led的设置
static unsigned int power_cfg_table [] = {
S3C2410_GPD14_INP,
S3C2410_GPD15_INP,
};
static int s3c2410_power_open(struct inode *inode,struct file *file)
{
printk("open/n");
return 0;
}
//设备驱动程序中对设备的I/O通道进行管理的函数,用来实现对led的操作
static int s3c2410_power_read(struct file *file, unsigned int * buffer, size_t count, loff_t *ppos)
{
unsigned int k1, k2 ;
k1=0;
k2=0;
if(s3c2410_gpio_getpin(S3C2410_GPD14))
{
k1=1;
//printk("%d../n",s3c2410_gpio_getpin(S3C2410_GPD14));
}
if(s3c2410_gpio_getpin(S3C2410_GPD15))
{
k2=1;
//printk("%d../n",s3c2410_gpio_getpin(S3C2410_GPD15));
}
//printk("%d..%d/n",k1,k2);
buffer++;
copy_to_user(buffer, &k1, sizeof(k1));
buffer++;
copy_to_user(buffer, &k2, sizeof(k2));
}
static struct file_operations s3c2410_power_fops = {
.owner = THIS_MODULE,
.open = s3c2410_power_open,
.read = s3c2410_power_read,
};
//模块加载函数
static int __init s3c2410_power_init(void)
{
int ret;
int i;
//注册设备号
ret = register_chrdev(POWER_MAJOR, DEVICE_NAME, &s3c2410_power_fops);
if (ret < 0) {
printk(DEVICE_NAME " can't register major number/n");
return ret;
}
devfs_mk_cdev(MKDEV(POWER_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, DEVICE_NAME);
for (i = 0; i < 2; i++) {
s3c2410_gpio_setpin(power_table[i], 0);
s3c2410_gpio_cfgpin(power_table[i], power_cfg_table[i]);
}
printk(DEVICE_NAME " initialized/n");
return 0;
}
//模块卸载函数
static void __exit s3c2410_power_exit(void)
{
devfs_remove(DEVICE_NAME);
unregister_chrdev(POWER_MAJOR, DEVICE_NAME);
}
module_init(s3c2410_power_init);
module_exit(s3c2410_power_exit);
MODULE_LICENSE("GPL");
pw= open("/dev/power",O_RDONLY);
if (pw < 0)
{
perror("xxx device power");
exit(1);
}
else
{
read(pw,buffer,2);
printf("%d,%d/n",buffer[1],buffer[2]);
}
就可以读到GPD14,GPD15的值了。
在globaltime_mib.txt中加入
SysMsgpower1status,
SysMsgpower2status,
并按提示写出具体定义,再在globaltime.h中添加
#define oidpower1status "1.3.6.1.4.1.2354.1.6.1.0"
#define oidpower2status "1.3.6.1.4.1.2354.1.6.2.0"
class power1status: public MibLeaf {
public:
power1status();
virtual ~power1status();
static power1status* instance;
virtual void get_request(Request*, int);
virtual long get_state();
virtual void set_state(long);
//--AgentGen BEGIN=gpsNumTrackSats
//--AgentGen END
};
class power2status: public MibLeaf {
public:
power2status();
virtual ~power2status();
static power2status* instance;
virtual void get_request(Request*, int);
virtual long get_state();
virtual void set_state(long);
//--AgentGen BEGIN=gpsNumTrackSats
//--AgentGen END
};
在globaltime.cpp中具体给出定义
power1status* power1status::instance = 0;
power1status::power1status():
MibLeaf(oidSysMsgpower1status, READONLY, new SnmpInt32())
{
instance = this;
}
power1status::~power1status()
{
//--AgentGen BEGIN=gpsNumTrackSats::~gpsNumTrackSats
//--AgentGen END
}
void power1status::get_request(Request* req, int ind)
{
g_lpSnmpData->readpowerstatus();
*((SnmpInt32*)value) =g_lpSnmpData->power1;
//--AgentGen BEGIN=gpsNumTrackSats::get_request
//--AgentGen END
MibLeaf::get_request(req, ind);
}
long power1status::get_state()
{
return (long)*((SnmpInt32*)value);
}
void power1status::set_state(long l)
{
*((SnmpInt32*)value) = l;
}
至于get_request怎么工作的暂时不用去管。
这些我们所需要的数据都是在readdata.h和readdata.cpp中我们自己写程序算出来的
trapMsgPower1Err的加入方法如下:
开始和get_reque的一样,后面的加入方法请看下一章
上一次讲到trapMsgPower1Err的加入方法,首先是在globaltime.h和globaltime.cpp里加入树的分支及trapMsgPower1Err这个类的声明和定义,其主要的实现部分在readdata.cpp里的SendAllTrapType这个类中if(oidTrapMsgPowerErr == id)
{
printf("oidTrapMsgPowerErr");
trapMsgPowerErr pTrap;
if(power1==0||power2==0)
vbs.set_value(SnmpInt32(0));
if(power1==1&&power2==1)
vbs.set_value(SnmpInt32(1));
power1jiu=power1;
power2jiu=power2;
pTrap.generate(&vbs, 1, "");//send trap
具体的power1,power2的值在void CAllSnmpData::readpowerstatus()
{
int pw, i;
unsigned int buffer[4];
buffer[0]=0;
buffer[1]=1;
buffer[2]=1;
buffer[3]=0;
pw= open("/dev/power",O_RDONLY);
if (pw < 0)
{
perror("xxx device power");
exit(1);
}
else
{
read(pw,buffer,2);
close(pw);
power1=buffer[1];
power2=buffer[2];
}
}
算出来的值还要进行分析,以确定是否要发生trap
//phase power data
void CAllSnmpData:: phasepowerdata()
{
readpowerstatus();
if(power1!=power1jiu||power2!=power2jiu)
SendAllTrapType(oidTrapMsgPowerErr);
}
我们的原则是只要有一路电源有故障就发生trap,如果那路电源又好了的话在发送一个trap来提示电源正常
上次讲完了电源的部分,现在讲讲关于系统状态的部分:
我们关于系统状态只有2个一个是cpu利用率另一个是memory利用率。
先说cpu利用率吧:
在/proc里关于cpu的信息好像只有cpuinfo,但是这里面只有cpu的一些出场信息,没什么有用的东西,在网上查了下,以下是一些关于cpu的资料:
在Linux的内核中,有一个全局变量:Jiffies。 Jiffies代表时间。它的单位随硬件平台的不同而不同。系统里定义了一个常数HZ,代表每秒种最小时间间隔的数目。这样jiffies的单位就是1/HZ。Intel平台jiffies的单位是1/100秒,这就是系统所能分辨的最小时间间隔了。每个CPU时间片,Jiffies都要加1。 CPU的利用率就是用执行用户态+系统态的Jiffies除以总的Jifffies来表示。
在Linux系统中,可以用/proc/stat文件来计算cpu的利用率(详细的解释可参考:http://www.linuxhowtos.org/System/procstat.htm)。这个文件包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻。
如:
QUOTE:
[sailorhzr@builder ~]$ cat /proc/stat
cpu 432661 13295 86656 422145968 171474 233 5346
cpu0 123075 2462 23494 105543694 16586 0 4615
cpu1 111917 4124 23858 105503820 69697 123 371
cpu2 103164 3554 21530 105521167 64032 106 334
cpu3 94504 3153 17772 105577285 21158 4 24
intr 1065711094 1057275779 92 0 6 6 0 4 0 3527 0 0 0 70 0 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7376958 0 0 0 0 0 0 0 1054602 0 0 0 0 0 0 0 30 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 19067887
btime 1139187531
processes 270014
procs_running 1
procs_blocked 0
输出解释
CPU 以及CPU0、CPU1、CPU2、CPU3每行的每个参数意思(以第一行为例)为:
参数 解释
user (432661) 从系统启动开始累计到当前时刻,用户态的CPU时间(单位:jiffies) ,不包含 nice值为负进程。1jiffies=0.01秒
nice (13295) 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间(单位:jiffies)
system (86656) 从系统启动开始累计到当前时刻,核心时间(单位:jiffies)
idle (422145968) 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies)
iowait (171474) 从系统启动开始累计到当前时刻,硬盘IO等待时间(单位:jiffies) ,
irq (233) 从系统启动开始累计到当前时刻,硬中断时间(单位:jiffies)
softirq (5346) 从系统启动开始累计到当前时刻,软中断时间(单位:jiffies)
CPU时间=user+system+nice+idle+iowait+irq+softirq
“intr”这行给出中断的信息,第一个为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。
“ctxt”给出了自系统启动以来CPU发生的上下文交换的次数。
“btime”给出了从系统启动到现在为止的时间,单位为秒。
“processes (total_forks) 自系统启动以来所创建的任务的个数目。
“procs_running”:当前运行队列的任务的数目。
“procs_blocked”:当前被阻塞的任务的数目。
那么CPU利用率可以使用以下两个方法。先取两个采样点,然后计算其差值:
QUOTE:
cpu usage=(idle2-idle1)/(cpu2-cpu1)*100
cpu usage=[(user_2 +sys_2+nice_2) - (user_1 + sys_1+nice_1)]/(total_2 - total_1)*100
我们采用第一种计算方法,自己写的shell,把cpu空闲的资源放在/var/cpu1.info下,总资源放在/var/cpu2.info下。5秒为间隔不断循环。
#!/bin/sh
while [ 1 ]
do
CPULOG_1=$(cat /proc/stat | grep 'cpu ' | awk '{print $2" "$3" "$4" "$5" "$6" "$7" "$8}')
SYS_IDLE_1=$(echo $CPULOG_1 | awk '{print $4}')
Total_1=$(echo $CPULOG_1 | awk '{print $1+$2+$3+$4+$5+$6+$7}')
sleep 5
CPULOG_2=$(cat /proc/stat | grep 'cpu ' | awk '{print $2" "$3" "$4" "$5" "$6" "$7" "$8}')
SYS_IDLE_2=$(echo $CPULOG_2 | awk '{print $4}')
Total_2=$(echo $CPULOG_2 | awk '{print $1+$2+$3+$4+$5+$6+$7}')
SYS_IDLE=`expr $SYS_IDLE_2 - $SYS_IDLE_1`
Total=`expr $Total_2 - $Total_1`
echo $SYS_IDLE >/var/cpu1.info
echo $Total >/var/cpu2.info
done
既然cpu利用率都可以计算出来了那我们就在snmp中添加这一项功能了。
首先给他定义一个树在globaltime_mib.txt里,添加代码如下:
sysMsgGroup OBJECT-GROUP
OBJECTS
{
sysMsgReBoot,
sysMsgLocalTime,
sysMsgLocalDate,
sysMsgTimeSource,
SysMsgSetTrapAddress,
SysMsgpower1status,
SysMsgpower2status,
SysMsgcpu,
SysMsgmemory
}
STATUS current
DESCRIPTION
"units of conformance"
::= { gttMIBGroups 1 }
其中SysMsgcpu,就是我们添加的然后具体说明他
SysMsgcpu OBJECT-TYPE
SYNTAX INTEGER(0..100)
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"The value of this variable indicates the Status of current cpu usage factor"
::= { sysMsg 8 }
在globaltime.h和globaltime.cpp里添加相应的代码
class cpu: public MibLeaf {
public:
cpu();
virtual ~cpu();
static cpu* instance;
virtual void get_request(Request*, int);
};
cpu* cpu::instance = 0;
cpu::cpu():
MibLeaf(oidSysMsgcpustatus, READONLY, new SnmpInt32())
{
// This leaf object is a singleton. In order to access it use
// the static pointer gpsLatitude::instance.
instance = this;
//--AgentGen BEGIN=gpsLatitude::gpsLatitude
//--AgentGen END
}
cpu::~cpu()
{
//--AgentGen BEGIN=gpsLatitude::~gpsLatitude
//--AgentGen END
}
void cpu::get_request(Request* req, int ind)
{
g_lpSnmpData->readcpustatus();
*((SnmpInt32*)value) = g_lpSnmpData->cpustatus;
MibLeaf::get_request(req, ind);
}
memory* memory::instance = 0;
memory::memory():
MibLeaf(oidSysMsgmemorystatus, READONLY, new SnmpInt32())
{
// This leaf object is a singleton. In order to access it use
// the static pointer gpsLatitude::instance.
instance = this;
//--AgentGen BEGIN=gpsLatitude::gpsLatitude
//--AgentGen END
}
g_lpSnmpData->cpustatus是在readdata.cpp理算出来的。
在readdata.cpp里
void CAllSnmpData:: readcpustatus()
{
int m, n ,d;
float a, b , c ;
//system("/mnt/bin/cpu.sh");
FILE *fd3;
char sz[5];
fd3 = fopen("/var/cpu1.info","r"); //以流方式打开
if(NULL == fd3)
exit(1);
else
{
if(fgets(sz, 4, fd3) != NULL)
m = atoi(sz);
fclose(fd3);
}
//printf("%d",m);
FILE *fd2;
char ss[5];
fd2 = fopen("/var/cpu2.info","r"); //以流方式打开
if(NULL == fd2)
exit(1);
else
{
if(fgets(ss, 4, fd2) != NULL)
n= atoi(ss);
fclose(fd2);
}
b=m;
c=n;
a=b/c;
a=(1-a);
cpustatus=(int)(a*100);
}
到此cpu利用率就算是添加上去了。
cpu利用率讲完了,现在讲讲memory利用率。
在/proc/meminfo里有关于memory的信息
[root@GlobalTime /proc]$cat meminfo
MemTotal: 61888 kB
MemFree: 49600 kB
Buffers: 2140 kB
Cached: 6428 kB
SwapCached: 0 kB
Active: 4504 kB
Inactive: 5028 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 61888 kB
LowFree: 49600 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
Mapped: 2516 kB
Slab: 1880 kB
CommitLimit: 30944 kB
Committed_AS: 8404 kB
PageTables: 148 kB
VmallocTotal: 450560 kB
VmallocUsed: 3240 kB
VmallocChunk: 445944 kB
前2项是memory的总量和空闲量,有了他就不难算出memory利用率了。
于cpu利用率一样,首先给他定义一个树在globaltime_mib.txt里,添加代码如下:
sysMsgGroup OBJECT-GROUP
OBJECTS
{
sysMsgReBoot,
sysMsgLocalTime,
sysMsgLocalDate,
sysMsgTimeSource,
SysMsgSetTrapAddress,
SysMsgpower1status,
SysMsgpower2status,
SysMsgcpu,
SysMsgmemory
}
STATUS current
DESCRIPTION
'units of conformance'
::= { gttMIBGroups 1 }
其中SysMsgmemory,就是我们添加的然后具体说明他
SysMsgmemory OBJECT-TYPE
SYNTAX INTEGER(0..100)
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"The value of this variable indicates the Status of current memory usage factor"
::= { sysMsg 9 }
在globaltime.h和globaltime.cpp里添加相应的代码
#define oidmemory "1.3.6.1.4.1.2354.1.6.4.0"
class memory: public MibLeaf {
public:
memory();
virtual ~memory();
static memory* instance;
virtual void get_request(Request*, int);
};
memory::~memory()
{
//--AgentGen BEGIN=gpsLatitude::~gpsLatitude
//--AgentGen END
}
void memory::get_request(Request* req, int ind)
{
g_lpSnmpData->readmemstatus();
*((SnmpInt32*)value) = g_lpSnmpData->memstatus;
// *((SnmpInt32*)value) =3;
MibLeaf::get_request(req, ind);
}
这时要注意了,之前我也犯这样的错误,就是globaltime::globaltime(): MibGroup("1.3.6.1.4.1.2354", "gttMIB")
{
add(new sysMsgReBoot());
add(new sysMsgLocalTime());
add(new sysMsgLocalDate());
add(new sysMsgSetTimeSource());
add(new sysMsgSetTrapAddress());
add(new ntpSysHostMode());
add(new ntpSysStratum());
add(new ntpSysPoll());
add(new ntpSysPrecision());
add(new ntpSysRootDelay());
add(new ntpSysRootDisp());
add(new ntpSysRefClockIdent());
add(new ntpSysRunTime());
add(new ntpSysDevDiscrible());
add(new ntpSysWorkStatus());
add(new ntpSysPulseStatus());
add(new gpsGroupValid());
add(new gpsNumTrackSats());
add(new gpsLongitude());
add(new gpsLatitude());
add(new gpsHeight());
add(new linjietest());
add(new power1status());
add(new power2status());
add(new cpu());
add(new memory());
}
里没有添加add(new power1status());
add(new power2status());
add(new cpu());
add(new memory());
,不添加这个mib里就没有他的信息,就会导致我们不能get
在readdata.cpp里算出g_lpSnmpData->memstatus
void CAllSnmpData:: readmemstatus()
{
FILE *fd3;
FILE *fd2;
int i=0, m, n;
float mm;
char sz[256],sa[256], ss[5], aa[5];
char *str1 , *ptr, *ptr1, *p, *p1, *p3;
fd3 = fopen("/proc/meminfo","r"); //以流方式打开
if(NULL == fd3)
exit(1);
else
{
if(fread(sz, 255,1, fd3) != NULL)
fclose(fd3);
}
str1=sz;
ptr=strstr(str1,"MemTotal:");
while(*ptr!='1'&&*ptr!='2'&&*ptr!='3'&&*ptr!='4'&&*ptr!='5'&&*ptr!='6'&&*ptr!='7'&&*ptr!='8'&&*ptr!='9')
{
ptr++;
}
ptr1=ptr;
while(*ptr1!='k')
{
ptr1++;
}
p1=ptr1;
ptr1--;
ptr1--;
for(i;ptr1>=ptr;ptr1--,i++)
ss[4-i]=*ptr1;
m = atoi(ss);
// printf("%d/n",m);
str1=sz;
ptr=strstr(str1,"MemFree: ");
while(*ptr!='1'&&*ptr!='2'&&*ptr!='3'&&*ptr!='4'&&*ptr!='5'&&*ptr!='6'&&*ptr!='7'&&*ptr!='8'&&*ptr!='9')
{
ptr++;
}
ptr1=ptr;
while(*ptr1!='k')
{
ptr1++;
}
p1=ptr1;
ptr1--;
ptr1--;
i=0;
for(i;ptr1>=ptr;ptr1--,i++)
aa[4-i]=*ptr1;
n = atoi(aa);
//printf("%d/n",n);
mm=1-(float)n/(float)m;
// printf("%f",mm);
// memstatus=mm;
memstatus=(int)(mm*100);
}
接下来是我花了最长时间才完成的发生trap时绑定162端口,就是说版子发送trap时用的是162端口。
先从源头找起,在readdata.cpp里都有pTrap.generate(&vbs, 1, "");//send trap这句话说明发trap的起点是generate这个函数,终点肯定是sendto,因为是以udp方式传送的。
pTrap.generate(&vbs, 1, "")首先看这个函数的定义
int NotificationOriginator::generate(Vbx* vbs, int size, const Oidx& id,
unsigned int timestamp,
const Oidx& enterprise,
const OctetStr& contextName)
{
// We have to be careful here about synchronisation because,
// we may be called after an interrupt
// Therefore synch everything or use synch methods like
// MibTable::get_rows_cloned();
List<MibTableRow>* typeList =
snmpNotifyEntry::instance->get_rows_cloned();
ListCursor<MibTableRow> typeCur;
List<MibTableRow>* list =
snmpTargetAddrEntry::instance->get_rows_cloned();
ListCursor<MibTableRow> cur;
#ifdef _SNMPv3
if (!localEngineID) {
if (!v3MP::I) {
LOG_BEGIN(ERROR_LOG | 0);
LOG("NotificationOriginator: v3MP has to be initialized before notifications can be sent");
LOG_END;
}
localEngineID = new OctetStr(v3MP::I->get_local_engine_id());
}
#endif
int totalStatus = SNMP_ERROR_SUCCESS;
NotificationOriginatorParams nop(vbs, size, id, timestamp, enterprise, contextName);
for (cur.init(list); cur.get(); cur.next()) {
int notify = NO_TRAP;
// look for tags that identify notifications
for (typeCur.init(typeList); typeCur.get(); typeCur.next()) {
OctetStr tag;
typeCur.get()->first()->get_value(tag);
char* tagstr = new char[tag.len()+1];
strncpy(tagstr, (char*)tag.data(), tag.len());
tagstr[tag.len()] = 0;
if (((SnmpTagList*)cur.get()->get_nth(4))->
contains(tagstr)) {
// determine notification type
typeCur.get()->get_nth(1)->get_value(notify);
nop.target = 0;
if (check_access(cur, nop)) {
int status = send_notify(cur, nop, notify);
if (status != SNMP_ERROR_SUCCESS)
totalStatus = status;
delete nop.target;
}
}
delete[] tagstr;
}
if (notify == NO_TRAP) {
LOG_BEGIN(DEBUG_LOG | 6);
LOG("NotificationOriginator: generate: could not find valid tag");
LOG_END;
continue;
}
}
typeList->clearAll();
delete typeList;
list->clearAll();
delete list;
return totalStatus;
}
在函数里她又调用send_notify(cur, nop, notify)我们接着找,在看send_notify这个函数的定义:
int NotificationOriginator::send_notify(ListCursor<MibTableRow>& cur,
NotificationOriginatorParams& nop, int notify)
{
Vbx*& vbs = nop.vbs;
int& size = nop.size;
const Oidx& id = nop.id;
const Oidx& enterprise = nop.enterprise;
OctetStr& securityName = nop.securityName;
int& mpModel = nop.mpModel;
#ifdef _SNMPv3
int& securityLevel = nop.securityLevel;
const OctetStr& contextName = nop.contextName;
unsigned int& timestamp = nop.timestamp;
UTarget*& target = nop.target;
#else
CTarget*& target = nop.target;
#endif
long targetDomain =
((snmpTargetAddrTDomain*)cur.get()->first())->get_state();
Oidx trapoid(id);
#ifdef _SNMPv3
Pdux pdu;
pdu.set_type((notify == TRAP) ? sNMP_PDU_TRAP : sNMP_PDU_INFORM);
pdu.set_vblist(vbs, size);
pdu.set_notify_id(id);
pdu.set_notify_enterprise(enterprise);
pdu.set_notify_timestamp(timestamp);
pdu.set_security_level(securityLevel);
pdu.set_context_name(contextName);
// get community info from SNMP-COMMUNITY-MIB
if (((mpModel == mpV1) || (mpModel == mpV2c)) &&
(snmpCommunityEntry::instance)) {
if (snmpCommunityEntry::instance->get_community(securityName,
*localEngineID,
contextName)) {
target->set_security_name(securityName);
}
else {
LOG_BEGIN(WARNING_LOG | 2);
LOG("NotificationOriginator: community lookup failed for (securityName) (context)");
LOG(securityName.get_printable());
LOG(OctetStr(contextName).get_printable());
LOG_END;
}
}
#endif
int status = SNMP_ERROR_SUCCESS;
if (mpModel == mpV1) {
#ifdef _SNMPv3
pdu.set_type(sNMP_PDU_V1TRAP);
#endif
target->set_version(version1);
#ifdef _SNMPv3
status = SnmpRequestV3::send(*target, pdu);
if (nlmLogEntry::instance) {
nlmLogEntry::instance->
add_notification(*target, pdu, *localEngineID);
}
#else
status = SnmpRequest::process_trap(*target, vbs, size,
id, enterprise,
(notify != TRAP));
#endif
GenAddress address;
target->get_address(address);
LOG_BEGIN(EVENT_LOG | 1);
LOG("NotificationGenerator: sent v1 trap (id)(tdomain)(addr)(vbs)(community)");
LOG(trapoid.get_printable());
LOG(targetDomain);
LOG(address.get_printable());
LOG(size);
LOG(securityName.get_printable());
LOG_END;
}
else {
#ifdef _SNMPv3
if (mpModel == mpV3)
target->set_version(version3);
else
#endif
target->set_version(version2c);
if (notify != TRAP) {
target->set_retry(((SnmpInt32MinMax*)
cur.get()->get_nth(3))->get_state());
target->set_timeout(((SnmpInt32MinMax*)
cur.get()->get_nth(2))->get_state());
}
#ifdef _SNMPv3
status = SnmpRequestV3::send(*target, pdu);
if (nlmLogEntry::instance) {
nlmLogEntry::instance->
add_notification(*target, pdu, *localEngineID);
}
#else
status = SnmpRequest::process_trap(*target, vbs, size, id, enterprise,
(notify != TRAP));
#endif
GenAddress address;
target->get_address(address);
LOG_BEGIN(EVENT_LOG | 1);
if (notify == TRAP)
LOG("NotificationGenerator: sent trap (vers)(id)(tdomain)(addr)(vbs)(community/secName)(status)");
else
LOG("NotificationGenerator: sent inform (vers)(id)(tdomain)(addr)(vbs)(community/secName)(status)");
LOG(mpModel);
LOG(trapoid.get_printable());
LOG(targetDomain);
LOG(address.get_printable());
LOG(size);
LOG(securityName.get_printable());
LOG(status);
LOG_END;
}
return status;
}
他又调用process_trap,我们进一步跟进
现在找process_trap函数的定义:
int SnmpRequest::process_trap(SnmpTarget& target,
Vbx* vbs, int sz,
const Oidx& oid,
const Oidx& enterprise, boolean ack)
{
int status;
Snmpx* snmp = get_new_snmp(status);
// check construction status
if (status != SNMP_CLASS_SUCCESS) {
if (snmp) delete snmp;
return status;
}
Pdux pdu;
// the request id is set by Snmpx
for (int i=0; i<sz; i++)
pdu += vbs[i];
pdu.set_notify_timestamp(sysUpTime::get());
pdu.set_notify_id(oid);
pdu.set_notify_enterprise(enterprise);
if (ack)
status = snmp->inform(pdu, target);
else
status = snmp->trap(pdu, target);
if (status == SNMP_CLASS_SUCCESS) {
MibIIsnmpCounters::incOutPkts();
MibIIsnmpCounters::incOutTraps();
}
delete snmp;
return status;
}
下面这2个函数还是让我头疼了一会。。。。
if (ack)
status = snmp->inform(pdu, target);
else
status = snmp->trap(pdu, target);
现在先找snmpx这个类吧
class AGENTPP_DECL Snmpx: public NS_SNMP Snmp {
public:
Snmpx (int &status , u_short port): Snmp(status, port) {};
#ifdef SNMP_PP_WITH_UDPADDR
Snmpx(int& status, const NS_SNMP UdpAddress& addr): Snmp(status, addr) { }
#endif
#ifdef _SNMPv3
int receive(struct tim*, Pdux&, NS_SNMP UTarget&);
#else
int receive(struct tim*, Pdux&, NS_SNMP UdpAddress&,
NS_SNMP snmp_version&, NS_SNMP OctetStr&);
#endif
#ifdef _SNMPv3
int send (Pdux, NS_SNMP SnmpTarget*);
#else
int send (Pdux, NS_SNMP UdpAddress, NS_SNMP snmp_version, NS_SNMP OctetStr);
#endif
u_short get_port();
#ifdef WIN32
unsigned long get_session_fds() { return iv_snmp_session; }
#else
SNMPHANDLE get_session_fds() { return iv_snmp_session; }
#endif
protected:
unsigned long ProcessizedReqId(unsigned short);
unsigned long MyMakeReqId();
int snmp_engine( NS_SNMP Pdu &, // pdu to use
long int, // # of non repititions
long int, // # of max repititions
NS_SNMP SnmpTarget&, // from this target
const NS_SNMP snmp_callback cb,
const void * cbd);
};
在snmpx里他包含了snmp这个类原因是AGENT++ uses Snmpx instead of Snmp, because Snmp does not allow to listen on an UDP port for incoming SNMP requests.
其实status = snmp->inform(pdu, target)就是调用snmp类的trap这个函数
//---------------------[ send a trap ]-----------------------------------
int Snmp::trap(Pdu &pdu, // pdu to send
const SnmpTarget &target) // destination target
{
OctetStr my_get_community;
OctetStr my_set_community;
GenAddress address;
unsigned long my_timeout;
int my_retry;
unsigned char version;
int status;
debugprintf(1, "++ SNMP++, Send a Trap");
//---------[ make sure pdu is valid ]---------------------------------
if ( !pdu.valid())
{
debugprintf(0, "-- SNMP++, PDU Object Invalid");
return SNMP_CLASS_INVALID_PDU;
}
//---------[ make sure target is valid ]------------------------------
if ( !target.valid())
{
debugprintf(0, "-- SNMP++, Target Object Invalid");
return SNMP_CLASS_INVALID_TARGET;
}
CTarget* ctarget = NULL;
UTarget* utarget = NULL;
OctetStr security_name;
int security_model;
switch (target.get_type()) {
case SnmpTarget::type_ctarget:
ctarget = (CTarget*)(&target);
break;
case SnmpTarget::type_utarget:
utarget = (UTarget*)(&target);
break;
case SnmpTarget::type_base:
debugprintf(0, "-- SNMP++, do not use SnmpTarget, use a CTarget or UTarget");
return SNMP_CLASS_INVALID_TARGET;
default:
// target is not known
debugprintf(0, "-- SNMP++, type of target is unknown!");
return SNMP_CLASS_UNSUPPORTED;
}
if (ctarget) {
debugprintf(3, "snmp::trap called with CTarget");
if (!ctarget->resolve_to_C( my_get_community, my_set_community, address,
my_timeout, my_retry, version))
{
debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
return SNMP_CLASS_UNSUPPORTED;
}
#ifdef _SNMPv3
if (version == version3)
{
debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
return SNMP_CLASS_INVALID_TARGET;
}
#endif
}
else { // target is not a CTarget:
if (utarget) {
debugprintf(3, "trap called with UTarget");
if (!utarget->resolve_to_U( security_name, security_model, address,
my_timeout, my_retry, version))
{
debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
return SNMP_CLASS_UNSUPPORTED;
}
#ifdef _SNMPv3
if (version != version3) {
#endif
my_get_community = security_name;
if ((security_model != SecurityModel_v1) &&
(security_model != SecurityModel_v2)) {
debugprintf(0, "-- SNMP++, Target contains invalid security_model/version combination");
return SNMP_CLASS_INVALID_TARGET;
}
#ifdef _SNMPv3
} // end if (version != version3)
#endif
}
else { // target is neither CTarget nor UTarget:
debugprintf(0, "-- SNMP++, Resolve Fail");
return SNMP_CLASS_INVALID_TARGET;
}
}
//--------[ determine request id to use ]------------------------------
pdu.set_request_id( MyMakeReqId());
//--------[ check timestamp, if null use system time ]-----------------
check_notify_timestamp(pdu);
//------[ validate address to use ]-------------------------------------
if (!address.valid()) {
debugprintf(0, "-- SNMP++, Bad address");
return SNMP_CLASS_INVALID_TARGET;
}
if ((address.get_type() != Address::type_ip) &&
(address.get_type() != Address::type_udp) )
{
debugprintf(0, "-- SNMP++, Bad address type");
return SNMP_CLASS_TL_UNSUPPORTED;
}
UdpAddress udp_address(address);
if (!udp_address.valid()) {
debugprintf(0, "-- SNMP++, copy address failed");
return SNMP_CLASS_RESOURCE_UNAVAIL;
}
//----------[ choose the target address port ]-----------------------
if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
udp_address.set_port(SNMP_TRAP_PORT);
//----------[ based on the target type, choose v1 or v1 trap type ]-----
if ( version == version1)
pdu.set_type( sNMP_PDU_V1TRAP);
else // v2 and v3 use v2TRAP
pdu.set_type( sNMP_PDU_TRAP);
SnmpMessage snmpmsg;
#ifdef _SNMPv3
if ( version == version3) {
OctetStr engine_id = v3MP::I->get_local_engine_id();
if (!utarget) {
debugprintf(0, "-- SNMP++, dont know how to handle SNMPv3 without UTarget!");
return SNMP_CLASS_INVALID_TARGET;
}
// set context_engine_id of pdu, if it is not set
if (pdu.get_context_engine_id().len() == 0)
{
debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
engine_id.get_printable());
pdu.set_context_engine_id(engine_id);
}
debugprintf(4,"Snmp::trap:");
debugprintf(4," engineID (%s), securityName (%s)/n securityModel (%i) security_level (%i)",
engine_id.get_printable(), security_name.get_printable(),
security_model, pdu.get_security_level());
debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
status = snmpmsg.loadv3( pdu, engine_id, security_name,
security_model, (snmp_version)version);
}
else
#endif
status = snmpmsg.load( pdu, my_get_community, (snmp_version) version);
if ( status != SNMP_CLASS_SUCCESS) {
debugprintf(0, "snmp message load error!");
return status;
}
lock();
//------[ send the trap ]
if (udp_address.get_ip_version() == Address::version_ipv4)
{
if (iv_snmp_session != INVALID_SOCKET)
status = send_snmp_request((int) iv_snmp_session,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);
else
{
udp_address.map_to_ipv6();
status = send_snmp_request((int) iv_snmp_session_ipv6,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);
}
}
else
status = send_snmp_request((int) iv_snmp_session_ipv6,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);
unlock();
if (status != 0)
return SNMP_CLASS_TL_FAILED;
return SNMP_CLASS_SUCCESS;
}
//----------------[ set notify_timestamp if it is null ]-------------
#if defined (CPU) && CPU == PPC603
struct SCommTimer
{
unsigned long NumMS;
unsigned long FractMS;
};
extern "C"
{
void GetTime (struct SCommTimer * Time);
}
#endif
他调用 send_snmp_request((int) iv_snmp_session,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);
去发送trap,接着找
//---------[ Send SNMP Request ]---------------------------------------
// Send out a snmp request
DLLOPT int send_snmp_request(int sock, unsigned char *send_buf,
size_t send_len, Address & address)
{
// UX only supports UDP type addresses (addr and port) right now
if (address.get_type() != Address::type_udp)
return -1;// unsupported address type
debugprintf(1, "++ SNMP++: sending to %s:",
((UdpAddress &)address).UdpAddress::get_printable());
debughexprintf(5, send_buf, send_len);
int send_result;
if (((UdpAddress &)address).get_ip_version() == Address::version_ipv4)
{
// prepare the destination address
struct sockaddr_in agent_addr; // send socket struct
memset(&agent_addr, 0, sizeof(agent_addr));
agent_addr.sin_family = AF_INET;
agent_addr.sin_addr.s_addr
= inet_addr(((IpAddress &)address).IpAddress::get_printable());
agent_addr.sin_port = htons(((UdpAddress &)address).get_port());
send_result = sendto( sock, (char*) send_buf, send_len, 0,
(struct sockaddr*) &agent_addr, sizeof(agent_addr));
}
else
{
#ifdef SNMP_PP_IPv6
struct sockaddr_in6 agent_addr;
memset(&agent_addr, 0, sizeof(agent_addr));
inet_pton(AF_INET6, ((IpAddress &)address).IpAddress::get_printable(),
&agent_addr.sin6_addr);
agent_addr.sin6_family = AF_INET6;
agent_addr.sin6_port = htons(((UdpAddress &)address).get_port());
send_result = sendto( sock, (char*) send_buf, send_len, 0,
(struct sockaddr*) &agent_addr, sizeof(agent_addr));
#else
debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
return -1;
#endif
}
if (send_result < 0)
{
debugprintf(0, "Error sending packet: %s", strerror(errno));
return -1; // send error!
}
return 0;
}
好,在这里就看到了sendto,这已经到了最低成了。
可我在sendto之前用bind()想绑定162端口,不行,因为无论是trap还是get通信最终都是sendto出去的所以在这绑定肯定不行。
在trap函数里找到这句 status = send_snmp_request((int) iv_snmp_session,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);
iv_snmp_session他就是我们发送trap的套接口描述符,我们要想办法把他和162端口绑在一起,在这句话之前进行绑定,发现也不行,只好继续找原因,我们找到了init函数,他初始化套接口,初始化套接口这个地方我们应该很敏感,因为你bind()函数要么在socket()之后,要么在sendto之前,结果我们在这发现了bind()函数,狂喜呀。不过也是做了一会在搞出来,不是简单的改为162就可以了,他的第一次通信还是通过161端口来完成的,以后在发送trap时在随机指定端口。
原来程序:if (( iv_snmp_session = socket( AF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET)
{
#ifdef WIN32
int werr = WSAGetLastError();
debugprintf(1, "Call to socket throws error %d", werr);
if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
status = SNMP_CLASS_RESOURCE_UNAVAIL;
else if (WSAEHOSTDOWN == werr)
status = SNMP_CLASS_TL_FAILED;
else
status = SNMP_CLASS_TL_UNSUPPORTED;
#else
if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
status = SNMP_CLASS_RESOURCE_UNAVAIL;
else if (EHOSTDOWN == errno)
status = SNMP_CLASS_TL_FAILED;
else
status = SNMP_CLASS_TL_UNSUPPORTED;
#endif
}
else
{
// set up the manager socket attributes
unsigned long inaddr = inet_addr(addresses[0]->get_printable());
struct sockaddr_in mgr_addr;
memset(&mgr_addr, 0, sizeof(mgr_addr));
mgr_addr.sin_family = AF_INET;
mgr_addr.sin_addr.s_addr = inaddr;
mgr_addr.sin_port = htons( port_v4);
#ifdef CYGPKG_NET_OPENBSD_STACK
mgr_addr.sin_len = sizeof(mgr_addr);
#endif
// bind the socket
if (bind((int)iv_snmp_session, (struct sockaddr*)&mgr_addr,
sizeof(mgr_addr)) < 0)
改为: if (( iv_snmp_session = socket( AF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET)
{
#ifdef WIN32
int werr = WSAGetLastError();
debugprintf(1, "Call to socket throws error %d", werr);
if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
status = SNMP_CLASS_RESOURCE_UNAVAIL;
else if (WSAEHOSTDOWN == werr)
status = SNMP_CLASS_TL_FAILED;
else
status = SNMP_CLASS_TL_UNSUPPORTED;
#else
if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
status = SNMP_CLASS_RESOURCE_UNAVAIL;
else if (EHOSTDOWN == errno)
status = SNMP_CLASS_TL_FAILED;
else
status = SNMP_CLASS_TL_UNSUPPORTED;
#endif
}
else
{
// set up the manager socket attributes
unsigned long inaddr = inet_addr(addresses[0]->get_printable());
struct sockaddr_in mgr_addr;
memset(&mgr_addr, 0, sizeof(mgr_addr));
//port_v4=162;
if(port_v4==161)
mgr_addr.sin_port = htons(port_v4);
if(port_v4!=161)
mgr_addr.sin_port = htons(162);
mgr_addr.sin_family = AF_INET;
mgr_addr.sin_addr.s_addr = inaddr;
printf("port=%d,ip=%s",port_v4,addresses[0]->get_printable());
// port_v4=162;
#ifdef CYGPKG_NET_OPENBSD_STACK
mgr_addr.sin_len = sizeof(mgr_addr);
#endif
// bind the socket
if (bind((int)iv_snmp_session, (struct sockaddr*)&mgr_addr,
sizeof(mgr_addr)) < 0)
{
在版子上跑下子,ok成功
呵呵,加上了162端口后又发现了新问题,就是你是哪个ip发过来的trap,用工具查看全是255.255.255.255,这样不行。我们得知道具体的ip。那就找吧,从最后一个地方找起。
//---------[ Send SNMP Request ]---------------------------------------
// Send out a snmp request
DLLOPT int send_snmp_request(int sock, unsigned char *send_buf,
size_t send_len, Address & address)
{
printf("send the trap");
// UX only supports UDP type addresses (addr and port) right now
if (address.get_type() != Address::type_udp)
return -1;// unsupported address type
debugprintf(1, "++ SNMP++: sending to %s:",
((UdpAddress &)address).UdpAddress::get_printable());
debughexprintf(5, send_buf, send_len);
int send_result;
if (((UdpAddress &)address).get_ip_version() == Address::version_ipv4)
{
// prepare the destination address
struct sockaddr_in agent_addr; // send socket struct
memset(&agent_addr, 0, sizeof(agent_addr));
agent_addr.sin_family = AF_INET;
agent_addr.sin_addr.s_addr
= inet_addr(((IpAddress &)address).IpAddress::get_printable());
agent_addr.sin_port = htons(((UdpAddress &)address).get_port());
printf("por1t=%d,ip1=%s",((UdpAddress &)address).get_port(),((IpAddress &)address).IpAddress::get_printable());
send_result = sendto( sock, (char*) send_buf, send_len, 0,
(struct sockaddr*) &agent_addr, sizeof(agent_addr));
}
send_buf这是发送出去的trap的内容这里面可能有本地的ip,接着找到。send_snmp_request这个函数是trap调用的进入trap函数
//---------------------[ send a trap ]-----------------------------------
int Snmp::trap(Pdu &pdu, // pdu to send
const SnmpTarget &target) // destination target
{
printf("trap");
OctetStr my_get_community;
OctetStr my_set_community;
GenAddress address;
unsigned long my_timeout;
int my_retry;
unsigned char version;
int status;
debugprintf(1, "++ SNMP++, Send a Trap");
//---------[ make sure pdu is valid ]---------------------------------
if ( !pdu.valid())
{
debugprintf(0, "-- SNMP++, PDU Object Invalid");
return SNMP_CLASS_INVALID_PDU;
}
//---------[ make sure target is valid ]------------------------------
if ( !target.valid())
{
debugprintf(0, "-- SNMP++, Target Object Invalid");
return SNMP_CLASS_INVALID_TARGET;
}
CTarget* ctarget = NULL;
UTarget* utarget = NULL;
OctetStr security_name;
int security_model;
switch (target.get_type()) {
case SnmpTarget::type_ctarget:
ctarget = (CTarget*)(&target);
break;
case SnmpTarget::type_utarget:
utarget = (UTarget*)(&target);
break;
case SnmpTarget::type_base:
debugprintf(0, "-- SNMP++, do not use SnmpTarget, use a CTarget or UTarget");
return SNMP_CLASS_INVALID_TARGET;
default:
// target is not known
debugprintf(0, "-- SNMP++, type of target is unknown!");
return SNMP_CLASS_UNSUPPORTED;
}
if (ctarget) {
debugprintf(3, "snmp::trap called with CTarget");
if (!ctarget->resolve_to_C( my_get_community, my_set_community, address,
my_timeout, my_retry, version))
{
debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
return SNMP_CLASS_UNSUPPORTED;
}
#ifdef _SNMPv3
if (version == version3)
{
debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
return SNMP_CLASS_INVALID_TARGET;
}
#endif
}
else { // target is not a CTarget:
if (utarget) {
debugprintf(3, "trap called with UTarget");
if (!utarget->resolve_to_U( security_name, security_model, address,
my_timeout, my_retry, version))
{
debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
return SNMP_CLASS_UNSUPPORTED;
}
#ifdef _SNMPv3
if (version != version3) {
#endif
my_get_community = security_name;
if ((security_model != SecurityModel_v1) &&
(security_model != SecurityModel_v2)) {
debugprintf(0, "-- SNMP++, Target contains invalid security_model/version combination");
return SNMP_CLASS_INVALID_TARGET;
}
#ifdef _SNMPv3
} // end if (version != version3)
#endif
}
else { // target is neither CTarget nor UTarget:
debugprintf(0, "-- SNMP++, Resolve Fail");
return SNMP_CLASS_INVALID_TARGET;
}
}
//--------[ determine request id to use ]------------------------------
pdu.set_request_id( MyMakeReqId());
//--------[ check timestamp, if null use system time ]-----------------
check_notify_timestamp(pdu);
//------[ validate address to use ]-------------------------------------
if (!address.valid()) {
debugprintf(0, "-- SNMP++, Bad address");
return SNMP_CLASS_INVALID_TARGET;
}
if ((address.get_type() != Address::type_ip) &&
(address.get_type() != Address::type_udp) )
{
debugprintf(0, "-- SNMP++, Bad address type");
return SNMP_CLASS_TL_UNSUPPORTED;
}
UdpAddress udp_address(address);
if (!udp_address.valid()) {
debugprintf(0, "-- SNMP++, copy address failed");
return SNMP_CLASS_RESOURCE_UNAVAIL;
}
//----------[ choose the target address port ]-----------------------
if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
udp_address.set_port(SNMP_TRAP_PORT);
//----------[ based on the target type, choose v1 or v1 trap type ]-----
if ( version == version1)
pdu.set_type( sNMP_PDU_V1TRAP);
else // v2 and v3 use v2TRAP
pdu.set_type( sNMP_PDU_TRAP);
SnmpMessage snmpmsg;
#ifdef _SNMPv3
if ( version == version3) {
OctetStr engine_id = v3MP::I->get_local_engine_id();
if (!utarget) {
debugprintf(0, "-- SNMP++, dont know how to handle SNMPv3 without UTarget!");
return SNMP_CLASS_INVALID_TARGET;
}
// set context_engine_id of pdu, if it is not set
if (pdu.get_context_engine_id().len() == 0)
{
debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
engine_id.get_printable());
pdu.set_context_engine_id(engine_id);
}
debugprintf(4,"Snmp::trap:");
debugprintf(4," engineID (%s), securityName (%s)/n securityModel (%i) security_level (%i)",
engine_id.get_printable(), security_name.get_printable(),
security_model, pdu.get_security_level());
debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
status = snmpmsg.loadv3( pdu, engine_id, security_name,
security_model, (snmp_version)version);
}
else
#endif
status = snmpmsg.load( pdu, my_get_community, (snmp_version) version);
if ( status != SNMP_CLASS_SUCCESS) {
debugprintf(0, "snmp message load error!");
return status;
}
lock();
printf("4444");
//------[ send the trap ]
if (udp_address.get_ip_version() == Address::version_ipv4)
{
printf("55555");
if (iv_snmp_session != INVALID_SOCKET)
{
printf("send the 111trap");
status = send_snmp_request((int) iv_snmp_session,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);
}
else
{
udp_address.map_to_ipv6();
status = send_snmp_request((int) iv_snmp_session_ipv6,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);
}
}
else
status = send_snmp_request((int) iv_snmp_session_ipv6,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);
unlock();
if (status != 0)
return SNMP_CLASS_TL_FAILED;
return SNMP_CLASS_SUCCESS;
}
这个函数还是要仔细看看的,先找到 status = send_snmp_request((int) iv_snmp_session,
snmpmsg.data(), (size_t)snmpmsg.len(),
udp_address);,是在这调用的。。。好,看里面的snmpmsg.data()这个就是send_buf的传递。好,现在接着找snmpmsg.data()。这个就在snmpmsg这个文件里了。
在snmpmsg.h里unsigned char *data() { return databuff; };
我们接着找databuff。找事找到了,但程序看起来很难理解,我换个方式进行。因为我看到了pdu,我想pdu里面应该含有本地ip。。于是我们找到了
#endif
int SnmpMessage::load(const Pdu &cpdu,
const OctetStr &community,
const snmp_version version,
const OctetStr* engine_id,
const OctetStr* security_name,
const int security_model)
{
int status;
const Pdu *pdu = &cpdu;
Pdu temppdu;
// make sure pdu is valid
if ( !pdu->valid())
return SNMP_CLASS_INVALID_PDU;
// create a raw pdu
snmp_pdu *raw_pdu;
raw_pdu = snmp_pdu_create( (int) pdu->get_type());
Oid enterprise;
// load it up
raw_pdu->reqid = pdu->get_request_id();
#ifdef _SNMPv3
raw_pdu->msgid = pdu->get_message_id();
#endif
raw_pdu->errstat= (unsigned long) pdu->get_error_status();
raw_pdu->errindex= (unsigned long) pdu->get_error_index();
// if its a V1 trap then load up other values
// for v2, use normal pdu format
if ( raw_pdu->command == sNMP_PDU_V1TRAP) {
// DON'T forget about the v1 trap agent address (changed by Frank Fock)
GenAddress gen_addr;
IpAddress ip_addr;
int addr_set = FALSE;
if (pdu->get_v1_trap_address(gen_addr))
{
if ((gen_addr.get_type() != Address::type_ip) &&
(gen_addr.get_type() != Address::type_udp) )
{
debugprintf(0, "Bad v1 trap address type in pdu");
snmp_free_pdu( raw_pdu);
return SNMP_CLASS_INVALID_PDU;
}
ip_addr = gen_addr;
if (!ip_addr.valid()) {
debugprintf(0, "Copy of v1 trap address failed");
snmp_free_pdu( raw_pdu);
return SNMP_CLASS_RESOURCE_UNAVAIL;
}
addr_set = TRUE;
}
else
{
char addrString[256];
if (gethostname(addrString, 255) == 0)
{
ip_addr = addrString;
addr_set = TRUE;
}
}
struct sockaddr_in agent_addr; // agent address socket struct
// prepare the agent address
memset(&agent_addr, 0, sizeof(agent_addr));
agent_addr.sin_family = AF_INET;
if (addr_set)
{
agent_addr.sin_addr.s_addr
= inet_addr(((IpAddress &)ip_addr).IpAddress::get_printable());
debugprintf(3, "setting v1 trap address to (%s).",
((IpAddress &)ip_addr).IpAddress::get_printable());
}
raw_pdu->agent_addr = agent_addr;
//-----[ compute generic trap value ]-------------------------------
// determine the generic value
// 0 - cold start
// 1 - warm start
// 2 - link down
// 3 - link up
// 4 - authentication failure
// 5 - egpneighborloss
// 6 - enterprise specific
Oid trapid;
pdu->get_notify_id( trapid);
if ( !trapid.valid() || trapid.len() < 2 )
{
snmp_free_pdu( raw_pdu);
return SNMP_CLASS_INVALID_NOTIFYID;
}
raw_pdu->specific_type=0;
if ( trapid == coldStart)
raw_pdu->trap_type = 0; // cold start
else if ( trapid == warmStart)
raw_pdu->trap_type = 1; // warm start
else if( trapid == linkDown)
raw_pdu->trap_type = 2; // link down
else if ( trapid == linkUp)
raw_pdu->trap_type = 3; // link up
else if ( trapid == authenticationFailure )
raw_pdu->trap_type = 4; // authentication failure
else if ( trapid == egpNeighborLoss)
raw_pdu->trap_type = 5; // egp neighbor loss
else {
raw_pdu->trap_type = 6; // enterprise specific
// last oid subid is the specific value
// if 2nd to last subid is "0", remove it
// enterprise is always the notify oid prefix
raw_pdu->specific_type = (int) trapid[(int) (trapid.len()-1)];
trapid.trim(1);
if ( trapid[(int)(trapid.len()-1)] == 0 )
trapid.trim(1);
enterprise = trapid;
}
if ( raw_pdu->trap_type !=6)
pdu->get_notify_enterprise( enterprise);
if ( enterprise.len() >0) {
// note!!
// these are hooks into an SNMP++ oid
// and therefor the raw_pdu enterprise
// should not free them. null them out!!
SmiLPOID rawOid;
rawOid = enterprise.oidval();
raw_pdu->enterprise = rawOid->ptr;
raw_pdu->enterprise_length = (int) rawOid->len;
}
// timestamp
TimeTicks timestamp;
pdu->get_notify_timestamp( timestamp);
raw_pdu->time = ( unsigned long) timestamp;
}
// if its a v2 trap then we need to make a few adjustments
// vb #1 is the timestamp
// vb #2 is the id, represented as an Oid
if (( raw_pdu->command == sNMP_PDU_TRAP) ||
( raw_pdu->command == sNMP_PDU_INFORM))
{
Vb tempvb;
temppdu = *pdu;
temppdu.trim(temppdu.get_vb_count());
// vb #1 is the timestamp
TimeTicks timestamp;
tempvb.set_oid(SNMP_MSG_OID_SYSUPTIME); // sysuptime
pdu->get_notify_timestamp( timestamp);
tempvb.set_value ( timestamp);
temppdu += tempvb;
// vb #2 is the id
Oid trapid;
tempvb.set_oid(SNMP_MSG_OID_TRAPID);
pdu->get_notify_id( trapid);
tempvb.set_value( trapid);
temppdu += tempvb;
// append the remaining vbs
for (int z=0; z<pdu->get_vb_count(); z++) {
pdu->get_vb( tempvb,z);
temppdu += tempvb;
}
pdu = &temppdu; // reassign the pdu to the temp one
}
// load up the payload
// for all Vbs in list, add them to the pdu
int vb_count;
Vb tempvb;
Oid tempoid;
SmiLPOID smioid;
SmiVALUE smival;
vb_count = pdu->get_vb_count();
for (int z=0;z<vb_count;z++) {
pdu->get_vb( tempvb,z);
tempvb.get_oid( tempoid);
smioid = tempoid.oidval();
// clear the value portion, in case its
// not already been done so by the app writer
// only do it in the case its a get,next or bulk
if ((raw_pdu->command == sNMP_PDU_GET) ||
(raw_pdu->command == sNMP_PDU_GETNEXT) ||
(raw_pdu->command == sNMP_PDU_GETBULK))
tempvb.set_null();
status = convertVbToSmival( tempvb, &smival );
if ( status != SNMP_CLASS_SUCCESS) {
snmp_free_pdu( raw_pdu);
return status;
}
// add the vb to the raw pdu
snmp_add_var( raw_pdu, smioid->ptr, (int) smioid->len, &smival);
freeSmivalDescriptor( &smival);
}
// ASN1 encode the pdu
#ifdef _SNMPv3
if (version == version3)
{
if ((!engine_id) || (!security_name))
{
debugprintf(1, "SnmpMessage::load, security_name and engine_id needed for SNMPv3 message.");
snmp_free_pdu( raw_pdu);
return SNMP_CLASS_INVALID_TARGET;
}
status = v3MP::I->snmp_build(raw_pdu, databuff, (int *)&bufflen,
*engine_id, *security_name, security_model,
pdu->get_security_level(),
pdu->get_context_engine_id(),
pdu->get_context_name());
if (status == SNMPv3_MP_OK) {
if ((pdu->get_type() == sNMP_PDU_RESPONSE) &&
((int)pdu->get_maxsize_scopedpdu() < pdu->get_asn1_length())) {
debugprintf(0, "ERROR: TOO BIG should not happen.");
// prevention of SNMP++ Enterprise Oid death
if ( enterprise.len() >0) {
raw_pdu->enterprise = 0;
raw_pdu->enterprise_length=0;
}
snmp_free_pdu( raw_pdu);
return SNMP_ERROR_TOO_BIG;
}
}
}
else
#endif
status = snmp_build( raw_pdu, databuff, (int *) &bufflen, version,
community.data(), (int) community.len());
debugprintf(3, "SnmpMsg: return status of snmpBuild (%i)",status);
if ((status != 0)
#ifdef _SNMPv3
&& ((version != version3) || (status != SNMPv3_MP_OK))
#endif
) {
valid_flag = false;
// prevention of SNMP++ Enterprise Oid death
if ( enterprise.len() >0) {
raw_pdu->enterprise = 0;
raw_pdu->enterprise_length=0;
}
snmp_free_pdu( raw_pdu);
#ifdef _SNMPv3
if (version == version3)
return status;
else
#endif
// NOTE: This is an assumption - in most cases during normal
// operation the reason is a tooBig - another could be a
// damaged variable binding.
return SNMP_ERROR_TOO_BIG;
}
valid_flag = true;
// prevention of SNMP++ Enterprise Oid death
if ( enterprise.len() >0) {
raw_pdu->enterprise = 0;
raw_pdu->enterprise_length=0;
}
snmp_free_pdu( raw_pdu);
return SNMP_CLASS_SUCCESS;
}
在load(const Pdu &cpdu,
const OctetStr &community,
const snmp_version version,
const OctetStr* engine_id,
const OctetStr* security_name,
const int security_model)里
他主要是加载pdu。在看看pdu的定义:
Trap PDU 格式如下所示:
PDU Type Enterp Agent Addr Gen Trap Spec Trap Time Stamp Obj 1,Val 1 Obj 1,Val 1 …
* PDU Type:指定传输的 PDU 类型(Trap=4)。
* Enterprise:识别管理企业,在其注册权下定义 Trap。
* Agent Address:代理器的 IP 地址,用于进一步的识别。
* Generic Trap Type:描述事件报告字段,以下定义了7个值。
* Specific Trap Type:当通用 Trap 成为企业指定类型时,用于识别非通用 Trap。
* Timestamp:SysUpTime 对象值,表示最后一次设置初值和产生对应 Trap 间的时间数量。
由此不难找到
struct sockaddr_in agent_addr; // agent address socket struct
// prepare the agent address
memset(&agent_addr, 0, sizeof(agent_addr));
agent_addr.sin_family = AF_INET;
if (addr_set)
{
agent_addr.sin_addr.s_addr
= inet_addr(((IpAddress &)ip_addr).IpAddress::get_printable());
的确就是在这里。把inet_addr后面换成自己本地的ip就好了
加的部分如下:
FILE *fd3;
int i=0, m;
char sz[256], ss[15];
char *str1 , *ptr;
fd3 = fopen("/mnt/etc/sysconfig/network-scripts/ifcfg-eth0","r"); //以流方式打开
if(NULL == fd3)
//exit(1);
return 0;
else
{
if(fread(sz, 255,1, fd3) != NULL)
fclose(fd3);
}
str1=sz;
ptr=strstr(str1,"IPADDR=");
for(m=0;m<7;m++)
ptr++;
for(;*ptr!='N';i++,ptr++)
ss[i]=*ptr;
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wangyi84971224/archive/2009/11/04/4767101.aspx