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