fixed bug in node's primary IP address change
[public/netxms.git] / src / server / core / netsrv.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
4fe87cdc 3** Copyright (C) 2003-2010 Victor Kirhenshtein
5039dede
AK
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: netsrv.cpp
20**
21**/
22
23#include "nxcore.h"
24
25
26//
27// Default constructor
28//
29
30NetworkService::NetworkService()
31 :NetObj()
32{
33 m_iServiceType = NETSRV_HTTP;
34 m_pHostNode = NULL;
35 m_dwPollerNode = 0;
36 m_wProto = IPPROTO_TCP;
37 m_wPort = 80;
38 m_pszRequest = NULL;
39 m_pszResponse = NULL;
40 m_iPendingStatus = -1;
41 m_iPollCount = 0;
42 m_iRequiredPollCount = 0; // Use system default
43}
44
171c2fd6
VK
45/**
46 * Extended constructor
47 * Note that pszRequest and pszResponse should be dynamically allocated
48 * and they will be freed by object's destructor!!!
49 */
5039dede
AK
50NetworkService::NetworkService(int iServiceType, WORD wProto, WORD wPort,
51 TCHAR *pszRequest, TCHAR *pszResponse,
52 Node *pHostNode, DWORD dwPollerNode)
53{
54 m_iServiceType = iServiceType;
55 m_pHostNode = pHostNode;
56 m_dwPollerNode = dwPollerNode;
57 m_wProto = wProto;
58 m_wPort = wPort;
59 m_pszRequest = pszRequest;
60 m_pszResponse = pszResponse;
61 m_iPendingStatus = -1;
62 m_iPollCount = 0;
63 m_iRequiredPollCount = 0; // Use system default
64 m_bIsHidden = TRUE;
65}
66
67
68//
69// Destructor
70//
71
72NetworkService::~NetworkService()
73{
74 safe_free(m_pszRequest);
75 safe_free(m_pszResponse);
76}
77
78
79//
80// Save object to database
81//
82
83BOOL NetworkService::SaveToDB(DB_HANDLE hdb)
84{
85 TCHAR *pszEscRequest, *pszEscResponse, szQuery[16384], szIpAddr[32];
86 DB_RESULT hResult;
87 BOOL bNewObject = TRUE;
88
89 LockData();
90
89135050 91 saveCommonProperties(hdb);
5039dede
AK
92
93 // Check for object's existence in database
35f836fe 94 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("SELECT id FROM network_services WHERE id=%d"), m_dwId);
5039dede
AK
95 hResult = DBSelect(hdb, szQuery);
96 if (hResult != NULL)
97 {
98 if (DBGetNumRows(hResult) > 0)
99 bNewObject = FALSE;
100 DBFreeResult(hResult);
101 }
102
103 // Form and execute INSERT or UPDATE query
104 pszEscRequest = EncodeSQLString(CHECK_NULL_EX(m_pszRequest));
105 pszEscResponse = EncodeSQLString(CHECK_NULL_EX(m_pszResponse));
106 if (bNewObject)
107 {
dda7c270 108 _sntprintf(szQuery, 16384, _T("INSERT INTO network_services (id,node_id,")
4fe87cdc
VK
109 _T("service_type,ip_bind_addr,ip_proto,ip_port,")
110 _T("check_request,check_responce,poller_node_id,")
dda7c270
VK
111 _T("required_polls) VALUES ")
112 _T("(%d,%d,%d,'%s',%d,%d,'%s','%s',%d,%d)"),
5039dede
AK
113 m_dwId, m_pHostNode->Id(), m_iServiceType,
114 IpToStr(m_dwIpAddr, szIpAddr), m_wProto, m_wPort, pszEscRequest,
115 pszEscResponse, m_dwPollerNode, m_iRequiredPollCount);
116 }
117 else
118 {
dda7c270 119 _sntprintf(szQuery, 16384, _T("UPDATE network_services SET node_id=%d,")
4fe87cdc
VK
120 _T("service_type=%d,ip_bind_addr='%s',")
121 _T("ip_proto=%d,ip_port=%d,check_request='%s',")
122 _T("check_responce='%s',poller_node_id=%d,")
dda7c270 123 _T("required_polls=%d WHERE id=%d"),
5039dede
AK
124 m_pHostNode->Id(), m_iServiceType,
125 IpToStr(m_dwIpAddr, szIpAddr), m_wProto, m_wPort, pszEscRequest,
126 pszEscResponse, m_dwPollerNode, m_iRequiredPollCount, m_dwId);
127 }
128 free(pszEscRequest);
129 free(pszEscResponse);
130 DBQuery(hdb, szQuery);
131
132 // Save access list
89135050 133 saveACLToDB(hdb);
5039dede
AK
134
135 // Unlock object and clear modification flag
136 m_bIsModified = FALSE;
137 UnlockData();
138 return TRUE;
139}
140
141
142//
143// Load properties from database
144//
145
146BOOL NetworkService::CreateFromDB(DWORD dwId)
147{
148 TCHAR szQuery[256];
149 DB_RESULT hResult;
150 DWORD dwHostNodeId;
151 NetObj *pObject;
152 BOOL bResult = FALSE;
153
154 m_dwId = dwId;
155
89135050 156 if (!loadCommonProperties())
5039dede
AK
157 return FALSE;
158
dda7c270 159 _sntprintf(szQuery, 256, _T("SELECT node_id,service_type,")
4fe87cdc 160 _T("ip_bind_addr,ip_proto,ip_port,check_request,check_responce,")
dda7c270 161 _T("poller_node_id,required_polls FROM network_services WHERE id=%d"), dwId);
5039dede
AK
162 hResult = DBSelect(g_hCoreDB, szQuery);
163 if (hResult == NULL)
164 return FALSE; // Query failed
165
166 if (DBGetNumRows(hResult) != 0)
167 {
168 dwHostNodeId = DBGetFieldULong(hResult, 0, 0);
169 m_iServiceType = DBGetFieldLong(hResult, 0, 1);
170 m_dwIpAddr = DBGetFieldIPAddr(hResult, 0, 2);
171 m_wProto = (WORD)DBGetFieldULong(hResult, 0, 3);
172 m_wPort = (WORD)DBGetFieldULong(hResult, 0, 4);
173 m_pszRequest = DBGetField(hResult, 0, 5, NULL, 0);
174 DecodeSQLString(m_pszRequest);
175 m_pszResponse = DBGetField(hResult, 0, 6, NULL, 0);
176 DecodeSQLString(m_pszResponse);
177 m_dwPollerNode = DBGetFieldULong(hResult, 0, 7);
178 m_iRequiredPollCount = DBGetFieldLong(hResult, 0, 8);
179
180 // Link service to node
181 if (!m_bIsDeleted)
182 {
183 // Find host node
184 pObject = FindObjectById(dwHostNodeId);
185 if (pObject == NULL)
186 {
35f836fe 187 nxlog_write(MSG_INVALID_NODE_ID_EX, EVENTLOG_ERROR_TYPE, "dds", dwId, dwHostNodeId, _T("network service"));
5039dede
AK
188 }
189 else if (pObject->Type() != OBJECT_NODE)
190 {
191 nxlog_write(MSG_NODE_NOT_NODE, EVENTLOG_ERROR_TYPE, "dd", dwId, dwHostNodeId);
192 }
193 else
194 {
195 m_pHostNode = (Node *)pObject;
196 pObject->AddChild(this);
197 AddParent(pObject);
198 bResult = TRUE;
199 }
200
201 // Check that polling node ID is valid
202 if ((m_dwPollerNode != 0) && bResult)
203 {
204 pObject = FindObjectById(m_dwPollerNode);
205 if (pObject == NULL)
206 {
207 nxlog_write(MSG_INVALID_NODE_ID_EX, EVENTLOG_ERROR_TYPE,
35f836fe 208 "dds", dwId, m_dwPollerNode, _T("network service"));
5039dede
AK
209 bResult = FALSE;
210 }
211 else if (pObject->Type() != OBJECT_NODE)
212 {
213 nxlog_write(MSG_NODE_NOT_NODE, EVENTLOG_ERROR_TYPE, "dd", dwId, m_dwPollerNode);
214 bResult = FALSE;
215 }
216 }
217 }
218 else
219 {
220 bResult = TRUE;
221 }
222 }
223
224 DBFreeResult(hResult);
225
226 // Load access list
89135050 227 loadACLFromDB();
5039dede
AK
228
229 return bResult;
230}
231
232
233//
234// Delete object from database
235//
236
60a99e76 237BOOL NetworkService::DeleteFromDB()
5039dede
AK
238{
239 TCHAR szQuery[128];
240 BOOL bSuccess;
241
242 bSuccess = NetObj::DeleteFromDB();
243 if (bSuccess)
244 {
245 _sntprintf(szQuery, 128, _T("DELETE FROM network_services WHERE id=%d"), m_dwId);
246 QueueSQLRequest(szQuery);
247 }
248 return bSuccess;
249}
250
251
252//
253// Create CSCP message with object's data
254//
255
256void NetworkService::CreateMessage(CSCPMessage *pMsg)
257{
258 NetObj::CreateMessage(pMsg);
259 pMsg->SetVariable(VID_SERVICE_TYPE, (WORD)m_iServiceType);
260 pMsg->SetVariable(VID_IP_PROTO, m_wProto);
261 pMsg->SetVariable(VID_IP_PORT, m_wPort);
262 pMsg->SetVariable(VID_POLLER_NODE_ID, m_dwPollerNode);
263 pMsg->SetVariable(VID_SERVICE_REQUEST, CHECK_NULL_EX(m_pszRequest));
264 pMsg->SetVariable(VID_SERVICE_RESPONSE, CHECK_NULL_EX(m_pszResponse));
265 pMsg->SetVariable(VID_REQUIRED_POLLS, (WORD)m_iRequiredPollCount);
266}
267
268
269//
270// Modify object from message
271//
272
273DWORD NetworkService::ModifyFromMessage(CSCPMessage *pRequest, BOOL bAlreadyLocked)
274{
275 if (!bAlreadyLocked)
276 LockData();
277
278 // Polling node
279 if (pRequest->IsVariableExist(VID_POLLER_NODE_ID))
280 {
281 DWORD dwNodeId;
282
283 dwNodeId = pRequest->GetVariableLong(VID_POLLER_NODE_ID);
284 if (dwNodeId == 0)
285 {
286 m_dwPollerNode = 0;
287 }
288 else
289 {
290 NetObj *pObject;
291
292 pObject = FindObjectById(dwNodeId);
293 if (pObject != NULL)
294 {
295 if (pObject->Type() == OBJECT_NODE)
296 {
297 m_dwPollerNode = dwNodeId;
298 }
299 else
300 {
301 UnlockData();
302 return RCC_INVALID_OBJECT_ID;
303 }
304 }
305 else
306 {
307 UnlockData();
308 return RCC_INVALID_OBJECT_ID;
309 }
310 }
311 }
312
313 // Listen IP address
314 if (pRequest->IsVariableExist(VID_IP_ADDRESS))
315 m_dwIpAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
316
317 // Service type
318 if (pRequest->IsVariableExist(VID_SERVICE_TYPE))
319 m_iServiceType = (int)pRequest->GetVariableShort(VID_SERVICE_TYPE);
320
321 // IP protocol
322 if (pRequest->IsVariableExist(VID_IP_PROTO))
323 m_wProto = pRequest->GetVariableShort(VID_IP_PROTO);
324
325 // TCP/UDP port
326 if (pRequest->IsVariableExist(VID_IP_PORT))
327 m_wPort = pRequest->GetVariableShort(VID_IP_PORT);
328
329 // Number of required polls
330 if (pRequest->IsVariableExist(VID_REQUIRED_POLLS))
331 m_iRequiredPollCount = (int)pRequest->GetVariableShort(VID_REQUIRED_POLLS);
332
333 // Check request
334 if (pRequest->IsVariableExist(VID_SERVICE_REQUEST))
335 {
336 safe_free(m_pszRequest);
337 m_pszRequest = pRequest->GetVariableStr(VID_SERVICE_REQUEST);
338 }
339
340 // Check response
341 if (pRequest->IsVariableExist(VID_SERVICE_RESPONSE))
342 {
343 safe_free(m_pszResponse);
344 m_pszResponse = pRequest->GetVariableStr(VID_SERVICE_RESPONSE);
345 }
346
347 return NetObj::ModifyFromMessage(pRequest, TRUE);
348}
349
350
351//
352// Perform status poll on network service
353//
354
355void NetworkService::StatusPoll(ClientSession *pSession, DWORD dwRqId,
356 Node *pPollerNode, Queue *pEventQueue)
357{
358 int oldStatus = m_iStatus, newStatus;
359 Node *pNode;
360
361 m_pPollRequestor = pSession;
362 if (m_pHostNode == NULL)
363 {
364 m_iStatus = STATUS_UNKNOWN;
365 return; // Service without host node, which is VERY strange
366 }
367
60a99e76
VK
368 SendPollerMsg(dwRqId, _T(" Starting status poll on network service %s\r\n"), m_szName);
369 SendPollerMsg(dwRqId, _T(" Current service status is %s\r\n"), g_szStatusTextSmall[m_iStatus]);
5039dede
AK
370
371 if (m_dwPollerNode != 0)
372 {
373 pNode = (Node *)FindObjectById(m_dwPollerNode);
374 if (pNode != NULL)
375 pNode->IncRefCount();
376 else
377 pNode = pPollerNode;
378 }
379 else
380 {
381 pNode = pPollerNode;
382 }
383
384 if (pNode != NULL)
385 {
386 TCHAR szBuffer[16];
387 DWORD dwStatus;
388
4fe87cdc 389 SendPollerMsg(dwRqId, _T(" Polling service from node %s [%s]\r\n"),
5039dede
AK
390 pNode->Name(), IpToStr(pNode->IpAddr(), szBuffer));
391 if (pNode->CheckNetworkService(&dwStatus,
392 (m_dwIpAddr == 0) ? m_pHostNode->IpAddr() : m_dwIpAddr,
393 m_iServiceType, m_wPort, m_wProto,
394 m_pszRequest, m_pszResponse) == ERR_SUCCESS)
395 {
396 newStatus = (dwStatus == 0) ? STATUS_NORMAL : STATUS_CRITICAL;
4fe87cdc 397 SendPollerMsg(dwRqId, _T(" Agent reports service status [%d]\r\n"), dwStatus);
5039dede
AK
398 }
399 else
400 {
4fe87cdc 401 SendPollerMsg(dwRqId, _T(" Unable to check service status due to agent or communication error\r\n"));
5039dede
AK
402 newStatus = STATUS_UNKNOWN;
403 }
404
405 if (pNode != pPollerNode)
406 pNode->DecRefCount();
407 }
408 else
409 {
4fe87cdc 410 SendPollerMsg(dwRqId, _T(" Unable to find node object for poll\r\n"));
5039dede
AK
411 newStatus = STATUS_UNKNOWN;
412 }
413
414 if (newStatus != oldStatus)
415 {
416 if (newStatus == m_iPendingStatus)
417 {
418 m_iPollCount++;
419 }
420 else
421 {
422 m_iPendingStatus = newStatus;
423 m_iPollCount = 1;
424 }
425
426 if (m_iPollCount >= ((m_iRequiredPollCount > 0) ? m_iRequiredPollCount : g_nRequiredPolls))
427 {
428 m_iStatus = newStatus;
429 m_iPendingStatus = -1; // Invalidate pending status
35f836fe 430 SendPollerMsg(dwRqId, _T(" Service status changed to %s\r\n"), g_szStatusTextSmall[m_iStatus]);
5039dede
AK
431 PostEventEx(pEventQueue, m_iStatus == STATUS_NORMAL ? EVENT_SERVICE_UP :
432 (m_iStatus == STATUS_CRITICAL ? EVENT_SERVICE_DOWN : EVENT_SERVICE_UNKNOWN),
433 m_pHostNode->Id(), "sdd", m_szName, m_dwId, m_iServiceType);
434 LockData();
435 Modify();
436 UnlockData();
437 }
438 }
35f836fe 439 SendPollerMsg(dwRqId, _T(" Finished status poll on network service %s\r\n"), m_szName);
5039dede
AK
440}
441
442
443//
444// Handler for object deletion
445//
446
447void NetworkService::OnObjectDelete(DWORD dwObjectId)
448{
f5d16551 449 LockData();
5039dede
AK
450 if (dwObjectId == m_dwPollerNode)
451 {
452 // If deleted object is our poller node, change it to default
453 m_dwPollerNode = 0;
454 Modify();
455 DbgPrintf(3, _T("Service \"%s\": poller node %d deleted"), m_szName, dwObjectId);
456 }
f5d16551 457 UnlockData();
5039dede 458}