5b41cdee2d5fb10c2b3b2e303e2840864a6bebe3
[public/netxms.git] / src / libnxcl / snmptrap.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Client Library
4 ** Copyright (C) 2004-2010 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: snmptrap.cpp
21 **
22 **/
23
24 #include "libnxcl.h"
25
26
27 //
28 // Fill trap configuration record from message
29 //
30
31 static void TrapCfgFromMsg(CSCPMessage *pMsg, NXC_TRAP_CFG_ENTRY *pTrap)
32 {
33 DWORD i, dwId1, dwId2, dwId3;
34
35 pTrap->dwEventCode = pMsg->GetVariableLong(VID_EVENT_CODE);
36 pMsg->GetVariableStr(VID_DESCRIPTION, pTrap->szDescription, MAX_DB_STRING);
37 pMsg->GetVariableStr(VID_USER_TAG, pTrap->szUserTag, MAX_USERTAG_LENGTH);
38 pTrap->dwOidLen = pMsg->GetVariableLong(VID_TRAP_OID_LEN);
39 pTrap->pdwObjectId = (DWORD *)malloc(sizeof(DWORD) * pTrap->dwOidLen);
40 pMsg->GetVariableInt32Array(VID_TRAP_OID, pTrap->dwOidLen, pTrap->pdwObjectId);
41 pTrap->dwNumMaps = pMsg->GetVariableLong(VID_TRAP_NUM_MAPS);
42 pTrap->pMaps = (NXC_OID_MAP *)malloc(sizeof(NXC_OID_MAP) * pTrap->dwNumMaps);
43 for(i = 0, dwId1 = VID_TRAP_PLEN_BASE, dwId2 = VID_TRAP_PNAME_BASE, dwId3 = VID_TRAP_PDESCR_BASE;
44 i < pTrap->dwNumMaps; i++, dwId1++, dwId2++, dwId3++)
45 {
46 pTrap->pMaps[i].dwOidLen = pMsg->GetVariableLong(dwId1);
47 if ((pTrap->pMaps[i].dwOidLen & 0x80000000) == 0)
48 {
49 pTrap->pMaps[i].pdwObjectId = (DWORD *)malloc(sizeof(DWORD) * pTrap->pMaps[i].dwOidLen);
50 pMsg->GetVariableInt32Array(dwId2, pTrap->pMaps[i].dwOidLen, pTrap->pMaps[i].pdwObjectId);
51 }
52 else
53 {
54 pTrap->pMaps[i].pdwObjectId = NULL;
55 }
56 pMsg->GetVariableStr(dwId3, pTrap->pMaps[i].szDescription, MAX_DB_STRING);
57 }
58 }
59
60
61 //
62 // Process CMD_TRAP_CFG_UPDATE message
63 //
64
65 void ProcessTrapCfgUpdate(NXCL_Session *pSession, CSCPMessage *pMsg)
66 {
67 NXC_TRAP_CFG_ENTRY trapCfg;
68 DWORD dwCode;
69
70 memset(&trapCfg, 0, sizeof(NXC_TRAP_CFG_ENTRY));
71
72 dwCode = pMsg->GetVariableLong(VID_NOTIFICATION_CODE);
73 trapCfg.dwId = pMsg->GetVariableLong(VID_TRAP_ID);
74 if (dwCode != NX_NOTIFY_TRAPCFG_DELETED)
75 TrapCfgFromMsg(pMsg, &trapCfg);
76
77 pSession->callEventHandler(NXC_EVENT_NOTIFICATION, dwCode, &trapCfg);
78
79 for(DWORD i = 0; i < trapCfg.dwNumMaps; i++)
80 safe_free(trapCfg.pMaps[i].pdwObjectId);
81 safe_free(trapCfg.pMaps);
82 safe_free(trapCfg.pdwObjectId);
83 }
84
85
86 //
87 // Copy NXC_TRAP_CFG_ENTRY
88 //
89
90 void LIBNXCL_EXPORTABLE NXCCopyTrapCfgEntry(NXC_TRAP_CFG_ENTRY *dst, NXC_TRAP_CFG_ENTRY *src)
91 {
92 memcpy(dst, src, sizeof(NXC_TRAP_CFG_ENTRY));
93 if (src->pdwObjectId != NULL)
94 dst->pdwObjectId = (DWORD *)nx_memdup(src->pdwObjectId, sizeof(DWORD) * src->dwOidLen);
95 if (src->pMaps != NULL)
96 {
97 dst->pMaps = (NXC_OID_MAP *)nx_memdup(src->pMaps, sizeof(NXC_OID_MAP) * src->dwNumMaps);
98 for(DWORD i = 0; i < src->dwNumMaps; i++)
99 {
100 if (src->pMaps[i].pdwObjectId != NULL)
101 dst->pMaps[i].pdwObjectId = (DWORD *)nx_memdup(src->pMaps[i].pdwObjectId, sizeof(DWORD) * src->pMaps[i].dwOidLen);
102 }
103 }
104 }
105
106
107 //
108 // Duplicate NXC_TRAP_CFG_ENTRY
109 //
110
111 NXC_TRAP_CFG_ENTRY LIBNXCL_EXPORTABLE *NXCDuplicateTrapCfgEntry(NXC_TRAP_CFG_ENTRY *src)
112 {
113 NXC_TRAP_CFG_ENTRY *dst = (NXC_TRAP_CFG_ENTRY *)malloc(sizeof(NXC_TRAP_CFG_ENTRY));
114 NXCCopyTrapCfgEntry(dst, src);
115 return dst;
116 }
117
118
119 //
120 // Destroy NXC_TRAP_CFG_ENTRY
121 //
122
123 void LIBNXCL_EXPORTABLE NXCDestroyTrapCfgEntry(NXC_TRAP_CFG_ENTRY *e)
124 {
125 if (e == NULL)
126 return;
127
128 for(DWORD i = 0; i < e->dwNumMaps; i++)
129 safe_free(e->pMaps[i].pdwObjectId);
130 safe_free(e->pMaps);
131 safe_free(e->pdwObjectId);
132 free(e);
133 }
134
135
136 //
137 // Load trap configuration from server
138 //
139
140 DWORD LIBNXCL_EXPORTABLE NXCLoadTrapCfg(NXC_SESSION hSession, DWORD *pdwNumTraps, NXC_TRAP_CFG_ENTRY **ppTrapList)
141 {
142 CSCPMessage msg, *pResponse;
143 DWORD dwRqId, dwRetCode = RCC_SUCCESS, dwNumTraps = 0, dwTrapId = 0;
144 NXC_TRAP_CFG_ENTRY *pList = NULL;
145
146 dwRqId = ((NXCL_Session *)hSession)->CreateRqId();
147
148 msg.SetCode(CMD_LOAD_TRAP_CFG);
149 msg.SetId(dwRqId);
150 ((NXCL_Session *)hSession)->SendMsg(&msg);
151
152 dwRetCode = ((NXCL_Session *)hSession)->WaitForRCC(dwRqId);
153 if (dwRetCode == RCC_SUCCESS)
154 {
155 do
156 {
157 pResponse = ((NXCL_Session *)hSession)->WaitForMessage(CMD_TRAP_CFG_RECORD, dwRqId);
158 if (pResponse != NULL)
159 {
160 dwTrapId = pResponse->GetVariableLong(VID_TRAP_ID);
161 if (dwTrapId != 0) // 0 is end of list indicator
162 {
163 pList = (NXC_TRAP_CFG_ENTRY *)realloc(pList,
164 sizeof(NXC_TRAP_CFG_ENTRY) * (dwNumTraps + 1));
165 pList[dwNumTraps].dwId = dwTrapId;
166 TrapCfgFromMsg(pResponse, &pList[dwNumTraps]);
167 dwNumTraps++;
168 }
169 delete pResponse;
170 }
171 else
172 {
173 dwRetCode = RCC_TIMEOUT;
174 dwTrapId = 0;
175 }
176 }
177 while(dwTrapId != 0);
178 }
179
180 // Destroy results on failure or save on success
181 if (dwRetCode == RCC_SUCCESS)
182 {
183 *ppTrapList = pList;
184 *pdwNumTraps = dwNumTraps;
185 }
186 else
187 {
188 safe_free(pList);
189 *ppTrapList = NULL;
190 *pdwNumTraps = 0;
191 }
192
193 return dwRetCode;
194 }
195
196
197 //
198 // Destroy list of traps
199 //
200
201 void LIBNXCL_EXPORTABLE NXCDestroyTrapList(DWORD dwNumTraps, NXC_TRAP_CFG_ENTRY *pTrapList)
202 {
203 DWORD i, j;
204
205 if (pTrapList == NULL)
206 return;
207
208 for(i = 0; i < dwNumTraps; i++)
209 {
210 for(j = 0; j < pTrapList[i].dwNumMaps; j++)
211 safe_free(pTrapList[i].pMaps[j].pdwObjectId);
212 safe_free(pTrapList[i].pMaps);
213 safe_free(pTrapList[i].pdwObjectId);
214 }
215 free(pTrapList);
216 }
217
218
219 //
220 // Delete trap configuration record by ID
221 //
222
223 DWORD LIBNXCL_EXPORTABLE NXCDeleteTrap(NXC_SESSION hSession, DWORD dwTrapId)
224 {
225 CSCPMessage msg;
226 DWORD dwRqId;
227
228 dwRqId = ((NXCL_Session *)hSession)->CreateRqId();
229
230 msg.SetCode(CMD_DELETE_TRAP);
231 msg.SetId(dwRqId);
232 msg.SetVariable(VID_TRAP_ID, dwTrapId);
233 ((NXCL_Session *)hSession)->SendMsg(&msg);
234
235 return ((NXCL_Session *)hSession)->WaitForRCC(dwRqId);
236 }
237
238
239 //
240 // Create new trap configuration record
241 //
242
243 DWORD LIBNXCL_EXPORTABLE NXCCreateTrap(NXC_SESSION hSession, DWORD *pdwTrapId)
244 {
245 CSCPMessage msg, *pResponse;
246 DWORD dwRqId, dwResult;
247
248 dwRqId = ((NXCL_Session *)hSession)->CreateRqId();
249
250 msg.SetCode(CMD_CREATE_TRAP);
251 msg.SetId(dwRqId);
252 ((NXCL_Session *)hSession)->SendMsg(&msg);
253
254 pResponse = ((NXCL_Session *)hSession)->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId);
255 if (pResponse != NULL)
256 {
257 dwResult = pResponse->GetVariableLong(VID_RCC);
258 if (dwResult == RCC_SUCCESS)
259 *pdwTrapId = pResponse->GetVariableLong(VID_TRAP_ID);
260 delete pResponse;
261 }
262 else
263 {
264 dwResult = RCC_TIMEOUT;
265 }
266
267 return dwResult;
268 }
269
270
271 //
272 // Update trap configuration record
273 //
274
275 DWORD LIBNXCL_EXPORTABLE NXCModifyTrap(NXC_SESSION hSession, NXC_TRAP_CFG_ENTRY *pTrap)
276 {
277 CSCPMessage msg;
278 DWORD i, dwRqId, dwId1, dwId2, dwId3;
279
280 dwRqId = ((NXCL_Session *)hSession)->CreateRqId();
281
282 msg.SetCode(CMD_MODIFY_TRAP);
283 msg.SetId(dwRqId);
284 msg.SetVariable(VID_TRAP_ID, pTrap->dwId);
285 msg.SetVariable(VID_TRAP_OID_LEN, pTrap->dwOidLen);
286 msg.SetVariableToInt32Array(VID_TRAP_OID, pTrap->dwOidLen, pTrap->pdwObjectId);
287 msg.SetVariable(VID_EVENT_CODE, pTrap->dwEventCode);
288 msg.SetVariable(VID_DESCRIPTION, pTrap->szDescription);
289 msg.SetVariable(VID_USER_TAG, pTrap->szUserTag);
290 msg.SetVariable(VID_TRAP_NUM_MAPS, pTrap->dwNumMaps);
291 for(i = 0, dwId1 = VID_TRAP_PLEN_BASE, dwId2 = VID_TRAP_PNAME_BASE, dwId3 = VID_TRAP_PDESCR_BASE;
292 i < pTrap->dwNumMaps; i++, dwId1++, dwId2++, dwId3++)
293 {
294 msg.SetVariable(dwId1, pTrap->pMaps[i].dwOidLen);
295 if ((pTrap->pMaps[i].dwOidLen & 0x80000000) == 0)
296 msg.SetVariableToInt32Array(dwId2, pTrap->pMaps[i].dwOidLen, pTrap->pMaps[i].pdwObjectId);
297 msg.SetVariable(dwId3, pTrap->pMaps[i].szDescription);
298 }
299 ((NXCL_Session *)hSession)->SendMsg(&msg);
300
301 return ((NXCL_Session *)hSession)->WaitForRCC(dwRqId);
302 }
303
304
305 //
306 // Process SNMP trap log records coming from server
307 //
308
309 void ProcessTrapLogRecords(NXCL_Session *pSession, CSCPMessage *pMsg)
310 {
311 DWORD i, dwNumRecords, dwId;
312 NXC_SNMP_TRAP_LOG_RECORD rec;
313 int nOrder;
314
315 dwNumRecords = pMsg->GetVariableLong(VID_NUM_RECORDS);
316 nOrder = (int)pMsg->GetVariableShort(VID_RECORDS_ORDER);
317 DebugPrintf(_T("ProcessTrapLogRecords(): %d records in message, in %s order"),
318 dwNumRecords, (nOrder == RECORD_ORDER_NORMAL) ? _T("normal") : _T("reversed"));
319 for(i = 0, dwId = VID_TRAP_LOG_MSG_BASE; i < dwNumRecords; i++)
320 {
321 rec.qwId = pMsg->GetVariableInt64(dwId++);
322 rec.dwTimeStamp = pMsg->GetVariableLong(dwId++);
323 rec.dwIpAddr = pMsg->GetVariableLong(dwId++);
324 rec.dwObjectId = pMsg->GetVariableLong(dwId++);
325 pMsg->GetVariableStr(dwId++, rec.szTrapOID, MAX_DB_STRING);
326 rec.pszTrapVarbinds = pMsg->GetVariableStr(dwId++);
327
328 // Call client's callback to handle new record
329 pSession->callEventHandler(NXC_EVENT_NEW_SNMP_TRAP, nOrder, &rec);
330 free(rec.pszTrapVarbinds);
331 }
332
333 // Notify requestor thread if all messages was received
334 if (pMsg->IsEndOfSequence())
335 pSession->CompleteSync(SYNC_TRAP_LOG, RCC_SUCCESS);
336 }
337
338
339 //
340 // Synchronize trap log
341 // This function is NOT REENTRANT
342 //
343
344 DWORD LIBNXCL_EXPORTABLE NXCSyncSNMPTrapLog(NXC_SESSION hSession, DWORD dwMaxRecords)
345 {
346 CSCPMessage msg;
347 DWORD dwRetCode, dwRqId;
348
349 dwRqId = ((NXCL_Session *)hSession)->CreateRqId();
350 ((NXCL_Session *)hSession)->PrepareForSync(SYNC_TRAP_LOG);
351
352 msg.SetCode(CMD_GET_TRAP_LOG);
353 msg.SetId(dwRqId);
354 msg.SetVariable(VID_MAX_RECORDS, dwMaxRecords);
355 ((NXCL_Session *)hSession)->SendMsg(&msg);
356
357 dwRetCode = ((NXCL_Session *)hSession)->WaitForRCC(dwRqId);
358 if (dwRetCode == RCC_SUCCESS)
359 dwRetCode = ((NXCL_Session *)hSession)->WaitForSync(SYNC_TRAP_LOG, INFINITE);
360 else
361 ((NXCL_Session *)hSession)->UnlockSyncOp(SYNC_TRAP_LOG);
362
363 return dwRetCode;
364 }
365
366
367 //
368 // Get read-only trap configuration without parameter bindings
369 //
370
371 DWORD LIBNXCL_EXPORTABLE NXCGetTrapCfgRO(NXC_SESSION hSession, DWORD *pdwNumTraps,
372 NXC_TRAP_CFG_ENTRY **ppTrapList)
373 {
374 CSCPMessage msg, *pResponse;
375 DWORD i, dwId, dwRqId, dwRetCode;
376
377 dwRqId = ((NXCL_Session *)hSession)->CreateRqId();
378
379 msg.SetCode(CMD_GET_TRAP_CFG_RO);
380 msg.SetId(dwRqId);
381 ((NXCL_Session *)hSession)->SendMsg(&msg);
382
383 pResponse = ((NXCL_Session *)hSession)->WaitForMessage(CMD_REQUEST_COMPLETED, dwRqId);
384 if (pResponse != NULL)
385 {
386 dwRetCode = pResponse->GetVariableLong(VID_RCC);
387 if (dwRetCode == RCC_SUCCESS)
388 {
389 *pdwNumTraps = pResponse->GetVariableLong(VID_NUM_TRAPS);
390 *ppTrapList = (NXC_TRAP_CFG_ENTRY *)malloc(sizeof(NXC_TRAP_CFG_ENTRY) * (*pdwNumTraps));
391 memset(*ppTrapList, 0, sizeof(NXC_TRAP_CFG_ENTRY) * (*pdwNumTraps));
392
393 for(i = 0, dwId = VID_TRAP_INFO_BASE; i < *pdwNumTraps; i++, dwId += 5)
394 {
395 (*ppTrapList)[i].dwId = pResponse->GetVariableLong(dwId++);
396 (*ppTrapList)[i].dwOidLen = pResponse->GetVariableLong(dwId++);
397 (*ppTrapList)[i].pdwObjectId = (DWORD *)malloc(sizeof(DWORD) * (*ppTrapList)[i].dwOidLen);
398 pResponse->GetVariableInt32Array(dwId++, (*ppTrapList)[i].dwOidLen, (*ppTrapList)[i].pdwObjectId);
399 (*ppTrapList)[i].dwEventCode = pResponse->GetVariableLong(dwId++);
400 pResponse->GetVariableStr(dwId++, (*ppTrapList)[i].szDescription, MAX_DB_STRING);
401 }
402 }
403 delete pResponse;
404 }
405 else
406 {
407 dwRetCode = RCC_TIMEOUT;
408 }
409 return dwRetCode;
410 }