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