77e5b9c2cbd4cae55b46e7fe0eb0664868269772
[public/netxms.git] / src / agent / core / trap.cpp
1 /*
2 ** NetXMS multiplatform core agent
3 ** Copyright (C) 2003-2013 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: trap.cpp
20 **
21 **/
22
23 #include "nxagentd.h"
24 #include <stdarg.h>
25
26 /**
27 * Static data
28 */
29 static Queue *s_trapQueue = NULL;
30 static UINT64 s_genTrapCount = 0; // Number of generated traps
31 static UINT64 s_sentTrapCount = 0; // Number of sent traps
32 static UINT64 s_trapIdBase = 0;
33 static VolatileCounter s_trapIdCounter = 0;
34 static time_t s_lastTrapTime = 0;
35
36 /**
37 * Trap sender
38 */
39 THREAD_RESULT THREAD_CALL TrapSender(void *pArg)
40 {
41 NXCP_MESSAGE *pMsg;
42 UINT32 i;
43 bool trapSent;
44
45 s_trapQueue = new Queue;
46 s_trapIdBase = (QWORD)time(NULL) << 32;
47 while(1)
48 {
49 pMsg = (NXCP_MESSAGE *)s_trapQueue->getOrBlock();
50 if (pMsg == INVALID_POINTER_VALUE)
51 break;
52
53 trapSent = false;
54
55 if (g_dwFlags & AF_SUBAGENT_LOADER)
56 {
57 trapSent = SendRawMessageToMasterAgent(pMsg);
58 }
59 else
60 {
61 MutexLock(g_hSessionListAccess);
62 for(i = 0; i < g_dwMaxSessions; i++)
63 if (g_pSessionList[i] != NULL)
64 if (g_pSessionList[i]->canAcceptTraps())
65 {
66 g_pSessionList[i]->sendRawMessage(pMsg);
67 trapSent = true;
68 }
69 MutexUnlock(g_hSessionListAccess);
70 }
71
72 if (trapSent)
73 {
74 free(pMsg);
75 s_sentTrapCount++;
76 }
77 else
78 {
79 s_trapQueue->insert(pMsg); // Re-queue trap
80 ThreadSleep(1);
81 }
82 }
83 delete s_trapQueue;
84 s_trapQueue = NULL;
85 DebugPrintf(INVALID_INDEX, 1, _T("Trap sender thread terminated"));
86 return THREAD_OK;
87 }
88
89 /**
90 * Shutdown trap sender
91 */
92 void ShutdownTrapSender()
93 {
94 s_trapQueue->setShutdownMode();
95 }
96
97 /**
98 * Send trap to server
99 */
100 void SendTrap(UINT32 dwEventCode, const TCHAR *eventName, int iNumArgs, TCHAR **ppArgList)
101 {
102 int i;
103 NXCPMessage msg;
104
105 DebugPrintf(INVALID_INDEX, 5, _T("SendTrap(): event_code=%d, event_name=%s, num_args=%d, arg[0]=\"%s\" arg[1]=\"%s\" arg[2]=\"%s\""),
106 dwEventCode, CHECK_NULL(eventName), iNumArgs,
107 (iNumArgs > 0) ? ppArgList[0] : _T("(null)"),
108 (iNumArgs > 1) ? ppArgList[1] : _T("(null)"),
109 (iNumArgs > 2) ? ppArgList[2] : _T("(null)"));
110
111 msg.setCode(CMD_TRAP);
112 msg.setId(0);
113 msg.setField(VID_TRAP_ID, s_trapIdBase | (UINT64)InterlockedIncrement(&s_trapIdCounter));
114 msg.setField(VID_EVENT_CODE, dwEventCode);
115 if (eventName != NULL)
116 msg.setField(VID_EVENT_NAME, eventName);
117 msg.setField(VID_NUM_ARGS, (WORD)iNumArgs);
118 for(i = 0; i < iNumArgs; i++)
119 msg.setField(VID_EVENT_ARG_BASE + i, ppArgList[i]);
120 if (s_trapQueue != NULL)
121 {
122 s_genTrapCount++;
123 s_lastTrapTime = time(NULL);
124 s_trapQueue->put(msg.createMessage());
125 }
126 }
127
128 /**
129 * Send trap - variant 2
130 * Arguments:
131 * dwEventCode - Event code
132 * eventName - event name; to send event by name, eventCode must be set to 0
133 * pszFormat - Parameter format string, each parameter represented by one character.
134 * The following format characters can be used:
135 * s - String
136 * m - Multibyte (non-UNICODE) string
137 * d - Decimal integer
138 * x - Hex integer
139 * a - IP address
140 * i - Object ID
141 * D - 64-bit decimal integer
142 * X - 64-bit hex integer
143 */
144 void SendTrap(UINT32 dwEventCode, const TCHAR *eventName, const char *pszFormat, va_list args)
145 {
146 int i, iNumArgs;
147 TCHAR *ppArgList[64];
148 static TCHAR badFormat[] = _T("BAD FORMAT");
149
150 iNumArgs = (pszFormat == NULL) ? 0 : (int)strlen(pszFormat);
151 for(i = 0; i < iNumArgs; i++)
152 {
153 switch(pszFormat[i])
154 {
155 case 's':
156 ppArgList[i] = va_arg(args, TCHAR *);
157 if (ppArgList[i] == NULL)
158 ppArgList[i] = (TCHAR *)_T("");
159 break;
160 case 'm':
161 ppArgList[i] = WideStringFromMBString(va_arg(args, char *));
162 break;
163 case 'd':
164 ppArgList[i] = (TCHAR *)malloc(16 * sizeof(TCHAR)); //
165 _sntprintf(ppArgList[i], 16, _T("%d"), va_arg(args, LONG)); //
166 break;
167 case 'D':
168 ppArgList[i] = (TCHAR *)malloc(32 * sizeof(TCHAR)); //
169 _sntprintf(ppArgList[i], 32, INT64_FMT, va_arg(args, INT64)); //
170 break;
171 case 'x':
172 case 'i':
173 ppArgList[i] = (TCHAR *)malloc(16 * sizeof(TCHAR)); //
174 _sntprintf(ppArgList[i], 16, _T("0x%08X"), va_arg(args, UINT32)); //
175 break;
176 case 'X':
177 ppArgList[i] = (TCHAR *)malloc(32 * sizeof(TCHAR));
178 _sntprintf(ppArgList[i], 32, UINT64X_FMT(_T("016")), va_arg(args, QWORD));
179 break;
180 case 'a':
181 ppArgList[i] = (TCHAR *)malloc(16 * sizeof(TCHAR));
182 IpToStr(va_arg(args, UINT32), ppArgList[i]);
183 break;
184 default:
185 ppArgList[i] = badFormat;
186 break;
187 }
188 }
189
190 SendTrap(dwEventCode, eventName, iNumArgs, ppArgList);
191
192 for(i = 0; i < iNumArgs; i++)
193 if ((pszFormat[i] == 'd') || (pszFormat[i] == 'x') ||
194 (pszFormat[i] == 'D') || (pszFormat[i] == 'X') ||
195 (pszFormat[i] == 'i') || (pszFormat[i] == 'a') ||
196 (pszFormat[i] == 'm'))
197 free(ppArgList[i]);
198
199 }
200
201 /**
202 * Send trap - variant 3
203 * Same as variant 2, but uses argument list instead of va_list
204 */
205 void SendTrap(UINT32 dwEventCode, const TCHAR *eventName, const char *pszFormat, ...)
206 {
207 va_list args;
208
209 va_start(args, pszFormat);
210 SendTrap(dwEventCode, eventName, pszFormat, args);
211 va_end(args);
212
213 }
214
215 /**
216 * Forward trap from external subagent to server
217 */
218 void ForwardTrap(NXCPMessage *msg)
219 {
220 msg->setField(VID_TRAP_ID, s_trapIdBase | (UINT64)InterlockedIncrement(&s_trapIdCounter));
221 if (s_trapQueue != NULL)
222 {
223 s_genTrapCount++;
224 s_lastTrapTime = time(NULL);
225 s_trapQueue->put(msg->createMessage());
226 }
227 }
228
229 /**
230 * Handler for trap statistic DCIs
231 */
232 LONG H_AgentTraps(const TCHAR *cmd, const TCHAR *arg, TCHAR *value, AbstractCommSession *session)
233 {
234 switch(arg[0])
235 {
236 case 'G':
237 ret_uint64(value, s_genTrapCount);
238 break;
239 case 'S':
240 ret_uint64(value, s_sentTrapCount);
241 break;
242 case 'T':
243 ret_uint64(value, (QWORD)s_lastTrapTime);
244 break;
245 default:
246 return SYSINFO_RC_UNSUPPORTED;
247 }
248 return SYSINFO_RC_SUCCESS;
249 }