+ conditions should work
[public/netxms.git] / src / server / core / main.cpp
CommitLineData
9a19737f
VK
1/*
2** Project X - Network Management System
3** Copyright (C) 2003 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** $module: main.cpp
20**
21**/
22
23#include "nms_core.h"
3a2f672c
VK
24#ifdef _WIN32
25#include <conio.h>
26#endif /* _WIN32 */
27
78bf9c68 28void DumpUsers(void);
ecb7e1ee 29void DumpSessions(void);
78bf9c68 30
3a2f672c
VK
31
32//
33// Thread functions
34//
35
067f2689
VK
36void HouseKeeper(void *pArg);
37void DiscoveryThread(void *pArg);
38void Syncer(void *pArg);
39void NodePoller(void *pArg);
40void StatusPoller(void *pArg);
41void ConfigurationPoller(void *pArg);
42void EventProcessor(void *pArg);
43void WatchdogThread(void *pArg);
44void ClientListener(void *pArg);
3e4e127f 45void LocalAdminListener(void *pArg);
067f2689 46void DBWriteThread(void *pArg);
9a19737f
VK
47
48
49//
50// Global variables
51//
52
3e4e127f 53DWORD g_dwFlags = AF_USE_EVENT_LOG;
4385fa12
VK
54char g_szConfigFile[MAX_PATH] = DEFAULT_CONFIG_FILE;
55char g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE;
3a2f672c 56DB_HANDLE g_hCoreDB = 0;
48b1c0ac 57DWORD g_dwDiscoveryPollingInterval;
f00307b7 58DWORD g_dwStatusPollingInterval;
364aa19a 59DWORD g_dwConfigurationPollingInterval;
3a2f672c
VK
60
61
62//
63// Static data
64//
65
d16cf8a5 66static CONDITION m_hEventShutdown;
9a19737f
VK
67
68
69//
d627ae40
VK
70// Sleep for specified number of seconds or until system shutdown arrives
71// Function will return TRUE if shutdown event occurs
72//
73
74BOOL SleepAndCheckForShutdown(int iSeconds)
75{
d16cf8a5 76 return ConditionWait(m_hEventShutdown, iSeconds * 1000);
d627ae40
VK
77}
78
79
80//
48b1c0ac
VK
81// Load global configuration parameters
82//
83
d627ae40 84static void LoadGlobalConfig()
48b1c0ac 85{
364aa19a 86 g_dwDiscoveryPollingInterval = ConfigReadInt("DiscoveryPollingInterval", 900);
f00307b7 87 g_dwStatusPollingInterval = ConfigReadInt("StatusPollingInterval", 60);
364aa19a 88 g_dwConfigurationPollingInterval = ConfigReadInt("ConfigurationPollingInterval", 3600);
3e4e127f
VK
89 if (ConfigReadInt("EnableAccessControl", 1))
90 g_dwFlags |= AF_ENABLE_ACCESS_CONTROL;
91 if (ConfigReadInt("EnableEventsAccessControl", 1))
92 g_dwFlags |= AF_ENABLE_EVENTS_ACCESS_CONTROL;
3ea35b38
VK
93 if (ConfigReadInt("DeleteEmptySubnets", 1))
94 g_dwFlags |= AF_DELETE_EMPTY_SUBNETS;
5add75d8
VK
95 if (ConfigReadInt("EnableSNMPTraps", 1))
96 g_dwFlags |= AF_ENABLE_SNMP_TRAPD;
48b1c0ac
VK
97}
98
99
100//
9a19737f
VK
101// Server initialization
102//
103
104BOOL Initialize(void)
105{
f9b7e653 106 int i, iNumThreads;
c7ca9142
VK
107 DWORD dwAddr;
108 char szInfo[256];
347b5bc6 109
4385fa12 110 InitLog();
0ee0c807
VK
111
112#ifdef _WIN32
113 WSADATA wsaData;
114 WSAStartup(0x0002, &wsaData);
115#endif
116
e77547c2
VK
117 // Initialize SSL library
118 SSL_library_init();
119 SSL_load_error_strings();
120
067f2689
VK
121 // Create queue for delayed SQL queries
122 g_pLazyRequestQueue = new Queue(64, 16);
123
d7d76e50 124 // Initialize SNMP stuff
be0a5a53 125 SnmpInit();
d7d76e50 126
3a2f672c
VK
127 if (!DBInit())
128 return FALSE;
129
130 g_hCoreDB = DBConnect();
131 if (g_hCoreDB == 0)
132 {
133 WriteLog(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, NULL);
134 return FALSE;
135 }
136
c7ca9142
VK
137 // Initialize locks
138 if (!InitLocks(&dwAddr, szInfo))
139 {
140 if (dwAddr == UNLOCKED) // Some SQL problems
141 WriteLog(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
142 else // Database already locked by another server instance
143 WriteLog(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "as", dwAddr, szInfo);
144 return FALSE;
145 }
146
48b1c0ac
VK
147 // Load global configuration parameters
148 LoadGlobalConfig();
149
3a2f672c 150 // Create synchronization stuff
d16cf8a5 151 m_hEventShutdown = ConditionCreate(TRUE);
3a2f672c 152
3ea35b38
VK
153 // Setup unique identifiers table
154 if (!InitIdTable())
155 return FALSE;
156
da54bd8d
VK
157 // Load users from database
158 if (!LoadUsers())
347b5bc6
VK
159 {
160 WriteLog(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
da54bd8d 161 return FALSE;
347b5bc6 162 }
da54bd8d 163
2da1357c 164 // Initialize objects infrastructure and load objects from database
74b83361 165 ObjectsInit();
2da1357c
VK
166 if (!LoadObjects())
167 return FALSE;
74b83361 168
7e495d97
VK
169 // Load event actions
170 if (!LoadActions())
171 return FALSE;
172
c7ca9142
VK
173 // Initialize event handling subsystem
174 if (!InitEventSubsystem())
175 return FALSE;
176
1275c750
VK
177 // Initialize data collection subsystem
178 if (!InitDataCollector())
179 return FALSE;
180
f91fa4c2
VK
181 // Initialize watchdog
182 WatchdogInit();
183
3a2f672c 184 // Start threads
f91fa4c2 185 ThreadCreate(WatchdogThread, 0, NULL);
3a2f672c 186 ThreadCreate(HouseKeeper, 0, NULL);
74b83361 187 ThreadCreate(Syncer, 0, NULL);
a68e217b 188 ThreadCreate(NodePoller, 0, NULL);
f00307b7 189 ThreadCreate(StatusPoller, 0, NULL);
323f8bec 190 ThreadCreate(ConfigurationPoller, 0, NULL);
5d0ff6bd 191 ThreadCreate(ClientListener, 0, NULL);
3e4e127f
VK
192
193 // Start network discovery thread if required
194 if (ConfigReadInt("RunNetworkDiscovery", 1))
195 ThreadCreate(DiscoveryThread, 0, NULL);
196 else
197 CheckForMgmtNode();
198
f9b7e653
VK
199 // Start event processors
200 iNumThreads = ConfigReadInt("NumberOfEventProcessors", 1);
201 for(i = 0; i < iNumThreads; i++)
202 ThreadCreate(EventProcessor, 0, NULL);
4385fa12 203
067f2689
VK
204 // Start database "lazy" write thread
205 ThreadCreate(DBWriteThread, 0, NULL);
206
3e4e127f
VK
207 // Start local administartive interface listener if required
208 if (ConfigReadInt("EnableAdminInterface", 1))
209 ThreadCreate(LocalAdminListener, 0, NULL);
210
9a19737f
VK
211 return TRUE;
212}
213
214
215//
83f0529c
VK
216// Handler for client notification
217//
218
219static void NotifyClient(ClientSession *pSession, void *pArg)
220{
221 pSession->Notify(NX_NOTIFY_SHUTDOWN);
222}
223
224
225//
9a19737f
VK
226// Server shutdown
227//
228
229void Shutdown(void)
230{
83f0529c
VK
231 // Notify clients
232 EnumerateClientSessions(NotifyClient, NULL);
233
3a2f672c 234 WriteLog(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
c7ca9142 235 g_dwFlags |= AF_SHUTDOWN; // Set shutdown flag
d16cf8a5 236 ConditionSet(m_hEventShutdown);
c7ca9142
VK
237
238 g_pEventQueue->Put(INVALID_POINTER_VALUE); // Stop event processor
d627ae40
VK
239 ThreadSleep(5); // Give other threads a chance to terminate in a safe way
240 SaveObjects();
83f0529c 241 StopDBWriter();
c7ca9142
VK
242
243 // Remove database lock
244 DBQuery(g_hCoreDB, "UPDATE locks SET lock_status=-1,owner_info='' WHERE component_id=0");
245
246 // Disconnect from database and unload driver
3a2f672c
VK
247 if (g_hCoreDB != 0)
248 DBDisconnect(g_hCoreDB);
cc140cce 249 DBUnloadDriver();
c7ca9142 250
7e495d97
VK
251 DestroyActionList();
252
4385fa12 253 CloseLog();
9a19737f
VK
254}
255
256
257//
258// Common main()
259//
260
261void Main(void)
262{
3a2f672c
VK
263 WriteLog(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
264
3a2f672c
VK
265 if (IsStandalone())
266 {
267 int ch;
268
269 printf("\n*** NMS Server operational. Press ESC to terminate. ***\n");
270 while(1)
271 {
d16cf8a5 272#ifdef _WIN32
3a2f672c
VK
273 ch = getch();
274 if (ch == 0)
275 ch = -getch();
276
277 if (ch == 27)
278 break;
cc140cce 279#ifdef _DEBUG
d16cf8a5 280
cc140cce
VK
281 switch(ch)
282 {
f91fa4c2
VK
283 case 't': // Thread status
284 case 'T':
285 WatchdogPrintStatus();
be0a5a53 286 printf("*** Done ***\n");
f91fa4c2 287 break;
cc140cce
VK
288 case 'd': // Dump objects
289 case 'D':
290 {
291 DWORD i;
067f2689 292 char *pBuffer;
cc140cce
VK
293 static char *objTypes[]={ "Generic", "Subnet", "Node", "Interface", "Network" };
294
067f2689 295 pBuffer = (char *)malloc(128000);
5d0ff6bd 296 MutexLock(g_hMutexIdIndex, INFINITE);
cc140cce
VK
297 for(i = 0; i < g_dwIdIndexSize; i++)
298 {
299 printf("Object ID %d\n"
5d0ff6bd 300 " Name='%s' Type=%s Addr=%s Status=%d IsModified=%d\n",
cc140cce
VK
301 g_pIndexById[i].pObject->Id(),g_pIndexById[i].pObject->Name(),
302 objTypes[g_pIndexById[i].pObject->Type()],
067f2689 303 IpToStr(g_pIndexById[i].pObject->IpAddr(), pBuffer),
5d0ff6bd 304 g_pIndexById[i].pObject->Status(), g_pIndexById[i].pObject->IsModified());
f00307b7 305 printf(" Parents: <%s> Childs: <%s>\n",
067f2689
VK
306 g_pIndexById[i].pObject->ParentList(pBuffer),
307 g_pIndexById[i].pObject->ChildList(&pBuffer[4096]));
469b937c 308 if (g_pIndexById[i].pObject->Type() == OBJECT_NODE)
ce19c304
VK
309 printf(" IsSNMP:%d IsAgent:%d IsLocal:%d OID='%s'\n",
310 ((Node *)(g_pIndexById[i].pObject))->IsSNMPSupported(),
311 ((Node *)(g_pIndexById[i].pObject))->IsNativeAgent(),
312 ((Node *)(g_pIndexById[i].pObject))->IsLocalManagenet(),
313 ((Node *)(g_pIndexById[i].pObject))->ObjectId());
cc140cce 314 }
5d0ff6bd 315 MutexUnlock(g_hMutexIdIndex);
067f2689 316 free(pBuffer);
cc140cce
VK
317 printf("*** Object dump complete ***\n");
318 }
319 break;
9437ca82
VK
320 case 'i': // Dump interface index by IP
321 case 'I':
322 {
323 DWORD i;
324 char szBuffer[32];
9437ca82
VK
325
326 for(i = 0; i < g_dwInterfaceAddrIndexSize; i++)
327 {
328 printf("%10u %-15s -> %d [0x%08x]\n",
329 g_pInterfaceIndexByAddr[i].dwKey,
330 IpToStr(g_pInterfaceIndexByAddr[i].dwKey, szBuffer),
331 g_pInterfaceIndexByAddr[i].pObject->Id(),
332 g_pInterfaceIndexByAddr[i].pObject);
333 }
334 printf("*** Interface IP index dump complete ***\n");
335 }
336 break;
be0a5a53
VK
337 case 'm': // Print mutex status
338 case 'M':
339 printf("Mutex status:\n");
340 DbgTestMutex(g_hMutexIdIndex, "g_hMutexIdIndex");
341 DbgTestMutex(g_hMutexNodeIndex, "g_hMutexNodeIndex");
342 DbgTestMutex(g_hMutexSubnetIndex, "g_hMutexSubnetIndex");
343 DbgTestMutex(g_hMutexInterfaceIndex, "g_hMutexInterfaceIndex");
344 DbgTestMutex(g_hMutexObjectAccess, "g_hMutexObjectAccess");
345 printf("*** Done ***\n");
5811233f 346 break;
067f2689
VK
347 case 'g': // Generate test objects
348 case 'G':
129f8f7b 349 {
067f2689
VK
350 int i;
351 char szQuery[1024];
129f8f7b 352
067f2689
VK
353 for(i = 0; i < 10000; i++)
354 {
355 sprintf(szQuery, "INSERT INTO newnodes (id,ip_addr,ip_netmask,discovery_flags) VALUES (%d,%d,65535,%d)",
356 i + 1000, htonl(0x0A800001 + i), DF_DEFAULT);
357 DBQuery(g_hCoreDB, szQuery);
358 }
359 }
360 break;
78bf9c68
VK
361 case 'u': // Dump users
362 case 'U':
363 DumpUsers();
364 break;
ecb7e1ee
VK
365 case 's': // Dump sessions
366 case 'S':
367 DumpSessions();
368 break;
cc140cce
VK
369 default:
370 break;
371 }
d16cf8a5
AK
372#endif // _DEBUG
373#endif // _WIN32
3a2f672c
VK
374 }
375
376 Shutdown();
377 }
378 else
379 {
d16cf8a5 380 ConditionWait(m_hEventShutdown, INFINITE);
3a2f672c 381 }
9a19737f
VK
382}
383
384
385//
386// Startup code
387//
388
389int main(int argc, char *argv[])
390{
4385fa12 391 if (!ParseCommandLine(argc, argv))
9a19737f
VK
392 return 1;
393
4385fa12 394 if (!LoadConfig())
9a19737f
VK
395 return 1;
396
b7271ccb 397#ifdef _WIN32
9a19737f
VK
398 if (!IsStandalone())
399 {
400 InitService();
401 }
402 else
403 {
404 if (!Initialize())
405 {
406 printf("NMS Core initialization failed\n");
b7271ccb 407 return 3;
9a19737f
VK
408 }
409 Main();
410 }
b7271ccb
VK
411#else /* _WIN32 */
412 if (!IsStandalone())
413 {
414 if (daemon(0, 0) == -1)
415 {
416 perror("Call to daemon() failed");
417 return 2;
418 }
419 }
420 if (!Initialize())
421 return 3;
422 Main();
423#endif /* _WIN32 */
9a19737f
VK
424 return 0;
425}