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