+ conditions should work
[public/netxms.git] / src / server / core / main.cpp
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"
24 #ifdef _WIN32
25 #include <conio.h>
26 #endif /* _WIN32 */
27
28 void DumpUsers(void);
29 void DumpSessions(void);
30
31
32 //
33 // Thread functions
34 //
35
36 void HouseKeeper(void *pArg);
37 void DiscoveryThread(void *pArg);
38 void Syncer(void *pArg);
39 void NodePoller(void *pArg);
40 void StatusPoller(void *pArg);
41 void ConfigurationPoller(void *pArg);
42 void EventProcessor(void *pArg);
43 void WatchdogThread(void *pArg);
44 void ClientListener(void *pArg);
45 void LocalAdminListener(void *pArg);
46 void DBWriteThread(void *pArg);
47
48
49 //
50 // Global variables
51 //
52
53 DWORD g_dwFlags = AF_USE_EVENT_LOG;
54 char g_szConfigFile[MAX_PATH] = DEFAULT_CONFIG_FILE;
55 char g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE;
56 DB_HANDLE g_hCoreDB = 0;
57 DWORD g_dwDiscoveryPollingInterval;
58 DWORD g_dwStatusPollingInterval;
59 DWORD g_dwConfigurationPollingInterval;
60
61
62 //
63 // Static data
64 //
65
66 static CONDITION m_hEventShutdown;
67
68
69 //
70 // Sleep for specified number of seconds or until system shutdown arrives
71 // Function will return TRUE if shutdown event occurs
72 //
73
74 BOOL SleepAndCheckForShutdown(int iSeconds)
75 {
76 return ConditionWait(m_hEventShutdown, iSeconds * 1000);
77 }
78
79
80 //
81 // Load global configuration parameters
82 //
83
84 static void LoadGlobalConfig()
85 {
86 g_dwDiscoveryPollingInterval = ConfigReadInt("DiscoveryPollingInterval", 900);
87 g_dwStatusPollingInterval = ConfigReadInt("StatusPollingInterval", 60);
88 g_dwConfigurationPollingInterval = ConfigReadInt("ConfigurationPollingInterval", 3600);
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;
93 if (ConfigReadInt("DeleteEmptySubnets", 1))
94 g_dwFlags |= AF_DELETE_EMPTY_SUBNETS;
95 if (ConfigReadInt("EnableSNMPTraps", 1))
96 g_dwFlags |= AF_ENABLE_SNMP_TRAPD;
97 }
98
99
100 //
101 // Server initialization
102 //
103
104 BOOL Initialize(void)
105 {
106 int i, iNumThreads;
107 DWORD dwAddr;
108 char szInfo[256];
109
110 InitLog();
111
112 #ifdef _WIN32
113 WSADATA wsaData;
114 WSAStartup(0x0002, &wsaData);
115 #endif
116
117 // Initialize SSL library
118 SSL_library_init();
119 SSL_load_error_strings();
120
121 // Create queue for delayed SQL queries
122 g_pLazyRequestQueue = new Queue(64, 16);
123
124 // Initialize SNMP stuff
125 SnmpInit();
126
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
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
147 // Load global configuration parameters
148 LoadGlobalConfig();
149
150 // Create synchronization stuff
151 m_hEventShutdown = ConditionCreate(TRUE);
152
153 // Setup unique identifiers table
154 if (!InitIdTable())
155 return FALSE;
156
157 // Load users from database
158 if (!LoadUsers())
159 {
160 WriteLog(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
161 return FALSE;
162 }
163
164 // Initialize objects infrastructure and load objects from database
165 ObjectsInit();
166 if (!LoadObjects())
167 return FALSE;
168
169 // Load event actions
170 if (!LoadActions())
171 return FALSE;
172
173 // Initialize event handling subsystem
174 if (!InitEventSubsystem())
175 return FALSE;
176
177 // Initialize data collection subsystem
178 if (!InitDataCollector())
179 return FALSE;
180
181 // Initialize watchdog
182 WatchdogInit();
183
184 // Start threads
185 ThreadCreate(WatchdogThread, 0, NULL);
186 ThreadCreate(HouseKeeper, 0, NULL);
187 ThreadCreate(Syncer, 0, NULL);
188 ThreadCreate(NodePoller, 0, NULL);
189 ThreadCreate(StatusPoller, 0, NULL);
190 ThreadCreate(ConfigurationPoller, 0, NULL);
191 ThreadCreate(ClientListener, 0, NULL);
192
193 // Start network discovery thread if required
194 if (ConfigReadInt("RunNetworkDiscovery", 1))
195 ThreadCreate(DiscoveryThread, 0, NULL);
196 else
197 CheckForMgmtNode();
198
199 // Start event processors
200 iNumThreads = ConfigReadInt("NumberOfEventProcessors", 1);
201 for(i = 0; i < iNumThreads; i++)
202 ThreadCreate(EventProcessor, 0, NULL);
203
204 // Start database "lazy" write thread
205 ThreadCreate(DBWriteThread, 0, NULL);
206
207 // Start local administartive interface listener if required
208 if (ConfigReadInt("EnableAdminInterface", 1))
209 ThreadCreate(LocalAdminListener, 0, NULL);
210
211 return TRUE;
212 }
213
214
215 //
216 // Handler for client notification
217 //
218
219 static void NotifyClient(ClientSession *pSession, void *pArg)
220 {
221 pSession->Notify(NX_NOTIFY_SHUTDOWN);
222 }
223
224
225 //
226 // Server shutdown
227 //
228
229 void Shutdown(void)
230 {
231 // Notify clients
232 EnumerateClientSessions(NotifyClient, NULL);
233
234 WriteLog(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
235 g_dwFlags |= AF_SHUTDOWN; // Set shutdown flag
236 ConditionSet(m_hEventShutdown);
237
238 g_pEventQueue->Put(INVALID_POINTER_VALUE); // Stop event processor
239 ThreadSleep(5); // Give other threads a chance to terminate in a safe way
240 SaveObjects();
241 StopDBWriter();
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
247 if (g_hCoreDB != 0)
248 DBDisconnect(g_hCoreDB);
249 DBUnloadDriver();
250
251 DestroyActionList();
252
253 CloseLog();
254 }
255
256
257 //
258 // Common main()
259 //
260
261 void Main(void)
262 {
263 WriteLog(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
264
265 if (IsStandalone())
266 {
267 int ch;
268
269 printf("\n*** NMS Server operational. Press ESC to terminate. ***\n");
270 while(1)
271 {
272 #ifdef _WIN32
273 ch = getch();
274 if (ch == 0)
275 ch = -getch();
276
277 if (ch == 27)
278 break;
279 #ifdef _DEBUG
280
281 switch(ch)
282 {
283 case 't': // Thread status
284 case 'T':
285 WatchdogPrintStatus();
286 printf("*** Done ***\n");
287 break;
288 case 'd': // Dump objects
289 case 'D':
290 {
291 DWORD i;
292 char *pBuffer;
293 static char *objTypes[]={ "Generic", "Subnet", "Node", "Interface", "Network" };
294
295 pBuffer = (char *)malloc(128000);
296 MutexLock(g_hMutexIdIndex, INFINITE);
297 for(i = 0; i < g_dwIdIndexSize; i++)
298 {
299 printf("Object ID %d\n"
300 " Name='%s' Type=%s Addr=%s Status=%d IsModified=%d\n",
301 g_pIndexById[i].pObject->Id(),g_pIndexById[i].pObject->Name(),
302 objTypes[g_pIndexById[i].pObject->Type()],
303 IpToStr(g_pIndexById[i].pObject->IpAddr(), pBuffer),
304 g_pIndexById[i].pObject->Status(), g_pIndexById[i].pObject->IsModified());
305 printf(" Parents: <%s> Childs: <%s>\n",
306 g_pIndexById[i].pObject->ParentList(pBuffer),
307 g_pIndexById[i].pObject->ChildList(&pBuffer[4096]));
308 if (g_pIndexById[i].pObject->Type() == OBJECT_NODE)
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());
314 }
315 MutexUnlock(g_hMutexIdIndex);
316 free(pBuffer);
317 printf("*** Object dump complete ***\n");
318 }
319 break;
320 case 'i': // Dump interface index by IP
321 case 'I':
322 {
323 DWORD i;
324 char szBuffer[32];
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;
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");
346 break;
347 case 'g': // Generate test objects
348 case 'G':
349 {
350 int i;
351 char szQuery[1024];
352
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;
361 case 'u': // Dump users
362 case 'U':
363 DumpUsers();
364 break;
365 case 's': // Dump sessions
366 case 'S':
367 DumpSessions();
368 break;
369 default:
370 break;
371 }
372 #endif // _DEBUG
373 #endif // _WIN32
374 }
375
376 Shutdown();
377 }
378 else
379 {
380 ConditionWait(m_hEventShutdown, INFINITE);
381 }
382 }
383
384
385 //
386 // Startup code
387 //
388
389 int main(int argc, char *argv[])
390 {
391 if (!ParseCommandLine(argc, argv))
392 return 1;
393
394 if (!LoadConfig())
395 return 1;
396
397 #ifdef _WIN32
398 if (!IsStandalone())
399 {
400 InitService();
401 }
402 else
403 {
404 if (!Initialize())
405 {
406 printf("NMS Core initialization failed\n");
407 return 3;
408 }
409 Main();
410 }
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 */
424 return 0;
425 }