object save optimization - object properties divided into groups and anly modified...
[public/netxms.git] / src / server / core / netsrv.cpp
CommitLineData
e83d726c 1/*
5039dede 2** NetXMS - Network Management System
db091a1f 3** Copyright (C) 2003-2016 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
c1482463
VK
25/**
26 * Default constructor
27 */
28NetworkService::NetworkService() : NetObj()
5039dede 29{
c59466d2
VK
30 m_serviceType = NETSRV_HTTP;
31 m_hostNode = NULL;
32 m_pollerNode = 0;
33 m_proto = IPPROTO_TCP;
34 m_port = 80;
35 m_request = NULL;
36 m_response = NULL;
37 m_pendingStatus = -1;
38 m_pollCount = 0;
39 m_requiredPollCount = 0; // Use system default
b8014eee 40 m_responseTime = 0;
5039dede
AK
41}
42
171c2fd6
VK
43/**
44 * Extended constructor
45 * Note that pszRequest and pszResponse should be dynamically allocated
46 * and they will be freed by object's destructor!!!
47 */
5039dede
AK
48NetworkService::NetworkService(int iServiceType, WORD wProto, WORD wPort,
49 TCHAR *pszRequest, TCHAR *pszResponse,
967893bb 50 Node *pHostNode, UINT32 dwPollerNode) : NetObj()
5039dede 51{
c59466d2
VK
52 m_serviceType = iServiceType;
53 m_hostNode = pHostNode;
54 m_pollerNode = dwPollerNode;
55 m_proto = wProto;
56 m_port = wPort;
57 m_request = pszRequest;
58 m_response = pszResponse;
59 m_pendingStatus = -1;
60 m_pollCount = 0;
61 m_requiredPollCount = 0; // Use system default
b8014eee 62 m_responseTime = 0;
01152a54 63 m_isHidden = true;
5039dede
AK
64}
65
c1482463
VK
66/**
67 * Destructor
68 */
5039dede
AK
69NetworkService::~NetworkService()
70{
e4926628
VK
71 free(m_request);
72 free(m_response);
5039dede
AK
73}
74
c1482463
VK
75/**
76 * Save object to database
77 */
b4277312 78bool NetworkService::saveToDatabase(DB_HANDLE hdb)
5039dede 79{
c42b4551 80 lockProperties();
5039dede 81
3d48d1b4 82 bool success = saveCommonProperties(hdb);
5039dede 83
3d48d1b4 84 if (success && (m_modified & MODIFY_OTHER))
5039dede 85 {
3d48d1b4
VK
86 DB_STATEMENT hStmt;
87 if (IsDatabaseRecordExist(hdb, _T("network_services"), _T("id"), m_id))
88 {
89 hStmt = DBPrepare(hdb, _T("UPDATE network_services SET node_id=?,")
90 _T("service_type=?,ip_bind_addr=?,")
91 _T("ip_proto=?,ip_port=?,check_request=?,")
92 _T("check_responce=?,poller_node_id=?,")
93 _T("required_polls=? WHERE id=?"));
94 }
95 else
96 {
97 hStmt = DBPrepare(hdb, _T("INSERT INTO network_services (node_id,")
98 _T("service_type,ip_bind_addr,ip_proto,ip_port,")
99 _T("check_request,check_responce,poller_node_id,")
100 _T("required_polls,id) VALUES (?,?,?,?,?,?,?,?,?,?)"));
101 }
102 if (hStmt != NULL)
103 {
104 TCHAR szIpAddr[64];
105
106 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_hostNode->getId());
107 DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, (LONG)m_serviceType);
108 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, m_ipAddress.toString(szIpAddr), DB_BIND_STATIC);
109 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (UINT32)m_proto);
110 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (UINT32)m_port);
111 DBBind(hStmt, 6, DB_SQLTYPE_TEXT, m_request, DB_BIND_STATIC);
112 DBBind(hStmt, 7, DB_SQLTYPE_TEXT, m_response, DB_BIND_STATIC);
113 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, m_pollerNode);
114 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, (LONG)m_requiredPollCount);
115 DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, m_id);
116
117 success = DBExecute(hStmt);
118
119 DBFreeStatement(hStmt);
120 }
121 else
122 {
123 success = false;
124 }
5039dede 125 }
e83d726c 126
5039dede 127 // Save access list
3d48d1b4
VK
128 if (success)
129 success = saveACLToDB(hdb);
5039dede
AK
130
131 // Unlock object and clear modification flag
3d48d1b4 132 m_modified = 0;
c42b4551 133 unlockProperties();
3d48d1b4 134 return success;
5039dede
AK
135}
136
c1482463
VK
137/**
138 * Load properties from database
139 */
9bd1bace 140bool NetworkService::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
5039dede
AK
141{
142 TCHAR szQuery[256];
143 DB_RESULT hResult;
967893bb 144 UINT32 dwHostNodeId;
5039dede 145 NetObj *pObject;
9bd1bace 146 bool bResult = false;
5039dede 147
c42b4551 148 m_id = dwId;
5039dede 149
9bd1bace
VK
150 if (!loadCommonProperties(hdb))
151 return false;
5039dede 152
dda7c270 153 _sntprintf(szQuery, 256, _T("SELECT node_id,service_type,")
4fe87cdc 154 _T("ip_bind_addr,ip_proto,ip_port,check_request,check_responce,")
dda7c270 155 _T("poller_node_id,required_polls FROM network_services WHERE id=%d"), dwId);
9bd1bace 156 hResult = DBSelect(hdb, szQuery);
5039dede 157 if (hResult == NULL)
9bd1bace 158 return false; // Query failed
5039dede
AK
159
160 if (DBGetNumRows(hResult) != 0)
161 {
162 dwHostNodeId = DBGetFieldULong(hResult, 0, 0);
c59466d2 163 m_serviceType = DBGetFieldLong(hResult, 0, 1);
c75e9ee4 164 m_ipAddress = DBGetFieldInetAddr(hResult, 0, 2);
c59466d2
VK
165 m_proto = (WORD)DBGetFieldULong(hResult, 0, 3);
166 m_port = (WORD)DBGetFieldULong(hResult, 0, 4);
167 m_request = DBGetField(hResult, 0, 5, NULL, 0);
168 m_response = DBGetField(hResult, 0, 6, NULL, 0);
169 m_pollerNode = DBGetFieldULong(hResult, 0, 7);
170 m_requiredPollCount = DBGetFieldLong(hResult, 0, 8);
5039dede
AK
171
172 // Link service to node
01152a54 173 if (!m_isDeleted)
5039dede
AK
174 {
175 // Find host node
176 pObject = FindObjectById(dwHostNodeId);
177 if (pObject == NULL)
178 {
35f836fe 179 nxlog_write(MSG_INVALID_NODE_ID_EX, EVENTLOG_ERROR_TYPE, "dds", dwId, dwHostNodeId, _T("network service"));
5039dede 180 }
c42b4551 181 else if (pObject->getObjectClass() != OBJECT_NODE)
5039dede
AK
182 {
183 nxlog_write(MSG_NODE_NOT_NODE, EVENTLOG_ERROR_TYPE, "dd", dwId, dwHostNodeId);
184 }
185 else
186 {
c59466d2 187 m_hostNode = (Node *)pObject;
1f8be1f4
VK
188 pObject->addChild(this);
189 addParent(pObject);
9bd1bace 190 bResult = true;
5039dede
AK
191 }
192
193 // Check that polling node ID is valid
c59466d2 194 if ((m_pollerNode != 0) && bResult)
5039dede 195 {
c59466d2 196 pObject = FindObjectById(m_pollerNode);
5039dede
AK
197 if (pObject == NULL)
198 {
9bd1bace
VK
199 nxlog_write(MSG_INVALID_NODE_ID_EX, EVENTLOG_ERROR_TYPE, "dds", dwId, m_pollerNode, _T("network service"));
200 bResult = false;
5039dede 201 }
c42b4551 202 else if (pObject->getObjectClass() != OBJECT_NODE)
5039dede 203 {
c59466d2 204 nxlog_write(MSG_NODE_NOT_NODE, EVENTLOG_ERROR_TYPE, "dd", dwId, m_pollerNode);
9bd1bace 205 bResult = false;
5039dede
AK
206 }
207 }
208 }
209 else
210 {
9bd1bace 211 bResult = true;
5039dede
AK
212 }
213 }
214
215 DBFreeResult(hResult);
216
217 // Load access list
9bd1bace 218 loadACLFromDB(hdb);
5039dede
AK
219
220 return bResult;
221}
222
c1482463
VK
223/**
224 * Delete object from database
225 */
c42b4551 226bool NetworkService::deleteFromDatabase(DB_HANDLE hdb)
5039dede 227{
c42b4551 228 bool success = NetObj::deleteFromDatabase(hdb);
22ee6d97
VK
229 if (success)
230 success = executeQueryOnObject(hdb, _T("DELETE FROM network_services WHERE id=?"));
231 return success;
5039dede
AK
232}
233
c1482463
VK
234/**
235 * Create NXCP message with object's data
236 */
8fe90adb 237void NetworkService::fillMessageInternal(NXCPMessage *pMsg)
5039dede 238{
8fe90adb 239 NetObj::fillMessageInternal(pMsg);
b368969c 240 pMsg->setField(VID_SERVICE_TYPE, (WORD)m_serviceType);
70a027d2 241 pMsg->setField(VID_IP_ADDRESS, m_ipAddress);
b368969c
VK
242 pMsg->setField(VID_IP_PROTO, m_proto);
243 pMsg->setField(VID_IP_PORT, m_port);
244 pMsg->setField(VID_POLLER_NODE_ID, m_pollerNode);
245 pMsg->setField(VID_SERVICE_REQUEST, CHECK_NULL_EX(m_request));
246 pMsg->setField(VID_SERVICE_RESPONSE, CHECK_NULL_EX(m_response));
247 pMsg->setField(VID_REQUIRED_POLLS, (WORD)m_requiredPollCount);
248 pMsg->setField(VID_RESPONSE_TIME, m_responseTime);
5039dede
AK
249}
250
c1482463
VK
251/**
252 * Modify object from message
253 */
8fe90adb 254UINT32 NetworkService::modifyFromMessageInternal(NXCPMessage *pRequest)
5039dede 255{
5039dede 256 // Polling node
5c44534b 257 if (pRequest->isFieldExist(VID_POLLER_NODE_ID))
5039dede 258 {
967893bb 259 UINT32 dwNodeId;
5039dede 260
b368969c 261 dwNodeId = pRequest->getFieldAsUInt32(VID_POLLER_NODE_ID);
5039dede
AK
262 if (dwNodeId == 0)
263 {
c59466d2 264 m_pollerNode = 0;
5039dede
AK
265 }
266 else
267 {
268 NetObj *pObject;
269
270 pObject = FindObjectById(dwNodeId);
271 if (pObject != NULL)
272 {
c42b4551 273 if (pObject->getObjectClass() == OBJECT_NODE)
5039dede 274 {
c59466d2 275 m_pollerNode = dwNodeId;
5039dede
AK
276 }
277 else
278 {
c42b4551 279 unlockProperties();
5039dede
AK
280 return RCC_INVALID_OBJECT_ID;
281 }
282 }
283 else
284 {
c42b4551 285 unlockProperties();
5039dede
AK
286 return RCC_INVALID_OBJECT_ID;
287 }
288 }
289 }
290
291 // Listen IP address
5c44534b 292 if (pRequest->isFieldExist(VID_IP_ADDRESS))
c75e9ee4 293 m_ipAddress = pRequest->getFieldAsInetAddress(VID_IP_ADDRESS);
5039dede
AK
294
295 // Service type
5c44534b 296 if (pRequest->isFieldExist(VID_SERVICE_TYPE))
b368969c 297 m_serviceType = (int)pRequest->getFieldAsUInt16(VID_SERVICE_TYPE);
5039dede
AK
298
299 // IP protocol
5c44534b 300 if (pRequest->isFieldExist(VID_IP_PROTO))
b368969c 301 m_proto = pRequest->getFieldAsUInt16(VID_IP_PROTO);
5039dede
AK
302
303 // TCP/UDP port
5c44534b 304 if (pRequest->isFieldExist(VID_IP_PORT))
b368969c 305 m_port = pRequest->getFieldAsUInt16(VID_IP_PORT);
5039dede
AK
306
307 // Number of required polls
5c44534b 308 if (pRequest->isFieldExist(VID_REQUIRED_POLLS))
b368969c 309 m_requiredPollCount = (int)pRequest->getFieldAsUInt16(VID_REQUIRED_POLLS);
5039dede
AK
310
311 // Check request
5c44534b 312 if (pRequest->isFieldExist(VID_SERVICE_REQUEST))
5039dede 313 {
c59466d2 314 safe_free(m_request);
b368969c 315 m_request = pRequest->getFieldAsString(VID_SERVICE_REQUEST);
5039dede
AK
316 }
317
318 // Check response
5c44534b 319 if (pRequest->isFieldExist(VID_SERVICE_RESPONSE))
5039dede 320 {
c59466d2 321 safe_free(m_response);
b368969c 322 m_response = pRequest->getFieldAsString(VID_SERVICE_RESPONSE);
5039dede
AK
323 }
324
8fe90adb 325 return NetObj::modifyFromMessageInternal(pRequest);
5039dede
AK
326}
327
c1482463
VK
328/**
329 * Perform status poll on network service
330 */
c59466d2 331void NetworkService::statusPoll(ClientSession *session, UINT32 rqId, Node *pollerNode, Queue *eventQueue)
5039dede 332{
db091a1f 333 int oldStatus = m_status, newStatus;
5039dede
AK
334 Node *pNode;
335
c59466d2
VK
336 m_pollRequestor = session;
337 if (m_hostNode == NULL)
5039dede 338 {
db091a1f 339 m_status = STATUS_UNKNOWN;
5039dede
AK
340 return; // Service without host node, which is VERY strange
341 }
342
c42b4551 343 sendPollerMsg(rqId, _T(" Starting status poll on network service %s\r\n"), m_name);
db091a1f 344 sendPollerMsg(rqId, _T(" Current service status is %s\r\n"), GetStatusAsText(m_status, true));
5039dede 345
c59466d2 346 if (m_pollerNode != 0)
5039dede 347 {
c59466d2 348 pNode = (Node *)FindObjectById(m_pollerNode);
5039dede 349 if (pNode != NULL)
21c9acce 350 pNode->incRefCount();
5039dede 351 else
c59466d2 352 pNode = pollerNode;
5039dede
AK
353 }
354 else
355 {
c59466d2 356 pNode = pollerNode;
5039dede
AK
357 }
358
359 if (pNode != NULL)
360 {
c75e9ee4 361 TCHAR szBuffer[64];
967893bb 362 UINT32 dwStatus;
5039dede 363
c59466d2 364 sendPollerMsg(rqId, _T(" Polling service from node %s [%s]\r\n"),
c75e9ee4 365 pNode->getName(), pNode->getIpAddress().toString(szBuffer));
e83d726c 366 if (pNode->checkNetworkService(&dwStatus,
82a0af5b 367 m_ipAddress.isValidUnicast() ? m_ipAddress : m_hostNode->getIpAddress(),
e83d726c 368 m_serviceType, m_port, m_proto,
b8014eee 369 m_request, m_response, &m_responseTime) == ERR_SUCCESS)
5039dede
AK
370 {
371 newStatus = (dwStatus == 0) ? STATUS_NORMAL : STATUS_CRITICAL;
c59466d2 372 sendPollerMsg(rqId, _T(" Agent reports service status [%d]\r\n"), dwStatus);
5039dede
AK
373 }
374 else
375 {
c59466d2 376 sendPollerMsg(rqId, _T(" Unable to check service status due to agent or communication error\r\n"));
5039dede
AK
377 newStatus = STATUS_UNKNOWN;
378 }
379
c59466d2 380 if (pNode != pollerNode)
21c9acce 381 pNode->decRefCount();
5039dede
AK
382 }
383 else
384 {
c59466d2 385 sendPollerMsg(rqId, _T(" Unable to find node object for poll\r\n"));
5039dede
AK
386 newStatus = STATUS_UNKNOWN;
387 }
388
c1482463 389 // Reset status to unknown if node has known network connectivity problems
a0cc56b3 390 if ((newStatus == STATUS_CRITICAL) && (pNode->getState() & DCSF_NETWORK_PATH_PROBLEM))
c1482463
VK
391 {
392 newStatus = STATUS_UNKNOWN;
c42b4551 393 DbgPrintf(6, _T("StatusPoll(%s): Status for network service %s reset to UNKNOWN"), pNode->getName(), m_name);
c1482463 394 }
e83d726c 395
5039dede
AK
396 if (newStatus != oldStatus)
397 {
c59466d2 398 if (newStatus == m_pendingStatus)
5039dede 399 {
c59466d2 400 m_pollCount++;
5039dede
AK
401 }
402 else
403 {
c59466d2
VK
404 m_pendingStatus = newStatus;
405 m_pollCount = 1;
5039dede
AK
406 }
407
c59466d2 408 if (m_pollCount >= ((m_requiredPollCount > 0) ? m_requiredPollCount : g_requiredPolls))
5039dede 409 {
db091a1f 410 m_status = newStatus;
c59466d2 411 m_pendingStatus = -1; // Invalidate pending status
db091a1f
VK
412 sendPollerMsg(rqId, _T(" Service status changed to %s\r\n"), GetStatusAsText(m_status, true));
413 PostEventEx(eventQueue, m_status == STATUS_NORMAL ? EVENT_SERVICE_UP :
414 (m_status == STATUS_CRITICAL ? EVENT_SERVICE_DOWN : EVENT_SERVICE_UNKNOWN),
c42b4551
VK
415 m_hostNode->getId(), "sdd", m_name, m_id, m_serviceType);
416 lockProperties();
3d48d1b4 417 setModified(MODIFY_RUNTIME);
c42b4551 418 unlockProperties();
5039dede
AK
419 }
420 }
c42b4551 421 sendPollerMsg(rqId, _T(" Finished status poll on network service %s\r\n"), m_name);
5039dede
AK
422}
423
c1482463
VK
424/**
425 * Handler for object deletion
426 */
967893bb 427void NetworkService::onObjectDelete(UINT32 dwObjectId)
5039dede 428{
c42b4551 429 lockProperties();
c59466d2 430 if (dwObjectId == m_pollerNode)
5039dede
AK
431 {
432 // If deleted object is our poller node, change it to default
c59466d2 433 m_pollerNode = 0;
3d48d1b4 434 setModified(MODIFY_OTHER);
c42b4551 435 DbgPrintf(3, _T("Service \"%s\": poller node %d deleted"), m_name, dwObjectId);
5039dede 436 }
c42b4551 437 unlockProperties();
5039dede 438}
950b229b
VK
439
440/**
441 * Serialize object to JSON
442 */
443json_t *NetworkService::toJson()
444{
445 json_t *root = NetObj::toJson();
446 json_object_set_new(root, "serviceType", json_integer(m_serviceType));
447 json_object_set_new(root, "pollerNode", json_integer(m_pollerNode));
448 json_object_set_new(root, "proto", json_integer(m_proto));
449 json_object_set_new(root, "port", json_integer(m_port));
450 json_object_set_new(root, "ipAddress", m_ipAddress.toJson());
451 json_object_set_new(root, "request", json_string_t(m_request));
452 json_object_set_new(root, "response", json_string_t(m_response));
453 json_object_set_new(root, "pendingStatus", json_integer(m_pendingStatus));
454 json_object_set_new(root, "pollCount", json_integer(m_pollCount));
455 json_object_set_new(root, "requiredPollCount", json_integer(m_requiredPollCount));
456 json_object_set_new(root, "responseTime", json_integer(m_responseTime));
457 return root;
458}