luo 3 years ago
parent
commit
04689367d2
24 changed files with 7346 additions and 0 deletions
  1. 1275 0
      CSnmpClass.cpp
  2. 131 0
      CSnmpClass.h
  3. 913 0
      CSnmptrap.cpp
  4. 24 0
      CSnmptrap.h
  5. 28 0
      SnmpRelay.sln
  6. 204 0
      SnmpRelay.vcxproj
  7. 87 0
      SnmpRelay.vcxproj.filters
  8. 8 0
      SnmpRelay.vcxproj.user
  9. 51 0
      SnmpRelayMain.cpp
  10. 29 0
      deveice.config
  11. 3 0
      log.cpp
  12. 9 0
      log.h
  13. 28 0
      snmp_transport_inits.h
  14. 27 0
      snmpd.h
  15. 189 0
      snmptrapd_auth.cpp
  16. 18 0
      snmptrapd_auth.h
  17. 19 0
      snmptrapd_ds.h
  18. 1194 0
      snmptrapd_handlers.cpp
  19. 73 0
      snmptrapd_handlers.h
  20. 1783 0
      snmptrapd_log.cpp
  21. 19 0
      snmptrapd_log.h
  22. 6 0
      snmptrapd_sql.h
  23. 1157 0
      winservice.cpp
  24. 71 0
      winservice.h

+ 1275 - 0
CSnmpClass.cpp

@@ -0,0 +1,1275 @@
+
+#include <signal.h>
+
+
+#include "json.h"
+#include "CSnmpClass.h"
+#include "CSnmptrap.h"
+#include "log.h"
+#include "TSysTime.h"
+//char* CSnmpClass::m_pDdefault_port = "udp:192.168.1.82:162";
+//char* CSnmpClass::m_pDdefault_port = "udp:192.168.12.10:162";
+
+char* CSnmpClass::m_pDdefault_port = "udp:162";
+char* CSnmpClass::m_pDefault_port = m_pDdefault_port;
+int CSnmpClass::m_nDofork = 1;
+void* CSnmpClass::m_pInstance = nullptr;
+CSnmpClass::CSnmpClass()
+{
+	m_nAlarmStatus = 0;
+	m_nPowerFlag = 0;
+	m_nErpsFlag = 0;
+	m_nPhyFlag = 0;
+	m_nBoardFlag = 0;
+	m_pOolInvoker = nullptr;
+	m_pTrap1_fmt_str_remember = nullptr;
+	m_nTrapd_status = SNMPTRAPD_STOPPED;
+	m_pApp_name_long = "Net-SNMP Trap Handler";  
+	m_pApp_name = "snmptrapd";
+	memset(m_bindip,0,100);
+	AppLogConfigure(nullptr, "netsnmp", "netsnmp");
+	m_pOolInvoker = new TSysThreadPool;
+	m_pOolInvoker->Start(2);
+}
+CSnmpClass::~CSnmpClass()
+{
+	Stop();
+	std::vector <DEVICEINFO*>::iterator iter = m_pWhite_list.begin();
+	for (; iter != m_pWhite_list.end();) {
+		if (*iter) {
+			delete (*iter);
+			(*iter) = NULL;
+		}
+		iter = m_pWhite_list.erase(iter);
+	}
+	if (m_pOolInvoker) {
+
+		delete m_pOolInvoker;
+		m_pOolInvoker = nullptr;
+	}
+	TermHandler(1);
+	BLOG_DEBUG("app closed");
+}
+
+RETSIGTYPE CSnmpClass::TermHandler(int sig)
+{
+	netsnmp_running = 0;
+	/*
+	* In case of windows, select() in receive() function will not return
+	* on signal. Thats why following function is called, which closes the
+	* socket descriptors and causes the select() to return
+	*/
+	snmp_close(main_session);
+}
+
+int CSnmpClass::PreParse(netsnmp_session * session, netsnmp_transport *transport, void *transport_data, int transport_data_length)
+{
+	return 1;
+}
+
+netsnmp_session* CSnmpClass::SnmptrapdAddSession(netsnmp_transport *t)
+{
+	netsnmp_session sess, *session = &sess, *rc = NULL;
+
+	snmp_sess_init(session);
+	session->peername = SNMP_DEFAULT_PEERNAME;  /* Original code had NULL here */
+	session->version = SNMP_DEFAULT_VERSION;
+	session->community_len = SNMP_DEFAULT_COMMUNITY_LEN;
+	session->retries = SNMP_DEFAULT_RETRIES;
+	session->timeout = SNMP_DEFAULT_TIMEOUT;
+	session->callback = snmp_input;
+	session->callback_magic = (void *)t;
+	session->authenticator = NULL;
+	sess.isAuthoritative = SNMP_SESS_UNKNOWNAUTH;
+
+	rc = snmp_add(session, t, PreParse, NULL);
+	if (rc == NULL) {
+		snmp_sess_perror("snmptrapd", session);
+	}
+	return rc;
+}
+
+void CSnmpClass::SnmptrapdCloseSessions(netsnmp_session * sess_list)
+{
+	netsnmp_session *s = NULL, *next = NULL;
+
+	for (s = sess_list; s != NULL; s = next) {
+		next = s->next;
+		snmp_close(s);
+	}
+}
+
+void CSnmpClass::ParseTrapdAddress(const char *token, char *cptr)
+{
+	char buf[BUFSIZ];
+	char *p;
+	cptr = copy_nword(cptr, buf, sizeof(buf));
+
+	if (m_pDefault_port == m_pDdefault_port) {
+		m_pDefault_port = strdup(buf);
+	}
+	else {
+		p = (char*)malloc(strlen(buf) + 1 + strlen(m_pDefault_port) + 1);
+		if (p) {
+			strcpy(p, buf);
+			strcat(p, ",");
+			strcat(p, m_pDefault_port);
+		}
+		free(m_pDefault_port);
+		m_pDefault_port = p;
+	}
+}
+
+void CSnmpClass::FreeTrapdAddress(void)
+{
+	if (m_pDefault_port != m_pDdefault_port) {
+		free(m_pDefault_port);
+		m_pDefault_port = m_pDdefault_port;
+	}
+}
+
+void CSnmpClass::ParseConfigDoNotLogTraps(const char *token, char *cptr)
+{
+	if (atoi(cptr) > 0)
+		SyslogTrap++;
+}
+
+void CSnmpClass::ParseConfigDoNotFork(const char *token, char *cptr)
+{
+	if (netsnmp_ds_parse_boolean(cptr) == 1)
+		m_nDofork = 0;
+}
+
+void CSnmpClass::ParseConfigIgnoreAuthFailure(const char *token, char *cptr)
+{
+	if (netsnmp_ds_parse_boolean(cptr) == 1)
+		dropauth = 1;
+}
+
+void CSnmpClass::ParseConfigOutputOption(const char *token, char *cptr)
+{
+	char *cp;
+
+	cp = snmp_out_toggle_options(cptr);
+	if (cp != NULL) {
+		fprintf(stderr, "Unknown output option passed to -O: %c\n",
+			*cp);
+	}
+}
+
+void CSnmpClass::ParseConfigAddForwarderInfo(const char *token, char *cptr)
+{
+	if (netsnmp_ds_parse_boolean(cptr) == 1) {
+		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+			NETSNMP_DS_LIB_ADD_FORWARDER_INFO, 1);
+	}
+}
+void CSnmpClass::Action()
+{
+	char custom[100] = "";
+	memcpy(custom, m_send_bind_ip.c_str(), m_send_bind_ip.size());
+	CSnmptrap* m_pTrap = new CSnmptrap;
+	while (!IsAborted()) {
+		Sleep(m_nMtime*1000);
+		if (m_systemType == "h3c")
+			continue;
+
+
+		//m_Alarm.lock();
+		int status = m_nAlarmStatus;
+		std::vector<std::string>::iterator iter;
+		for (iter = m_dst_ip.begin(); iter != m_dst_ip.end(); iter++) {
+			m_pTrap->SendTrap2(status, *iter, m_sCommunity, "KTT Alarm", "1.3.6.1.4.1.2345", custom, m_needTime);
+			BLOG_DEBUG(fmt::format("Action SendTrap:: ip:{},comunnity:{},KTT Alarm:{}", *iter, m_sCommunity, status));
+		}
+		//m_pTrap->SendTrap2(status, m_dst_ip, m_sCommunity, "KTT Alarm", "1.3.6.1.4.1.2345",custom, m_needTime);
+	}
+	delete m_pTrap;
+}
+
+std::string CSnmpClass::FindString(std::string a, std::string b)
+{
+	if (a.size()>b.size())
+		swap(a, b);       //确保前面的一个字符串短;
+	std::string str_m;
+	for (int i = 0; i<a.size(); i++)
+	{
+		for (int j = i; j<a.size(); j++)
+		{
+			std::string temp = a.substr(i, j - i + 1);
+			if (int(b.find(temp))<0)
+				break;
+			else if (str_m.size()<temp.size())
+				str_m = temp;
+		}
+	}
+	return str_m;
+}
+void CSnmpClass::SendStringH3c(int status, std::string comunnity, std::string buf)
+{
+	CSnmptrap* m_pTrap = new CSnmptrap;
+	//
+
+	std::string m_sAlarmType = "ADB-;WVB-;EVB-;CTR-";
+	std::string m_sResult = FindString(buf, m_sAlarmType);
+	BLOG_DEBUG(fmt::format("Find The AlarmType :{}", m_sResult.c_str()));
+	char m_cFirst = (m_sResult.c_str())[0];
+	switch (m_cFirst)
+	{
+	case 'A':
+	case 'W':
+	case 'E':
+		m_pTrap->SendTrapH3c(status, "10.1.101.21", comunnity, "TKO Alarm");
+		m_pTrap->SendTrapH3c(status, "10.1.201.21", comunnity, "TKO Alarm");
+		m_pTrap->SendTrapH3c(status, "10.1.101.22", comunnity, "TKO Alarm");
+		m_pTrap->SendTrapH3c(status, "10.1.201.22", comunnity, "TKO Alarm");
+		BLOG_DEBUG(fmt::format("SendTrap:: comunnity:{},TKO Alarm:{}", comunnity, status));
+		break;
+	case 'C':
+		m_pTrap->SendTrapH3c(status, "10.4.101.21", comunnity, "CBL Alarm");
+		m_pTrap->SendTrapH3c(status, "10.4.201.21", comunnity, "CBL Alarm");
+		m_pTrap->SendTrapH3c(status, "10.4.101.22", comunnity, "CBL Alarm");
+		m_pTrap->SendTrapH3c(status, "10.4.201.22", comunnity, "CBL Alarm");
+		BLOG_DEBUG(fmt::format("SendTrap:: comunnity:{},CBL Alarm:{}", comunnity, status));
+		break;
+	default:
+		break;
+	}
+	//
+	delete m_pTrap;
+}
+void CSnmpClass::SendString(int status, std::string comunnity, std::string buf, std::string moduleIdentity, std::string power)
+{
+	m_Alarm.lock();
+	m_nAlarmStatus = status;
+	m_Alarm.unlock();
+
+	CSnmptrap* m_pTrap = new CSnmptrap;
+	char custom[100] = "";
+	memcpy(custom, m_send_bind_ip.c_str(), m_send_bind_ip.size());
+	std::vector<std::string>::iterator iter;
+	for (iter = m_dst_ip.begin(); iter != m_dst_ip.end(); iter++) {
+		m_pTrap->SendTrap(status, *iter, comunnity, "KTT Alarm", moduleIdentity, power, custom, m_needTime);
+		BLOG_DEBUG(fmt::format("SendTrap:: ip:{},comunnity:{},KTT Alarm:{}", *iter, comunnity, status));
+	}
+	//m_pTrap->SendTrap(status, m_dst_ip, comunnity, "KTT Alarm", moduleIdentity, power,custom, m_needTime);
+	/*m_pTrap->SendTrap(status, "192.168.31.8:161", comunnity, "KTT Alarm", moduleIdentity, power);*/
+	
+	delete m_pTrap;
+}
+
+int CSnmpClass::ParsePtype(std::string buf,std::string upAnddown)
+{
+	//POWER_FAILED  
+	//POWER_RECOVERED   
+	//PHY_UPDOWN   
+	int m_nResult = 1;
+	if ("POWER_FAILED" == buf) {
+		m_nPowerFlag = 1;
+		m_nResult = 0;
+		//SendString(1,buf);
+	}
+	if ("POWER_RECOVERED" == buf) {
+		m_nPowerFlag = 0;
+		m_nResult = 0;
+	}
+	if ("PHY_UPDOWN" == buf) {
+		std::string::size_type m_nindex = upAnddown.find("changed to down");
+		if (m_nindex != upAnddown.npos) {
+			//buff = buff.substr(0, m_nindex);
+			m_nPhyFlag = 1;
+		}
+		else {
+			m_nPhyFlag = 0;
+		}
+		m_nResult = 0;
+	}
+	return m_nResult;
+}
+int CSnmpClass::ParseEtype(std::string buf, std::string upAnddown)
+{
+	//ERPS_STATE_CHANGED     
+	int m_nResult = 1;
+	if ("ERPS_STATE_CHANGED" == buf) {
+		std::string::size_type m_nindex = upAnddown.find("changed state to Protection");
+		if (m_nindex != upAnddown.npos) {
+			BLOG_DEBUG("find changed state to Protection");
+			m_nErpsFlag = 1;
+			m_nResult = 0;
+		}
+		else {
+			std::string::size_type m_nindex_2 = upAnddown.find("changed state to Idle");
+			if (m_nindex_2 != upAnddown.npos) {
+				//buff = buff.substr(0, m_nindex);
+				BLOG_DEBUG("find changed state to Idle");
+				m_nErpsFlag = 0;
+				m_nResult = 0;
+			}
+		}
+	}
+	return m_nResult;
+}
+int CSnmpClass::ParseBtype(std::string buf) 
+{
+	int m_nResult = 1;
+	//BOARD_STATE_FAULT   
+	//BOARD_STATE_NORMAL   
+	if ("BOARD_STATE_FAULT" == buf) {
+		m_nBoardFlag = 1;
+		m_nResult = 0;
+	}
+	if ("BOARD_STATE_NORMAL" == buf) {
+		m_nBoardFlag = 0;
+		m_nResult = 0;
+	}
+	return m_nResult;
+}
+void CSnmpClass::MoxaParseBuffer(std::string buf, std::string comunnity)
+{
+	//printf("RECV:%s\n", buf.c_str());
+	//std::string test = "{2022-03-23 13:52:51 192.168.12.253 [192.168.12.253] (via UDP: [192.168.1.82]:49990->[192.168.1.82]:162) TRAP, SNMP v1, community public \
+	//	SNMPv2 - SMI::enterprises.8691.7.7 Enterprise Specific Trap(2) Uptime: 0 : 03 : 57.68 \
+	//	SNMPv2 - SMI::enterprises.8691.7.7.2.2 = INTEGER : 3}";
+	if (CheckPower(buf, comunnity) || CheckResetPower(buf, comunnity) || CheckNetwork(buf, comunnity))
+		return;
+}
+void CSnmpClass::H3cParseBuffer(std::string buf, std::string comunnity)
+{
+	//POWER_FAILED  
+	//POWER_RECOVERED  
+	//ERPS_STATE_CHANGED      
+	//PHY_UPDOWN     
+	//BOARD_STATE_FAULT   
+	//BOARD_STATE_NORMAL   
+	std::string m_sdata = "POWER_FAILED;POWER_RECOVERED;ERPS_STATE_CHANGED;PHY_UPDOWN;BOARD_STATE_FAULT;BOARD_STATE_NORMAL";
+#if 1
+	std::string m_sResult = FindString(buf, m_sdata);
+#else
+	std::string test1 = "2021-06-10 10:19:20 <UNKNOWN> [UDP: [10.2.100.1]:10703->[10.1.100.99]:162]:DISMAN - EVENT - MIB::sysUpTimeInstance = Timeticks: (1295968167) 149 days, 23 : 54 : 41.67SNMPv2 - MIB::snmpTrapOID.0 = OID :  SNMPv2 - SMI::mib - 2.192.0.1SNMPv2 - SMI::mib - 2.192.1.2.1.2.1143 = INTEGER : 23SNMPv2 - SMI::mib - 2.192.1.2.1.3.1143 = INTEGER : 5SNMPv2 - SMI::mib - 2.192.1.2.1.4.1143 = Gauge32 : 1SNMPv2 - SMI::mib - 2.192.1.2.1.5.1143 = Hex - STRING : 07 E5 06 0A 0A 11 2E 00 00 00 2B 08 00SNMPv2 - SMI::mib - 2.192.1.2.1.6.1143 = STRING: \"WVB-COM-CSW\"SNMPv2 - SMI::mib - 2.192.1.2.1.7.1143 = STRING : \"DEV\"SNMPv2 - SMI::mib - 2.192.1.2.1.8.1143 = STRING : \"-\"SNMPv2 - SMI::mib - 2.192.1.2.1.9.1143 = STRING : \"BOARD_REBOOT\"SNMPv2 - SMI::mib - 2.192.1.2.1.10.1143 = Gauge32 : 3SNMPv2 - SMI::mib - 2.192.1.2.1.11.1143 = STRING : \"Physical state on the interface Ten-GigabitEthernet1/2/0/29 changed to up.\"SNMPv2 - SMI::mib - 2.192.1.3.1.4.1143.1.12.83.121.115.76.111.99.64.50.53.53.48.54.7.67.104.97.115.115.105.115 = STRING : \"1\"SNMPv2 - SMI::mib - 2.192.1.3.1.4.1143.2.12.83.121.115.76.111.99.64.50.53.53.48.54.4.83.108.111.116 = STRING : \"0\"SNMPv2 - SMI::mib - 2.192.1.3.1.4.1143.3.12.83.121.115.76.111.99.64.50.53.53.48.54.3.77.68.67 = STRING : \"1\"";
+	std::string m_sResult = FindString(m_sdata, test1);
+	buf = test1;
+#endif
+	int m_nFlag = 0;
+	char m_cFirst = (m_sResult.c_str())[0];
+	switch (m_cFirst)
+	{
+	case 'P':
+		m_nFlag = ParsePtype(m_sResult, buf);
+		break;
+	case 'E':
+		m_nFlag = ParseEtype(m_sResult, buf);
+		break;
+	case 'B':
+		m_nFlag = ParseBtype(m_sResult);
+		break;
+	default:
+		m_nFlag = 1;
+		break;
+	}
+	if (0 == m_nFlag) {
+		printf("RECV:{%s}\n", m_sResult.c_str());
+		BLOG_DEBUG(fmt::format("RECV:{}", m_sResult));
+		BLOG_DEBUG(fmt::format("[comunnity::{}]m_nPowerFlag:{},m_nErpsFlag:{},m_nPhyFlag:{},m_nBoardFlag:{}", comunnity, m_nPowerFlag, m_nErpsFlag, m_nPhyFlag, m_nBoardFlag));
+		if (m_nPowerFlag || m_nErpsFlag || m_nPhyFlag || m_nBoardFlag)
+		{
+			SendStringH3c(1, comunnity, buf);
+		}
+		else {
+			SendStringH3c(0, comunnity, buf);
+		}
+	}
+}
+void CSnmpClass::ParseBuffer(std::string buf, std::string comunnity)
+{
+	OutputDebugStringA(fmt::format("RECV:{}", buf).c_str());
+	if (m_systemType == "moxa")
+		MoxaParseBuffer(buf, comunnity);
+	if (m_systemType == "h3c")
+		H3cParseBuffer(buf, comunnity);
+}
+int  CSnmpClass::RecvHandler(netsnmp_pdu* pdu, netsnmp_transport* transport, netsnmp_trapd_handler * handler)
+{
+#if 1
+	u_char         *rbuf = NULL;
+	size_t          r_len = 64, o_len = 0;
+	int             trunc = 0;
+	DEBUGMSGTL(("snmptrapd", "print_handler\n"));
+
+	/*
+	*  Don't bother logging authentication failures
+	*  XXX - can we handle this via suitable handler entries instead?
+	*/
+	if (pdu->trap_type == SNMP_TRAP_AUTHFAIL && dropauth)
+		return NETSNMPTRAPD_HANDLER_OK;
+
+	if ((rbuf = (u_char *)calloc(r_len, 1)) == NULL) {
+		snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n");
+		return NETSNMPTRAPD_HANDLER_FAIL;	/* Failed but keep going */
+	}
+
+	/*
+	*  If there's a format string registered for this trap, then use it.
+	*/
+	if (handler && handler->format) {
+		DEBUGMSGTL(("snmptrapd", "format = '%s'\n", handler->format));
+		if (*handler->format) {
+			trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+				handler->format, pdu, transport);
+		}
+		else {
+			free(rbuf);
+			return NETSNMPTRAPD_HANDLER_OK;    /* A 0-length format string means don't log */
+		}
+
+		/*
+		*  Otherwise (i.e. a NULL handler format string),
+		*      use a standard output format setting
+		*      either configurable, or hardwired
+		*
+		*  XXX - v1 traps use a different routine for hardwired output
+		*        Do we actually need this separate v1 routine?
+		*        Or would a suitable format string be sufficient?
+		*/
+	}
+	else {
+		if (pdu->command == SNMP_MSG_TRAP) {
+			if (print_format1) {
+				DEBUGMSGTL(("snmptrapd", "print_format v1 = '%s'\n", print_format1));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					print_format1, pdu, transport);
+			}
+			else {
+				DEBUGMSGTL(("snmptrapd", "v1 format\n"));
+				trunc = !realloc_format_plain_trap(&rbuf, &r_len, &o_len, 1,
+					pdu, transport);
+			}
+		}
+		else {
+			if (print_format2) {
+				DEBUGMSGTL(("snmptrapd", "print_format v2 = '%s'\n", print_format2));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					print_format2, pdu, transport);
+			}
+			else {
+				DEBUGMSGTL(("snmptrapd", "v2/3 format\n"));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					PRINT_V23_NOTIFICATION_FORMAT,
+					pdu, transport);
+			}
+		}
+	}
+
+	//snmp_log(LOG_INFO, "%s%s", rbuf, (trunc ? " [TRUNCATED]\n" : ""));
+	std::string m_sBuff = (char*)rbuf;
+	BLOG_DEBUG(m_sBuff);
+	//
+	char* m_pCom = (char*)malloc(pdu->community_len + 1);
+	memset(m_pCom,0, pdu->community_len + 1);
+	memcpy(m_pCom, pdu->community, pdu->community_len);
+	std::string Community = std::string(m_pCom);
+	free(m_pCom);
+
+	evpp::EventLoop* curr_loop = ((CSnmpClass*)m_pInstance)->m_pOolInvoker->GetNextLoop();
+	if (!curr_loop) {
+		//BLOG_DEBUG(fmt::format("[FAIL] find an executive for AcknowledgeEntityStatusEX"));
+	}
+	else {
+		curr_loop->RunInLoop(std::bind(&CSnmpClass::ReadProcess, (CSnmpClass*)m_pInstance, m_sBuff, Community));
+	}
+	free(rbuf);
+#endif
+	return NETSNMPTRAPD_HANDLER_OK;
+}
+int   CSnmpClass::PrintHandler(netsnmp_pdu* pdu,netsnmp_transport* transport,netsnmp_trapd_handler * handler)
+{
+	printf("print_handler\n");
+	//std::string m_sBuff = (char*)rbuf;
+#if 0
+	u_char         *rbuf = NULL;
+	size_t          r_len = 64, o_len = 0;
+	int             trunc = 0;
+	printf("print_handler\n");
+	DEBUGMSGTL(("snmptrapd", "print_handler\n"));
+
+	/*
+	*  Don't bother logging authentication failures
+	*  XXX - can we handle this via suitable handler entries instead?
+	*/
+	if (pdu->trap_type == SNMP_TRAP_AUTHFAIL && dropauth)
+		return NETSNMPTRAPD_HANDLER_OK;
+
+	if ((rbuf = (u_char *)calloc(r_len, 1)) == NULL) {
+		snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n");
+		return NETSNMPTRAPD_HANDLER_FAIL;	/* Failed but keep going */
+	}
+
+	/*
+	*  If there's a format string registered for this trap, then use it.
+	*/
+	if (handler && handler->format) {
+		DEBUGMSGTL(("snmptrapd", "format = '%s'\n", handler->format));
+		if (*handler->format) {
+			trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+				handler->format, pdu, transport);
+		}
+		else {
+			free(rbuf);
+			return NETSNMPTRAPD_HANDLER_OK;    /* A 0-length format string means don't log */
+		}
+
+		/*
+		*  Otherwise (i.e. a NULL handler format string),
+		*      use a standard output format setting
+		*      either configurable, or hardwired
+		*
+		*  XXX - v1 traps use a different routine for hardwired output
+		*        Do we actually need this separate v1 routine?
+		*        Or would a suitable format string be sufficient?
+		*/
+	}
+	else {
+		if (pdu->command == SNMP_MSG_TRAP) {
+			if (print_format1) {
+				DEBUGMSGTL(("snmptrapd", "print_format v1 = '%s'\n", print_format1));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					print_format1, pdu, transport);
+			}
+			else {
+				DEBUGMSGTL(("snmptrapd", "v1 format\n"));
+				trunc = !realloc_format_plain_trap(&rbuf, &r_len, &o_len, 1,
+					pdu, transport);
+			}
+		}
+		else {
+			if (print_format2) {
+				DEBUGMSGTL(("snmptrapd", "print_format v2 = '%s'\n", print_format2));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					print_format2, pdu, transport);
+			}
+			else {
+				DEBUGMSGTL(("snmptrapd", "v2/3 format\n"));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					PRINT_V23_NOTIFICATION_FORMAT,
+					pdu, transport);
+			}
+		}
+	}
+	snmp_log(LOG_INFO, "%s%s", rbuf, (trunc ? " [TRUNCATED]\n" : ""));
+	std::string bufftest = (char*)rbuf;
+	//SnmptrapdMainLoop();
+	evpp::EventLoop* curr_loop = ((CSnmpClass*)m_pInstance)->m_pOolInvoker->GetNextLoop();
+	if (!curr_loop) {
+		//BLOG_DEBUG(fmt::format("[FAIL] find an executive for AcknowledgeEntityStatusEX"));
+	}
+	else {
+		curr_loop->RunInLoop(std::bind(&CSnmpClass::ReadProcess, (CSnmpClass*)m_pInstance, bufftest));
+	}
+	free(rbuf);
+#endif
+	return NETSNMPTRAPD_HANDLER_OK;
+}
+
+void CSnmpClass::ReadProcess(std::string buf, std::string comunnity)
+{
+	//STRING:
+	//INTEGER:
+	m_sCommunity = comunnity;
+	ParseBuffer(buf, comunnity);
+}
+void CSnmpClass::SnmptrapdMainLoop(void)
+{
+	int             count, numfds, block;
+	fd_set          readfds, writefds, exceptfds;
+	struct timeval  timeout;
+	NETSNMP_SELECT_TIMEVAL timeout2;
+	while (netsnmp_running) {
+
+		numfds = 0;
+		FD_ZERO(&readfds);
+		FD_ZERO(&writefds);
+		FD_ZERO(&exceptfds);
+		block = 0;
+		timerclear(&timeout);
+		timeout.tv_sec = 5;
+		snmp_select_info(&numfds, &readfds, &timeout, &block);
+#ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
+		netsnmp_external_event_info(&numfds, &readfds, &writefds, &exceptfds);
+#endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
+		timeout2.tv_sec = timeout.tv_sec;
+		timeout2.tv_usec = timeout.tv_usec;
+		count = select(numfds, &readfds, &writefds, &exceptfds,
+			!block ? &timeout2 : NULL);
+		if (count > 0) {
+#ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
+			netsnmp_dispatch_external_events(&count, &readfds, &writefds,
+				&exceptfds);
+#endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
+			/* If there are any more events after external events, then
+			* try SNMP events. */
+			if (count > 0) {
+				snmp_read(&readfds);
+			}
+		}
+		else {
+			switch (count) {
+			case 0:
+				snmp_timeout();
+				break;
+			case -1:
+				if (errno == EINTR)
+					continue;
+				snmp_log_perror("select");
+				netsnmp_running = 0;
+				break;
+			default:
+				fprintf(stderr, "select returned %d\n", count);
+				netsnmp_running = 0;
+			}
+		}
+		run_alarms();
+	}
+}
+/*******************************************************************-o-******
+* main - Non Windows
+* SnmpTrapdMain - Windows to support windows service
+*
+* Parameters:
+*	 argc
+*	*argv[]
+*
+* Returns:
+*	0	Always succeeds.  (?)
+*
+*
+* Setup and start the trap receiver daemon.
+*
+* Also successfully EXITs with zero for some options.
+*/
+void CSnmpClass::InitNetsnmpTrapdAuth(void)
+{
+	/* register our function as a authorization handler */
+	netsnmp_trapd_handler *traph;
+	//RecvHandler
+	//traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_AUTH_HANDLER,netsnmp_trapd_auth);
+	traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_AUTH_HANDLER, RecvHandler);
+	traph->authtypes = TRAP_AUTH_NONE;
+
+#ifdef USING_MIBII_VACM_CONF_MODULE
+	/* register our configuration tokens for VACM configs */
+	init_vacm_config_tokens();
+#endif
+
+	/* register a config token for turning off the authorization entirely */
+	netsnmp_ds_register_config(ASN_BOOLEAN, "snmptrapd", "disableAuthorization",
+		NETSNMP_DS_APPLICATION_ID,
+		NETSNMP_DS_APP_NO_AUTHORIZATION);
+}
+int CSnmpClass::SnmpTrapdMain(int argc, char * argv[])
+{
+	static const char options[] = "aAc:CdD::efF:g:hHI:L:m:M:no:O:Ptu:vx:X-:""p:";
+	netsnmp_session *sess_list = NULL, *ss = NULL;
+	netsnmp_transport *transport = NULL;
+	int             arg, i = 0;
+	int             uid = 0, gid = 0;
+	int             exit_code = 1;
+	char           *cp, *listen_ports = NULL;
+#if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
+	int             agentx_subagent = 1;
+#endif
+	netsnmp_trapd_handler *traph;
+	signal(SIGTERM,TermHandler);
+	signal(SIGINT,TermHandler);
+
+	/*
+	* register our configuration handlers now so -H properly displays them
+	*/
+	snmptrapd_register_configs();
+#ifdef NETSNMP_SECMOD_USM
+	init_usm_conf("snmptrapd");
+#endif /* NETSNMP_SECMOD_USM */
+	register_config_handler("snmptrapd", "snmpTrapdAddr",
+		ParseTrapdAddress, FreeTrapdAddress, "string");
+
+	register_config_handler("snmptrapd", "doNotLogTraps",
+		ParseConfigDoNotLogTraps, NULL, "(1|yes|true|0|no|false)");
+
+	register_config_handler("snmptrapd", "doNotFork",
+		ParseConfigDoNotFork, NULL, "(1|yes|true|0|no|false)");
+
+	register_config_handler("snmptrapd", "ignoreAuthFailure",
+		ParseConfigIgnoreAuthFailure, NULL, "(1|yes|true|0|no|false)");
+
+	register_config_handler("snmptrapd", "outputOption",
+		ParseConfigOutputOption, NULL, "string");
+
+	register_config_handler("snmptrapd", "addForwarderInfo",
+		ParseConfigAddForwarderInfo, NULL,
+		"(1|yes|true|0|no|false)");
+
+	snmp_log_syslogname(m_pApp_name_long);
+	/*
+	* Now process options normally.
+	*/
+#if 1
+	while ((arg = getopt(argc, argv, options)) != EOF) {
+		switch (arg) {
+		case 'c':
+			if (optarg != NULL) {
+				netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
+					NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
+			}
+			else {
+				return 1;
+			}
+			break;
+
+		case 'C':
+			netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+				NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
+			break;
+
+		case 'd':
+			netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+				NETSNMP_DS_LIB_DUMP_PACKET, 1);
+			break;
+
+		case 'D':
+			debug_register_tokens(optarg);
+			snmp_set_do_debugging(1);
+			break;
+
+		case 'f':
+			m_nDofork = 0;
+			break;
+
+		case 'F':
+			if (optarg != NULL) {
+				if ((strncmp(optarg, "print", 5) == 0) ||
+					(strncmp(optarg, "syslog", 6) == 0) ||
+					(strncmp(optarg, "execute", 7) == 0)) {
+					/* New style: "type=format" */
+					m_pTrap1_fmt_str_remember = strdup(optarg);
+					cp = strchr(m_pTrap1_fmt_str_remember, '=');
+					if (cp)
+						*cp = ' ';
+				}
+				else {
+					/* Old style: implicitly "print=format" */
+					m_pTrap1_fmt_str_remember = (char*)malloc(strlen(optarg) + 7);
+					sprintf(m_pTrap1_fmt_str_remember, "print %s", optarg);
+				}
+			}
+			else {
+				return 1;
+			}
+			break;
+
+		case 'L':
+			if (snmp_log_options(optarg, argc, argv) < 0) {
+				return 1;
+			}
+			break;
+		}
+	}
+#endif
+	SOCK_STARTUP;
+
+	/*
+	* I'm being lazy here, and not checking the
+	* return value from these registration calls.
+	* Don't try this at home, children!
+	*/
+	if (0 == snmp_get_do_logging()) {
+		traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER,
+			syslog_handler);
+		traph->authtypes = TRAP_AUTH_LOG;
+		snmp_enable_syslog();
+	}
+	else {
+		traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER,
+			PrintHandler);
+		traph->authtypes = TRAP_AUTH_LOG;
+	}
+
+#if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
+	/*
+	* we're an agentx subagent?
+	*/
+	if (agentx_subagent) {
+		/*
+		* make us a agentx client.
+		*/
+		netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
+			NETSNMP_DS_AGENT_ROLE, 1);
+	}
+#endif
+
+	/*
+	* don't fail if we can't do agentx (ie, socket not there, or not root)
+	*/
+	netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
+		NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
+	/*
+	* ignore any warning messages.
+	*/
+	netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
+		NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS);
+
+	/*
+	* initialize the agent library
+	*/
+	init_agent("snmptrapd");
+
+#if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
+#ifdef NETSNMP_FEATURE_CHECKING
+	netsnmp_feature_require(register_snmpEngine_scalars_context)
+#endif /* NETSNMP_FEATURE_CHECKING */
+		/*
+		* initialize local modules
+		*/
+		if (agentx_subagent) {
+			subagent_init();
+#ifdef USING_SNMPV3_SNMPENGINE_MODULE
+			/*
+			* register scalars from SNMP-FRAMEWORK-MIB::snmpEngineID group;
+			* allows engineID probes via the master agent under the
+			* snmptrapd context
+			*/
+			register_snmpEngine_scalars_context("snmptrapd");
+#endif
+		}
+#endif /* USING_AGENTX_SUBAGENT_MODULE && !NETSNMP_SNMPTRAPD_DISABLE_AGENTX */
+
+	/* register our authorization handler */
+	InitNetsnmpTrapdAuth();
+
+
+#if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
+	if (agentx_subagent) {
+#ifdef USING_SNMPV3_USMUSER_MODULE
+#ifdef NETSNMP_FEATURE_CHECKING
+		netsnmp_feature_require(init_register_usmUser_context)
+#endif /* NETSNMP_FEATURE_CHECKING */
+			/* register ourselves as having a USM user database */
+			init_register_usmUser_context("snmptrapd");
+#endif
+#ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE
+		/* register net-snmp vacm extensions */
+		init_register_nsVacm_context("snmptrapd");
+#endif
+#ifdef USING_TLSTM_MIB_SNMPTLSTMCERTTOTSNTABLE_MODULE
+		init_snmpTlstmCertToTSNTable_context("snmptrapd");
+#endif
+	}
+#endif
+	/*
+	* Initialize the world.
+	*/
+	init_snmp("snmptrapd");
+	if (m_pTrap1_fmt_str_remember) {
+		parse_format(NULL, m_pTrap1_fmt_str_remember);
+	}
+
+	if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
+		NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) {
+		/*
+		* just starting up to process specific configuration and then
+		* shutting down immediately.
+		*/
+		netsnmp_running = 0;
+	}
+
+	/*
+	* if no logging options on command line or in conf files, use syslog
+	*/
+
+	if (0 == snmp_get_do_logging()) {
+		snmp_enable_syslog_ident(m_pApp_name_long, LOG_DAEMON);
+	}
+
+	if (listen_ports)
+		cp = listen_ports;
+	else
+		cp = m_pDefault_port;
+	printf("%s\n", m_pDefault_port);
+	while (cp != NULL) {
+		char *sep = strchr(cp, ',');
+
+		if (sep != NULL) {
+			*sep = 0;
+		}
+
+		transport = netsnmp_transport_open_server("snmptrap", cp);
+		if (transport == NULL) {
+			snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n",
+				cp, errno, strerror(errno));
+			SnmptrapdCloseSessions(sess_list);
+			goto sock_cleanup;
+		}
+		else {
+			ss = SnmptrapdAddSession(transport);
+			if (ss == NULL) {
+				/*
+				* Shouldn't happen?  We have already opened the transport
+				* successfully so what could have gone wrong?
+				*/
+				SnmptrapdCloseSessions(sess_list);
+				snmp_log(LOG_ERR, "couldn't open snmp - %s", strerror(errno));
+				goto sock_cleanup;
+			}
+			else {
+				ss->next = sess_list;
+				sess_list = ss;
+			}
+		}
+
+		/*
+		* Process next listen address, if there is one.
+		*/
+
+		if (sep != NULL) {
+			*sep = ',';
+			cp = sep + 1;
+		}
+		else {
+			cp = NULL;
+		}
+	}
+	SNMP_FREE(listen_ports); /* done with them */
+
+#ifdef NETSNMP_USE_MYSQL
+	if (netsnmp_mysql_init()) {
+		fprintf(stderr, "MySQL initialization failed\n");
+		goto sock_cleanup;
+	}
+#endif
+	snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version());
+
+#ifdef WIN32SERVICE
+	m_nTrapd_status = SNMPTRAPD_RUNNING;
+#endif
+
+	SnmptrapdMainLoop();
+	if (snmp_get_do_logging()) {
+		struct tm      *tm;
+		time_t          timer;
+		time(&timer);
+		tm = localtime(&timer);
+		snmp_log(LOG_INFO,
+			"%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n",
+			tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
+			tm->tm_min, tm->tm_sec, netsnmp_get_version());
+	}
+	snmp_log(LOG_INFO, "Stopping snmptrapd\n");
+
+#ifdef NETSNMP_EMBEDDED_PERL
+	shutdown_perl();
+#endif
+	SnmptrapdCloseSessions(sess_list);
+	snmp_shutdown("snmptrapd");
+#ifdef WIN32SERVICE
+	m_nTrapd_status = SNMPTRAPD_STOPPED;
+#endif
+	snmp_disable_log();
+
+	exit_code = 0;
+
+sock_cleanup:
+	SOCK_CLEANUP;
+
+out:
+	return exit_code;
+}
+void CSnmpClass::GetIdentity(std::string data)
+{
+	//enterprises.8691.7.XXX.2对应着moxa的mib中的swTraps
+	std::string buf = data;
+	while(1) {
+		std::string::size_type index = buf.find(",");
+		if (index != std::string::npos) {
+			/*std::string ff = buf.substr(0,index);*/
+			std::string tmp = buf.substr(0, index);
+			tmp =	"enterprises.8691.7." + tmp;
+			m_identity.emplace_back(tmp);
+			buf = buf.substr(index + 1);
+		}
+		else {
+			if (buf != "") {
+				buf = "enterprises.8691.7." + buf;
+				m_identity.emplace_back(buf);
+			}
+			break;
+		}
+	}
+	return;
+}
+bool CSnmpClass::LoadDeviceInfo()
+{
+	char* text = NULL;
+	FILE *pf = fopen("deveice.config", "rb+");
+	if (!pf) {
+		printf("open deveice.config failed\n");
+		return false;
+	}
+	fseek(pf, 0, SEEK_END);
+	long lSize = ftell(pf);
+	text = (char*)malloc(lSize);
+	rewind(pf);
+	fread(text, sizeof(char), lSize, pf);
+	std::string filedata = std::string(text, lSize);
+	free(text);
+	fclose(pf);
+
+	nlohmann::json j = nlohmann::json::parse(filedata);
+	std::string system = j["system"];
+	m_systemType = system;
+
+	m_needTime = j["times"];
+	m_nMtime = j["interval"];
+	std::string receive_bind_ip = j["receive_bind_ip"];
+	std::string send_bind_ip = j["send_bind_ip"];
+
+	for (int i = 0; i < j["dst_ip"].size(); i++) {
+		std::string dst_ip = j["dst_ip"][i];
+		m_dst_ip.emplace_back(dst_ip);
+	}
+
+	m_receive_bind_ip = receive_bind_ip;
+	if (send_bind_ip != "")
+		m_send_bind_ip = send_bind_ip;
+	else
+		m_send_bind_ip = "0.0.0.0";
+
+	memcpy(m_bindip, m_receive_bind_ip.c_str(), m_receive_bind_ip.size());
+	m_pDdefault_port = m_bindip;
+	m_pDefault_port = m_pDdefault_port;
+
+	std::string data = j["module-identity"];
+	GetIdentity(data);
+	int sizeef = j["white_list"].size();
+	for (int i = 0; i < sizeef; i++) {
+		DEVICEINFO* point = new DEVICEINFO;
+		std::string srcIp = j["white_list"][i]["ip"];
+		std::string port = j["white_list"][i]["port_index"];
+
+		point->srcip = srcIp;
+		point->port_index = port;
+		m_pWhite_list.emplace_back(point);
+	}
+	return true;
+}
+bool CSnmpClass::FindIntegerOrSend(std::string src, std::string comunnity, std::string moduleIdentity, std::string power)
+{
+	bool re = false;
+	std::string::size_type index = src.find("INTEGER:");
+	if (index != std::string::npos) {
+		int integer = std::stoi(src.substr(index + 8, src.size()));
+		//printf("INTEGER=%d\n", integer);
+		
+		if (integer == 2) {
+			OutputDebugStringA("Power Alarm");
+			SendString(1, comunnity, src, moduleIdentity, power);
+			re = true;
+		}
+		if (integer == 3) {
+			
+			OutputDebugStringA("Power Alarm Clear");
+			SendString(0, comunnity, src, moduleIdentity, power);
+			re = true;
+		}
+	}
+	else {
+		OutputDebugStringA("not find Power");
+	}
+	return re;
+}
+bool CSnmpClass::CheckResetPower(std::string buf, std::string comunnity)
+{
+	bool result = false;
+	//std::string test = "SNMPv2-SMI::enterprises.8691.7.98 Cold Start Trap";
+	//buf = test;
+	std::string::size_type index = buf.find("Cold Start Trap");
+	if (index != std::string::npos) {
+		CSnmptrap* m_pTrap = new CSnmptrap;
+		std::vector <std::string>::iterator iter = m_identity.begin();
+		for (; iter != m_identity.end(); iter++) {
+			std::string::size_type index2 = buf.find(*iter);
+			if (index2 != std::string::npos) {
+				char custom[100] = "";
+				memcpy(custom, m_send_bind_ip.c_str(), m_send_bind_ip.size());
+				printf("%s,Reset sucess Alarm clear\n",(*iter).c_str());
+				std::vector<std::string>::iterator iter2;
+				for (iter2 = m_dst_ip.begin(); iter2 != m_dst_ip.end(); iter2++) {
+					m_pTrap->SendTrap2(0, *iter2, comunnity, "KTT Alarm", *iter2, custom, m_needTime);
+					BLOG_DEBUG(fmt::format("SendTrap:: ip:{},comunnity:{},KTT Alarm:{}", *iter2, comunnity, 0));
+				}
+				/*m_pTrap->SendTrap2(0, m_dst_ip, comunnity, "KTT Alarm", *iter,custom, m_needTime);*/
+				m_Alarm.lock();
+				m_nAlarmStatus = 0;
+				m_Alarm.unlock();
+
+				result = true;
+				break;
+			}
+		}
+		delete m_pTrap;
+	}
+	return result;
+}
+bool CSnmpClass::CheckPower(std::string buf, std::string comunnity)
+{
+	bool result = false;
+	//std::string test = "2022-03-23 13:52:51 192.168.12.253 [192.168.12.253] (via UDP: [192.168.1.82]:49990->[192.168.1.82]:162) TRAP, SNMP v1, community public \
+	//	SNMPv2 - SMI::enterprises.8691.7.7 Enterprise Specific Trap(2) Uptime: 0 : 03 : 57.68 \
+	//	SNMPv2 - SMI::enterprises.8691.7.7.2.2=INTEGER: 3";
+	//buf = test;
+	std::vector <std::string>::iterator iter = m_identity.begin();
+	for (; iter != m_identity.end(); iter++) {
+		//enterprises.8691.7.XXX.2对应着moxa的mib中的swTraps
+		std::string power1 = (*iter) + ".2.2";
+		std::string power2 = (*iter) + ".2.3";
+		std::string::size_type index = buf.find(power1);
+		if (index != std::string::npos) {
+			OutputDebugStringA("power1");
+			result = FindIntegerOrSend(buf, comunnity, (*iter), power1);
+			break;
+		}
+		index = buf.find(power2);
+		if (index != std::string::npos) {
+			OutputDebugStringA("power2");
+			result = FindIntegerOrSend(buf, comunnity, (*iter), power2);
+			break;
+		}
+	}
+	return result;
+}
+bool CSnmpClass::CheckPort_index(std::string src, std::string port_index)
+{
+	bool result = false;
+	std::string::size_type index2 = src.find("INTEGER:");
+	if (index2 != std::string::npos) {
+		int integer = std::stoi(src.substr(index2 + 8, src.size()));
+		char tmp[100] = "";
+		sprintf(tmp, "%d", integer);
+		std::string::size_type index = port_index.find(std::string(tmp));
+		if (index != std::string::npos) {
+			result = true;
+		}
+	}
+	return result;
+}
+bool CSnmpClass::FindNetAlarm(std::string buf, std::string comunnity, std::string moduleIdentity)
+{
+	bool result = false;
+	int status = 2;
+	std::string::size_type link = buf.find("Link Down Trap");
+	if (link != std::string::npos) {
+		status = 1;
+	}
+	link = buf.find("Link Up Trap");
+	if (link != std::string::npos) {
+		status = 0;
+	}
+	if (status == 2)
+		return result;
+
+	std::vector <DEVICEINFO*>::iterator iter = m_pWhite_list.begin();
+	for (; iter != m_pWhite_list.end(); iter++) {
+		if ((*iter)->srcip == "")
+			continue;
+		std::string::size_type index = buf.find((*iter)->srcip);
+		//没在白名单的ip地址数据直接发送snmp
+		if (index == std::string::npos) {
+			char custom[100] = "";
+			memcpy(custom, m_send_bind_ip.c_str(), m_send_bind_ip.size());
+			CSnmptrap* m_pTrap = new CSnmptrap;
+			//printf("Link Alarm %d\n",status);
+			OutputDebugStringA(fmt::format("Link Alarm {}", status).c_str());
+			std::vector<std::string>::iterator iter2;
+			for (iter2 = m_dst_ip.begin(); iter2 != m_dst_ip.end(); iter2++) {
+				m_pTrap->SendTrap2(status, *iter2, comunnity, "KTT Alarm", moduleIdentity, custom, m_needTime);
+				BLOG_DEBUG(fmt::format("SendTrap:: ip:{},comunnity:{},KTT Alarm:{}", *iter2, comunnity, status));
+			}
+			/*m_pTrap->SendTrap2(status, m_dst_ip, comunnity, "KTT Alarm", moduleIdentity, custom, m_needTime);*/
+			result = true;
+			m_Alarm.lock();
+			m_nAlarmStatus = status;
+			m_Alarm.unlock();
+			delete m_pTrap;
+		}
+		else {
+			//white_list处理忽略port
+			CSnmptrap* m_pTrap = new CSnmptrap;
+			if (!CheckPort_index(buf, (*iter)->port_index)) {
+				char custom[100] = "";
+				memcpy(custom, m_send_bind_ip.c_str(), m_send_bind_ip.size());
+				m_Alarm.lock();
+				m_nAlarmStatus = status;
+				m_Alarm.unlock();
+				printf("white_list Link Alarm %d\n",status);
+				std::vector<std::string>::iterator iter2;
+				for (iter2 = m_dst_ip.begin(); iter2 != m_dst_ip.end(); iter2++) {
+					m_pTrap->SendTrap2(status, *iter2, comunnity, "KTT Alarm", moduleIdentity, custom, m_needTime);
+					BLOG_DEBUG(fmt::format("SendTrap:: ip:{},comunnity:{},KTT Alarm:{}", *iter2, comunnity, status));
+				}
+				/*m_pTrap->SendTrap2(status, m_dst_ip, comunnity, "KTT Alarm", moduleIdentity,custom, m_needTime);*/
+				result = true;
+			}
+			else {
+				printf("white_list port\n");
+			}
+
+			delete m_pTrap;
+			break;
+		}
+	}
+	return result;
+}
+bool CSnmpClass::CheckNetwork(std::string buf, std::string comunnity)
+{
+	bool result = false;
+	//std::string test = "2022-03-23 14:04:21 192.168.12.253 [192.168.12.253] (via UDP: [192.168.1.82]:64451->[192.168.1.82]:162) TRAP, SNMP v1, community public \
+	//	SNMPv2 - SMI::enterprises.8691.7.7 Link Down Trap(0) Uptime: 0 : 15 : 28.53 \
+	//	IF - MIB::ifIndex.2 = INTEGER:3";
+	//buf = test;
+
+	std::vector <std::string>::iterator iter = m_identity.begin();
+	for (; iter != m_identity.end(); iter++) {
+		std::string::size_type identity = buf.find(*iter);
+		if (identity != std::string::npos) {
+			result = FindNetAlarm(buf,comunnity, *iter);
+			break;
+		}
+	}
+	return result;
+}
+int CSnmpClass::Init(std::string addr)
+{
+	if (!LoadDeviceInfo())
+		return -1;
+
+	Start();
+	BLOG_DEBUG("application start");
+	m_sDeviceIp = addr;
+	m_pInstance = (void*)this;
+	char* argv2[] = { "netsnmp_ALL.exe","-Lo" };
+	return  SnmpTrapdMain(2, argv2);
+}
+/*
+* To stop Snmp Trap Receiver daemon
+* This portion is still not working
+*/
+void CSnmpClass::StopSnmpTrapd(void)
+{
+	/*
+	* Shut Down Service
+	*/
+	TermHandler(1);
+	/*
+	* Wait till trap receiver is completely stopped
+	*/
+	while (m_nTrapd_status != SNMPTRAPD_STOPPED) {
+		Sleep(100);
+	}
+}
+

+ 131 - 0
CSnmpClass.h

@@ -0,0 +1,131 @@
+#pragma once
+
+#include "TSysThread.h"
+#include "TSysThreadPool.h"
+
+#define HAVE_SSIZE_T
+
+extern "C" {
+
+	#include "net-snmp/net-snmp-config.h"
+	#include "net-snmp/net-snmp-includes.h"
+	#include "net-snmp/agent/net-snmp-agent-includes.h"
+	#include "net-snmp/library/fd_event_manager.h"
+	#include "net-snmp/agent/netsnmp_close_fds.h"
+	#include "net-snmp/snmplib/snmp_syslog.h"
+	#include "net-snmp/agent/agent_global_vars.h"
+
+	#include "net-snmp/agent/mibgroup/snmpv3/snmpEngine.h"
+	#include "net-snmp/agent/mibgroup/snmpv3/usmUser.h"
+	#include "net-snmp/agent/mibgroup/agent/nsVacmAccessTable.h"
+	#include "net-snmp/agent/mibgroup/agentx/subagent.h"
+	
+	
+	#include "net-snmp/agent/mibgroup/notification-log-mib/notification_log.h"
+	#include "net-snmp/agent/mibgroup/tlstm-mib/snmpTlstmCertToTSNTable/snmpTlstmCertToTSNTable.h"
+	#include "net-snmp/agent/mibgroup/mibII/vacm_conf.h"
+}
+
+#include "snmptrapd_handlers.h"
+#include "snmptrapd_log.h"
+#include "snmptrapd_auth.h"
+#include "snmptrapd_sql.h"
+
+/*
+* Include winservice.h to support Windows Service
+*/
+#ifdef WIN32
+#include <windows.h>
+#include <tchar.h>
+extern "C" {
+	#include "net-snmp/library/winservice.h"
+}
+#define WIN32SERVICE
+#endif
+extern "C" {
+	#include "net-snmp/net-snmp-features.h"
+}
+
+
+#ifndef BSD4_3
+#define BSD4_2
+#endif
+#define SNMPTRAPD_RUNNING 1
+#define SNMPTRAPD_STOPPED 0
+#define PRINT_V23_NOTIFICATION_FORMAT "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b]:\n%v\n"
+typedef struct tagDEVICEINFO_{
+	std::string srcip;
+	std::string port_index;
+}DEVICEINFO;
+
+class CSnmpClass : public TSysThreadImpl {
+public:
+	CSnmpClass();
+	~CSnmpClass();
+	int Init(std::string addr);
+	static void* m_pInstance;
+	TSysThreadPool								*m_pOolInvoker;
+	void Action();
+	std::string m_sDeviceIp;
+	int m_nPowerFlag; // 0/正常 1/报警
+	int m_nErpsFlag;// 0/正常 1/报警
+	int m_nPhyFlag;// 0/正常 1/报警
+	int m_nBoardFlag;// 0/正常 1/报警
+	std::vector <DEVICEINFO*> m_pWhite_list;
+	int m_nAlarmStatus;
+	int m_nMtime;
+	int m_needTime;
+	std::mutex m_Alarm;
+	std::string m_sCommunity;
+	std::string  m_receive_bind_ip;
+	std::string  m_send_bind_ip;
+	char m_bindip[100];
+	std::vector<std::string> m_identity;
+	std::vector<std::string> m_dst_ip;
+	std::string m_systemType;
+private:
+	static char            *m_pDdefault_port;	/* Default default port */
+	static char           *m_pDefault_port;
+	char           *m_pTrap1_fmt_str_remember;
+	static int             m_nDofork;
+	int             m_nTrapd_status;
+	/* m_pApp_name_long used for SCM, registry etc */
+	LPCSTR          m_pApp_name_long;     /* Application Name */
+	const char     *m_pApp_name;
+	void GetIdentity(std::string data);
+	bool LoadDeviceInfo();
+	bool CheckPower(std::string buf, std::string comunnity);
+	bool CheckResetPower(std::string buf, std::string comunnity);
+	bool CheckNetwork(std::string buf, std::string comunnity);
+	bool CheckPort_index(std::string src,std::string port_index);
+	bool FindNetAlarm(std::string buf, std::string comunnity, std::string moduleIdentity);
+	void     StopSnmpTrapd(void);
+	static RETSIGTYPE TermHandler(int sig);
+	static int PreParse(netsnmp_session * session, netsnmp_transport *transport, void *transport_data, int transport_data_length);
+	netsnmp_session * SnmptrapdAddSession(netsnmp_transport *t);
+	void SnmptrapdCloseSessions(netsnmp_session * sess_list);
+	static void ParseTrapdAddress(const char *token, char *cptr);
+	static void FreeTrapdAddress(void);
+	static void ParseConfigDoNotLogTraps(const char *token, char *cptr);
+	static void ParseConfigDoNotFork(const char *token, char *cptr);
+	static void ParseConfigIgnoreAuthFailure(const char *token, char *cptr);
+	static void ParseConfigOutputOption(const char *token, char *cptr);
+	static void ParseConfigAddForwarderInfo(const char *token, char *cptr);
+	void SnmptrapdMainLoop(void);
+	int SnmpTrapdMain(int argc, char * argv[]);
+	void ReadProcess(std::string buf, std::string comunnity);
+	void InitNetsnmpTrapdAuth(void);
+	static int   PrintHandler(netsnmp_pdu* pdu, netsnmp_transport* transport, netsnmp_trapd_handler * handler);
+	static int RecvHandler(netsnmp_pdu* pdu, netsnmp_transport *transport, netsnmp_trapd_handler * handler);
+	void ParseBuffer(std::string buf, std::string comunnity);
+	void MoxaParseBuffer(std::string buf, std::string comunnity);
+	void H3cParseBuffer(std::string buf, std::string comunnity);
+
+	int ParsePtype(std::string buf, std::string upAnddown);
+	int ParseEtype(std::string buf, std::string upAnddown);
+	int ParseBtype(std::string buf);
+	std::string FindString(std::string a, std::string b);
+	bool FindIntegerOrSend(std::string src, std::string comunnity, std::string moduleIdentity, std::string power);
+	void SendString(int status, std::string comunnity, std::string buf, std::string moduleIdentity, std::string power);
+	void SendStringH3c(int status, std::string comunnity, std::string buf);
+};

+ 913 - 0
CSnmptrap.cpp

@@ -0,0 +1,913 @@
+#include "CSnmptrap.h"
+#include "TSysTime.h"
+#include "CSysFormat.h"
+oid   CSnmptrap::objid_enterprise[] = { 1, 3, 6, 1, 4, 1, 3, 1, 1 };
+oid   CSnmptrap::objid_sysuptime[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
+oid   CSnmptrap::objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
+CSnmptrap::CSnmptrap()
+{
+	inform = 0;
+}
+CSnmptrap::~CSnmptrap()
+{
+
+}
+std::string CSnmptrap::FindString(std::string a, std::string b)
+{
+	if (a.size()>b.size())
+		swap(a, b);       //确保前面的一个字符串短;
+	std::string str_m;
+	for (int i = 0; i<a.size(); i++)
+	{
+		for (int j = i; j<a.size(); j++)
+		{
+			std::string temp = a.substr(i, j - i + 1);
+			if (int(b.find(temp))<0)
+				break;
+			else if (str_m.size()<temp.size())
+				str_m = temp;
+		}
+	}
+	return str_m;
+}
+char* CSnmptrap::CreateBuff(std::string src)
+{
+	char* m_pResult = NULL;
+	m_pResult = (char*)malloc(src.size() + 1);
+	memset(m_pResult, 0, src.size() + 1);
+	memcpy(m_pResult, src.c_str(), src.size());
+
+	return m_pResult;
+}
+bool CSnmptrap::SendTrap2(int status, std::string ip, std::string comunnity, std::string alarmType, std::string moduleIdentity, const char* custom, int needTime)
+{
+	if (ip == "")
+		return false;
+	char* m_pIp = CreateBuff(ip);
+	char* m_pComunnity = CreateBuff(comunnity);
+	char* m_Iidentity = CreateBuff(moduleIdentity);
+	std::string times = "[" + TSysTimeHelper::GetLocalTimeString() + "]";
+	if (needTime)
+		OutputDebugStringA(fmt::format("Send Trap Times:{}",times).c_str());
+	if (0 == status) {
+		std::string m_sbuffer = alarmType + " Cleared";
+		if (needTime) {
+			m_sbuffer = times + m_sbuffer;
+		}		
+		char* m_pAlarm = CreateBuff(m_sbuffer);
+		if (m_pAlarm) {
+			char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", m_pComunnity, m_pIp, "", m_Iidentity, "SNMPv2-MIB::sysLocation.0","s",m_pAlarm };
+			trapmain(11, argv2,custom);
+
+			free(m_pAlarm);
+			m_pAlarm = NULL;
+		}
+
+	}
+	else {
+		std::string buf = alarmType;
+		if (needTime) {
+			buf = times + buf;
+		}
+		char* m_pAlarm = CreateBuff(buf);
+		if (m_pAlarm) {
+			char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", m_pComunnity, m_pIp, "", m_Iidentity, "SNMPv2-MIB::sysLocation.0","s",m_pAlarm };
+			trapmain(11, argv2,custom);
+
+			free(m_pAlarm);
+			m_pAlarm = NULL;
+		}
+	}
+	free(m_pIp);
+	free(m_pComunnity);
+	free(m_Iidentity);
+	m_pIp = NULL;
+	m_pComunnity = NULL;
+	m_Iidentity = NULL;
+	return true;
+}
+//status: 0/正常  1/触发报警
+void CSnmptrap::SendTrapH3c(int status, std::string ip, std::string comunnity, std::string alarmType)
+{
+	//char* argv2[] = {"netsnmp_ALL.exe","-v", "2c", "-c", "public", "192.168.31.181", "", "1.3.6.1.4.1.2345", "HH3C-REDUNDANCY-POWER-MIB::hh3credundancyPowerStatus","i","2"};
+	//char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", "public", "192.168.31.181", "", "1.3.6.1.4.1.2345", "SNMPv2-MIB::sysLocation.0","s","just666" };
+	//去除\n回车,否则影响整形数据
+	//int m_nindex = buff.find('\n');
+	//if (m_nindex != buff.npos) {
+	//	buff = buff.substr(0, m_nindex);
+	//}
+	//char* m_pbuf = (char*)malloc(buff.size() + 1);
+	//memset(m_pbuf,0, buff.size() + 1);
+	//memcpy(m_pbuf, buff.c_str(), buff.size());
+	char* m_pIp = CreateBuff(ip);
+
+	char* m_pComunnity = CreateBuff(comunnity);
+
+	if (0 == status) {
+		std::string m_sbuffer = alarmType + " Cleared";
+		char* m_pAlarm = CreateBuff(m_sbuffer);
+		if (m_pAlarm) {
+			char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", m_pComunnity, m_pIp, "", "1.3.6.1.4.1.2345", "SNMPv2-MIB::sysLocation.0","s",m_pAlarm };
+			trapmain(11, argv2,"0.0.0.0");
+
+			free(m_pAlarm);
+			m_pAlarm = NULL;
+		}
+
+	}
+	else {
+		char* m_pAlarm = CreateBuff(alarmType);
+		if (m_pAlarm) {
+			char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", m_pComunnity, m_pIp, "", "1.3.6.1.4.1.2345", "SNMPv2-MIB::sysLocation.0","s",m_pAlarm };
+			trapmain(11, argv2,"0.0.0.0");
+
+			free(m_pAlarm);
+			m_pAlarm = NULL;
+		}
+	}
+
+	free(m_pIp);
+	free(m_pComunnity);
+	m_pIp = NULL;
+	m_pComunnity = NULL;
+}
+//status: 0/正常  1/触发报警
+void CSnmptrap::SendTrap(int status,std::string ip, std::string comunnity,std::string alarmType, std::string moduleIdentity, std::string power, const char* custom, int needTime)
+{
+	//char* argv2[] = {"netsnmp_ALL.exe","-v", "2c", "-c", "public", "192.168.31.181", "", "1.3.6.1.4.1.2345", "HH3C-REDUNDANCY-POWER-MIB::hh3credundancyPowerStatus","i","2"};
+	//char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", "public", "192.168.31.181", "", "1.3.6.1.4.1.2345", "SNMPv2-MIB::sysLocation.0","s","just666" };
+	if (ip == "")
+		return;
+	char* m_pIp = CreateBuff(ip);
+	char* m_pComunnity = CreateBuff(comunnity);
+	char* m_Iidentity = CreateBuff(moduleIdentity);
+	char* m_pPower = CreateBuff(power);
+	std::string times = "[" + TSysTimeHelper::GetLocalTimeString() + "]";
+	if (needTime)
+		OutputDebugStringA(fmt::format("Send Trap Times:{}", times).c_str());
+	if (0 == status) {
+		std::string m_sbuffer = alarmType + " Cleared";
+		if (needTime) {
+			m_sbuffer = times + m_sbuffer;
+		}
+		char* m_pAlarm = CreateBuff(m_sbuffer);
+		if (m_pAlarm) {
+			char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", m_pComunnity, m_pIp, "", m_Iidentity, m_pPower,"s",m_pAlarm };
+			trapmain(11, argv2,custom);
+
+			free(m_pAlarm);
+			m_pAlarm = NULL;
+		}
+
+	}
+	else {
+		std::string buf = alarmType;
+		if (needTime) {
+			buf = times + buf;
+		}
+		char* m_pAlarm = CreateBuff(buf);
+		if (m_pAlarm) {
+			char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", m_pComunnity, m_pIp, "", m_Iidentity, m_pPower,"s",m_pAlarm };
+			trapmain(11, argv2,custom);
+
+			free(m_pAlarm);
+			m_pAlarm = NULL;
+		}
+	}
+
+	free(m_pIp);
+	free(m_pComunnity);
+	free(m_Iidentity);
+	free(m_pPower);
+	m_pIp = NULL;
+	m_pComunnity = NULL;
+	m_pPower = NULL;
+	m_Iidentity = NULL;
+}
+int CSnmptrap::snmp_input1(int operation,netsnmp_session * session,int reqid, netsnmp_pdu *pdu, void *magic)
+{
+	printf("session.callback\n");
+	return 1;
+}
+
+void CSnmptrap::optProc(int argc, char *const *argv, int opt)
+{
+	switch (opt) {
+	case 'C':
+		while (*optarg) {
+			switch (*optarg++) {
+			case 'i':
+				//inform = 1;
+				break;
+			default:
+				fprintf(stderr,
+					"Unknown flag passed to -C: %c\n", optarg[-1]);
+				exit(1);
+			}
+		}
+		break;
+	}
+}
+int CSnmptrap::netsnmp_parse_args1(int argc,char **argv,netsnmp_session * session, const char *localOpts,void(*proc) (int, char *const *, int),int flags)
+{
+	int             arg, ret, sp = 0;
+	char           *cp;
+	char           *Apsz = NULL;
+	char           *Xpsz = NULL;
+	char           *Cpsz = NULL;
+	char            Opts[512];
+	int             zero_sensitive = !(flags & NETSNMP_PARSE_ARGS_NOZERO);
+	char           *backup_NETSNMP_DS_LIB_OUTPUT_PRECISION = NULL;
+
+	/*
+	* initialize session to default values
+	*/
+	snmp_sess_init(session);
+	strcpy(Opts, "Y:VhHm:M:O:I:P:D:dv:r:t:c:Z:e:E:n:u:l:x:X:a:A:p:T:-:3:L:s:");
+	if (localOpts) {
+		if (strlen(localOpts) + strlen(Opts) >= sizeof(Opts)) {
+			snmp_log(LOG_ERR, "Too many localOpts in snmp_parse_args()\n");
+			return -1;
+		}
+		strcat(Opts, localOpts);
+	}
+
+	/*
+	* get the options
+	*/
+	DEBUGMSGTL(("snmp_parse_args", "starting: %d/%d\n", optind, argc));
+	for (arg = 0; arg < argc; arg++) {
+		DEBUGMSGTL(("snmp_parse_args", " arg %d = %s\n", arg, argv[arg]));
+	}
+
+	optind = 1;
+	while ((arg = getopt(argc, argv, Opts)) != EOF) {
+		DEBUGMSGTL(("snmp_parse_args", "handling (#%d): %c (optarg %s) (sp %d)\n",
+			optind, arg, optarg, sp));
+		switch (arg) {
+		case '-':
+			if (strcasecmp(optarg, "help") == 0) {
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			if (strcasecmp(optarg, "version") == 0) {
+				fprintf(stderr, "NET-SNMP version: %s\n", netsnmp_get_version());
+				ret = NETSNMP_PARSE_ARGS_SUCCESS_EXIT;
+				goto out;
+			}
+
+			handle_long_opt(optarg);
+			break;
+
+		case 'V':
+			fprintf(stderr, "NET-SNMP version: %s\n", netsnmp_get_version());
+			ret = NETSNMP_PARSE_ARGS_SUCCESS_EXIT;
+			goto out;
+
+		case 'h':
+			ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+			goto out;
+
+		case 'H':
+			init_snmp(NETSNMP_APPLICATION_CONFIG_TYPE);
+			fprintf(stderr, "Configuration directives understood:\n");
+			read_config_print_usage("  ");
+			ret = NETSNMP_PARSE_ARGS_SUCCESS_EXIT;
+			goto out;
+
+		case 'Y':
+			netsnmp_config_remember(optarg);
+			break;
+		case 'm':
+			setenv("MIBS", optarg, 1);
+			break;
+
+		case 'M':
+			netsnmp_get_mib_directory(); /* prepare the default directories */
+			netsnmp_set_mib_directory(optarg);
+			break;
+		case 'O':
+			cp = snmp_out_options(optarg, argc, argv);
+			if (cp != NULL) {
+				fprintf(stderr, "Unknown output option passed to -O: %c.\n",
+					*cp);
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+
+		case 'I':
+			cp = snmp_in_options(optarg, argc, argv);
+			if (cp != NULL) {
+				fprintf(stderr, "Unknown input option passed to -I: %c.\n",
+					*cp);
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+		case 'P':
+			cp = snmp_mib_toggle_options(optarg);
+			if (cp != NULL) {
+				fprintf(stderr,
+					"Unknown parsing option passed to -P: %c.\n", *cp);
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+
+		case 'D':
+			debug_register_tokens(optarg);
+			snmp_set_do_debugging(1);
+
+			break;
+
+		case 'd':
+			netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+				NETSNMP_DS_LIB_DUMP_PACKET, 1);
+			break;
+
+		case 's':
+			session->localname = strdup(optarg);
+			break;
+
+		case 'v':
+			session->version = -1;
+			if (!strcmp(optarg, "1")) {
+				session->version = SNMP_VERSION_1;
+			}
+			if (!strcasecmp(optarg, "2c")) {
+				session->version = SNMP_VERSION_2c;
+			}
+
+			if (!strcasecmp(optarg, "3")) {
+				session->version = SNMP_VERSION_3;
+			}
+			if (session->version == -1) {
+				fprintf(stderr,
+					"Invalid version specified after -v flag: %s\n",
+					optarg);
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+
+		case 'p':
+			fprintf(stderr, "Warning: -p option is no longer used - ");
+			fprintf(stderr, "specify the remote host as HOST:PORT\n");
+			ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+			goto out;
+
+		case 'T':
+		{
+			char leftside[SNMP_MAXBUF_MEDIUM], rightside[SNMP_MAXBUF_MEDIUM];
+			char *tmpcp, *tmpopt;
+
+			/* ensure we have a proper argument */
+			tmpopt = strdup(optarg);
+			tmpcp = strchr(tmpopt, '=');
+			if (!tmpcp) {
+				fprintf(stderr, "-T expects a NAME=VALUE pair.\n");
+				free(tmpopt);
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			*tmpcp++ = '\0';
+
+			/* create the transport config container if this is the first */
+			if (!session->transport_configuration) {
+				netsnmp_container_init_list();
+				session->transport_configuration =
+					netsnmp_container_find("transport_configuration:fifo");
+				if (!session->transport_configuration) {
+					fprintf(stderr, "failed to initialize the transport configuration container\n");
+					free(tmpopt);
+					ret = NETSNMP_PARSE_ARGS_ERROR;
+					goto out;
+				}
+
+				session->transport_configuration->compare =
+					(netsnmp_container_compare*)
+					netsnmp_transport_config_compare;
+			}
+
+			/* set the config */
+			strlcpy(leftside, tmpopt, sizeof(leftside));
+			strlcpy(rightside, tmpcp, sizeof(rightside));
+
+			CONTAINER_INSERT(session->transport_configuration,
+				netsnmp_transport_create_config(leftside,
+					rightside));
+			free(tmpopt);
+		}
+		break;
+
+		case 't':
+			session->timeout = (long)(atof(optarg) * 1000000L);
+			if (session->timeout <= 0) {
+				fprintf(stderr, "Invalid timeout in seconds after -t flag.\n");
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+
+		case 'r':
+			session->retries = atoi(optarg);
+			if (session->retries < 0 || !isdigit((unsigned char)(optarg[0]))) {
+				fprintf(stderr, "Invalid number of retries after -r flag.\n");
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+
+		case 'c':
+			if (zero_sensitive) {
+				SNMP_FREE(Cpsz); /* free any previous value */
+				if ((Cpsz = strdup(optarg)) != NULL) {
+					//memcpy(optarg,0, sizeof(optarg));
+					//memset(optarg, '\0', strlen(optarg));
+				}
+				else {
+					fprintf(stderr, "malloc failure processing -c flag.\n");
+					ret = NETSNMP_PARSE_ARGS_ERROR;
+					goto out;
+				}
+			}
+			else {
+				Cpsz = strdup(optarg);
+			}
+			break;
+
+		case '3':
+			if (snmpv3_parse_args(optarg, session, &Apsz, &Xpsz, argc, argv,
+				flags) < 0) {
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+
+		case 'L':
+			if (snmp_log_options(optarg, argc, argv) < 0) {
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+
+#define SNMPV3_CMD_OPTIONS
+#ifdef  SNMPV3_CMD_OPTIONS
+		case 'Z':
+		case 'e':
+		case 'E':
+		case 'n':
+		case 'l':
+		case 'u':
+#ifdef NETSNMP_SECMOD_USM
+		case 'a':
+		case 'x':
+		case 'A':
+		case 'X':
+#endif             /* NETSNMP_SECMOD_USM */
+			if (snmpv3_parse_arg(arg, optarg, session, &Apsz, &Xpsz, argc,
+				argv, flags) < 0) {
+				ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+				goto out;
+			}
+			break;
+#endif                          /* SNMPV3_CMD_OPTIONS */
+
+		case '?':
+			ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+			goto out;
+
+		default:
+			proc(argc, argv, arg);
+			break;
+		}
+	}
+	DEBUGMSGTL(("snmp_parse_args", "finished: %d/%d\n", optind, argc));
+
+	/*
+	* save command line parameters which should have precedence above config file settings
+	*    (There ought to be a more scalable approach than this....)
+	*/
+	if (netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION)) {
+		backup_NETSNMP_DS_LIB_OUTPUT_PRECISION =
+			strdup(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION));
+	}
+
+	/*
+	* read in MIB database and initialize the snmp library, read the config file
+	*/
+	init_snmp(NETSNMP_APPLICATION_CONFIG_TYPE);
+
+	/*
+	* restore command line parameters which should have precedence above config file settings
+	*/
+	if (backup_NETSNMP_DS_LIB_OUTPUT_PRECISION) {
+		netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION, backup_NETSNMP_DS_LIB_OUTPUT_PRECISION);
+		free(backup_NETSNMP_DS_LIB_OUTPUT_PRECISION);
+	}
+
+	/*
+	* session default version
+	*/
+	if (session->version == SNMP_DEFAULT_VERSION) {
+		/*
+		* run time default version
+		*/
+		session->version = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+			NETSNMP_DS_LIB_SNMPVERSION);
+
+		/*
+		* compile time default version
+		*/
+		if (!session->version) {
+			switch (NETSNMP_DEFAULT_SNMP_VERSION) {
+			case 1:
+				session->version = SNMP_VERSION_1;
+				break;
+			case 2:
+				session->version = SNMP_VERSION_2c;
+				break;
+			case 3:
+				session->version = SNMP_VERSION_3;
+				break;
+			default:
+				snmp_log(LOG_ERR, "Can't determine a valid SNMP version for the session\n");
+				return(NETSNMP_PARSE_ARGS_ERROR);
+			}
+		}
+		else {
+			if (session->version == NETSNMP_DS_SNMP_VERSION_1)  /* bogus value.  version 1 actually = 0 */
+				session->version = SNMP_VERSION_1;
+		}
+	}
+
+#ifdef NETSNMP_SECMOD_USM
+	/* XXX: this should ideally be moved to snmpusm.c somehow */
+
+	/*
+	* make master key from pass phrases
+	*/
+	if (Apsz) {
+		session->securityAuthKeyLen = USM_AUTH_KU_LEN;
+		if (session->securityAuthProto == NULL) {
+			/*
+			* get .conf set default
+			*/
+			const oid      *def =
+				get_default_authtype(&session->securityAuthProtoLen);
+			session->securityAuthProto =
+				snmp_duplicate_objid(def, session->securityAuthProtoLen);
+		}
+		if (session->securityAuthProto == NULL) {
+			session->securityAuthProto =
+				snmp_duplicate_objid(SNMP_DEFAULT_AUTH_PROTO,
+					SNMP_DEFAULT_AUTH_PROTOLEN);
+			session->securityAuthProtoLen = SNMP_DEFAULT_AUTH_PROTOLEN;
+		}
+		if (generate_Ku(session->securityAuthProto,
+			session->securityAuthProtoLen,
+			(u_char *)Apsz, strlen(Apsz),
+			session->securityAuthKey,
+			&session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
+			snmp_perror(argv[0]);
+			fprintf(stderr,
+				"Error generating a key (Ku) from the supplied authentication pass phrase. \n");
+			ret = NETSNMP_PARSE_ARGS_ERROR;
+			goto out;
+		}
+		free(Apsz);
+		Apsz = NULL;
+	}
+	if (Xpsz) {
+		session->securityPrivKeyLen = USM_PRIV_KU_LEN;
+		if (session->securityPrivProto == NULL) {
+			/*
+			* get .conf set default
+			*/
+			const oid      *def =
+				get_default_privtype(&session->securityPrivProtoLen);
+			session->securityPrivProto =
+				snmp_duplicate_objid(def, session->securityPrivProtoLen);
+		}
+		if (session->securityPrivProto == NULL) {
+			session->securityPrivProto =
+				snmp_duplicate_objid(SNMP_DEFAULT_PRIV_PROTO,
+					SNMP_DEFAULT_PRIV_PROTOLEN);
+			session->securityPrivProtoLen = SNMP_DEFAULT_PRIV_PROTOLEN;
+		}
+		if (generate_Ku(session->securityAuthProto,
+			session->securityAuthProtoLen,
+			(u_char *)Xpsz, strlen(Xpsz),
+			session->securityPrivKey,
+			&session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
+			snmp_perror(argv[0]);
+			fprintf(stderr,
+				"Error generating a key (Ku) from the supplied privacy pass phrase. \n");
+			ret = NETSNMP_PARSE_ARGS_ERROR;
+			goto out;
+		}
+		free(Xpsz);
+		Xpsz = NULL;
+	}
+#endif /* NETSNMP_SECMOD_USM */
+
+	/*
+	* get the hostname
+	*/
+	if (optind == argc) {
+		fprintf(stderr, "No hostname specified.\n");
+		ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+		goto out;
+	}
+	session->peername = argv[optind++]; /* hostname */
+
+#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
+										/*
+										* If v1 or v2c, check community has been set, either by a -c option above,
+										* or via a default token somewhere.
+										* If neither, it will be taken from the incoming request PDU.
+										*/
+	if (session->version == SNMP_VERSION_1 || session->version == SNMP_VERSION_2c)
+	{
+		if (Cpsz == NULL) {
+			Cpsz = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
+				NETSNMP_DS_LIB_COMMUNITY);
+			if (Cpsz == NULL) {
+				if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
+					NETSNMP_DS_LIB_IGNORE_NO_COMMUNITY)) {
+					DEBUGMSGTL(("snmp_parse_args",
+						"ignoring that the community string is not present\n"));
+					session->community = NULL;
+					session->community_len = 0;
+				}
+				else {
+					fprintf(stderr, "No community name specified.\n");
+					ret = NETSNMP_PARSE_ARGS_ERROR_USAGE;
+					goto out;
+				}
+			}
+			else {
+				Cpsz = NULL;
+			}
+		}
+		else {
+			session->community = (unsigned char *)Cpsz;
+			session->community_len = strlen(Cpsz);
+			Cpsz = NULL;
+		}
+	}
+#endif /* support for community based SNMP */
+
+	ret = optind;
+
+out:
+	free(Apsz);
+	free(Xpsz);
+	free(Cpsz);
+	return ret;
+}
+
+int CSnmptrap::snmp_parse_args1(int argc, char **argv, netsnmp_session * session, const char *localOpts, void(*proc) (int, char *const *, int))
+{
+	return netsnmp_parse_args1(argc, argv, session, localOpts, proc, 0);
+}
+int CSnmptrap::trapmain(int argc, char *argv[],const char* custom)
+{
+	netsnmp_session session, *ss;
+	netsnmp_pdu    *pdu, *response;
+	oid             name[MAX_OID_LEN];
+	size_t          name_length;
+	int             arg;
+	int             status;
+	char           *trap = NULL;
+	int             exitval = 1;
+#ifndef NETSNMP_DISABLE_SNMPV1
+	char           *specific = NULL, *description = NULL, *agent = NULL;
+	in_addr_t      *pdu_in_addr_t;
+#endif
+
+	SOCK_STARTUP;
+	//char* argv2[] = { "netsnmp_ALL.exe","-v", "2c", "-c", "public", "192.168.31.8", "", "1.3.6.1.4.1.2345", "HH3C-REDUNDANCY-POWER-MIB::hh3credundancyPowerStatus","i","2" };
+	//argv = argv2;
+	/** parse args (also initializes session) */
+	arg = snmp_parse_args1(argc, argv, &session, "C:", optProc);
+
+	session.callback = snmp_input1;
+	session.callback_magic = NULL;
+
+	/*
+	* setup the local engineID which may be for either or both of the
+	* contextEngineID and/or the securityEngineID.
+	*/
+	setup_engineID(NULL, NULL);
+
+	/* if we don't have a contextEngineID set via command line
+	arguments, use our internal engineID as the context. */
+	if (session.contextEngineIDLen == 0 ||
+		session.contextEngineID == NULL) {
+		session.contextEngineID =
+			snmpv3_generate_engineID(&session.contextEngineIDLen);
+	}
+
+	if (session.version == SNMP_VERSION_3 && !inform) {
+		/*
+		* for traps, we use ourselves as the authoritative engine
+		* which is really stupid since command line apps don't have a
+		* notion of a persistent engine.  Hence, our boots and time
+		* values are probably always really wacked with respect to what
+		* a manager would like to see.
+		*
+		* The following should be enough to:
+		*
+		* 1) prevent the library from doing discovery for engineid & time.
+		* 2) use our engineid instead of the remote engineid for
+		* authoritative & privacy related operations.
+		* 3) The remote engine must be configured with users for our engineID.
+		*
+		* -- Wes
+		*/
+
+		/*
+		* pick our own engineID
+		*/
+		if (session.securityEngineIDLen == 0 ||
+			session.securityEngineID == NULL) {
+			session.securityEngineID =
+				snmpv3_generate_engineID(&session.securityEngineIDLen);
+		}
+
+		/*
+		* set boots and time, which will cause problems if this
+		* machine ever reboots and a remote trap receiver has cached our
+		* boots and time...  I'll cause a not-in-time-window report to
+		* be sent back to this machine.
+		*/
+		if (session.engineBoots == 0)
+			session.engineBoots = 1;
+		if (session.engineTime == 0)    /* not really correct, */
+			session.engineTime = get_uptime();  /* but it'll work. Sort of. */
+
+		set_enginetime(session.securityEngineID, session.securityEngineIDLen,
+			session.engineBoots, session.engineTime, TRUE);
+	}
+
+	ss = snmp_add(&session,
+		netsnmp_transport_open_client("snmptrap", session.peername,custom),
+		NULL, NULL);
+	if (ss == NULL) {
+		/*
+		* diagnose netsnmp_transport_open_client and snmp_add errors with
+		* the input netsnmp_session pointer
+		*/
+		snmp_sess_perror("snmptrap", &session);
+		goto out;
+	}
+
+#ifndef NETSNMP_DISABLE_SNMPV1
+	if (session.version == SNMP_VERSION_1) {
+		if (inform) {
+			fprintf(stderr, "Cannot send INFORM as SNMPv1 PDU\n");
+			goto out;
+		}
+		pdu = snmp_pdu_create(SNMP_MSG_TRAP);
+		if (!pdu) {
+			fprintf(stderr, "Failed to create trap PDU\n");
+			goto out;
+		}
+		pdu_in_addr_t = (in_addr_t *)pdu->agent_addr;
+		if (arg == argc) {
+			fprintf(stderr, "No enterprise oid\n");
+			goto out;
+		}
+		if (argv[arg][0] == 0) {
+			pdu->enterprise = (oid *)malloc(sizeof(objid_enterprise));
+			memcpy(pdu->enterprise, objid_enterprise,
+				sizeof(objid_enterprise));
+			pdu->enterprise_length =
+				sizeof(objid_enterprise) / sizeof(oid);
+		}
+		else {
+			name_length = MAX_OID_LEN;
+			if (!snmp_parse_oid(argv[arg], name, &name_length)) {
+				snmp_perror(argv[arg]);
+				goto out;
+			}
+			pdu->enterprise = (oid *)malloc(name_length * sizeof(oid));
+			memcpy(pdu->enterprise, name, name_length * sizeof(oid));
+			pdu->enterprise_length = name_length;
+		}
+		if (++arg >= argc) {
+			fprintf(stderr, "Missing agent parameter\n");
+			goto out;
+		}
+		agent = argv[arg];
+		if (agent != NULL && strlen(agent) != 0) {
+			int ret = netsnmp_gethostbyname_v4(agent, pdu_in_addr_t);
+			if (ret < 0) {
+				fprintf(stderr, "unknown host: %s\n", agent);
+				goto out;
+			}
+		}
+		else {
+			*pdu_in_addr_t = get_myaddr();
+		}
+		if (++arg == argc) {
+			fprintf(stderr, "Missing generic-trap parameter\n");
+			//			usage();
+			goto out;
+		}
+		trap = argv[arg];
+		pdu->trap_type = atoi(trap);
+		if (++arg == argc) {
+			fprintf(stderr, "Missing specific-trap parameter\n");
+			goto out;
+		}
+		specific = argv[arg];
+		pdu->specific_type = atoi(specific);
+		if (++arg == argc) {
+			fprintf(stderr, "Missing uptime parameter\n");
+			goto out;
+		}
+		description = argv[arg];
+		if (description == NULL || *description == 0)
+			pdu->time = get_uptime();
+		else
+			pdu->time = atol(description);
+	}
+	else
+#endif
+	{
+		long            sysuptime;
+		char            csysuptime[20];
+
+		pdu = snmp_pdu_create(inform ? SNMP_MSG_INFORM : SNMP_MSG_TRAP2);
+		if (!pdu) {
+			fprintf(stderr, "Failed to create notification PDU\n");
+			goto out;
+		}
+		if (arg == argc) {
+			fprintf(stderr, "Missing up-time parameter\n");
+			goto out;
+		}
+		trap = argv[arg];
+		if (*trap == 0) {
+			sysuptime = get_uptime();
+			sprintf(csysuptime, "%ld", sysuptime);
+			trap = csysuptime;
+		}
+		snmp_add_var(pdu, objid_sysuptime,
+			sizeof(objid_sysuptime) / sizeof(oid), 't', trap);
+		if (++arg == argc) {
+			fprintf(stderr, "Missing trap-oid parameter\n");
+			goto out;
+		}
+		if (snmp_add_var
+		(pdu, objid_snmptrap, sizeof(objid_snmptrap) / sizeof(oid),
+			'o', argv[arg]) != 0) {
+			snmp_perror(argv[arg]);
+			goto out;
+		}
+	}
+	arg++;
+
+	while (arg < argc) {
+		arg += 3;
+		if (arg > argc) {
+			fprintf(stderr, "%s: Missing type/value for variable\n",
+				argv[arg - 3]);
+			goto out;
+		}
+		name_length = MAX_OID_LEN;
+		if (!snmp_parse_oid(argv[arg - 3], name, &name_length)) {
+			snmp_perror(argv[arg - 3]);
+			goto out;
+		}
+		if (snmp_add_var(pdu, name, name_length, argv[arg - 2][0],argv[arg - 1]) != 0) {
+			snmp_perror(argv[arg - 3]);
+			goto out;
+		}
+	}
+
+	if (inform)
+		status = snmp_synch_response(ss, pdu, &response);
+	else
+		status = snmp_send(ss, pdu) == 0;
+	if (status) {
+		snmp_sess_perror(inform ? "snmpinform" : "snmptrap", ss);
+		if (!inform)
+			snmp_free_pdu(pdu);
+		goto close_session;
+	}
+	else if (inform)
+		snmp_free_pdu(response);
+
+	exitval = 0;
+
+close_session:
+	snmp_close(ss);
+	//snmp_shutdown(NETSNMP_APPLICATION_CONFIG_TYPE);
+out:
+	SOCK_CLEANUP;
+	return exitval;
+}

+ 24 - 0
CSnmptrap.h

@@ -0,0 +1,24 @@
+#pragma once
+
+#include "CSnmpClass.h"
+
+class CSnmptrap {
+public:
+	CSnmptrap();
+	~CSnmptrap();
+	static int snmp_input1(int operation, netsnmp_session * session, int reqid, netsnmp_pdu *pdu, void *magic);
+	static void optProc(int argc, char *const *argv, int opt);
+	void SendTrapH3c(int status, std::string ip, std::string comunnity, std::string alarmType);
+	void SendTrap(int status, std::string ip, std::string comunnity, std::string alarmType, std::string moduleIdentity, std::string power, const char* custom, int needTime);
+	bool SendTrap2(int status, std::string ip, std::string comunnity, std::string alarmType, std::string moduleIdentity,const char* custom,int needTime);
+	static oid             objid_enterprise[];
+	static oid             objid_sysuptime[];
+	static oid             objid_snmptrap[];
+private:
+	int inform;
+	int netsnmp_parse_args1(int argc, char **argv, netsnmp_session * session, const char *localOpts, void(*proc) (int, char *const *, int), int flags);
+	int snmp_parse_args1(int argc, char **argv, netsnmp_session * session, const char *localOpts, void(*proc) (int, char *const *, int));
+	int trapmain(int argc, char *argv[],const char* custom);
+	std::string FindString(std::string a, std::string b);
+	char* CreateBuff(std::string src);
+};

+ 28 - 0
SnmpRelay.sln

@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SnmpRelay", "SnmpRelay.vcxproj", "{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}.Debug|x64.ActiveCfg = Debug|x64
+		{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}.Debug|x64.Build.0 = Debug|x64
+		{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}.Debug|x86.ActiveCfg = Debug|Win32
+		{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}.Debug|x86.Build.0 = Debug|Win32
+		{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}.Release|x64.ActiveCfg = Release|x64
+		{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}.Release|x64.Build.0 = Release|x64
+		{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}.Release|x86.ActiveCfg = Release|Win32
+		{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 204 - 0
SnmpRelay.vcxproj

@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A3C4AD17-B6D3-4A95-896C-2E2E0B25DC5E}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>netsnmp_ALL</RootNamespace>
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+    <ProjectName>SnmpRelay</ProjectName>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetName>snmprelay</TargetName>
+    <OutDir>$(ProjectDir)$(PlatformToolset)\$(PlatformTarget)\$(Configuration)\</OutDir>
+    <IntDir>$(PlatformToolset)\$(PlatformTarget)\$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <TargetName>snmprelay</TargetName>
+    <OutDir>$(ProjectDir)$(PlatformToolset)\$(PlatformTarget)\$(Configuration)\</OutDir>
+    <IntDir>$(PlatformToolset)\$(PlatformTarget)\$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <TargetName>snmprelay</TargetName>
+    <OutDir>$(ProjectDir)$(PlatformToolset)\$(PlatformTarget)\$(Configuration)\</OutDir>
+    <IntDir>$(PlatformToolset)\$(PlatformTarget)\$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(ProjectDir)$(PlatformToolset)\$(PlatformTarget)\$(Configuration)\</OutDir>
+    <IntDir>$(PlatformToolset)\$(PlatformTarget)\$(Configuration)\$(ProjectName)\</IntDir>
+    <TargetName>snmprelay</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\cvs\DeviceSDKs\liblog4cxx\include;..\cvs\DeviceSDKs\libevpp\include;..\cvs\DeviceSDKs\libevent;..\cvs\DeviceSDKs\libglog\include;..\cvs\DeviceSDKs\libnetsnmp\include;..\cvs\SysUtils;..\cvs\IOIUtils</AdditionalIncludeDirectories>
+      <PrecompiledHeaderFile />
+      <PrecompiledHeaderOutputFile />
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>..\cvs\DeviceSDKs\liblog4cxx\lib\$(PlatformTarget);..\cvs\DeviceSDKs\libglog\lib\$(PlatformToolset)\$(PlatformTarget);..\cvs\DeviceSDKs\libevent\lib\$(PlatformToolset)\$(PlatformTarget)\$(Configuration);..\cvs\DeviceSDKs\libevpp\lib\$(PlatformToolset)\$(PlatformTarget);..\cvs\DeviceSDKs\libopenssl\lib\$(PlatformTarget);..\cvs\DeviceSDKs\libnetsnmp\lib\$(PlatformToolset)\$(PlatformTarget);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>ws2_32.lib;netsnmp.lib;netsnmpagent.lib;netsnmpmibs.lib;netsnmptrapd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\cvs\DeviceSDKs\liblog4cxx\include;..\cvs\DeviceSDKs\libevpp\include;..\cvs\DeviceSDKs\libevent;..\cvs\DeviceSDKs\libglog\include;..\cvs\DeviceSDKs\libnetsnmp\include;..\cvs\SysUtils;..\cvs\IOIUtils</AdditionalIncludeDirectories>
+      <PrecompiledHeaderFile />
+      <PrecompiledHeaderOutputFile />
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>..\cvs\DeviceSDKs\liblog4cxx\lib\$(PlatformTarget);..\cvs\DeviceSDKs\libglog\lib\$(PlatformToolset)\$(PlatformTarget);..\cvs\DeviceSDKs\libevent\lib\$(PlatformToolset)\$(PlatformTarget)\$(Configuration);..\cvs\DeviceSDKs\libevpp\lib\$(PlatformToolset)\$(PlatformTarget);..\cvs\DeviceSDKs\libopenssl\lib\$(PlatformTarget);..\cvs\DeviceSDKs\libnetsnmp\lib\$(PlatformToolset)\$(PlatformTarget);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>..\cvs\DeviceSDKs\liblog4cxx\include;..\cvs\DeviceSDKs\libevpp\include;..\cvs\DeviceSDKs\libevent;..\cvs\DeviceSDKs\libglog\include;..\cvs\DeviceSDKs\libnetsnmp\include;..\cvs\SysUtils;..\cvs\IOIUtils</AdditionalIncludeDirectories>
+      <PrecompiledHeaderFile />
+      <PrecompiledHeaderOutputFile />
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>ws2_32.lib;netsnmp.lib;netsnmpagent.lib;netsnmpmibs.lib;netsnmptrapd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>..\cvs\DeviceSDKs\liblog4cxx\lib\$(PlatformTarget);..\cvs\DeviceSDKs\libglog\lib\$(PlatformToolset)\$(PlatformTarget);..\cvs\DeviceSDKs\libevent\lib\$(PlatformToolset)\$(PlatformTarget)\$(Configuration);..\cvs\DeviceSDKs\libevpp\lib\$(PlatformToolset)\$(PlatformTarget);..\cvs\DeviceSDKs\libopenssl\lib\$(PlatformTarget);..\cvs\DeviceSDKs\libnetsnmp\lib\$(PlatformToolset)\$(PlatformTarget);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeaderFile />
+      <PrecompiledHeaderOutputFile />
+      <AdditionalIncludeDirectories>..\cvs\DeviceSDKs\liblog4cxx\include;..\cvs\DeviceSDKs\libevpp\include;..\cvs\DeviceSDKs\libevent;..\cvs\DeviceSDKs\libglog\include;..\cvs\DeviceSDKs\libnetsnmp\include;..\cvs\SysUtils;..\cvs\IOIUtils</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>..\cvs\DeviceSDKs\liblog4cxx\lib\$(PlatformTarget);..\cvs\DeviceSDKs\libglog\lib\$(PlatformToolset)\$(PlatformTarget);..\cvs\DeviceSDKs\libevent\lib\$(PlatformToolset)\$(PlatformTarget)\$(Configuration);..\cvs\DeviceSDKs\libevpp\lib\$(PlatformToolset)\$(PlatformTarget);..\cvs\DeviceSDKs\libopenssl\lib\$(PlatformTarget);..\cvs\DeviceSDKs\libnetsnmp\lib\$(PlatformToolset)\$(PlatformTarget);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="CSnmpClass.h" />
+    <ClInclude Include="CSnmptrap.h" />
+    <ClInclude Include="log.h" />
+    <ClInclude Include="snmpd.h" />
+    <ClInclude Include="snmptrapd_auth.h" />
+    <ClInclude Include="snmptrapd_ds.h" />
+    <ClInclude Include="snmptrapd_handlers.h" />
+    <ClInclude Include="snmptrapd_log.h" />
+    <ClInclude Include="snmptrapd_sql.h" />
+    <ClInclude Include="winservice.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\cvs\IOIUtils\TSysThread.cpp" />
+    <ClCompile Include="..\cvs\IOIUtils\TSysThreadPool.cpp" />
+    <ClCompile Include="..\cvs\IOIUtils\TSysTime.cpp" />
+    <ClCompile Include="..\cvs\SysUtils\AppLog.cpp" />
+    <ClCompile Include="..\cvs\SysUtils\CSysFormat.cpp" />
+    <ClCompile Include="CSnmpClass.cpp" />
+    <ClCompile Include="CSnmptrap.cpp" />
+    <ClCompile Include="log.cpp" />
+    <ClCompile Include="SnmpRelayMain.cpp" />
+    <ClCompile Include="snmptrapd_handlers.cpp" />
+    <ClCompile Include="snmptrapd_log.cpp" />
+    <ClCompile Include="winservice.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 87 - 0
SnmpRelay.vcxproj.filters

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="winservice.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="snmptrapd_handlers.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="snmptrapd_ds.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="snmptrapd_log.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="snmptrapd_sql.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="snmptrapd_auth.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="CSnmpClass.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="CSnmptrap.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="snmpd.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="log.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="winservice.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="snmptrapd_handlers.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="CSnmpClass.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="CSnmptrap.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="log.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="snmptrapd_log.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="SnmpRelayMain.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\cvs\SysUtils\AppLog.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\cvs\SysUtils\CSysFormat.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\cvs\IOIUtils\TSysThread.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\cvs\IOIUtils\TSysThreadPool.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\cvs\IOIUtils\TSysTime.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

+ 8 - 0
SnmpRelay.vcxproj.user

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LocalDebuggerCommandArguments>
+    </LocalDebuggerCommandArguments>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+</Project>

+ 51 - 0
SnmpRelayMain.cpp

@@ -0,0 +1,51 @@
+//
+//
+
+#include "CSnmpClass.h"
+
+#ifdef _DEBUG
+	#pragma comment (lib, "netsnmpd.lib")
+	#pragma comment (lib, "netsnmpagentd.lib")
+	#pragma comment (lib, "netsnmpmibsd.lib")
+	#pragma comment (lib, "netsnmptrapdd.lib")
+#else
+
+	#pragma comment (lib, "netsnmp.lib")
+	#pragma comment (lib, "netsnmpagent.lib")
+	#pragma comment (lib, "netsnmpmibs.lib")
+	#pragma comment (lib, "netsnmptrapd.lib")
+#endif
+
+namespace {
+
+	struct OnApp {
+		OnApp() {
+#ifdef WIN32
+			// Initialize Winsock 2.2
+			WSADATA wsaData;
+			int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
+
+			if (err) {
+				std::cout << "WSAStartup() failed with error: %d" << err;
+			}
+#endif
+		}
+		~OnApp() {
+#ifdef WIN32
+			system("pause");
+			WSACleanup();
+#endif
+		}
+	} __s_onexit_pause;
+}
+
+
+int __cdecl main(int argc, char * argv[])
+{
+	CSnmpClass* m_pDemo = new CSnmpClass;
+	//m_pDemo->Start();
+	m_pDemo->Init("");
+	delete m_pDemo;
+}
+
+

+ 29 - 0
deveice.config

@@ -0,0 +1,29 @@
+{
+  "description":{
+  "interval":"间隔发送报警时间,单位s/秒",
+  "ip":"设备端ip地址",
+  "times":"发送的snmp Alarm是否包含时间,1为需要/0为不需要",
+  "send_bind_ip":"发送trap程序需要绑定的地址",
+  "dst_ip":"trap目的地址",
+  "receive_bind_ip":"接收绑定地址",
+  "port_index":"里面的数字表示着moxa硬件上网络插头上的数字标号,例如port_index:4,5表示忽略4,5这两个端口标号出现的Link Down Trap或者Link up Trap信息.",
+  "module-identity":"对应着mib文件里的MODULE-IDENTITY,例如enterprises.8691.7.7,enterprises.8691.7.70,7和70就是module-identity的值",
+  "system":"暂时区分h3c系统和moxa系统,在receive_bind_ip里设置端口需要留意h3c的端口号为1622,moxa为162。h3c系统只需要关注receive_bind_ip和system即可。"
+  },
+  "white_list":[
+    {
+	  "ip":"192.168.12.253",
+      "port_index":"{3,0}"
+    }
+  ],
+  "dst_ip":[
+  "192.168.31.10:162",
+  "192.168.31.9:163"
+  ],
+  "system":"moxa",
+  "times":1,
+  "interval":2,
+  "receive_bind_ip":"udp:192.168.31.181:162",
+  "send_bind_ip":"192.168.31.181",
+  "module-identity":"7,98,70,100,106,117,95"
+}

+ 3 - 0
log.cpp

@@ -0,0 +1,3 @@
+#include "log.h"
+
+log4cxx::LoggerPtr app_logger(log4cxx::Logger::getLogger("netsnmp"));

+ 9 - 0
log.h

@@ -0,0 +1,9 @@
+#pragma once
+#include "AppLog.h"
+#include "CSysFormat.h"
+
+
+
+#define BLOG_DEBUG(msg) LOG4CXX_INFO(app_logger, msg); 
+#define BLOG_ERROR(msg) LOG4CXX_ERROR(app_logger, msg); 
+#define BLOG_WARN(msg) LOG4CXX_WARN(app_logger, msg); 

+ 28 - 0
snmp_transport_inits.h

@@ -0,0 +1,28 @@
+#ifdef NETSNMP_TRANSPORT_UDP_DOMAIN
+netsnmp_udp_base_ctor();
+netsnmp_udp_ctor();
+#endif
+#ifdef NETSNMP_TRANSPORT_TCP_DOMAIN
+netsnmp_tcp_ctor();
+#endif
+#ifdef NETSNMP_TRANSPORT_ALIAS_DOMAIN
+netsnmp_alias_ctor();
+#endif
+#ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
+netsnmp_udpipv6_ctor();
+#endif
+#ifdef NETSNMP_TRANSPORT_TCPIPV6_DOMAIN
+netsnmp_tcpipv6_ctor();
+#endif
+#ifdef NETSNMP_TRANSPORT_TLSBASE_DOMAIN
+netsnmp_tlsbase_ctor();
+#endif
+#ifdef NETSNMP_TRANSPORT_DTLSUDP_DOMAIN
+netsnmp_dtlsudp_ctor();
+#endif
+#ifdef NETSNMP_TRANSPORT_TLSTCP_DOMAIN
+netsnmp_tlstcp_ctor();
+#endif
+#ifdef NETSNMP_TRANSPORT_STD_DOMAIN
+netsnmp_std_ctor();
+#endif

+ 27 - 0
snmpd.h

@@ -0,0 +1,27 @@
+/*
+ * snmpd.h
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MASTER_AGENT 0
+#define SUB_AGENT    1
+extern int      agent_role;
+
+extern int      snmp_dump_packet;
+extern int      verbose;
+extern int      (*sd_handlers[]) (int);
+extern int      smux_listen_sd;
+
+extern int      snmp_read_packet(int);
+
+/*
+ * config file parsing routines 
+ */
+void            agentBoots_conf(char *, char *);
+
+#ifdef __cplusplus
+}
+#endif

+ 189 - 0
snmptrapd_auth.cpp

@@ -0,0 +1,189 @@
+/*
+ * snmptrapd_auth.c - authorize notifications for further processing
+ *
+ * Portions of this file are copyrighted by:
+ * Copyright (c) 2016 VMware, Inc. All rights reserved.
+ * Use is subject to license terms specified in the COPYING file
+ * distributed with the Net-SNMP package.
+ *
+ */
+#include <net-snmp/net-snmp-config.h>
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include <net-snmp/net-snmp-includes.h>
+#include "snmptrapd_handlers.h"
+#include "snmptrapd_auth.h"
+#include "snmptrapd_ds.h"
+
+#include <net-snmp/agent/agent_module_config.h>
+#include <net-snmp/agent/mib_module_config.h>
+
+#ifdef USING_MIBII_VACM_CONF_MODULE
+#include "net-snmp/agent/mibgroup/mibII/vacm_conf.h"
+#endif
+
+#include <net-snmp/agent/agent_trap.h>
+
+/**
+ * initializes the snmptrapd authorization code registering needed
+ * handlers and config parsers.
+ */
+void init_netsnmp_trapd_auth(void)
+{
+    /* register our function as a authorization handler */
+    netsnmp_trapd_handler *traph;
+	printf("new********5\n");
+    traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_AUTH_HANDLER,
+                                           netsnmp_trapd_auth);
+    traph->authtypes = TRAP_AUTH_NONE;
+
+#ifdef USING_MIBII_VACM_CONF_MODULE
+    /* register our configuration tokens for VACM configs */
+    init_vacm_config_tokens();
+#endif
+
+    /* register a config token for turning off the authorization entirely */
+    netsnmp_ds_register_config(ASN_BOOLEAN, "snmptrapd", "disableAuthorization",
+                               NETSNMP_DS_APPLICATION_ID,
+                               NETSNMP_DS_APP_NO_AUTHORIZATION);
+}
+
+/* XXX: store somewhere in the PDU instead */
+static int lastlookup;
+
+/**
+ * Authorizes incoming notifications for further processing
+ */
+int netsnmp_trapd_auth(netsnmp_pdu* pdu,netsnmp_transport *transport, netsnmp_trapd_handler * handler)
+{
+	printf("netsnmp_trapd_auth\n");
+#if 1
+    int ret = 0;
+    oid snmptrapoid[] = { 1,3,6,1,6,3,1,1,4,1,0 };
+    size_t snmptrapoid_len = OID_LENGTH(snmptrapoid);
+    netsnmp_pdu *newpdu = pdu;
+    netsnmp_variable_list *var;
+#ifdef USING_MIBII_VACM_CONF_MODULE
+    int i;
+#endif
+
+    /* check to see if authorization was not disabled */
+    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
+                               NETSNMP_DS_APP_NO_AUTHORIZATION)) {
+        DEBUGMSGTL(("snmptrapd:auth",
+                    "authorization turned off: not checking\n"));
+        return NETSNMPTRAPD_HANDLER_OK;
+    }
+
+    /* bail early if called illegally */
+    if (!pdu || !transport || !handler)
+        return NETSNMPTRAPD_HANDLER_FINISH;
+    
+    /* convert to v2 so we can check it in a consistent manner */
+#ifndef NETSNMP_DISABLE_SNMPV1
+    if (pdu->version == SNMP_VERSION_1) {
+        newpdu = convert_v1pdu_to_v2(pdu);
+        if (!newpdu) {
+            snmp_log(LOG_ERR, "Failed to duplicate incoming PDU.  Refusing to authorize.\n");
+            return NETSNMPTRAPD_HANDLER_FINISH;
+        }
+    }
+#endif
+
+    if (!vacm_is_configured()) {
+#ifndef NETSNMP_DISABLE_SNMPV1
+        if (newpdu != pdu)
+            snmp_free_pdu(newpdu);
+#endif
+        snmp_log(LOG_WARNING, "No access configuration - dropping trap.\n");
+        return NETSNMPTRAPD_HANDLER_FINISH;
+    }
+
+    /* loop through each variable and find the snmpTrapOID.0 var
+       indicating what the trap is we're staring at. */
+    for (var = newpdu->variables; var != NULL; var = var->next_variable) {
+        if (netsnmp_oid_equals(var->name, var->name_length,
+                               snmptrapoid, snmptrapoid_len) == 0)
+            break;
+    }
+
+    /* make sure we can continue: we found the snmpTrapOID.0 and its an oid */
+    if (!var || var->type != ASN_OBJECT_ID) {
+        snmp_log(LOG_ERR, "Can't determine trap identifier; refusing to authorize it\n");
+#ifndef NETSNMP_DISABLE_SNMPV1
+        if (newpdu != pdu)
+            snmp_free_pdu(newpdu);
+#endif
+        return NETSNMPTRAPD_HANDLER_FINISH;
+    }
+
+#ifdef USING_MIBII_VACM_CONF_MODULE
+    /* check the pdu against each typo of VACM access we may want to
+       check up on later.  We cache the results for future lookup on
+       each call to netsnmp_trapd_check_auth */
+    for(i = 0; i < VACM_MAX_VIEWS; i++) {
+        /* pass the PDU to the VACM routine for handling authorization */
+        DEBUGMSGTL(("snmptrapd:auth", "Calling VACM for checking phase %d:%s\n",
+                    i, se_find_label_in_slist(VACM_VIEW_ENUM_NAME, i)));
+        if (vacm_check_view_contents(newpdu, var->val.objid,
+                                     var->val_len/sizeof(oid), 0, i,
+                                     VACM_CHECK_VIEW_CONTENTS_DNE_CONTEXT_OK)
+            == VACM_SUCCESS) {
+            DEBUGMSGTL(("snmptrapd:auth", "  result: authorized\n"));
+            ret |= 1 << i;
+        } else {
+            DEBUGMSGTL(("snmptrapd:auth", "  result: not authorized\n"));
+        }
+    }
+    DEBUGMSGTL(("snmptrapd:auth", "Final bitmask auth: %x\n", ret));
+#endif
+
+    if (ret) {
+        /* we have policy to at least do "something".  Remember and continue. */
+        lastlookup = ret;
+#ifndef NETSNMP_DISABLE_SNMPV1
+        if (newpdu != pdu)
+            snmp_free_pdu(newpdu);
+#endif
+        return NETSNMPTRAPD_HANDLER_OK;
+    }
+
+    /* No policy was met, so we drop the PDU from further processing */
+    DEBUGMSGTL(("snmptrapd:auth", "Dropping unauthorized message\n"));
+#ifndef NETSNMP_DISABLE_SNMPV1
+    if (newpdu != pdu)
+        snmp_free_pdu(newpdu);
+#endif
+#endif
+
+    return NETSNMPTRAPD_HANDLER_FINISH;
+}
+
+/**
+ * Checks to see if the pdu is authorized for a set of given action types.
+ * @returns 1 if authorized, 0 if not.
+ */
+int netsnmp_trapd_check_auth(int authtypes)
+{
+    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
+                               NETSNMP_DS_APP_NO_AUTHORIZATION)) {
+        DEBUGMSGTL(("snmptrapd:auth", "authorization turned off\n"));
+        return 1;
+    }
+
+    DEBUGMSGTL(("snmptrapd:auth",
+                "Comparing auth types: result=%d, request=%d, result=%d\n",
+                lastlookup, authtypes,
+                ((authtypes & lastlookup) == authtypes)));
+    return ((authtypes & lastlookup) == authtypes);
+}
+

+ 18 - 0
snmptrapd_auth.h

@@ -0,0 +1,18 @@
+#ifndef SNMPTRAPD_AUTH_H
+#define SNMPTRAPD_AUTH_H
+
+extern "C" {
+	void init_netsnmp_trapd_auth(void);
+	int netsnmp_trapd_auth(netsnmp_pdu *pdu, netsnmp_transport *transport,
+		netsnmp_trapd_handler *handler);
+	int netsnmp_trapd_check_auth(int authtypes);
+
+	#define TRAP_AUTH_LOG (1 << VACM_VIEW_LOG)      /* displaying and logging */
+	#define TRAP_AUTH_EXE (1 << VACM_VIEW_EXECUTE)  /* executing code or binaries */
+	#define TRAP_AUTH_NET (1 << VACM_VIEW_NET)      /* forwarding and net access */
+
+	#define TRAP_AUTH_ALL (TRAP_AUTH_LOG | TRAP_AUTH_EXE | TRAP_AUTH_NET)
+	#define TRAP_AUTH_NONE 0
+}
+
+#endif /* SNMPTRAPD_AUTH_H */

+ 19 - 0
snmptrapd_ds.h

@@ -0,0 +1,19 @@
+#ifndef SNMPTRAPD_DS_H
+#define SNMPTRAPD_DS_H
+
+/* booleans
+ *
+ * WARNING: These must not conflict with the agent's DS booleans
+ * If you define additional entries here, check in <agent/ds_agent.h> first
+ *  (and consider repeating the definitions there) */
+
+#define NETSNMP_DS_APP_NUMERIC_IP       16
+#define NETSNMP_DS_APP_NO_AUTHORIZATION 17
+
+/*
+ * NB: The NETSNMP_DS_APP_NO_AUTHORIZATION definition is repeated
+ *     in the code file agent/mibgroup/mibII/vacm_conf.c
+ *     If this definition is changed, it should be updated there too.
+ */
+
+#endif /* SNMPTRAPD_DS_H */

+ 1194 - 0
snmptrapd_handlers.cpp

@@ -0,0 +1,1194 @@
+
+#include "net-snmp/net-snmp-config.h"
+#include "net-snmp/net-snmp-features.h"
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <ctype.h>
+#include <sys/types.h>
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+extern "C" {
+
+	#include "net-snmp/config_api.h"
+	#include "net-snmp/output_api.h"
+	#include "net-snmp/mib_api.h"
+	#include "net-snmp/utilities.h"
+	
+	#include "net-snmp/net-snmp-includes.h"
+	#include "net-snmp/agent/net-snmp-agent-includes.h"
+	#include "net-snmp/agent/mibgroup/utilities/execute.h"
+	#include "snmptrapd_handlers.h"
+	#include "snmptrapd_auth.h"
+	#include "snmptrapd_log.h"
+	#include "net-snmp/agent/mibgroup/notification-log-mib/notification_log.h"
+	
+	netsnmp_feature_child_of(add_default_traphandler, snmptrapd);
+
+}
+
+char *syslog_format1 = NULL;
+char *syslog_format2 = NULL;
+char *print_format1 = NULL;
+char *print_format2 = NULL;
+char *exec_format1 = NULL;
+char *exec_format2 = NULL;
+
+int   SyslogTrap = 0;
+int   dropauth = 0;
+
+const char     *trap1_std_str = "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b] (via %A [%a]): %N\n\t%W Trap (%q) Uptime: %#T\n%v\n";
+const char     *trap2_std_str = "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b]:\n%v\n";
+
+void snmptrapd_free_traphandle(void);
+
+const char *
+trap_description(int trap)
+{
+	switch (trap) {
+	case SNMP_TRAP_COLDSTART:
+		return "Cold Start";
+	case SNMP_TRAP_WARMSTART:
+		return "Warm Start";
+	case SNMP_TRAP_LINKDOWN:
+		return "Link Down";
+	case SNMP_TRAP_LINKUP:
+		return "Link Up";
+	case SNMP_TRAP_AUTHFAIL:
+		return "Authentication Failure";
+	case SNMP_TRAP_EGPNEIGHBORLOSS:
+		return "EGP Neighbor Loss";
+	case SNMP_TRAP_ENTERPRISESPECIFIC:
+		return "Enterprise Specific";
+	default:
+		return "Unknown Type";
+	}
+}
+
+
+
+void
+snmptrapd_parse_traphandle(const char *token, char *line)
+{
+	char            buf[STRINGMAX];
+	oid             obuf[MAX_OID_LEN];
+	size_t          olen = MAX_OID_LEN;
+	char           *cptr, *cp;
+	netsnmp_trapd_handler *traph;
+	int             flags = 0;
+	char           *format = NULL;
+
+	memset(buf, 0, sizeof(buf));
+	memset(obuf, 0, sizeof(obuf));
+	cptr = copy_nword(line, buf, sizeof(buf));
+
+	if (buf[0] == '-' && buf[1] == 'F') {
+		cptr = copy_nword(cptr, buf, sizeof(buf));
+		format = strdup(buf);
+		cptr = copy_nword(cptr, buf, sizeof(buf));
+	}
+	if (!cptr) {
+		netsnmp_config_error("Missing traphandle command (%s)", buf);
+		free(format);
+		return;
+	}
+
+	DEBUGMSGTL(("read_config:traphandle", "registering handler for: "));
+	if (!strcmp(buf, "default")) {
+		DEBUGMSG(("read_config:traphandle", "default"));
+		traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_DEFAULT_HANDLER,
+			command_handler);
+	}
+	else {
+		cp = buf + strlen(buf) - 1;
+		if (*cp == '*') {
+			flags |= NETSNMP_TRAPHANDLER_FLAG_MATCH_TREE;
+			*(cp--) = '\0';
+			if (*cp == '.') {
+				/*
+				* Distinguish between 'oid.*' & 'oid*'
+				*/
+				flags |= NETSNMP_TRAPHANDLER_FLAG_STRICT_SUBTREE;
+				*(cp--) = '\0';
+			}
+		}
+		if (!read_objid(buf, obuf, &olen)) {
+			netsnmp_config_error("Bad trap OID in traphandle directive: %s",
+				buf);
+			free(format);
+			return;
+		}
+		DEBUGMSGOID(("read_config:traphandle", obuf, olen));
+		traph = netsnmp_add_traphandler(command_handler, obuf, olen);
+	}
+
+	DEBUGMSG(("read_config:traphandle", "\n"));
+
+	if (traph) {
+		traph->flags = flags;
+		traph->authtypes = TRAP_AUTH_EXE;
+		traph->token = strdup(cptr);
+		if (format) {
+			traph->format = format;
+			format = NULL;
+		}
+	}
+	free(format);
+}
+
+
+static void
+parse_forward(const char *token, char *line)
+{
+	char            buf[STRINGMAX];
+	oid             obuf[MAX_OID_LEN];
+	size_t          olen = MAX_OID_LEN;
+	char           *cptr, *cp;
+	netsnmp_trapd_handler *traph;
+	int             flags = 0;
+	char           *format = NULL;
+
+	memset(buf, 0, sizeof(buf));
+	memset(obuf, 0, sizeof(obuf));
+	cptr = copy_nword(line, buf, sizeof(buf));
+
+	if (buf[0] == '-' && buf[1] == 'F') {
+		cptr = copy_nword(cptr, buf, sizeof(buf));
+		format = strdup(buf);
+		cptr = copy_nword(cptr, buf, sizeof(buf));
+	}
+	DEBUGMSGTL(("read_config:forward", "registering forward for: "));
+	if (!strcmp(buf, "default")) {
+		DEBUGMSG(("read_config:forward", "default"));
+		if (!strcmp(cptr, "agentx"))
+			traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_DEFAULT_HANDLER,
+				axforward_handler);
+		else
+			traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_DEFAULT_HANDLER,
+				forward_handler);
+	}
+	else {
+		cp = buf + strlen(buf) - 1;
+		if (*cp == '*') {
+			flags |= NETSNMP_TRAPHANDLER_FLAG_MATCH_TREE;
+			*(cp--) = '\0';
+			if (*cp == '.') {
+				/*
+				* Distinguish between 'oid.*' & 'oid*'
+				*/
+				flags |= NETSNMP_TRAPHANDLER_FLAG_STRICT_SUBTREE;
+				*(cp--) = '\0';
+			}
+		}
+
+		if (!read_objid(buf, obuf, &olen)) {
+			netsnmp_config_error("Bad trap OID in forward directive: %s", buf);
+			free(format);
+			return;
+		}
+		DEBUGMSGOID(("read_config:forward", obuf, olen));
+		if (!strcmp(cptr, "agentx"))
+			traph = netsnmp_add_traphandler(axforward_handler, obuf, olen);
+		else
+			traph = netsnmp_add_traphandler(forward_handler, obuf, olen);
+	}
+
+	DEBUGMSG(("read_config:forward", "\n"));
+
+	if (traph) {
+		traph->flags = flags;
+		traph->authtypes = TRAP_AUTH_NET;
+		traph->token = strdup(cptr);
+		if (format)
+			traph->format = format;
+	}
+	else {
+		free(format);
+	}
+}
+
+
+void
+parse_format(const char *token, char *line)
+{
+	char *cp, *sep;
+
+	/*
+	* Extract the first token from the value
+	* which tells us which style of format this is
+	*/
+	cp = line;
+	while (*cp && !isspace((unsigned char)(*cp)))
+		cp++;
+	if (!(*cp)) {
+		/*
+		* If we haven't got anything left,
+		* then this entry is malformed.
+		* So report this, and give up
+		*/
+		return;
+	}
+
+	sep = cp;
+	*(cp++) = '\0';
+	while (*cp && isspace((unsigned char)(*cp)))
+		cp++;
+
+	/*
+	* OK - now "line" contains the format type,
+	*      and cp points to the actual format string.
+	* So update the appropriate pointer(s).
+	*/
+	if (!strcmp(line, "print1")) {
+		SNMP_FREE(print_format1);
+		print_format1 = strdup(cp);
+	}
+	else if (!strcmp(line, "print2")) {
+		SNMP_FREE(print_format2);
+		print_format2 = strdup(cp);
+	}
+	else if (!strcmp(line, "print")) {
+		SNMP_FREE(print_format1);
+		SNMP_FREE(print_format2);
+		print_format1 = strdup(cp);
+		print_format2 = strdup(cp);
+	}
+	else if (!strcmp(line, "syslog1")) {
+		SNMP_FREE(syslog_format1);
+		syslog_format1 = strdup(cp);
+	}
+	else if (!strcmp(line, "syslog2")) {
+		SNMP_FREE(syslog_format2);
+		syslog_format2 = strdup(cp);
+	}
+	else if (!strcmp(line, "syslog")) {
+		SNMP_FREE(syslog_format1);
+		SNMP_FREE(syslog_format2);
+		syslog_format1 = strdup(cp);
+		syslog_format2 = strdup(cp);
+	}
+	else if (!strcmp(line, "execute1")) {
+		SNMP_FREE(exec_format1);
+		exec_format1 = strdup(cp);
+	}
+	else if (!strcmp(line, "execute2")) {
+		SNMP_FREE(exec_format2);
+		exec_format2 = strdup(cp);
+	}
+	else if (!strcmp(line, "execute")) {
+		SNMP_FREE(exec_format1);
+		SNMP_FREE(exec_format2);
+		exec_format1 = strdup(cp);
+		exec_format2 = strdup(cp);
+	}
+
+	*sep = ' ';
+}
+
+
+static void
+parse_trap1_fmt(const char *token, char *line)
+{
+	print_format1 = strdup(line);
+}
+
+
+void
+free_trap1_fmt(void)
+{
+	if (print_format1 && print_format1 != trap1_std_str)
+		free((char *)print_format1);
+	print_format1 = NULL;
+}
+
+
+static void
+parse_trap2_fmt(const char *token, char *line)
+{
+	print_format2 = strdup(line);
+}
+
+
+void
+free_trap2_fmt(void)
+{
+	if (print_format2 && print_format2 != trap2_std_str)
+		free((char *)print_format2);
+	print_format2 = NULL;
+}
+
+
+void
+snmptrapd_register_configs(void)
+{
+	register_config_handler("snmptrapd", "traphandle",
+		snmptrapd_parse_traphandle,
+		snmptrapd_free_traphandle,
+		"oid|\"default\" program [args ...] ");
+	register_config_handler("snmptrapd", "format1",
+		parse_trap1_fmt, free_trap1_fmt, "format");
+	register_config_handler("snmptrapd", "format2",
+		parse_trap2_fmt, free_trap2_fmt, "format");
+	register_config_handler("snmptrapd", "format",
+		parse_format, NULL,
+		"[print{,1,2}|syslog{,1,2}|execute{,1,2}] format");
+	register_config_handler("snmptrapd", "forward",
+		parse_forward, NULL, "OID|\"default\" destination");
+}
+
+
+
+/*-----------------------------
+*
+* Routines to implement a "registry" of trap handlers
+*
+*-----------------------------*/
+
+netsnmp_trapd_handler *netsnmp_auth_global_traphandlers = NULL;
+netsnmp_trapd_handler *netsnmp_pre_global_traphandlers = NULL;
+netsnmp_trapd_handler *netsnmp_post_global_traphandlers = NULL;
+netsnmp_trapd_handler *netsnmp_default_traphandlers = NULL;
+netsnmp_trapd_handler *netsnmp_specific_traphandlers = NULL;
+
+typedef struct netsnmp_handler_map_t {
+	netsnmp_trapd_handler **handler;
+	const char             *descr;
+} netsnmp_handler_map;
+
+static netsnmp_handler_map handlers[] = {
+	{ &netsnmp_auth_global_traphandlers, "auth trap" },
+	{ &netsnmp_pre_global_traphandlers, "pre-global trap" },
+	{ NULL, "trap specific" },
+	{ &netsnmp_post_global_traphandlers, "global" },
+	{ NULL, NULL }
+};
+
+/*
+* Register a new "global" traphandler,
+* to be applied to *all* incoming traps
+*/
+netsnmp_trapd_handler * netsnmp_add_global_traphandler(int list, Netsnmp_Trap_Handler *handler)
+{
+	netsnmp_trapd_handler *traph;
+
+	if (!handler)
+		return NULL;
+
+	traph = SNMP_MALLOC_TYPEDEF(netsnmp_trapd_handler);
+	if (!traph)
+		return NULL;
+
+	/*
+	* Add this new handler to the front of the appropriate list
+	*   (or should it go on the end?)
+	*/
+	traph->handler = handler;
+	traph->authtypes = TRAP_AUTH_ALL; /* callers will likely change this */
+	switch (list) {
+	case NETSNMPTRAPD_AUTH_HANDLER:
+		traph->nexth = netsnmp_auth_global_traphandlers;
+		netsnmp_auth_global_traphandlers = traph;
+		break;
+	case NETSNMPTRAPD_PRE_HANDLER:
+		traph->nexth = netsnmp_pre_global_traphandlers;
+		netsnmp_pre_global_traphandlers = traph;
+		break;
+	case NETSNMPTRAPD_POST_HANDLER:
+		traph->nexth = netsnmp_post_global_traphandlers;
+		netsnmp_post_global_traphandlers = traph;
+		break;
+	case NETSNMPTRAPD_DEFAULT_HANDLER:
+		traph->nexth = netsnmp_default_traphandlers;
+		netsnmp_default_traphandlers = traph;
+		break;
+	default:
+		free(traph);
+		return NULL;
+	}
+	return traph;
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_ADD_DEFAULT_TRAPHANDLER
+/*
+* Register a new "default" traphandler, to be applied to all
+* traps with no specific trap handlers of their own.
+*/
+netsnmp_trapd_handler *
+netsnmp_add_default_traphandler(Netsnmp_Trap_Handler *handler) {
+	return netsnmp_add_global_traphandler(NETSNMPTRAPD_DEFAULT_HANDLER,
+		handler);
+}
+#endif /* NETSNMP_FEATURE_REMOVE_ADD_DEFAULT_TRAPHANDLER */
+
+
+/*
+* Register a new trap-specific traphandler
+*/
+netsnmp_trapd_handler *
+netsnmp_add_traphandler(Netsnmp_Trap_Handler* handler,
+	oid *trapOid, int trapOidLen) {
+	netsnmp_trapd_handler *traph, *traph2;
+
+	if (!handler)
+		return NULL;
+
+	traph = SNMP_MALLOC_TYPEDEF(netsnmp_trapd_handler);
+	if (!traph)
+		return NULL;
+
+	/*
+	* Populate this new handler with the trap information
+	*   (NB: the OID fields were not used in the default/global lists)
+	*/
+	traph->authtypes = TRAP_AUTH_ALL; /* callers will likely change this */
+	traph->handler = handler;
+	traph->trapoid_len = trapOidLen;
+	traph->trapoid = snmp_duplicate_objid(trapOid, trapOidLen);
+
+	/*
+	* Now try to find the appropriate place in the trap-specific
+	* list for this particular trap OID.  If there's a matching OID
+	* already, then find it.  Otherwise find the one that follows.
+	* If we run out of entried, the new one should be tacked onto the end.
+	*/
+	for (traph2 = netsnmp_specific_traphandlers;
+		traph2; traph2 = traph2->nextt) {
+		/* XXX - check this! */
+		if (snmp_oid_compare(traph2->trapoid, traph2->trapoid_len,
+			trapOid, trapOidLen) <= 0)
+			break;
+	}
+	if (traph2) {
+		/*
+		* OK - We've either got an exact match, or we've found the
+		*   entry *after* where the new one should go.
+		*/
+		if (!snmp_oid_compare(traph->trapoid, traph->trapoid_len,
+			traph2->trapoid, traph2->trapoid_len)) {
+			/*
+			* Exact match, so find the end of the *handler* list
+			*   and tack on this new entry...
+			*/
+			while (traph2->nexth)
+				traph2 = traph2->nexth;
+			traph2->nexth = traph;
+			traph->nextt = traph2->nextt;   /* Might as well... */
+			traph->prevt = traph2->prevt;
+		}
+		else {
+			/*
+			* .. or the following entry, so insert the new one before it.
+			*/
+			traph->prevt = traph2->prevt;
+			if (traph2->prevt)
+				traph2->prevt->nextt = traph;
+			else
+				netsnmp_specific_traphandlers = traph;
+			traph2->prevt = traph;
+			traph->nextt = traph2;
+		}
+	}
+	else {
+		/*
+		* If we've run out of entries without finding a suitable spot,
+		*   the new one should be tacked onto the end.....
+		*/
+		if (netsnmp_specific_traphandlers) {
+			traph2 = netsnmp_specific_traphandlers;
+			while (traph2->nextt)
+				traph2 = traph2->nextt;
+			traph2->nextt = traph;
+			traph->prevt = traph2;
+		}
+		else {
+			/*
+			* .... unless this is the very first entry, of course!
+			*/
+			netsnmp_specific_traphandlers = traph;
+		}
+	}
+
+	return traph;
+}
+
+void
+snmptrapd_free_traphandle(void)
+{
+	netsnmp_trapd_handler *traph = NULL, *nextt = NULL, *nexth = NULL;
+
+	DEBUGMSGTL(("snmptrapd", "Freeing trap handler lists\n"));
+
+	/*
+	* Free default trap handlers
+	*/
+	traph = netsnmp_default_traphandlers;
+	/* loop over handlers */
+	while (traph) {
+		DEBUGMSG(("snmptrapd", "Freeing default trap handler\n"));
+		nexth = traph->nexth;
+		SNMP_FREE(traph->token);
+		SNMP_FREE(traph);
+		traph = nexth;
+	}
+	netsnmp_default_traphandlers = NULL;
+
+	/*
+	* Free specific trap handlers
+	*/
+	traph = netsnmp_specific_traphandlers;
+	/* loop over traps */
+	while (traph) {
+		nextt = traph->nextt;
+		/* loop over handlers for this trap */
+		while (traph) {
+			DEBUGMSG(("snmptrapd", "Freeing specific trap handler\n"));
+			nexth = traph->nexth;
+			SNMP_FREE(traph->token);
+			SNMP_FREE(traph->trapoid);
+			SNMP_FREE(traph);
+			traph = nexth;
+		}
+		traph = nextt;
+	}
+	netsnmp_specific_traphandlers = NULL;
+}
+
+/*
+* Locate the list of handlers for this particular Trap OID
+* Returns NULL if there are no relevant traps
+*/
+netsnmp_trapd_handler *
+netsnmp_get_traphandler(oid *trapOid, int trapOidLen) {
+	netsnmp_trapd_handler *traph;
+
+	if (!trapOid || !trapOidLen) {
+		DEBUGMSGTL(("snmptrapd:lookup", "get_traphandler no OID!\n"));
+		return NULL;
+	}
+	DEBUGMSGTL(("snmptrapd:lookup", "Looking up Trap OID: "));
+	DEBUGMSGOID(("snmptrapd:lookup", trapOid, trapOidLen));
+	DEBUGMSG(("snmptrapd:lookup", "\n"));
+
+	/*
+	* Look for a matching OID, and return that list...
+	*/
+	for (traph = netsnmp_specific_traphandlers;
+		traph; traph = traph->nextt) {
+
+		/*
+		* If the trap handler wasn't wildcarded, then the trapOID
+		*   should match the registered OID exactly.
+		*/
+		if (!(traph->flags & NETSNMP_TRAPHANDLER_FLAG_MATCH_TREE)) {
+			if (snmp_oid_compare(traph->trapoid, traph->trapoid_len,
+				trapOid, trapOidLen) == 0) {
+				DEBUGMSGTL(("snmptrapd:lookup",
+					"get_traphandler exact match (%p)\n", traph));
+				return traph;
+			}
+		}
+		else {
+			/*
+			* If the trap handler *was* wildcarded, then the trapOID
+			*   should have the registered OID as a prefix...
+			*/
+			if (snmp_oidsubtree_compare(traph->trapoid,
+				traph->trapoid_len,
+				trapOid, trapOidLen) == 0) {
+				if (traph->flags & NETSNMP_TRAPHANDLER_FLAG_STRICT_SUBTREE) {
+					/*
+					* ... and (optionally) *strictly* as a prefix
+					*   i.e. not including an exact match.
+					*/
+					if (snmp_oid_compare(traph->trapoid, traph->trapoid_len,
+						trapOid, trapOidLen) != 0) {
+						DEBUGMSGTL(("snmptrapd:lookup", "get_traphandler strict subtree match (%p)\n", traph));
+						return traph;
+					}
+				}
+				else {
+					DEBUGMSGTL(("snmptrapd:lookup", "get_traphandler subtree match (%p)\n", traph));
+					return traph;
+				}
+			}
+		}
+	}
+
+	/*
+	* .... or failing that, return the "default" list (which may be NULL)
+	*/
+	DEBUGMSGTL(("snmptrapd:lookup", "get_traphandler default (%p)\n",
+		netsnmp_default_traphandlers));
+	return netsnmp_default_traphandlers;
+}
+
+/*-----------------------------
+*
+* Standard traphandlers for the common requirements
+*
+*-----------------------------*/
+
+#define SYSLOG_V1_STANDARD_FORMAT      "%a: %W Trap (%q) Uptime: %#T%#v\n"
+#define SYSLOG_V1_ENTERPRISE_FORMAT    "%a: %W Trap (%q) Uptime: %#T%#v\n" /* XXX - (%q) become (.N) ??? */
+#define SYSLOG_V23_NOTIFICATION_FORMAT "%B [%b]: Trap %#v\n"	 	   /* XXX - introduces a leading " ," */
+
+/*
+*  Trap handler for logging via syslog
+*/
+int   syslog_handler(netsnmp_pdu           *pdu,
+	netsnmp_transport     *transport,
+	netsnmp_trapd_handler *handler)
+{
+	u_char         *rbuf = NULL;
+	size_t          r_len = 64, o_len = 0;
+	int             trunc = 0;
+
+	DEBUGMSGTL(("snmptrapd", "syslog_handler\n"));
+
+	if (SyslogTrap)
+		return NETSNMPTRAPD_HANDLER_OK;
+
+	if ((rbuf = (u_char *)calloc(r_len, 1)) == NULL) {
+		snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n");
+		return NETSNMPTRAPD_HANDLER_FAIL;	/* Failed but keep going */
+	}
+
+	/*
+	*  If there's a format string registered for this trap, then use it.
+	*/
+	if (handler && handler->format) {
+		DEBUGMSGTL(("snmptrapd", "format = '%s'\n", handler->format));
+		if (*handler->format) {
+			trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+				handler->format, pdu, transport);
+		}
+		else {
+			free(rbuf);
+			return NETSNMPTRAPD_HANDLER_OK;    /* A 0-length format string means don't log */
+		}
+
+		/*
+		*  Otherwise (i.e. a NULL handler format string),
+		*      use a standard output format setting
+		*      either configurable, or hardwired
+		*
+		*  XXX - v1 traps use a different hardwired formats for
+		*        standard and enterprise specific traps
+		*        Do we actually need this?
+		*/
+	}
+	else {
+		if (pdu->command == SNMP_MSG_TRAP) {
+			if (syslog_format1) {
+				DEBUGMSGTL(("snmptrapd", "syslog_format v1 = '%s'\n", syslog_format1));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					syslog_format1, pdu, transport);
+
+			}
+			else if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
+				DEBUGMSGTL(("snmptrapd", "v1 enterprise format\n"));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					SYSLOG_V1_ENTERPRISE_FORMAT,
+					pdu, transport);
+			}
+			else {
+				DEBUGMSGTL(("snmptrapd", "v1 standard trap format\n"));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					SYSLOG_V1_STANDARD_FORMAT,
+					pdu, transport);
+			}
+		}
+		else {	/* SNMPv2/3 notifications */
+			if (syslog_format2) {
+				DEBUGMSGTL(("snmptrapd", "syslog_format v1 = '%s'\n", syslog_format2));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					syslog_format2, pdu, transport);
+			}
+			else {
+				DEBUGMSGTL(("snmptrapd", "v2/3 format\n"));
+				trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					SYSLOG_V23_NOTIFICATION_FORMAT,
+					pdu, transport);
+			}
+		}
+	}
+	snmp_log(LOG_WARNING, "%s%s", rbuf, (trunc ? " [TRUNCATED]\n" : ""));
+	free(rbuf);
+	return NETSNMPTRAPD_HANDLER_OK;
+}
+
+#define EXECUTE_FORMAT	"%B\n%b\n%V\n%v\n"
+
+/*
+*  Trap handler for invoking a suitable script
+*/
+int   command_handler(netsnmp_pdu           *pdu,
+	netsnmp_transport     *transport,
+	netsnmp_trapd_handler *handler)
+{
+#ifndef USING_UTILITIES_EXECUTE_MODULE
+	NETSNMP_LOGONCE((LOG_WARNING,
+		"support for run_shell_command not available\n"));
+	return NETSNMPTRAPD_HANDLER_FAIL;
+#else
+	u_char         *rbuf = NULL;
+	size_t          r_len = 64, o_len = 0;
+	int             oldquick;
+
+	DEBUGMSGTL(("snmptrapd", "command_handler\n"));
+	DEBUGMSGTL(("snmptrapd", "token = '%s'\n", handler->token));
+	if (handler && handler->token && *handler->token) {
+		netsnmp_pdu    *v2_pdu = NULL;
+		if (pdu->command == SNMP_MSG_TRAP)
+			v2_pdu = convert_v1pdu_to_v2(pdu);
+		else
+			v2_pdu = pdu;
+		oldquick = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
+			NETSNMP_DS_LIB_QUICK_PRINT);
+		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+			NETSNMP_DS_LIB_QUICK_PRINT, 1);
+
+		/*
+		* Format the trap and pass this string to the external command
+		*/
+		if ((rbuf = (u_char *)calloc(r_len, 1)) == NULL) {
+			snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n");
+			return NETSNMPTRAPD_HANDLER_FAIL;	/* Failed but keep going */
+		}
+
+		/*
+		*  If there's a format string registered for this trap, then use it.
+		*  Otherwise use the standard execution format setting.
+		*/
+		if (handler && handler->format && *handler->format) {
+			DEBUGMSGTL(("snmptrapd", "format = '%s'\n", handler->format));
+			realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+				handler->format,
+				v2_pdu, transport);
+		}
+		else {
+			if (pdu->command == SNMP_MSG_TRAP && exec_format1) {
+				DEBUGMSGTL(("snmptrapd", "exec v1 = '%s'\n", exec_format1));
+				realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					exec_format1, pdu, transport);
+			}
+			else if (pdu->command != SNMP_MSG_TRAP && exec_format2) {
+				DEBUGMSGTL(("snmptrapd", "exec v2/3 = '%s'\n", exec_format2));
+				realloc_format_trap(&rbuf, &r_len, &o_len, 1,
+					exec_format2, pdu, transport);
+			}
+			else {
+				DEBUGMSGTL(("snmptrapd", "execute format\n"));
+				realloc_format_trap(&rbuf, &r_len, &o_len, 1, EXECUTE_FORMAT,
+					v2_pdu, transport);
+			}
+		}
+
+		/*
+		*  and pass this formatted string to the command specified
+		*/
+		run_shell_command(handler->token, (char*)rbuf, NULL, NULL);   /* Not interested in output */
+		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
+			NETSNMP_DS_LIB_QUICK_PRINT, oldquick);
+		if (pdu->command == SNMP_MSG_TRAP)
+			snmp_free_pdu(v2_pdu);
+		free(rbuf);
+	}
+	return NETSNMPTRAPD_HANDLER_OK;
+#endif /* !def USING_UTILITIES_EXECUTE_MODULE */
+}
+
+
+
+
+/*
+*  Trap handler for forwarding to the AgentX master agent
+*/
+int axforward_handler(netsnmp_pdu           *pdu,
+	netsnmp_transport     *transport,
+	netsnmp_trapd_handler *handler)
+{
+	send_v2trap(pdu->variables);
+	return NETSNMPTRAPD_HANDLER_OK;
+}
+
+static int add_forwarder_info(netsnmp_pdu *pdu, netsnmp_pdu *pdu2)
+{
+	netsnmp_indexed_addr_pair *addr_pair1;
+	struct sockaddr_in *to1 = NULL;
+	struct sockaddr_in *to2 = NULL;
+	int            last_snmpTrapAddress_index = -1;
+	/* snmpTrapAddress_oid.0 is also defined as agentaddr_oid */
+	const oid      snmpTrapAddress_oid[] = { 1,3,6,1,6,3,18,1,3 };
+	/* each forwarder will add this OID with changed last index */
+	oid            forwarder_oid[] = { 1,3,6,1,6,3,18,1,3,0 };
+	const size_t   snmpTrapAddress_oid_size = OID_LENGTH(snmpTrapAddress_oid);
+	const size_t   forwarder_oid_len = OID_LENGTH(forwarder_oid);
+	struct in_addr agent_addr;
+	struct in_addr my_ip_addr;
+
+	memset(&agent_addr, 0, sizeof(agent_addr));
+	memset(&my_ip_addr, 0, sizeof(my_ip_addr));
+
+	if (pdu && pdu->transport_data &&
+		pdu->transport_data_length == sizeof(*addr_pair1)) {
+		addr_pair1 = (netsnmp_indexed_addr_pair *)pdu->transport_data;
+
+		/*
+		* Get the IPv4 address of the host that this trap was sent from =
+		* last forwarder's IP address.
+		*/
+		if (addr_pair1->remote_addr.sa.sa_family == AF_INET) {
+			to1 = (struct sockaddr_in *)&(addr_pair1->remote_addr);
+			agent_addr = to1->sin_addr;
+		}
+		/*
+		* Get the IPv4 address of the host that this trap was sent to =
+		* this forwarder's IP address.
+		*/
+		if (addr_pair1->local_addr.sa.sa_family == AF_INET) {
+			to2 = (struct sockaddr_in *)&(addr_pair1->local_addr);
+			my_ip_addr = to2->sin_addr;
+		}
+	}
+
+	if (to1) {
+		netsnmp_variable_list *vblist = NULL;
+		netsnmp_variable_list *var = NULL;
+
+		if (*(in_addr_t *)pdu2->agent_addr == INADDR_ANY) {
+			/*
+			* there was no agent address defined in PDU. copy the forwarding
+			* agent IP address from the transport socket.
+			*/
+			*(struct in_addr *)pdu2->agent_addr = agent_addr;
+		}
+
+		vblist = pdu2->variables;
+
+		/*
+		* Iterate over all varbinds in the PDU to see if it already has any
+		* forwarder information.
+		*/
+		for (var = vblist; var; var = var->next_variable) {
+			if (snmp_oid_ncompare(var->name, var->name_length,
+				snmpTrapAddress_oid,
+				snmpTrapAddress_oid_size,
+				snmpTrapAddress_oid_size) == 0) {
+				int my_snmpTrapAddress_index =
+					var->name[var->name_length - 1];
+
+				DEBUGMSGTL(("snmptrapd", "  my_snmpTrapAddress_index=%d, last_snmpTrapAddress_index=%d, my_ip_addr=%s\n",
+					my_snmpTrapAddress_index,
+					last_snmpTrapAddress_index,
+					inet_ntoa(my_ip_addr)));
+
+				if (last_snmpTrapAddress_index < my_snmpTrapAddress_index)
+					last_snmpTrapAddress_index = my_snmpTrapAddress_index;
+
+				/* Detect forwarding loop. */
+				if (var->val_len < 4) {
+					snmp_log(LOG_ERR, "Length of IP address of OID .1.3.6.1.6.3.18.1.3.%d in PDU is less than %d bytes = %d\n",
+						my_snmpTrapAddress_index, 4,
+						(int)var->val_len);
+				}
+				else {
+					if (to2 &&
+						memcmp(var->val.string, &my_ip_addr, 4) == 0) {
+						snmp_log(LOG_ERR, "Forwarding loop detected, OID .1.3.6.1.6.3.18.1.3.%d already has this forwarder's IP address=%s, not forwarding this trap\n",
+							my_snmpTrapAddress_index,
+							inet_ntoa(my_ip_addr));
+						return 0;
+					}
+					if (memcmp(var->val.string, &agent_addr, 4) == 0) {
+						snmp_log(LOG_ERR, "Forwarding loop detected, OID .1.3.6.1.6.3.18.1.3.%d already has the sender's IP address=%s, not forwarding this trap\n",
+							my_snmpTrapAddress_index,
+							inet_ntoa(agent_addr));
+						return 0;
+					}
+				}
+			}
+		} /* for var in vblist */
+
+		DEBUGMSGTL(("snmptrapd",
+			"  last_snmpTrapAddress_index=%d, adding index=%d\n",
+			last_snmpTrapAddress_index, last_snmpTrapAddress_index + 1));
+		/* Change the last index of this OID to the next avaiable number. */
+		forwarder_oid[forwarder_oid_len - 1] = last_snmpTrapAddress_index + 1;
+
+		/*
+		* Add forwarder IP address as OID to trap payload. Use the value
+		* from the transport, so if a v1 PDU is sent, the same IP is not
+		* duplicated you want every forwarder to add this OID with its
+		* own IP address.
+		*/
+		snmp_pdu_add_variable(pdu2, forwarder_oid, forwarder_oid_len,
+			ASN_IPADDRESS, (u_char *)&agent_addr, 4);
+	}
+	return 1;
+}
+
+/*
+*  Trap handler for forwarding to another destination
+*/
+int   forward_handler(netsnmp_pdu           *pdu,
+	netsnmp_transport     *transport,
+	netsnmp_trapd_handler *handler)
+{
+	netsnmp_session session, *ss;
+	netsnmp_pdu *pdu2;
+	char buf[BUFSIZ], *cp;
+
+	DEBUGMSGTL(("snmptrapd", "forward_handler (%s)\n", handler->token));
+
+	snmp_sess_init(&session);
+	if (strchr(handler->token, ':') == NULL) {
+		snprintf(buf, BUFSIZ, "%s:%d", handler->token, SNMP_TRAP_PORT);
+		cp = buf;
+	}
+	else {
+		cp = handler->token;
+	}
+	session.peername = cp;
+	session.version = pdu->version;
+	ss = snmp_open(&session);
+	if (!ss)
+		return NETSNMPTRAPD_HANDLER_FAIL;
+
+	/* XXX: wjh we should be caching sessions here and not always
+	reopening a session.  It's very ineffecient, especially with v3
+	INFORMS which may require engineID probing */
+
+	pdu2 = snmp_clone_pdu(pdu);
+
+	if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
+		NETSNMP_DS_LIB_ADD_FORWARDER_INFO) &&
+		!add_forwarder_info(pdu, pdu2)) {
+		snmp_close(ss);
+		return NETSNMPTRAPD_HANDLER_FAIL;
+	}
+
+	if (pdu2->transport_data) {
+		free(pdu2->transport_data);
+		pdu2->transport_data = NULL;
+		pdu2->transport_data_length = 0;
+	}
+
+	ss->s_snmp_errno = SNMPERR_SUCCESS;
+	if (!snmp_send(ss, pdu2) &&
+		ss->s_snmp_errno != SNMPERR_SUCCESS) {
+		snmp_sess_perror("Forward failed", ss);
+		snmp_free_pdu(pdu2);
+	}
+	snmp_close(ss);
+	return NETSNMPTRAPD_HANDLER_OK;
+}
+
+#if defined(USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE) && defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
+/*
+*  "Notification" handler for implementing NOTIFICATION-MIB
+*  		(presumably)
+*/
+int   notification_handler(netsnmp_pdu           *pdu,
+	netsnmp_transport     *transport,
+	netsnmp_trapd_handler *handler)
+{
+	DEBUGMSGTL(("snmptrapd", "notification_handler\n"));
+	log_notification(pdu, transport);
+	return NETSNMPTRAPD_HANDLER_OK;
+}
+#endif 
+
+/*-----------------------------
+*
+* Main driving code, to process an incoming trap
+*
+*-----------------------------*/
+int
+snmp_input(int op, netsnmp_session *session,
+	int reqid, netsnmp_pdu *pdu, void *magic)
+{
+	oid stdTrapOidRoot[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 };
+	oid snmpTrapOid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
+	oid trapOid[MAX_OID_LEN + 2] = { 0 };
+	int trapOidLen;
+	netsnmp_variable_list *vars;
+	netsnmp_trapd_handler *traph;
+	netsnmp_transport *transport = (netsnmp_transport *)magic;
+	int ret, idx;
+	//printf("snmp_input \n");
+	switch (op) {
+	case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
+		/*
+		* Drops packets with reception problems
+		*/
+		if (session->s_snmp_errno) {
+			/* drop problem packets */
+			return 1;
+		}
+
+		/*
+		* Determine the OID that identifies the trap being handled
+		*/
+		DEBUGMSGTL(("snmptrapd", "input: %x\n", pdu->command));
+		switch (pdu->command) {
+		case SNMP_MSG_TRAP:
+			/*
+			* Convert v1 traps into a v2-style trap OID
+			*    (following RFC 2576)
+			*/
+			if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
+				trapOidLen = pdu->enterprise_length;
+				memcpy(trapOid, pdu->enterprise, sizeof(oid) * trapOidLen);
+				if (trapOid[trapOidLen - 1] != 0) {
+					trapOid[trapOidLen++] = 0;
+				}
+				trapOid[trapOidLen++] = pdu->specific_type;
+			}
+			else {
+				memcpy(trapOid, stdTrapOidRoot, sizeof(stdTrapOidRoot));
+				trapOidLen = OID_LENGTH(stdTrapOidRoot);  /* 9 */
+				trapOid[trapOidLen++] = pdu->trap_type + 1;
+			}
+			break;
+
+		case SNMP_MSG_TRAP2:
+		case SNMP_MSG_INFORM:
+			/*
+			* v2c/v3 notifications *should* have snmpTrapOID as the
+			*    second varbind, so we can go straight there.
+			*    But check, just to make sure
+			*/
+			vars = pdu->variables;
+			if (vars)
+				vars = vars->next_variable;
+			if (!vars || snmp_oid_compare(vars->name, vars->name_length,
+				snmpTrapOid, OID_LENGTH(snmpTrapOid))) {
+				/*
+				* Didn't find it!
+				* Let's look through the full list....
+				*/
+				for (vars = pdu->variables; vars; vars = vars->next_variable) {
+					if (!snmp_oid_compare(vars->name, vars->name_length,
+						snmpTrapOid, OID_LENGTH(snmpTrapOid)))
+						break;
+				}
+				if (!vars) {
+					/*
+					* Still can't find it!  Give up.
+					*/
+					snmp_log(LOG_ERR, "Cannot find TrapOID in TRAP2 PDU\n");
+					return 1;		/* ??? */
+				}
+			}
+			memcpy(trapOid, vars->val.objid, vars->val_len);
+			trapOidLen = vars->val_len / sizeof(oid);
+			break;
+
+		default:
+			/* SHOULDN'T HAPPEN! */
+			return 1;	/* ??? */
+		}
+		DEBUGMSGTL(("snmptrapd", "Trap OID: "));
+		DEBUGMSGOID(("snmptrapd", trapOid, trapOidLen));
+		DEBUGMSG(("snmptrapd", "\n"));
+
+
+		/*
+		*  OK - We've found the Trap OID used to identify this trap.
+		*  Call each of the various lists of handlers:
+		*     a) authentication-related handlers,
+		*     b) other handlers to be applied to all traps
+		*		(*before* trap-specific handlers)
+		*     c) the handler(s) specific to this trap
+		t        *     d) any other global handlers
+		*
+		*  In each case, a particular trap handler can abort further
+		*     processing - either just for that particular list,
+		*     or for the trap completely.
+		*
+		*  This is particularly designed for authentication-related
+		*     handlers, but can also be used elsewhere.
+		*
+		*  OK - Enough waffling, let's get to work.....
+		*/
+
+		for (idx = 0; handlers[idx].descr; ++idx) {
+			DEBUGMSGTL(("snmptrapd", "Running %s handlers\n",
+				handlers[idx].descr));
+			if (NULL == handlers[idx].handler) /* specific */
+				traph = netsnmp_get_traphandler(trapOid, trapOidLen);
+			else
+				traph = *handlers[idx].handler;
+
+			for (; traph; traph = traph->nexth) {
+				if (!netsnmp_trapd_check_auth(traph->authtypes))
+					continue; /* we continue on and skip this one */
+				ret = (*(traph->handler))(pdu, transport, traph);
+				if (NETSNMPTRAPD_HANDLER_FINISH == ret)
+					return 1;
+				if (ret == NETSNMPTRAPD_HANDLER_BREAK)
+					break; /* move on to next type */
+			} /* traph */
+		} /* handlers */
+
+
+		if (pdu->command == SNMP_MSG_INFORM) {
+			netsnmp_pdu *reply = snmp_clone_pdu(pdu);
+			if (!reply) {
+				snmp_log(LOG_ERR, "couldn't clone PDU for INFORM response\n");
+			}
+			else {
+				reply->command = SNMP_MSG_RESPONSE;
+				reply->errstat = 0;
+				reply->errindex = 0;
+				if (!snmp_send(session, reply)) {
+					snmp_sess_perror("snmptrapd: Couldn't respond to inform pdu",
+						session);
+					snmp_free_pdu(reply);
+				}
+			}
+		}
+
+		break;
+
+	case NETSNMP_CALLBACK_OP_TIMED_OUT:
+		snmp_log(LOG_ERR, "Timeout: This shouldn't happen!\n");
+		break;
+
+	case NETSNMP_CALLBACK_OP_SEND_FAILED:
+		snmp_log(LOG_ERR, "Send Failed: This shouldn't happen either!\n");
+		break;
+
+	case NETSNMP_CALLBACK_OP_CONNECT:
+	case NETSNMP_CALLBACK_OP_DISCONNECT:
+		/* Ignore silently */
+		break;
+
+	default:
+		snmp_log(LOG_ERR, "Unknown operation (%d): This shouldn't happen!\n", op);
+		break;
+	}
+	return 0;
+}

+ 73 - 0
snmptrapd_handlers.h

@@ -0,0 +1,73 @@
+#ifndef SNMPTRAPD_HANDLERS_H
+#define SNMPTRAPD_HANDLERS_H
+
+extern "C" {
+
+typedef struct netsnmp_trapd_handler_s netsnmp_trapd_handler;
+
+typedef int (Netsnmp_Trap_Handler)(netsnmp_pdu           *pdu,
+                                   netsnmp_transport     *transport,
+                                   netsnmp_trapd_handler *handler);
+
+
+#define NETSNMP_TRAPHANDLER_FLAG_MATCH_TREE     0x1
+#define NETSNMP_TRAPHANDLER_FLAG_STRICT_SUBTREE 0x2
+
+struct netsnmp_trapd_handler_s {
+     oid  *trapoid;
+     int   trapoid_len;
+     char *token;		/* Or an array of tokens? */
+     char *format;		/* Formatting string */
+     int   version;		/* ??? */
+     int   authtypes;
+     int   flags;
+     Netsnmp_Trap_Handler *handler;
+     void *handler_data;
+
+     netsnmp_trapd_handler *nexth;	/* Next handler for this trap */
+             /* Doubly-linked list of traps with registered handlers */
+     netsnmp_trapd_handler *prevt;
+     netsnmp_trapd_handler *nextt;
+};
+
+Netsnmp_Trap_Handler   syslog_handler;
+Netsnmp_Trap_Handler   command_handler;
+Netsnmp_Trap_Handler   event_handler;
+Netsnmp_Trap_Handler   forward_handler;
+Netsnmp_Trap_Handler   axforward_handler;
+Netsnmp_Trap_Handler   notification_handler;
+Netsnmp_Trap_Handler   mysql_handler;
+
+void free_trap1_fmt(void);
+void free_trap2_fmt(void);
+extern char *print_format1;
+extern char *print_format2;
+extern int   SyslogTrap;
+extern int   dropauth;
+
+#define NETSNMPTRAPD_AUTH_HANDLER    1
+#define NETSNMPTRAPD_PRE_HANDLER     2
+#define NETSNMPTRAPD_POST_HANDLER    3
+#define NETSNMPTRAPD_DEFAULT_HANDLER 4
+
+#define NETSNMPTRAPD_HANDLER_OK      1	/* Succeed, & keep going */
+#define NETSNMPTRAPD_HANDLER_FAIL    2	/* Failed but keep going */
+#define NETSNMPTRAPD_HANDLER_BREAK   3	/* Move to the next list */
+#define NETSNMPTRAPD_HANDLER_FINISH  4	/* No further processing */
+
+void snmptrapd_register_configs( void );
+netsnmp_trapd_handler *netsnmp_add_global_traphandler(int list, Netsnmp_Trap_Handler* handler);
+netsnmp_trapd_handler *netsnmp_add_default_traphandler(Netsnmp_Trap_Handler* handler);
+netsnmp_trapd_handler *netsnmp_add_traphandler(Netsnmp_Trap_Handler* handler,
+                        oid *trapOid, int trapOidLen);
+netsnmp_trapd_handler *netsnmp_get_traphandler(oid *trapOid, int trapOidLen);
+
+const char *trap_description(int trap);
+int snmp_input(int op, netsnmp_session *session,
+           int reqid, netsnmp_pdu *pdu, void *magic);
+
+void parse_format(const char *token, char *line);
+
+}
+
+#endif                          /* SNMPTRAPD_HANDLERS_H */

+ 1783 - 0
snmptrapd_log.cpp

@@ -0,0 +1,1783 @@
+/*
+ * snmptrapd_log.c - format SNMP trap information for logging
+ *
+ */
+/*****************************************************************
+	Copyright 1989, 1991, 1992 by Carnegie Mellon University
+
+                      All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of CMU not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+******************************************************************/
+#include "net-snmp/net-snmp-config.h"
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#if !defined(mingw32) && defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+# if TIME_WITH_SYS_TIME
+#  include <time.h>
+# endif
+#else
+# include <time.h>
+#endif
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "net-snmp/net-snmp-includes.h"
+#include "snmptrapd_handlers.h"
+#include "snmptrapd_log.h"
+
+
+#ifndef BSD4_3
+#define BSD4_2
+#endif
+
+/*
+ * These flags mark undefined values in the options structure 
+ */
+#define UNDEF_CMD '*'
+#define UNDEF_PRECISION -1
+
+/*
+ * This structure holds the options for a single format command 
+ */
+typedef struct {
+    char            cmd;        /* the format command itself */
+    size_t          width;      /* the field's minimum width */
+    int             precision;  /* the field's precision */
+    int             left_justify;       /* if true, left justify this field */
+    int             alt_format; /* if true, display in alternate format */
+    int             leading_zeroes;     /* if true, display with leading zeroes */
+} options_type;
+
+char            separator[32];
+
+/*
+ * These symbols define the characters that the parser recognizes.
+ * The rather odd choice of symbols comes from an attempt to avoid
+ * colliding with the ones that printf uses, so that someone could add
+ * printf functionality to this code and turn it into a library
+ * routine in the future.  
+ */
+typedef enum {
+    CHR_FMT_DELIM = '%',        /* starts a format command */
+    CHR_LEFT_JUST = '-',        /* left justify */
+    CHR_LEAD_ZERO = '0',        /* use leading zeroes */
+    CHR_ALT_FORM = '#',         /* use alternate format */
+    CHR_FIELD_SEP = '.',        /* separates width and precision fields */
+
+    /* Date / Time Information */
+    CHR_CUR_TIME = 't',         /* current time, Unix format */
+    CHR_CUR_YEAR = 'y',         /* current year */
+    CHR_CUR_MONTH = 'm',        /* current month */
+    CHR_CUR_MDAY = 'l',         /* current day of month */
+    CHR_CUR_HOUR = 'h',         /* current hour */
+    CHR_CUR_MIN = 'j',          /* current minute */
+    CHR_CUR_SEC = 'k',          /* current second */
+    CHR_UP_TIME = 'T',          /* uptime, Unix format */
+    CHR_UP_YEAR = 'Y',          /* uptime year */
+    CHR_UP_MONTH = 'M',         /* uptime month */
+    CHR_UP_MDAY = 'L',          /* uptime day of month */
+    CHR_UP_HOUR = 'H',          /* uptime hour */
+    CHR_UP_MIN = 'J',           /* uptime minute */
+    CHR_UP_SEC = 'K',           /* uptime second */
+
+    /* transport information */
+    CHR_AGENT_IP = 'a',         /* agent's IP address */
+    CHR_AGENT_NAME = 'A',       /* agent's host name if available */
+
+    /* authentication information */
+    CHR_SNMP_VERSION = 's',     /* SNMP Version Number */
+    CHR_SNMP_SECMOD  = 'S',     /* SNMPv3 Security Model Version Number */
+    CHR_SNMP_USER = 'u',        /* SNMPv3 secName or v1/v2c community */
+    CHR_TRAP_CONTEXTID = 'E',   /* SNMPv3 context engineID if available */
+
+    /* PDU information */
+    CHR_PDU_IP = 'b',           /* PDU's IP address */
+    CHR_PDU_NAME = 'B',         /* PDU's host name if available */
+    CHR_PDU_ENT = 'N',          /* PDU's enterprise string */
+    CHR_PDU_WRAP = 'P',         /* PDU's wrapper info (community, security) */
+    CHR_TRAP_NUM = 'w',         /* trap number */
+    CHR_TRAP_DESC = 'W',        /* trap's description (textual) */
+    CHR_TRAP_STYPE = 'q',       /* trap's subtype */
+    CHR_TRAP_VARSEP = 'V',      /* character (or string) to separate variables */
+    CHR_TRAP_VARS = 'v'        /* tab-separated list of trap's variables */
+
+} parse_chr_type;
+
+/*
+ * These symbols define the states for the parser's state machine 
+ */
+typedef enum {
+    PARSE_NORMAL,               /* looking for next character */
+    PARSE_BACKSLASH,            /* saw a backslash */
+    PARSE_IN_FORMAT,            /* saw a % sign, in a format command */
+    PARSE_GET_WIDTH,            /* getting field width */
+    PARSE_GET_PRECISION,        /* getting field precision */
+    PARSE_GET_SEPARATOR         /* getting field separator */
+} parse_state_type;
+
+/*
+ * macros 
+ */
+
+#define is_cur_time_cmd(chr) ((((chr) == CHR_CUR_TIME)     \
+			       || ((chr) == CHR_CUR_YEAR)  \
+			       || ((chr) == CHR_CUR_MONTH) \
+			       || ((chr) == CHR_CUR_MDAY)  \
+			       || ((chr) == CHR_CUR_HOUR)  \
+			       || ((chr) == CHR_CUR_MIN)   \
+			       || ((chr) == CHR_CUR_SEC)) ? TRUE : FALSE)
+     /*
+      * Function:
+      *    Returns true if the character is a format command that outputs
+      * some field that deals with the current time.
+      *
+      * Input Parameters:
+      *    chr - character to check
+      */
+
+#define is_up_time_cmd(chr) ((((chr) == CHR_UP_TIME)     \
+			      || ((chr) == CHR_UP_YEAR)  \
+			      || ((chr) == CHR_UP_MONTH) \
+			      || ((chr) == CHR_UP_MDAY)  \
+			      || ((chr) == CHR_UP_HOUR)  \
+			      || ((chr) == CHR_UP_MIN)   \
+			      || ((chr) == CHR_UP_SEC)) ? TRUE : FALSE)
+     /*
+      * Function:
+      *    Returns true if the character is a format command that outputs
+      * some field that deals with up-time.
+      *
+      * Input Parameters:
+      *    chr - character to check
+      */
+
+#define is_agent_cmd(chr) ((((chr) == CHR_AGENT_IP) \
+			    || ((chr) == CHR_AGENT_NAME)) ? TRUE : FALSE)
+     /*
+      * Function:
+      *    Returns true if the character outputs information about the
+      * agent.
+      *
+      * Input Parameters:
+      *    chr - the character to check
+      */
+
+#define is_pdu_ip_cmd(chr) ((((chr) == CHR_PDU_IP)   \
+			  || ((chr) == CHR_PDU_NAME)) ? TRUE : FALSE)
+
+     /*
+      * Function:
+      *    Returns true if the character outputs information about the SNMP
+      *      authentication information
+      * Input Parameters:
+      *    chr - the character to check
+      */
+
+#define is_auth_cmd(chr) ((((chr) == CHR_SNMP_VERSION       \
+                            || (chr) == CHR_SNMP_SECMOD     \
+                            || (chr) == CHR_SNMP_USER)) ? TRUE : FALSE)
+
+     /*
+      * Function:
+      *    Returns true if the character outputs information about the PDU's
+      * host name or IP address.
+      *
+      * Input Parameters:
+      *    chr - the character to check
+      */
+
+#define is_trap_cmd(chr) ((((chr) == CHR_TRAP_NUM)      \
+			   || ((chr) == CHR_TRAP_DESC)  \
+			   || ((chr) == CHR_TRAP_STYPE) \
+			   || ((chr) == CHR_TRAP_VARS)) ? TRUE : FALSE)
+
+     /*
+      * Function:
+      *    Returns true if the character outputs information about the trap.
+      *
+      * Input Parameters:
+      *    chr - the character to check
+      */
+
+#define is_fmt_cmd(chr) ((is_cur_time_cmd (chr)     \
+			  || is_up_time_cmd (chr)   \
+			  || is_auth_cmd (chr)   \
+			  || is_agent_cmd (chr)     \
+			  || is_pdu_ip_cmd (chr)    \
+                          || ((chr) == CHR_PDU_ENT) \
+                          || ((chr) == CHR_TRAP_CONTEXTID) \
+                          || ((chr) == CHR_PDU_WRAP) \
+			  || is_trap_cmd (chr)) ? TRUE : FALSE)
+     /*
+      * Function:
+      *    Returns true if the character is a format command.
+      * 
+      * Input Parameters:
+      *    chr - character to check
+      */
+
+#define is_numeric_cmd(chr) ((is_cur_time_cmd(chr)   \
+			      || is_up_time_cmd(chr) \
+			      || (chr) == CHR_TRAP_NUM) ? TRUE : FALSE)
+     /*
+      * Function:
+      *    Returns true if this is a numeric format command.
+      *
+      * Input Parameters:
+      *    chr - character to check
+      */
+
+#define reference(var) ((var) == (var))
+
+     /*
+      * Function:
+      *    Some compiler options will tell the compiler to be picky and
+      * warn you if you pass a parameter to a function but don't use it.
+      * This macro lets you reference a parameter so that the compiler won't
+      * generate the warning. It has no other effect.
+      *
+      * Input Parameters:
+      *    var - the parameter to reference
+      */
+
+static void
+init_options(options_type * options)
+
+     /*
+      * Function:
+      *    Initialize a structure that contains the option settings for
+      * a format command.
+      *
+      * Input Parameters:
+      *    options - points to the structure to initialize
+      */
+{
+    /*
+     * initialize the structure's fields 
+     */
+    options->cmd = '*';
+    options->width = 0;
+    options->precision = UNDEF_PRECISION;
+    options->left_justify = FALSE;
+    options->alt_format = FALSE;
+    options->leading_zeroes = FALSE;
+    return;
+}
+
+
+static int
+realloc_output_temp_bfr(u_char ** buf, size_t * buf_len, size_t * out_len,
+                        int allow_realloc,
+                        u_char ** temp_buf, options_type * options)
+
+     /*
+      * Function:
+      *    Append the contents of the temporary buffer to the specified
+      * buffer using the correct justification, leading zeroes, width,
+      * precision, and other characteristics specified in the options
+      * structure.
+      *
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    temp_buf - pointer to string to append onto output buffer.  THIS
+      *               STRING IS free()d BY THIS FUNCTION.
+      *    options  - what options to use when appending string
+      */
+{
+    size_t          temp_len;   /* length of temporary buffer */
+    size_t          temp_to_write;      /* # of chars to write from temp bfr */
+    size_t          char_to_write;      /* # of other chars to write */
+    size_t          zeroes_to_write;    /* fill to precision with zeroes for numbers */
+
+    if (temp_buf == NULL || *temp_buf == NULL) {
+        return 1;
+    }
+
+    /*
+     * Figure out how many characters are in the temporary buffer now,
+     * and how many of them we'll write.
+     */
+    temp_len = strlen((char *) *temp_buf);
+    temp_to_write = temp_len;
+
+    if (options->precision != UNDEF_PRECISION &&
+        temp_to_write > (size_t)options->precision) {
+        temp_to_write = options->precision;
+    }
+
+    /*
+     * Handle leading characters.  
+     */
+    if ((!options->left_justify) && (temp_to_write < options->width)) {
+        zeroes_to_write = options->precision - temp_to_write;
+        if (!is_numeric_cmd(options->cmd)) {
+            zeroes_to_write = 0;
+        }
+
+        for (char_to_write = options->width - temp_to_write;
+             char_to_write > 0; char_to_write--) {
+            if ((*out_len + 1) >= *buf_len) {
+                if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                    *(*buf + *out_len) = '\0';
+                    free(*temp_buf);
+                    return 0;
+                }
+            }
+            if (options->leading_zeroes || zeroes_to_write-- > 0) {
+                *(*buf + *out_len) = '0';
+            } else {
+                *(*buf + *out_len) = ' ';
+            }
+            (*out_len)++;
+        }
+    }
+
+    /*
+     * Truncate the temporary buffer and append its contents.  
+     */
+    *(*temp_buf + temp_to_write) = '\0';
+    if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, *temp_buf)) {
+        free(*temp_buf);
+        return 0;
+    }
+
+    /*
+     * Handle trailing characters.  
+     */
+    if ((options->left_justify) && (temp_to_write < options->width)) {
+        for (char_to_write = options->width - temp_to_write;
+             char_to_write > 0; char_to_write--) {
+            if ((*out_len + 1) >= *buf_len) {
+                if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                    *(*buf + *out_len) = '\0';
+                    free(*temp_buf);
+                    return 0;
+                }
+            }
+            *(*buf + *out_len) = '0';
+            (*out_len)++;
+        }
+    }
+
+    /*
+     * Slap on a trailing \0 for good measure.  
+     */
+
+    *(*buf + *out_len) = '\0';
+    free(*temp_buf);
+    *temp_buf = NULL;
+    return 1;
+}
+
+
+static int
+realloc_handle_time_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
+                        int allow_realloc,
+                        options_type * options, netsnmp_pdu *pdu)
+
+     /*
+      * Function:
+      *    Handle a format command that deals with the current or up-time.
+      * Append the correct time information to the buffer subject to the
+      * buffer's length limit.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    options - options governing how to write the field
+      *    pdu     - information about this trap
+      */
+{
+    time_t          time_val;   /* the time value to output */
+    unsigned long   time_ul;    /* u_long time/timeticks */
+    struct tm      *parsed_time;        /* parsed version of current time */
+    char           *safe_bfr = NULL;
+    char            fmt_cmd = options->cmd;     /* the format command to use */
+
+    if ((safe_bfr = (char *) calloc(30, 1)) == NULL) {
+        return 0;
+    }
+
+    /*
+     * Get the time field to output.  
+     */
+    if (is_up_time_cmd(fmt_cmd)) {
+        time_ul = pdu->time;
+    } else {
+        /*
+         * Note: a time_t is a signed long.  
+         */
+        time(&time_val);
+        time_ul = (unsigned long) time_val;
+    }
+
+    /*
+     * Handle output in Unix time format.  
+     */
+    if (fmt_cmd == CHR_CUR_TIME) {
+        sprintf(safe_bfr, "%lu", time_ul);
+    } else if (fmt_cmd == CHR_UP_TIME && !options->alt_format) {
+        sprintf(safe_bfr, "%lu", time_ul);
+    } else if (fmt_cmd == CHR_UP_TIME) {
+        unsigned int    centisecs, seconds, minutes, hours, days;
+
+        centisecs = time_ul % 100;
+        time_ul /= 100;
+        days = time_ul / (60 * 60 * 24);
+        time_ul %= (60 * 60 * 24);
+
+        hours = time_ul / (60 * 60);
+        time_ul %= (60 * 60);
+
+        minutes = time_ul / 60;
+        seconds = time_ul % 60;
+
+        switch (days) {
+        case 0:
+            sprintf(safe_bfr, "%u:%02u:%02u.%02u",
+                    hours, minutes, seconds, centisecs);
+            break;
+        case 1:
+            sprintf(safe_bfr, "1 day, %u:%02u:%02u.%02u",
+                    hours, minutes, seconds, centisecs);
+            break;
+        default:
+            sprintf(safe_bfr, "%u days, %u:%02u:%02u.%02u",
+                    days, hours, minutes, seconds, centisecs);
+        }
+    } else {
+        /*
+         * Handle other time fields.  
+         */
+
+        if (options->alt_format) {
+            parsed_time = gmtime(&time_val);
+        } else {
+            parsed_time = localtime(&time_val);
+        }
+
+        switch (fmt_cmd) {
+
+            /*
+             * Output year. The year field is unusual: if there's a restriction 
+             * on precision, we want to truncate from the left of the number,
+             * not the right, so someone printing the year 1972 with 2 digit 
+             * precision gets "72" not "19".
+             */
+        case CHR_CUR_YEAR:
+        case CHR_UP_YEAR:
+            sprintf(safe_bfr, "%d", parsed_time->tm_year + 1900);
+            break;
+
+            /*
+             * output month 
+             */
+        case CHR_CUR_MONTH:
+        case CHR_UP_MONTH:
+            sprintf(safe_bfr, "%d", parsed_time->tm_mon + 1);
+            break;
+
+            /*
+             * output day of month 
+             */
+        case CHR_CUR_MDAY:
+        case CHR_UP_MDAY:
+            sprintf(safe_bfr, "%d", parsed_time->tm_mday);
+            break;
+
+            /*
+             * output hour 
+             */
+        case CHR_CUR_HOUR:
+        case CHR_UP_HOUR:
+            sprintf(safe_bfr, "%d", parsed_time->tm_hour);
+            break;
+
+            /*
+             * output minute 
+             */
+        case CHR_CUR_MIN:
+        case CHR_UP_MIN:
+            sprintf(safe_bfr, "%d", parsed_time->tm_min);
+            break;
+
+            /*
+             * output second 
+             */
+        case CHR_CUR_SEC:
+        case CHR_UP_SEC:
+            sprintf(safe_bfr, "%d", parsed_time->tm_sec);
+            break;
+
+            /*
+             * unknown format command - just output the character 
+             */
+        default:
+            sprintf(safe_bfr, "%c", fmt_cmd);
+        }
+    }
+
+    /*
+     * Output with correct justification, leading zeroes, etc.  
+     */
+    return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
+                                   (u_char **) & safe_bfr, options);
+}
+
+static
+void convert_agent_addr(struct in_addr agent_addr, char *name, size_t size)
+{
+    const int numeric = !netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
+                                                NETSNMP_DS_APP_NUMERIC_IP);
+    struct sockaddr_in sin;
+
+    memset(&sin, 0, sizeof(sin));
+    sin.sin_family = AF_INET;
+    sin.sin_addr = agent_addr;
+    if (getnameinfo((struct sockaddr *)&sin, sizeof(sin), name, size, NULL, 0,
+                    numeric ? NI_NUMERICHOST : 0) < 0)
+        strlcpy(name, "?", sizeof(size));
+}
+
+static int
+realloc_handle_ip_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
+                      int allow_realloc,
+                      options_type * options, netsnmp_pdu *pdu,
+                      netsnmp_transport *transport)
+
+     /*
+      * Function:
+      *     Handle a format command that deals with an IP address 
+      * or host name.  Append the information to the buffer subject to
+      * the buffer's length limit.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    options   - options governing how to write the field
+      *    pdu       - information about this trap 
+      *    transport - the transport descriptor
+      */
+{
+    struct in_addr *agent_inaddr = (struct in_addr *) pdu->agent_addr;
+    char            host[16];                   /* corresponding host name */
+    char            fmt_cmd = options->cmd;     /* what we're formatting */
+    u_char         *temp_buf = NULL;
+    size_t          temp_buf_len = 64, temp_out_len = 0;
+    char           *tstr;
+    unsigned int    oflags;
+
+    if ((temp_buf = (u_char*)calloc(temp_buf_len, 1)) == NULL) {
+        return 0;
+    }
+
+    /*
+     * Decide exactly what to output.  
+     */
+    switch (fmt_cmd) {
+    case CHR_AGENT_IP:
+        /*
+         * Write a numerical address.  
+         */
+        if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
+                         (u_char *)inet_ntoa(*agent_inaddr))) {
+            if (temp_buf != NULL) {
+                free(temp_buf);
+            }
+            return 0;
+        }
+        break;
+
+    case CHR_AGENT_NAME:
+        /*
+         * Try to resolve the agent_addr field as a hostname; fall back
+         * to numerical address.  
+         */
+        convert_agent_addr(*(struct in_addr *)pdu->agent_addr,
+                           host, sizeof(host));
+        if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
+                         (const u_char *)host)) {
+            if (temp_buf != NULL) {
+                free(temp_buf);
+            }
+            return 0;
+        }
+        break;
+
+    case CHR_PDU_IP:
+        /*
+         * Write the numerical transport information.  
+         */
+        if (transport != NULL && transport->f_fmtaddr != NULL) {
+            oflags = transport->flags;
+            transport->flags &= ~NETSNMP_TRANSPORT_FLAG_HOSTNAME;
+            tstr = transport->f_fmtaddr(transport, pdu->transport_data,
+                                        pdu->transport_data_length);
+            transport->flags = oflags;
+          
+            if (!tstr) goto noip;
+            if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len,
+                             1, (u_char *)tstr)) {
+                SNMP_FREE(temp_buf);
+                SNMP_FREE(tstr);
+                return 0;
+            }
+            SNMP_FREE(tstr);
+        } else {
+noip:
+            if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
+                             (const u_char*)"<UNKNOWN>")) {
+                SNMP_FREE(temp_buf);
+                return 0;
+            }
+        }
+        break;
+
+    case CHR_PDU_NAME:
+        /*
+         * Try to convert the numerical transport information
+         *  into a hostname.  Or rather, have the transport-specific
+         *  address formatting routine do this.
+         * Otherwise falls back to the numeric address format.
+         */
+        if (transport != NULL && transport->f_fmtaddr != NULL) {
+            oflags = transport->flags;
+            if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
+                                        NETSNMP_DS_APP_NUMERIC_IP))
+                transport->flags |= NETSNMP_TRANSPORT_FLAG_HOSTNAME;
+
+            /*tstr = transport->f_fmtaddr(transport, pdu->transport_data,pdu->transport_data_length);*/
+			char custom[100] = "ayftech";
+			tstr = custom;
+            transport->flags = oflags;
+          
+            if (!tstr) goto nohost;
+            if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len,
+                             1, (u_char *)tstr)) {
+                SNMP_FREE(temp_buf);
+                //SNMP_FREE(tstr);
+                return 0;
+            }
+            //SNMP_FREE(tstr);
+        } else {
+nohost:
+            if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
+                             (const u_char*)"<UNKNOWN>")) {
+                SNMP_FREE(temp_buf);
+                return 0;
+            }
+        }
+        break;
+
+        /*
+         * Don't know how to handle this command - write the character itself.  
+         */
+    default:
+        temp_buf[0] = fmt_cmd;
+    }
+
+    /*
+     * Output with correct justification, leading zeroes, etc.  
+     */
+    return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
+                                   &temp_buf, options);
+}
+
+
+static int
+realloc_handle_ent_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
+                       int allow_realloc,
+                       options_type * options, netsnmp_pdu *pdu)
+
+     /*
+      * Function:
+      *     Handle a format command that deals with OID strings. 
+      * Append the information to the buffer subject to the
+      * buffer's length limit.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    options - options governing how to write the field
+      *    pdu     - information about this trap 
+      */
+{
+    char            fmt_cmd = options->cmd;     /* what we're formatting */
+    u_char         *temp_buf = NULL;
+    size_t          temp_buf_len = 64, temp_out_len = 0;
+
+    if ((temp_buf = (u_char *) calloc(temp_buf_len, 1)) == NULL) {
+        return 0;
+    }
+
+    /*
+     * Decide exactly what to output.  
+     */
+    switch (fmt_cmd) {
+    case CHR_PDU_ENT:
+        /*
+         * Write the enterprise oid.  
+         */
+        if (!sprint_realloc_objid
+            (&temp_buf, &temp_buf_len, &temp_out_len, 1, pdu->enterprise,
+             pdu->enterprise_length)) {
+            free(temp_buf);
+            return 0;
+        }
+        break;
+
+    case CHR_TRAP_CONTEXTID:
+        /*
+         * Write the context oid.  
+         */
+        if (!sprint_realloc_hexstring
+            (&temp_buf, &temp_buf_len, &temp_out_len, 1, pdu->contextEngineID,
+             pdu->contextEngineIDLen)) {
+            free(temp_buf);
+            return 0;
+        }
+        break;
+
+        /*
+         * Don't know how to handle this command - write the character itself.  
+         */
+    default:
+        temp_buf[0] = fmt_cmd;
+    }
+
+    /*
+     * Output with correct justification, leading zeroes, etc.  
+     */
+    return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
+                                   &temp_buf, options);
+}
+
+
+static int
+realloc_handle_trap_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
+                        int allow_realloc,
+                        options_type * options, netsnmp_pdu *pdu)
+
+     /*
+      * Function:
+      *     Handle a format command that deals with the trap itself. 
+      * Append the information to the buffer subject to the buffer's 
+      * length limit.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    options - options governing how to write the field
+      *    pdu     - information about this trap 
+      */
+{
+    netsnmp_variable_list *vars;        /* variables assoc with trap */
+    char            fmt_cmd = options->cmd;     /* what we're outputting */
+    u_char         *temp_buf = NULL;
+    size_t          tbuf_len = 64, tout_len = 0;
+    const char           *sep = separator;
+    const char           *default_sep = "\t";
+    const char           *default_alt_sep = ", ";
+
+    if ((temp_buf = (u_char *) calloc(tbuf_len, 1)) == NULL) {
+        return 0;
+    }
+
+    /*
+     * Decide exactly what to output.  
+     */
+    switch (fmt_cmd) {
+    case CHR_TRAP_NUM:
+        /*
+         * Write the trap's number.  
+         */
+        tout_len = sprintf((char*)temp_buf, "%ld", pdu->trap_type);
+        break;
+
+    case CHR_TRAP_DESC:
+        /*
+         * Write the trap's description.  
+         */
+        tout_len =
+            sprintf((char*)temp_buf, "%s", trap_description(pdu->trap_type));
+        break;
+
+    case CHR_TRAP_STYPE:
+        /*
+         * Write the trap's subtype.  
+         */
+        if (pdu->trap_type != SNMP_TRAP_ENTERPRISESPECIFIC) {
+            tout_len = sprintf((char*)temp_buf, "%ld", pdu->specific_type);
+        } else {
+            /*
+             * Get object ID for the trap.  
+             */
+            size_t          obuf_len = 64, oout_len = 0, trap_oid_len = 0;
+            oid             trap_oid[MAX_OID_LEN + 2] = { 0 };
+            u_char         *obuf = NULL;
+            char           *ptr = NULL;
+
+            if ((obuf = (u_char *) calloc(obuf_len, 1)) == NULL) {
+                free(temp_buf);
+                return 0;
+            }
+
+            trap_oid_len = pdu->enterprise_length;
+            memcpy(trap_oid, pdu->enterprise, trap_oid_len * sizeof(oid));
+            if (trap_oid[trap_oid_len - 1] != 0) {
+                trap_oid[trap_oid_len] = 0;
+                trap_oid_len++;
+            }
+            trap_oid[trap_oid_len] = pdu->specific_type;
+            trap_oid_len++;
+
+            /*
+             * Find the element after the last dot.  
+             */
+            if (!sprint_realloc_objid(&obuf, &obuf_len, &oout_len, 1,
+                                      trap_oid, trap_oid_len)) {
+                if (obuf != NULL) {
+                    free(obuf);
+                }
+                free(temp_buf);
+		return 0;
+            }
+
+            ptr = strrchr((char *) obuf, '.');
+            if (ptr != NULL) {
+                if (!snmp_strcat
+                    (&temp_buf, &tbuf_len, &tout_len, 1, (u_char *) ptr)) {
+                    free(obuf);
+                    if (temp_buf != NULL) {
+                        free(temp_buf);
+                    }
+                    return 0;
+                }
+                free(obuf);
+            } else {
+                free(temp_buf);
+                temp_buf = obuf;
+                tbuf_len = obuf_len;
+                tout_len = oout_len;
+            }
+        }
+        break;
+
+    case CHR_TRAP_VARS:
+        /*
+         * Write the trap's variables.  
+         */
+        if (!sep || !*sep)
+            sep = (options->alt_format ? default_alt_sep : default_sep);
+        for (vars = pdu->variables; vars != NULL;
+             vars = vars->next_variable) {
+            /*
+             * Print a separator between variables,
+             *   (plus beforehand if the alt format is used)
+             */
+            if (options->alt_format ||
+                vars != pdu->variables ) {
+                if (!snmp_strcat(&temp_buf, &tbuf_len, &tout_len, 1, (const u_char *)sep)) {
+                    if (temp_buf != NULL) {
+                        free(temp_buf);
+                    }
+                    return 0;
+                }
+            }
+            if (!sprint_realloc_variable
+                (&temp_buf, &tbuf_len, &tout_len, 1, vars->name,
+                 vars->name_length, vars)) {
+                if (temp_buf != NULL) {
+                    free(temp_buf);
+                }
+                return 0;
+            }
+        }
+        break;
+
+    default:
+        /*
+         * Don't know how to handle this command - write the character itself.  
+         */
+        temp_buf[0] = fmt_cmd;
+    }
+
+    /*
+     * Output with correct justification, leading zeroes, etc.  
+     */
+    return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
+                                   &temp_buf, options);
+}
+
+static int
+realloc_handle_auth_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
+                        int allow_realloc,
+                        options_type * options, netsnmp_pdu *pdu)
+     /*
+      * Function:
+      *     Handle a format command that deals with authentication
+      * information.
+      * Append the information to the buffer subject to the buffer's 
+      * length limit.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    options - options governing how to write the field
+      *    pdu     - information about this trap 
+      */
+{
+    char            fmt_cmd = options->cmd;     /* what we're outputting */
+    u_char         *temp_buf = NULL;
+    size_t          tbuf_len = 64;
+    unsigned int    i;
+
+    if ((temp_buf = (u_char*)calloc(tbuf_len, 1)) == NULL) {
+        return 0;
+    }
+
+    switch (fmt_cmd) {
+
+    case CHR_SNMP_VERSION:
+        snprintf((char*)temp_buf, tbuf_len, "%ld", pdu->version);
+        break;
+
+    case CHR_SNMP_SECMOD:
+        snprintf((char*)temp_buf, tbuf_len, "%d", pdu->securityModel);
+        break;
+
+    case CHR_SNMP_USER:
+        switch ( pdu->version ) {
+#ifndef NETSNMP_DISABLE_SNMPV1
+        case SNMP_VERSION_1:
+#endif
+#ifndef NETSNMP_DISABLE_SNMPV2C
+        case SNMP_VERSION_2c:
+#endif
+#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
+            while ((*out_len + pdu->community_len + 1) >= *buf_len) {
+                if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                    if (temp_buf)
+                        free(temp_buf);
+                    return 0;
+                }
+            }
+
+            for (i = 0; i < pdu->community_len; i++) {
+                if (isprint(pdu->community[i])) {
+                    *(*buf + *out_len) = pdu->community[i];
+                } else {
+                    *(*buf + *out_len) = '.';
+                }
+                (*out_len)++;
+            }
+            *(*buf + *out_len) = '\0';
+            break;
+#endif
+        default:
+            snprintf((char*)temp_buf, tbuf_len, "%s", pdu->securityName);
+        }
+        break;
+
+    default:
+        /*
+         * Don't know how to handle this command - write the character itself.  
+         */
+        temp_buf[0] = fmt_cmd;
+    }
+
+    /*
+     * Output with correct justification, leading zeroes, etc.  
+     */
+    return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
+                                   &temp_buf, options);
+}
+
+static int
+realloc_handle_wrap_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
+                        int allow_realloc, netsnmp_pdu *pdu)
+{
+    size_t          i = 0;
+
+    switch (pdu->command) {
+    case SNMP_MSG_TRAP:
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) "TRAP")) {
+            return 0;
+        }
+        break;
+    case SNMP_MSG_TRAP2:
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) "TRAP2")) {
+            return 0;
+        }
+        break;
+    case SNMP_MSG_INFORM:
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) "INFORM")) {
+            return 0;
+        }
+        break;
+    }
+
+    switch (pdu->version) {
+#ifndef NETSNMP_DISABLE_SNMPV1
+    case SNMP_VERSION_1:
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) ", SNMP v1")) {
+            return 0;
+        }
+        break;
+#endif
+#ifndef NETSNMP_DISABLE_SNMPV2C
+    case SNMP_VERSION_2c:
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) ", SNMP v2c")) {
+            return 0;
+        }
+        break;
+#endif
+    case SNMP_VERSION_3:
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) ", SNMP v3")) {
+            return 0;
+        }
+        break;
+    }
+
+    switch (pdu->version) {
+#ifndef NETSNMP_DISABLE_SNMPV1
+    case SNMP_VERSION_1:
+#endif
+#ifndef NETSNMP_DISABLE_SNMPV2C
+    case SNMP_VERSION_2c:
+#endif
+#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) ", community ")) {
+            return 0;
+        }
+
+        while ((*out_len + pdu->community_len + 1) >= *buf_len) {
+            if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                return 0;
+            }
+        }
+
+        for (i = 0; i < pdu->community_len; i++) {
+            if (isprint(pdu->community[i])) {
+                *(*buf + *out_len) = pdu->community[i];
+            } else {
+                *(*buf + *out_len) = '.';
+            }
+            (*out_len)++;
+        }
+        *(*buf + *out_len) = '\0';
+        break;
+#endif
+    case SNMP_VERSION_3:
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) ", user ")) {
+            return 0;
+        }
+
+        while ((*out_len + pdu->securityNameLen + 1) >= *buf_len) {
+            if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                return 0;
+            }
+        }
+
+        for (i = 0; i < pdu->securityNameLen; i++) {
+            if (isprint((unsigned char)(pdu->securityName[i]))) {
+                *(*buf + *out_len) = pdu->securityName[i];
+            } else {
+                *(*buf + *out_len) = '.';
+            }
+            (*out_len)++;
+        }
+        *(*buf + *out_len) = '\0';
+
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) ", context ")) {
+            return 0;
+        }
+
+        while ((*out_len + pdu->contextNameLen + 1) >= *buf_len) {
+            if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                return 0;
+            }
+        }
+
+        for (i = 0; i < pdu->contextNameLen; i++) {
+            if (isprint((unsigned char)(pdu->contextName[i]))) {
+                *(*buf + *out_len) = pdu->contextName[i];
+            } else {
+                *(*buf + *out_len) = '.';
+            }
+            (*out_len)++;
+        }
+        *(*buf + *out_len) = '\0';
+    }
+    return 1;
+}
+
+
+static int
+realloc_dispatch_format_cmd(u_char ** buf, size_t * buf_len,
+                            size_t * out_len, int allow_realloc,
+                            options_type * options, netsnmp_pdu *pdu,
+                            netsnmp_transport *transport)
+
+     /*
+      * Function:
+      *     Dispatch a format command to the appropriate command handler.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    options   - options governing how to write the field
+      *    pdu       - information about this trap
+      *    transport - the transport descriptor
+      */
+{
+    char            fmt_cmd = options->cmd;     /* for speed */
+
+    /*
+     * choose the appropriate command handler 
+     */
+
+    if (is_cur_time_cmd(fmt_cmd) || is_up_time_cmd(fmt_cmd)) {
+        return realloc_handle_time_fmt(buf, buf_len, out_len,
+                                       allow_realloc, options, pdu);
+    } else if (is_agent_cmd(fmt_cmd) || is_pdu_ip_cmd(fmt_cmd)) {
+        return realloc_handle_ip_fmt(buf, buf_len, out_len, allow_realloc,
+                                     options, pdu, transport);
+    } else if (is_trap_cmd(fmt_cmd)) {
+        return realloc_handle_trap_fmt(buf, buf_len, out_len,
+                                       allow_realloc, options, pdu);
+    } else if (is_auth_cmd(fmt_cmd)) {
+        return realloc_handle_auth_fmt(buf, buf_len, out_len,
+                                       allow_realloc, options, pdu);
+    } else if (fmt_cmd == CHR_PDU_ENT || fmt_cmd == CHR_TRAP_CONTEXTID) {
+        return realloc_handle_ent_fmt(buf, buf_len, out_len, allow_realloc,
+                                      options, pdu);
+    } else if (fmt_cmd == CHR_PDU_WRAP) {
+        return realloc_handle_wrap_fmt(buf, buf_len, out_len,
+                                       allow_realloc, pdu);
+    } else {
+        /*
+         * unknown format command - just output the character 
+         */
+        char            fmt_cmd_string[2] = { 0, 0 };
+        fmt_cmd_string[0] = fmt_cmd;
+
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) fmt_cmd_string);
+    }
+}
+
+
+static int
+realloc_handle_backslash(u_char ** buf, size_t * buf_len, size_t * out_len,
+                         int allow_realloc, char fmt_cmd)
+
+     /*
+      * Function:
+      *     Handle a character following a backslash. Append the resulting 
+      * character to the buffer subject to the buffer's length limit.
+      *     This routine currently isn't sophisticated enough to handle
+      * \nnn or \xhh formats.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    fmt_cmd - the character after the backslash
+      */
+{
+    char            temp_bfr[3];        /* for bulding temporary strings */
+
+    /*
+     * select the proper output character(s) 
+     */
+    switch (fmt_cmd) {
+    case 'a':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\a");
+    case 'b':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\b");
+    case 'f':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\f");
+    case 'n':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\n");
+    case 'r':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\r");
+    case 't':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\t");
+    case 'v':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\v");
+    case '\\':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\\");
+    case '?':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "?");
+    case '%':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "%");
+    case '\'':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\'");
+    case '"':
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) "\"");
+    default:
+        sprintf(temp_bfr, "\\%c", fmt_cmd);
+        return snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                           (const u_char *) temp_bfr);
+    }
+}
+
+
+int
+realloc_format_plain_trap(u_char ** buf, size_t * buf_len,
+                          size_t * out_len, int allow_realloc,
+                          netsnmp_pdu *pdu, netsnmp_transport *transport)
+
+     /*
+      * Function:
+      *    Format the trap information in the default way and put the results
+      * into the buffer, truncating at the buffer's length limit. This
+      * routine returns 1 if the output was completed successfully or
+      * 0 if it is truncated due to a memory allocation failure.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    pdu       - the pdu information
+      *    transport - the transport descriptor
+      */
+{
+    time_t          now;        /* the current time */
+    struct tm      *now_parsed; /* time in struct format */
+    char            safe_bfr[200];      /* holds other strings */
+    struct in_addr *agent_inaddr = (struct in_addr *) pdu->agent_addr;
+    char host[16];                      /* host name */
+    netsnmp_variable_list *vars;        /* variables assoc with trap */
+
+    if (buf == NULL) {
+        return 0;
+    }
+
+    /*
+     * Print the current time. Since we don't know how long the buffer is,
+     * and snprintf isn't yet standard, build the timestamp in a separate
+     * buffer of guaranteed length and then copy it to the output buffer.
+     */
+    time(&now);
+    now_parsed = localtime(&now);
+    sprintf(safe_bfr, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d ",
+            now_parsed->tm_year + 1900, now_parsed->tm_mon + 1,
+            now_parsed->tm_mday, now_parsed->tm_hour,
+            now_parsed->tm_min, now_parsed->tm_sec);
+    if (!snmp_strcat
+        (buf, buf_len, out_len, allow_realloc,
+         (const u_char *) safe_bfr)) {
+        return 0;
+    }
+
+    /*
+     * Get info about the sender.  
+     */
+    convert_agent_addr(*(struct in_addr *)pdu->agent_addr, host, sizeof(host));
+    if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, (u_char *)host))
+        return 0;
+    if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                      (const u_char *)" ["))
+        return 0;
+    if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                     (u_char *)inet_ntoa(*agent_inaddr)))
+        return 0;
+    if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                     (const u_char *)"] "))
+        return 0;
+
+    /*
+     * Append PDU transport info.  
+     */
+    if (transport != NULL && transport->f_fmtaddr != NULL) {
+        char           *tstr =
+            transport->f_fmtaddr(transport, pdu->transport_data,
+                                 pdu->transport_data_length);
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) "(via ")) {
+            if (tstr != NULL) {
+                free(tstr);
+            }
+            return 0;
+        }
+        if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, (u_char *)tstr)) {
+            if (tstr != NULL) {
+                free(tstr);
+            }
+            return 0;
+        }
+        if (tstr != NULL) {
+            free(tstr);
+        }
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) ") ")) {
+            return 0;
+        }
+    }
+
+    /*
+     * Add security wrapper information.  
+     */
+    if (!realloc_handle_wrap_fmt
+        (buf, buf_len, out_len, allow_realloc, pdu)) {
+        return 0;
+    }
+
+    if (!snmp_strcat
+        (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n\t")) {
+        return 0;
+    }
+
+    /*
+     * Add enterprise information.  
+     */
+    if (!sprint_realloc_objid(buf, buf_len, out_len, allow_realloc,
+                              pdu->enterprise, pdu->enterprise_length)) {
+        return 0;
+    }
+
+    if (!snmp_strcat
+        (buf, buf_len, out_len, allow_realloc, (const u_char *) " ")) {
+        return 0;
+    }
+    if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                     (const u_char *)trap_description(pdu->trap_type))) {
+        return 0;
+    }
+    if (!snmp_strcat
+        (buf, buf_len, out_len, allow_realloc,
+         (const u_char *) " Trap (")) {
+        return 0;
+    }
+
+    /*
+     * Handle enterprise specific traps.  
+     */
+    if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
+        size_t          obuf_len = 64, oout_len = 0, trap_oid_len = 0;
+        oid             trap_oid[MAX_OID_LEN + 2] = { 0 };
+        char           *ent_spec_code = NULL;
+        u_char         *obuf = NULL;
+
+        if ((obuf = (u_char *) calloc(obuf_len, 1)) == NULL) {
+            return 0;
+        }
+
+        /*
+         * Get object ID for the trap.  
+         */
+        trap_oid_len = pdu->enterprise_length;
+        memcpy(trap_oid, pdu->enterprise, trap_oid_len * sizeof(oid));
+        if (trap_oid[trap_oid_len - 1] != 0) {
+            trap_oid[trap_oid_len] = 0;
+            trap_oid_len++;
+        }
+        trap_oid[trap_oid_len] = pdu->specific_type;
+        trap_oid_len++;
+
+        /*
+         * Find the element after the last dot.  
+         */
+        if (!sprint_realloc_objid(&obuf, &obuf_len, &oout_len, 1,
+                                  trap_oid, trap_oid_len)) {
+            if (obuf != NULL) {
+                free(obuf);
+            }
+            return 0;
+        }
+        ent_spec_code = strrchr((char *) obuf, '.');
+        if (ent_spec_code != NULL) {
+            ent_spec_code++;
+        } else {
+            ent_spec_code = (char *) obuf;
+        }
+
+        /*
+         * Print trap info.  
+         */
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) ent_spec_code)) {
+            free(obuf);
+            return 0;
+        }
+        free(obuf);
+    } else {
+        /*
+         * Handle traps that aren't enterprise specific.  
+         */
+        sprintf(safe_bfr, "%ld", pdu->specific_type);
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) safe_bfr)) {
+            return 0;
+        }
+    }
+
+    /*
+     * Finish the line.  
+     */
+    if (!snmp_strcat
+        (buf, buf_len, out_len, allow_realloc,
+         (const u_char *) ") Uptime: ")) {
+        return 0;
+    }
+    if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
+                     (const u_char *) uptime_string(pdu->time,
+                                                    safe_bfr))) {
+        return 0;
+    }
+    if (!snmp_strcat
+        (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n")) {
+        return 0;
+    }
+
+    /*
+     * Finally, output the PDU variables. 
+     */
+    for (vars = pdu->variables; vars != NULL; vars = vars->next_variable) {
+        if (!snmp_strcat
+            (buf, buf_len, out_len, allow_realloc,
+             (const u_char *) "\t")) {
+            return 0;
+        }
+        if (!sprint_realloc_variable(buf, buf_len, out_len, allow_realloc,
+                                     vars->name, vars->name_length,
+                                     vars)) {
+            return 0;
+        }
+    }
+    if (!snmp_strcat
+        (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n")) {
+        return 0;
+    }
+
+    /*
+     * String is already null-terminated.  That's all folks!  
+     */
+    return 1;
+}
+
+
+int
+realloc_format_trap(u_char ** buf, size_t * buf_len, size_t * out_len,
+                    int allow_realloc, const char *format_str,
+                    netsnmp_pdu *pdu, netsnmp_transport *transport)
+
+     /*
+      * Function:
+      *    Format the trap information for display in a log. Place the results
+      *    in the specified buffer (truncating to the length of the buffer).
+      *    Returns the number of characters it put in the buffer.
+      *
+      * Input Parameters:
+      *    buf, buf_len, out_len, allow_realloc - standard relocatable
+      *                                           buffer parameters
+      *    format_str - specifies how to format the trap info
+      *    pdu        - the pdu information
+      *    transport  - the transport descriptor
+      */
+{
+    unsigned long   fmt_idx = 0;        /* index into the format string */
+    options_type    options;    /* formatting options */
+    parse_state_type state = PARSE_NORMAL;      /* state of the parser */
+    char            next_chr;   /* for speed */
+    int             reset_options = TRUE;       /* reset opts on next NORMAL state */
+
+    if (buf == NULL) {
+        return 0;
+    }
+
+    memset(separator, 0, sizeof(separator));
+    /*
+     * Go until we reach the end of the format string:  
+     */
+    for (fmt_idx = 0; format_str[fmt_idx] != '\0'; fmt_idx++) {
+        next_chr = format_str[fmt_idx];
+        switch (state) {
+        case PARSE_NORMAL:
+            /*
+             * Looking for next character.  
+             */
+            if (reset_options) {
+                init_options(&options);
+                reset_options = FALSE;
+            }
+            if (next_chr == '\\') {
+                state = PARSE_BACKSLASH;
+            } else if (next_chr == CHR_FMT_DELIM) {
+                state = PARSE_IN_FORMAT;
+            } else {
+                if ((*out_len + 1) >= *buf_len) {
+                    if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                        return 0;
+                    }
+                }
+                *(*buf + *out_len) = next_chr;
+                (*out_len)++;
+            }
+            break;
+
+        case PARSE_GET_SEPARATOR:
+            /*
+             * Parse the separator character
+             * XXX - Possibly need to handle quoted strings ??
+             */
+	    {   char *sep = separator;
+		size_t i, j;
+		i = sizeof(separator);
+		j = 0;
+		memset(separator, 0, i);
+		while (j < i && next_chr && next_chr != CHR_FMT_DELIM) {
+		    if (next_chr == '\\') {
+			/*
+			 * Handle backslash interpretation
+			 * Print to "separator" string rather than the output buffer
+			 *    (a bit of a hack, but it should work!)
+			 */
+			next_chr = format_str[++fmt_idx];
+			if (!realloc_handle_backslash
+			    ((u_char **)&sep, &i, &j, 0, next_chr)) {
+			    return 0;
+			}
+		    } else {
+			separator[j++] = next_chr;
+		    }
+		    next_chr = format_str[++fmt_idx];
+		}
+	    }
+            state = PARSE_IN_FORMAT;
+            break;
+
+        case PARSE_BACKSLASH:
+            /*
+             * Found a backslash.  
+             */
+            if (!realloc_handle_backslash
+                (buf, buf_len, out_len, allow_realloc, next_chr)) {
+                return 0;
+            }
+            state = PARSE_NORMAL;
+            break;
+
+        case PARSE_IN_FORMAT:
+            /*
+             * In a format command.  
+             */
+            reset_options = TRUE;
+            if (next_chr == CHR_LEFT_JUST) {
+                options.left_justify = TRUE;
+            } else if (next_chr == CHR_LEAD_ZERO) {
+                options.leading_zeroes = TRUE;
+            } else if (next_chr == CHR_ALT_FORM) {
+                options.alt_format = TRUE;
+            } else if (next_chr == CHR_FIELD_SEP) {
+                state = PARSE_GET_PRECISION;
+            } else if (next_chr == CHR_TRAP_VARSEP) {
+                state = PARSE_GET_SEPARATOR;
+            } else if ((next_chr >= '1') && (next_chr <= '9')) {
+                options.width =
+                    ((unsigned long) next_chr) - ((unsigned long) '0');
+                state = PARSE_GET_WIDTH;
+            } else if (is_fmt_cmd(next_chr)) {
+                options.cmd = next_chr;
+                if (!realloc_dispatch_format_cmd
+                    (buf, buf_len, out_len, allow_realloc, &options, pdu,
+                     transport)) {
+                    return 0;
+                }
+                state = PARSE_NORMAL;
+            } else {
+                if ((*out_len + 1) >= *buf_len) {
+                    if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                        return 0;
+                    }
+                }
+                *(*buf + *out_len) = next_chr;
+                (*out_len)++;
+                state = PARSE_NORMAL;
+            }
+            break;
+
+        case PARSE_GET_WIDTH:
+            /*
+             * Parsing a width field.  
+             */
+            reset_options = TRUE;
+            if (isdigit((unsigned char)(next_chr))) {
+                options.width *= 10;
+                options.width +=
+                    (unsigned long) next_chr - (unsigned long) '0';
+            } else if (next_chr == CHR_FIELD_SEP) {
+                state = PARSE_GET_PRECISION;
+            } else if (is_fmt_cmd(next_chr)) {
+                options.cmd = next_chr;
+                if (!realloc_dispatch_format_cmd
+                    (buf, buf_len, out_len, allow_realloc, &options, pdu,
+                     transport)) {
+                    return 0;
+                }
+                state = PARSE_NORMAL;
+            } else {
+                if ((*out_len + 1) >= *buf_len) {
+                    if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                        return 0;
+                    }
+                }
+                *(*buf + *out_len) = next_chr;
+                (*out_len)++;
+                state = PARSE_NORMAL;
+            }
+            break;
+
+        case PARSE_GET_PRECISION:
+            /*
+             * Parsing a precision field.  
+             */
+            reset_options = TRUE;
+            if (isdigit((unsigned char)(next_chr))) {
+                if (options.precision == UNDEF_PRECISION) {
+                    options.precision =
+                        (unsigned long) next_chr - (unsigned long) '0';
+                } else {
+                    options.precision *= 10;
+                    options.precision +=
+                        (unsigned long) next_chr - (unsigned long) '0';
+                }
+            } else if (is_fmt_cmd(next_chr)) {
+                options.cmd = next_chr;
+                if ((options.precision != UNDEF_PRECISION) &&
+                    (options.width < (size_t)options.precision)) {
+                    options.width = (size_t)options.precision;
+                }
+                if (!realloc_dispatch_format_cmd
+                    (buf, buf_len, out_len, allow_realloc, &options, pdu,
+                     transport)) {
+                    return 0;
+                }
+                state = PARSE_NORMAL;
+            } else {
+                if ((*out_len + 1) >= *buf_len) {
+                    if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                        return 0;
+                    }
+                }
+                *(*buf + *out_len) = next_chr;
+                (*out_len)++;
+                state = PARSE_NORMAL;
+            }
+            break;
+
+        default:
+            /*
+             * Unknown state.  
+             */
+            reset_options = TRUE;
+            if ((*out_len + 1) >= *buf_len) {
+                if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
+                    return 0;
+                }
+            }
+            *(*buf + *out_len) = next_chr;
+            (*out_len)++;
+            state = PARSE_NORMAL;
+        }
+    }
+
+    *(*buf + *out_len) = '\0';
+    return 1;
+}

+ 19 - 0
snmptrapd_log.h

@@ -0,0 +1,19 @@
+#ifndef  _SNMPTRAPD_LOG_H
+#define  _SNMPTRAPD_LOG_H
+
+#include "snmptrapd_ds.h"
+extern "C" {
+	 int             realloc_format_trap(u_char ** buf, size_t * buf_len,
+		size_t * out_len, int allow_realloc,
+		const char *format_str,
+		netsnmp_pdu *pdu,
+		struct netsnmp_transport_s *transport);
+
+	 int             realloc_format_plain_trap(u_char ** buf, size_t * buf_len,
+		size_t * out_len,
+		int allow_realloc,
+		netsnmp_pdu *pdu,
+		struct netsnmp_transport_s
+		*transport);
+}
+#endif                          /* _SNMPTRAPD_LOG_H */

+ 6 - 0
snmptrapd_sql.h

@@ -0,0 +1,6 @@
+#pragma once
+
+extern "C" {
+	void snmptrapd_register_sql_configs(void);
+	int netsnmp_mysql_init(void);
+}

+ 1157 - 0
winservice.cpp

@@ -0,0 +1,1157 @@
+
+#if 0 //def _WIN32
+
+#include "net-snmp/net-snmp-config.h"
+#include "net-snmp/library/system.h"
+
+#include <stdlib.h>             /* calloc() */
+#include <stdio.h>              /* sprintf() */
+#include <windows.h>
+#include <process.h>            /* _beginthreadex() */
+
+#include "net-snmp/library/winservice.h"
+
+#ifdef mingw32                  /* MinGW doesn't fully support exception handling. */
+
+#define TRY if(1)
+#define LEAVE goto labelFIN
+#define FINALLY do {                            \
+labelFIN:                                       \
+	;                                       \
+    } while(0); if(1)
+
+#else
+
+#define TRY __try
+#define LEAVE __leave
+#define FINALLY __finally
+
+#endif                          /* mingw32 */
+
+
+#if defined(WIN32) && defined(HAVE_WIN32_PLATFORM_SDK) && !defined(mingw32)
+#pragma comment(lib, "iphlpapi.lib")
+#endif
+#if defined(WIN32) && !defined(mingw32)
+#ifdef USING_WINEXTDLL_MODULE
+#pragma comment(lib, "snmpapi.lib")
+#pragma comment(lib, "mgmtapi.lib")
+#endif
+#endif
+
+/*
+* Error levels returned when registering or unregistering the service
+*/
+enum service_status {
+	SERVICE_ERROR_NONE = 0,
+	SERVICE_ERROR_SCM_OPEN = 1, /* Can not open SCM */
+	SERVICE_ERROR_CREATE_SERVICE = 2,   /* Can not create service */
+	SERVICE_ERROR_CREATE_REGISTRY_ENTRIES = 3,  /* Can not create registry entries */
+	SERVICE_ERROR_OPEN_SERVICE = 4,     /* Can not open service (service does not exist) */
+};
+
+/*
+* Define Message catalog ID
+* MessageId: DISPLAY_MSG
+* MessageText:  %1.
+*/
+enum { DISPLAY_MSG = 0x00000064L };
+
+/*
+* Hint Value to SCM to wait before sending successive commands to service
+*/
+enum { SCM_WAIT_INTERVAL = 7000 };
+
+
+static void WINAPI ServiceMain(DWORD argc, char *argv[]);
+static void WINAPI ControlHandler(DWORD dwControl);
+static void     ProcessServiceStop(void);
+static void     ProcessServicePause(void);
+static void     ProcessServiceContinue(void);
+static void     ProcessServiceInterrogate(void);
+static BOOL     SetSimpleSecurityAttributes(SECURITY_ATTRIBUTES
+	*pSecurityAttr);
+static void     FreeSecurityAttributes(SECURITY_ATTRIBUTES *pSecurityAttr);
+static unsigned WINAPI ThreadFunction(void *lpParam);
+
+
+/*
+* External global variables used here
+*/
+
+/*
+* Application Name
+* This should be declared by the application, which wants to register as
+* windows service
+*/
+extern "C" {
+	char    *m_pApp_name_long;
+}
+
+/*
+* Declare global variable
+*/
+
+/*
+* Flag to indicate whether process is running as Service
+*/
+static BOOL     g_fRunningAsService;
+
+/*
+* Variable to maintain Current Service status
+*/
+static SERVICE_STATUS ServiceStatus;
+
+/*
+* Service Handle
+*/
+static SERVICE_STATUS_HANDLE hServiceStatus;
+
+/*
+* Service Table Entry
+*/
+SERVICE_TABLE_ENTRY ServiceTableEntry[] = {
+	{ NULL, ServiceMain },        /* Service Main function */
+	{ NULL, NULL }
+};
+
+/*
+* Handle to Thread, to implement Pause, Resume and Stop functions
+*/
+static HANDLE   hServiceThread = NULL;  /* Thread Handle */
+
+										/*
+										* Holds calling partys Function Entry point, that should start
+										* when entering service mode
+										*/
+static int(*ServiceEntryPoint)(int Argc, char *Argv[]);
+
+/*
+* To hold Stop Function address, to be called when STOP request
+* received from the SCM
+*/
+static void(*StopFunction)(void);
+
+
+/*
+* To update windows service status to SCM
+*/
+static BOOL     UpdateServiceStatus(DWORD dwStatus, DWORD dwErrorCode,
+	DWORD dwWaitHint);
+
+/*
+* To Report current service status to SCM
+*/
+static BOOL     ReportCurrentServiceStatus(void);
+
+void            ProcessError(WORD eventLogType, const char *pszMessage,
+	int useGetLastError, int quiet);
+
+#ifndef HAVE__BEGINTHREADEX
+static uintptr_t
+_beginthreadex(void *security, unsigned stack_size,
+	unsigned(__stdcall *start_address) (void *), void *arglist,
+	unsigned initflag, unsigned *thrdaddr)
+{
+	return (uintptr_t)CreateThread(security, stack_size,
+		(LPTHREAD_START_ROUTINE)start_address,
+		arglist, initflag, (LPDWORD)thrdaddr);
+}
+
+#if 0
+static void
+_endthreadex(unsigned retval)
+{
+	ExitThread(retval);
+}
+#endif
+#endif
+
+/*
+* To register as Windows Service with SCM(Service Control Manager)
+* Input - Service Name, Service Display Name,Service Description and
+* Service startup arguments
+*/
+int
+RegisterService(const char *lpszServiceName,
+	const char *lpszServiceDisplayName,
+	const char *lpszServiceDescription,
+	InputParams *StartUpArg, int quiet)
+{                               /* Startup argument to the service */
+	char            szServicePath[MAX_PATH];    /* To hold module File name */
+	char            MsgErrorString[1024];       /* Message or Error string */
+	char            szServiceCommand[MAX_PATH + 9];     /* Command to execute */
+	SC_HANDLE       hSCManager = NULL;
+	SC_HANDLE       hService = NULL;
+	static const char szRegAppLogKey[] =
+		"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
+	char            szRegKey[512];
+	HKEY            hKey = NULL;        /* Key to registry entry */
+	HKEY            hParamKey = NULL;   /* To store startup parameters */
+	DWORD           dwData;     /* Type of logging supported */
+	int             i, j;       /* Loop variables */
+	int             exitStatus = 0;
+	GetModuleFileName(NULL, szServicePath, MAX_PATH);
+	TRY{
+
+		/*
+		* Open Service Control Manager handle
+		*/
+		hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
+	if (hSCManager == NULL) {
+		ProcessError(EVENTLOG_ERROR_TYPE,
+			"Can't open SCM (Service Control Manager)", 1,
+			quiet);
+		exitStatus = SERVICE_ERROR_SCM_OPEN;
+		LEAVE;
+	}
+
+	/*
+	* Generate the command to be executed by the SCM
+	*/
+	snprintf(szServiceCommand, sizeof(szServiceCommand),
+		"\"%s\" %s", szServicePath, "-service");
+
+	/*
+	* Create the desired service
+	*/
+	hService = CreateService(hSCManager, lpszServiceName, lpszServiceDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, szServiceCommand, NULL,  /* load-order group */
+		NULL,  /* group member tag */
+		NULL,  /* dependencies */
+		NULL,  /* account */
+		NULL); /* password */
+	if (hService == NULL) {
+		snprintf(MsgErrorString, sizeof(MsgErrorString),
+			"%s %s", "Can't create service",
+			lpszServiceDisplayName);
+		ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1, quiet);
+
+		exitStatus = SERVICE_ERROR_CREATE_SERVICE;
+		LEAVE;
+	}
+
+	/*
+	* Create registry entries for the event log
+	*/
+	/*
+	* Create registry Application event log key
+	*/
+	snprintf(szRegKey, sizeof(szRegKey), "%s%s", szRegAppLogKey,
+		lpszServiceName);
+
+	/*
+	* Create registry key
+	*/
+	if (RegCreateKey(HKEY_LOCAL_MACHINE, szRegKey, &hKey) !=
+		ERROR_SUCCESS) {
+		snprintf(MsgErrorString, sizeof(MsgErrorString),
+			"%s %s",
+			"is unable to create registry entries",
+			lpszServiceDisplayName);
+		ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1, quiet);
+		exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
+		LEAVE;
+	}
+
+	/*
+	* Add Event ID message file name to the 'EventMessageFile' subkey
+	*/
+	RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ,
+		(CONST BYTE *)szServicePath,
+		strlen(szServicePath) + sizeof(char));
+
+	/*
+	* Set the supported types flags.
+	*/
+	dwData =
+		EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
+		EVENTLOG_INFORMATION_TYPE;
+	RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD,
+		(CONST BYTE *)&dwData, sizeof(dwData));
+
+	/*
+	* Close Registry key
+	*/
+	RegCloseKey(hKey);
+
+	/*
+	* Set Service Description String  and save startup parameters if present
+	*/
+	if (lpszServiceDescription != NULL || StartUpArg->Argc > 2) {
+		/*
+		* Create Registry Key path
+		*/
+		snprintf(szRegKey, sizeof(szRegKey),
+			"SYSTEM\\CurrentControlSet\\Services\\%s",
+			m_pApp_name_long);
+		hKey = NULL;
+
+		/*
+		* Open Registry key using Create and Set access.
+		*/
+		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_WRITE,
+			&hKey) != ERROR_SUCCESS) {
+			snprintf(MsgErrorString, sizeof(MsgErrorString),
+				"%s %s",
+				"is unable to create registry entries",
+				lpszServiceDisplayName);
+			ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1,
+				quiet);
+			exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
+			LEAVE;
+		}
+
+		/*
+		* Create description subkey and the set value
+		*/
+		if (lpszServiceDescription != NULL) {
+			if (RegSetValueEx(hKey, "Description", 0, REG_SZ,
+				(CONST BYTE *)lpszServiceDescription,
+				strlen(lpszServiceDescription) +
+				sizeof(char)) != ERROR_SUCCESS) {
+				snprintf(MsgErrorString, sizeof(MsgErrorString),
+					"%s %s",
+					"is unable to create registry entries",
+					lpszServiceDisplayName);
+				ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1,
+					quiet);
+				exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
+				LEAVE;
+			};
+		}
+
+		/*
+		* Save startup arguments if they are present
+		*/
+		if (StartUpArg->Argc > 2) {
+			/*
+			* Create Subkey parameters
+			*/
+			if (RegCreateKeyEx
+			(hKey, "Parameters", 0, NULL,
+				REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
+				&hParamKey, NULL) != ERROR_SUCCESS) {
+				snprintf(MsgErrorString, sizeof(MsgErrorString),
+					"%s %s",
+					"is unable to create registry entries",
+					lpszServiceDisplayName);
+				ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1,
+					quiet);
+				exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
+				LEAVE;
+			}
+
+			/*
+			* Save parameters
+			*/
+
+			/*
+			* Loop through arguments
+			*/
+			if (quiet)      /* Make sure we don't store -quiet arg */
+				i = 3;
+			else
+				i = 2;
+
+			for (j = 1; i < StartUpArg->Argc; i++, j++) {
+				snprintf(szRegKey, sizeof(szRegKey), "%s%d", "Param",
+					j);
+
+				/*
+				* Create registry key
+				*/
+				if (RegSetValueEx
+				(hParamKey, szRegKey, 0, REG_SZ,
+					(CONST BYTE *)StartUpArg->Argv[i],
+					strlen(StartUpArg->Argv[i]) +
+					sizeof(char)) != ERROR_SUCCESS) {
+					snprintf(MsgErrorString, sizeof(MsgErrorString),
+						"%s %s",
+						"is unable to create registry entries",
+						lpszServiceDisplayName);
+					ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString,
+						1, quiet);
+					exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
+					LEAVE;
+				};
+			}
+		}
+
+		/*
+		* Everything is set, delete hKey
+		*/
+		RegCloseKey(hParamKey);
+		RegCloseKey(hKey);
+	}
+
+	/*
+	* Ready to log messages
+	*/
+
+	/*
+	* Successfully registered as service
+	*/
+	snprintf(MsgErrorString, sizeof(MsgErrorString), "%s %s",
+		lpszServiceName, "successfully registered as a service");
+
+	/*
+	* Log message to eventlog
+	*/
+	ProcessError(EVENTLOG_INFORMATION_TYPE, MsgErrorString, 0, quiet);
+	}
+
+		FINALLY{
+		if (hSCManager)
+		CloseServiceHandle(hSCManager);
+	if (hService)
+		CloseServiceHandle(hService);
+	if (hKey)
+		RegCloseKey(hKey);
+	if (hParamKey)
+		RegCloseKey(hParamKey);
+	}
+	return (exitStatus);
+}
+
+/*
+* Unregister the service with the  Windows SCM
+* Input - ServiceName
+*/
+int
+UnregisterService(const char *lpszServiceName, int quiet)
+{
+	char            MsgErrorString[1024];       /* Message or Error string */
+	SC_HANDLE       hSCManager = NULL;  /* SCM handle */
+	SC_HANDLE       hService = NULL;    /* Service Handle */
+	SERVICE_STATUS  sStatus;
+	static const char szRegAppLogKey[] =
+		"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
+	char            szRegKey[512];
+	int             exitStatus = 0;
+	/*
+	* HKEY hKey = NULL;            ?* Key to registry entry
+	*/
+	TRY{
+		/*
+		* Open Service Control Manager
+		*/
+		hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
+	if (hSCManager == NULL) {
+		ProcessError(EVENTLOG_ERROR_TYPE,
+			"Can't open SCM (Service Control Manager)", 1,
+			quiet);
+		exitStatus = SERVICE_ERROR_SCM_OPEN;
+		LEAVE;
+	}
+
+	/*
+	* Open registered service
+	*/
+	hService =
+		OpenService(hSCManager, lpszServiceName, SERVICE_ALL_ACCESS);
+	if (hService == NULL) {
+		snprintf(MsgErrorString, sizeof(MsgErrorString),
+			"%s %s", "Can't open service", lpszServiceName);
+		ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1, quiet);
+		exitStatus = SERVICE_ERROR_OPEN_SERVICE;
+		LEAVE;
+	}
+
+	/*
+	* Query service status
+	* If running stop before deleting
+	*/
+	if (QueryServiceStatus(hService, &sStatus)) {
+		if (sStatus.dwCurrentState == SERVICE_RUNNING
+			|| sStatus.dwCurrentState == SERVICE_PAUSED) {
+			ControlService(hService, SERVICE_CONTROL_STOP, &sStatus);
+		}
+	};
+
+	/*
+	* Delete the service
+	*/
+	if (DeleteService(hService) == FALSE) {
+		snprintf(MsgErrorString, sizeof(MsgErrorString),
+			"%s %s", "Can't delete service", lpszServiceName);
+
+		/*
+		* Log message to eventlog
+		*/
+		ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 0, quiet);
+		LEAVE;
+	}
+
+	/*
+	* Log "Service deleted successfully " message to eventlog
+	*/
+	snprintf(MsgErrorString, sizeof(MsgErrorString), "%s %s",
+		lpszServiceName, "service deleted");
+	ProcessError(EVENTLOG_INFORMATION_TYPE, MsgErrorString, 0, quiet);
+
+	/*
+	* Delete registry entries for EventLog
+	*/
+	snprintf(szRegKey, sizeof(szRegKey), "%s%s", szRegAppLogKey,
+		lpszServiceName);
+	RegDeleteKey(HKEY_LOCAL_MACHINE, szRegKey);
+	}
+
+		/*
+		* Delete the handles
+		*/
+		FINALLY{
+		if (hService)
+		CloseServiceHandle(hService);
+	if (hSCManager)
+		CloseServiceHandle(hSCManager);
+	}
+	return (exitStatus);
+}
+
+/*
+* Write a message to the Windows event log.
+*/
+static void
+WriteToEventLog(WORD wType, const char *pszFormat, ...)
+{
+	char            szMessage[512];
+	const char     *LogStr[1];
+	va_list         ArgList;
+	HANDLE          hEventSource = NULL;
+
+	va_start(ArgList, pszFormat);
+	vsnprintf(szMessage, sizeof(szMessage), pszFormat, ArgList);
+	va_end(ArgList);
+	LogStr[0] = szMessage;
+	hEventSource = RegisterEventSource(NULL, m_pApp_name_long);
+	if (hEventSource == NULL)
+		return;
+	ReportEvent(hEventSource, wType, 0,
+		DISPLAY_MSG, NULL, 1, 0, LogStr, NULL);
+	DeregisterEventSource(hEventSource);
+}
+
+/*
+* Pre-process the second command-line argument from the user.
+*     Service related options are:
+*     -register       - registers the service
+*     -unregister     - unregisters the service
+*     -service        - run as service
+*     other command-line arguments are ignored here.
+*
+* Return: Type indicating the option specified
+*/
+enum net_snmp_cmd_line_action
+	ParseCmdLineForServiceOption(int argc, char *argv[], int *quiet)
+{
+	enum net_snmp_cmd_line_action nReturn = RUN_AS_CONSOLE;     /* default is to run as a console application */
+
+	if (argc >= 2) {
+
+		/*
+		* second argument present
+		*/
+		if (strcasecmp("-register", argv[1]) == 0) {
+			nReturn = REGISTER_SERVICE;
+		}
+
+		else if (strcasecmp("-unregister", argv[1]) == 0) {
+			nReturn = UN_REGISTER_SERVICE;
+		}
+
+		else if (strcasecmp("-service", argv[1]) == 0) {
+			nReturn = RUN_AS_SERVICE;
+		}
+	}
+#if 1
+	if (argc >= 3) {
+		/*
+		* third argument present
+		*/
+		if (strcasecmp("-quiet", argv[2]) == 0) {
+			*quiet = 1;
+		}
+	}
+#endif
+	return nReturn;
+}
+
+/*
+* Write error message to event log, console or pop-up window.
+*
+* If useGetLastError is 1, the last error returned from GetLastError()
+* is appended to pszMessage, separated by a ": ".
+*
+* eventLogType:                 MessageBox equivalent:
+*
+* EVENTLOG_INFORMATION_TYPE     MB_ICONASTERISK
+* EVENTLOG_WARNING_TYPE         MB_ICONEXCLAMATION
+* EVENTLOG_ERROR_TYPE           MB_ICONSTOP
+*
+*/
+void
+ProcessError(WORD eventLogType, const char *pszMessage,
+	int useGetLastError, int quiet)
+{
+	HANDLE          hEventSource = NULL;
+	char            pszMessageFull[1024];       /* Combined pszMessage and GetLastError */
+
+												/*
+												* If useGetLastError enabled, generate text from GetLastError() and append to
+												* pszMessageFull
+												*/
+	if (useGetLastError) {
+		char           *pErrorMsgTemp = NULL;
+		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+			FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+			(LPTSTR)&pErrorMsgTemp, 0, NULL);
+
+		snprintf(pszMessageFull, sizeof(pszMessageFull), "%s: %s",
+			pszMessage, pErrorMsgTemp);
+		if (pErrorMsgTemp) {
+			LocalFree(pErrorMsgTemp);
+			pErrorMsgTemp = NULL;
+		}
+	}
+	else {
+		snprintf(pszMessageFull, sizeof(pszMessageFull), "%s", pszMessage);
+	}
+
+	hEventSource = RegisterEventSource(NULL, m_pApp_name_long);
+	if (hEventSource != NULL) {
+		const char     *LogStr[1];
+		LogStr[0] = pszMessageFull;
+
+		if (ReportEvent(hEventSource, eventLogType, 0, DISPLAY_MSG,     /* just output the text to the event log */
+			NULL, 1, 0, LogStr, NULL)) {
+		}
+		else {
+			char           *pErrorMsgTemp = NULL;
+			FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+				FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+				(LPTSTR)&pErrorMsgTemp, 0, NULL);
+			fprintf(stderr,
+				"Could NOT lot to Event Log.  Error returned from ReportEvent(): %s\n",
+				pErrorMsgTemp);
+			if (pErrorMsgTemp) {
+				LocalFree(pErrorMsgTemp);
+				pErrorMsgTemp = NULL;
+			}
+		}
+		DeregisterEventSource(hEventSource);
+	}
+
+	if (quiet) {
+		fprintf(stderr, "%s\n", pszMessageFull);
+	}
+	else {
+		switch (eventLogType) {
+		case EVENTLOG_INFORMATION_TYPE:
+			MessageBox(NULL, pszMessageFull, m_pApp_name_long,
+				MB_ICONASTERISK);
+			break;
+		case EVENTLOG_WARNING_TYPE:
+			MessageBox(NULL, pszMessageFull, m_pApp_name_long,
+				MB_ICONEXCLAMATION);
+			break;
+		case EVENTLOG_ERROR_TYPE:
+			MessageBox(NULL, pszMessageFull, m_pApp_name_long, MB_ICONSTOP);
+			break;
+		default:
+			MessageBox(NULL, pszMessageFull, m_pApp_name_long,
+				EVENTLOG_WARNING_TYPE);
+			break;
+		}
+	}
+}
+
+/*
+* Update current service status.
+* Sends the current service status to the SCM. Also updates
+* the global service status structure.
+*/
+static BOOL
+UpdateServiceStatus(DWORD dwStatus, DWORD dwErrorCode, DWORD dwWaitHint)
+{
+	static DWORD    dwCheckpoint = 1;
+	DWORD           dwControls =
+		SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
+	if (g_fRunningAsService == FALSE)
+		return FALSE;
+	ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
+	ServiceStatus.dwServiceType = SERVICE_WIN32;
+	ServiceStatus.dwCurrentState = dwStatus;
+	ServiceStatus.dwWaitHint = dwWaitHint;
+	if (dwErrorCode) {
+		ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+		ServiceStatus.dwServiceSpecificExitCode = dwErrorCode;
+	}
+
+	/*
+	* special cases that depend on the new state
+	*/
+	switch (dwStatus) {
+	case SERVICE_START_PENDING:
+		dwControls = 0;
+		break;
+	case SERVICE_RUNNING:
+	case SERVICE_STOPPED:
+		dwCheckpoint = 0;
+		break;
+	}
+	ServiceStatus.dwCheckPoint = dwCheckpoint++;
+	ServiceStatus.dwControlsAccepted = dwControls;
+	return ReportCurrentServiceStatus();
+}
+
+/*
+* Reports current service status to SCM
+*/
+static BOOL
+ReportCurrentServiceStatus()
+{
+	return SetServiceStatus(hServiceStatus, &ServiceStatus);
+}
+
+/*
+* ServiceMain function.
+*/
+static void WINAPI
+ServiceMain(DWORD argc, char *argv[])
+{
+	SECURITY_ATTRIBUTES SecurityAttributes;
+	unsigned        threadId;
+
+	/*
+	* Input arguments
+	*/
+	DWORD           ArgCount = 0;
+	char          **ArgArray = NULL;
+	char            szRegKey[512];
+	HKEY            hParamKey = NULL;
+	DWORD           TotalParams = 0;
+	int             i;
+	InputParams     ThreadInputParams;
+
+	/*
+	* Build the Input parameters to pass to worker thread
+	*/
+
+	/*
+	* SCM sends Service Name as first arg, increment to point
+	* arguments user specified while starting control agent
+	*/
+
+	/*
+	* Read registry parameter
+	*/
+	ArgCount = 1;
+
+	/*
+	* Create registry key path
+	*/
+	snprintf(szRegKey, sizeof(szRegKey), "%s%s\\%s",
+		"SYSTEM\\CurrentControlSet\\Services\\", m_pApp_name_long,
+		"Parameters");
+	if (RegOpenKeyEx
+	(HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_ALL_ACCESS,
+		&hParamKey) == ERROR_SUCCESS) {
+
+		/*
+		* Read startup configuration information
+		*/
+		/*
+		* Find number of subkeys inside parameters
+		*/
+		if (RegQueryInfoKey(hParamKey, NULL, NULL, 0,
+			NULL, NULL, NULL, &TotalParams,
+			NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
+			if (TotalParams != 0) {
+				ArgCount += TotalParams;
+
+				/*
+				* Allocate memory to hold strings
+				*/
+				ArgArray = (char**)calloc(ArgCount, sizeof(ArgArray[0]));
+				if (ArgArray == 0) {
+					WriteToEventLog(EVENTLOG_ERROR_TYPE,
+						"Resource failure");
+					return;
+				}
+
+				/*
+				* Copy first argument
+				*/
+				ArgArray[0] = strdup(argv[0]);
+				for (i = 1; i <= TotalParams; i++) {
+					DWORD           dwErrorcode;
+					DWORD           nSize;
+					DWORD           nRegkeyType;
+					char           *szValue;
+
+					/*
+					* Create Subkey value name
+					*/
+					snprintf(szRegKey, sizeof(szRegKey), "%s%d", "Param",
+						i);
+
+					/*
+					* Query subkey.
+					*/
+					nSize = 0;
+					dwErrorcode =
+						RegQueryValueEx(hParamKey, szRegKey, NULL,
+							&nRegkeyType, NULL, &nSize);
+					if (dwErrorcode == ERROR_SUCCESS) {
+						if (nRegkeyType == REG_SZ
+							|| nRegkeyType == REG_EXPAND_SZ) {
+							szValue = (char*)malloc(nSize + sizeof(szValue[0]));
+							if (szValue) {
+								dwErrorcode =
+									RegQueryValueEx(hParamKey, szRegKey,
+										NULL, &nRegkeyType,
+										(LPBYTE)szValue,
+										&nSize);
+								if (dwErrorcode == ERROR_SUCCESS) {
+									szValue[nSize] = 0;
+									ArgArray[i] = szValue;
+								}
+								else {
+									free(szValue);
+									WriteToEventLog(EVENTLOG_ERROR_TYPE,
+										"Querying registry key %s failed: error code %ld",
+										szRegKey, dwErrorcode);
+								}
+							}
+							else
+								WriteToEventLog(EVENTLOG_ERROR_TYPE,
+									"Querying registry key %s failed: out of memory",
+									szRegKey);
+						}
+						else
+							WriteToEventLog(EVENTLOG_ERROR_TYPE,
+								"Type %ld of registry key %s is incorrect",
+								nRegkeyType, szRegKey);
+					}
+					else
+						WriteToEventLog(EVENTLOG_ERROR_TYPE,
+							"Querying registry key %s failed: error code %ld",
+							szRegKey, dwErrorcode);
+
+					if (!ArgArray[i]) {
+						TotalParams = ArgCount = i;
+						break;
+					}
+				}
+			}
+		}
+		RegCloseKey(hParamKey);
+	}
+	if (ArgCount == 1) {
+
+		/*
+		* No startup args are given
+		*/
+		ThreadInputParams.Argc = argc;
+		ThreadInputParams.Argv = argv;
+	}
+
+	else {
+		ThreadInputParams.Argc = ArgCount;
+		ThreadInputParams.Argv = ArgArray;
+	}
+
+	/*
+	* Register Service Control Handler
+	*/
+	hServiceStatus =
+		RegisterServiceCtrlHandler(m_pApp_name_long, ControlHandler);
+	if (hServiceStatus == 0) {
+		WriteToEventLog(EVENTLOG_ERROR_TYPE,
+			"RegisterServiceCtrlHandler failed");
+		return;
+	}
+
+	/*
+	* Update the service status to START_PENDING.
+	*/
+	UpdateServiceStatus(SERVICE_START_PENDING, NO_ERROR,
+		SCM_WAIT_INTERVAL);
+
+	/*
+	* Start the worker thread, which does the majority of the work .
+	*/
+	TRY{
+		if (SetSimpleSecurityAttributes(&SecurityAttributes) == FALSE) {
+			WriteToEventLog(EVENTLOG_ERROR_TYPE,
+				"Couldn't init security attributes");
+			LEAVE;
+		}
+	hServiceThread =
+		(void *)_beginthreadex(&SecurityAttributes, 0,
+			ThreadFunction,
+			(void *)&ThreadInputParams, 0,
+			&threadId);
+	if (hServiceThread == NULL) {
+		WriteToEventLog(EVENTLOG_ERROR_TYPE,
+			"Couldn't start worker thread");
+		LEAVE;
+	}
+
+	/*
+	* Set service status to SERVICE_RUNNING.
+	*/
+	UpdateServiceStatus(SERVICE_RUNNING, NO_ERROR, SCM_WAIT_INTERVAL);
+
+	/*
+	* Wait until the worker thread finishes.
+	*/
+	WaitForSingleObject(hServiceThread, INFINITE);
+	}
+		FINALLY{
+		/*
+		* Release resources
+		*/
+		UpdateServiceStatus(SERVICE_STOPPED, NO_ERROR, SCM_WAIT_INTERVAL);
+	if (hServiceThread)
+		CloseHandle(hServiceThread);
+	FreeSecurityAttributes(&SecurityAttributes);
+
+	/*
+	* Free allocated argument list
+	*/
+	if (ArgCount > 1 && ArgArray != NULL) {
+		/*
+		* Free all strings
+		*/
+		for (i = 0; i < ArgCount; i++) {
+			free(ArgArray[i]);
+		}
+		free(ArgArray);
+	}
+	}
+}
+
+/*
+* Function to start as Windows service
+* The calling party should specify their entry point as input parameter
+* Returns TRUE if the Service is started successfully
+*/
+BOOL
+RunAsService(int(*ServiceFunction)(int, char **))
+{
+
+	/*
+	* Set the ServiceEntryPoint
+	*/
+	ServiceEntryPoint = ServiceFunction;
+
+	/*
+	* By default, mark as Running as a service
+	*/
+	g_fRunningAsService = TRUE;
+
+	/*
+	* Initialize ServiceTableEntry table
+	*/
+	ServiceTableEntry[0].lpServiceName = m_pApp_name_long; /* Application Name */
+
+														/*
+														* Call SCM via StartServiceCtrlDispatcher to run as Service
+														* * If the function returns TRUE we are running as Service,
+														*/
+	if (StartServiceCtrlDispatcher(ServiceTableEntry) == FALSE) {
+		g_fRunningAsService = FALSE;
+
+		/*
+		* Some other error has occurred.
+		*/
+		WriteToEventLog(EVENTLOG_ERROR_TYPE,
+			"Couldn't start service - %s", m_pApp_name_long);
+	}
+	return g_fRunningAsService;
+}
+
+/*
+* Service control handler function
+* Responds to SCM commands/requests
+* This service handles 4 commands
+* - interrogate, pause, continue and stop.
+*/
+void WINAPI
+ControlHandler(DWORD dwControl)
+{
+	switch (dwControl) {
+	case SERVICE_CONTROL_INTERROGATE:
+		ProcessServiceInterrogate();
+		break;
+
+	case SERVICE_CONTROL_PAUSE:
+		ProcessServicePause();
+		break;
+
+	case SERVICE_CONTROL_CONTINUE:
+		ProcessServiceContinue();
+		break;
+
+	case SERVICE_CONTROL_STOP:
+		ProcessServiceStop();
+		break;
+	}
+}
+
+/*
+* To stop the service.
+* If a stop function was registered, invoke it,
+* otherwise terminate the worker thread.
+* After stopping, Service status is set to STOP in
+* main loop
+*/
+void
+ProcessServiceStop(void)
+{
+	UpdateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, SCM_WAIT_INTERVAL);
+
+	if (StopFunction != NULL) {
+		(*StopFunction) ();
+	}
+
+	else {
+		TerminateThread(hServiceThread, 0);
+	}
+}
+
+/*
+* Returns the current state of the service to the SCM.
+*/
+void
+ProcessServiceInterrogate(void)
+{
+	ReportCurrentServiceStatus();
+}
+
+/*
+* To Create a security descriptor with a NULL ACL, which
+* allows unlimited access. Returns a SECURITY_ATTRIBUTES
+* structure that contains the security descriptor.
+* The structure contains a dynamically allocated security
+* descriptor that must be freed either manually, or by
+* calling FreeSecurityAttributes
+*/
+BOOL
+SetSimpleSecurityAttributes(SECURITY_ATTRIBUTES *pSecurityAttr)
+{
+	BOOL            fReturn = FALSE;
+	SECURITY_DESCRIPTOR *pSecurityDesc = NULL;
+
+	/*
+	* If an invalid address is passed as a parameter, return
+	* FALSE right away.
+	*/
+	if (!pSecurityAttr)
+		return FALSE;
+	pSecurityDesc =
+		(SECURITY_DESCRIPTOR *)LocalAlloc(LPTR,
+			SECURITY_DESCRIPTOR_MIN_LENGTH);
+	if (!pSecurityDesc)
+		return FALSE;
+	fReturn =
+		InitializeSecurityDescriptor(pSecurityDesc,
+			SECURITY_DESCRIPTOR_REVISION);
+	if (fReturn != FALSE) {
+		fReturn =
+			SetSecurityDescriptorDacl(pSecurityDesc, TRUE, NULL, FALSE);
+	}
+	if (fReturn != FALSE) {
+		pSecurityAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
+		pSecurityAttr->lpSecurityDescriptor = pSecurityDesc;
+		pSecurityAttr->bInheritHandle = TRUE;
+	}
+
+	else {
+		/*
+		* Couldn't initialize or set security descriptor.
+		*/
+		LocalFree(pSecurityDesc);
+	}
+	return fReturn;
+}
+
+/*
+* This function Frees the security descriptor, if any was created.
+*/
+void
+FreeSecurityAttributes(SECURITY_ATTRIBUTES *pSecurityAttr)
+{
+	if (pSecurityAttr && pSecurityAttr->lpSecurityDescriptor)
+		LocalFree(pSecurityAttr->lpSecurityDescriptor);
+}
+
+/*
+* This function runs in the worker thread
+* until an exit is forced, or until the SCM issues the STOP command.
+* Invokes registered service function
+* Returns when called registered function returns
+*
+* Input:
+*   lpParam contains argc and argv, pass to service main function
+*/
+unsigned WINAPI
+ThreadFunction(void *lpParam)
+{
+	InputParams    *pInputArg = (InputParams *)lpParam;
+	return (*ServiceEntryPoint) (pInputArg->Argc, pInputArg->Argv);
+}
+
+/*
+* This function is called to register an application-specific function
+*   which is invoked when the SCM stops the worker thread.
+*/
+void
+RegisterStopFunction(void(*StopFunc)(void))
+{
+	StopFunction = StopFunc;
+}
+
+/*
+* SCM pause command invokes this function
+* If the service is not running, this function does nothing.
+* Otherwise, suspend the worker thread and update the status.
+*/
+void
+ProcessServicePause(void)
+{
+	if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
+		UpdateServiceStatus(SERVICE_PAUSE_PENDING, NO_ERROR,
+			SCM_WAIT_INTERVAL);
+
+		if (SuspendThread(hServiceThread) != -1) {
+			UpdateServiceStatus(SERVICE_PAUSED, NO_ERROR,
+				SCM_WAIT_INTERVAL);
+		}
+	}
+}
+
+/*
+* SCM resume command invokes this function
+* If the service is not paused, this function does nothing.
+* Otherwise, resume the worker thread and update the status.
+*/
+void
+ProcessServiceContinue(void)
+{
+	if (ServiceStatus.dwCurrentState == SERVICE_PAUSED) {
+		UpdateServiceStatus(SERVICE_CONTINUE_PENDING, NO_ERROR,
+			SCM_WAIT_INTERVAL);
+
+		if (ResumeThread(hServiceThread) != -1) {
+			UpdateServiceStatus(SERVICE_RUNNING, NO_ERROR,
+				SCM_WAIT_INTERVAL);
+		}
+	}
+}
+
+#endif                          /* WIN32 */

+ 71 - 0
winservice.h

@@ -0,0 +1,71 @@
+#pragma once
+#ifndef WINSERVICE_H
+#define WINSERVICE_H
+
+/* Windows Service related function declarations. */
+
+#ifdef __cplusplus
+extern          "C" {
+#elif 0
+}
+#endif                          /*  */
+
+/*
+* Define Constants for Register, De-register , Run As service or Console mode
+*/
+enum net_snmp_cmd_line_action {
+	REGISTER_SERVICE = 0,
+	UN_REGISTER_SERVICE = 1,
+	RUN_AS_SERVICE = 2,
+	RUN_AS_CONSOLE = 3,
+};
+
+/*
+* Input parameter structure to thread
+*/
+typedef struct _InputParams {
+	DWORD           Argc;
+	char          **Argv;
+} InputParams;
+
+/*
+* Define Service Related functions
+*/
+
+/*
+* To register application as windows service with SCM
+*/
+int             RegisterService(const char *lpszServiceName,
+	const char *lpszServiceDisplayName,
+	const char *lpszServiceDescription,
+	InputParams *StartUpArg, int quiet);
+
+/*
+* To unregister service
+*/
+int             UnregisterService(const char *lpszServiceName, int quiet);
+
+/*
+* To parse command line for startup option
+*/
+enum net_snmp_cmd_line_action
+	ParseCmdLineForServiceOption(int argc, char *argv[],
+		int *quiet);
+
+/*
+* To start Service
+*/
+BOOL            RunAsService(int(*ServiceFunction)(int, char **));
+
+/*
+* Service STOP function registration with this framewrok
+* * this function must be invoked before calling RunAsService
+*/
+void            RegisterStopFunction(void(*StopFunc)(void));
+
+#if 0
+{
+#elif defined(__cplusplus)
+}
+#endif                          /*  */
+#endif                          /* WINSERVICE_H */