- Added component locks
[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
66#ifdef _WIN32
d627ae40
VK
67static HANDLE m_hEventShutdown = INVALID_HANDLE_VALUE;
68#else /* _WIN32 */
69static pthread_cond_t m_hCondShutdown;
3a2f672c 70#endif
9a19737f
VK
71
72
d627ae40
VK
73//
74// Sleep for specified number of seconds or until system shutdown arrives
75// Function will return TRUE if shutdown event occurs
76//
77
78BOOL SleepAndCheckForShutdown(int iSeconds)
79{
80#ifdef _WIN32
81 return WaitForSingleObject(m_hEventShutdown, iSeconds * 1000) == WAIT_OBJECT_0;
82#else /* _WIN32 */
83 /* TODO: Implement UNIX code */
84#endif
85}
86
87
48b1c0ac
VK
88//
89// Load global configuration parameters
90//
91
d627ae40 92static void LoadGlobalConfig()
48b1c0ac 93{
364aa19a 94 g_dwDiscoveryPollingInterval = ConfigReadInt("DiscoveryPollingInterval", 900);
f00307b7 95 g_dwStatusPollingInterval = ConfigReadInt("StatusPollingInterval", 60);
364aa19a 96 g_dwConfigurationPollingInterval = ConfigReadInt("ConfigurationPollingInterval", 3600);
3e4e127f
VK
97 if (ConfigReadInt("EnableAccessControl", 1))
98 g_dwFlags |= AF_ENABLE_ACCESS_CONTROL;
99 if (ConfigReadInt("EnableEventsAccessControl", 1))
100 g_dwFlags |= AF_ENABLE_EVENTS_ACCESS_CONTROL;
48b1c0ac
VK
101}
102
103
9a19737f
VK
104//
105// Server initialization
106//
107
108BOOL Initialize(void)
109{
f9b7e653 110 int i, iNumThreads;
c7ca9142
VK
111 DWORD dwAddr;
112 char szInfo[256];
347b5bc6 113
4385fa12 114 InitLog();
0ee0c807
VK
115
116#ifdef _WIN32
117 WSADATA wsaData;
118 WSAStartup(0x0002, &wsaData);
119#endif
120
e77547c2
VK
121 // Initialize SSL library
122 SSL_library_init();
123 SSL_load_error_strings();
124
067f2689
VK
125 // Create queue for delayed SQL queries
126 g_pLazyRequestQueue = new Queue(64, 16);
127
d7d76e50 128 // Initialize SNMP stuff
be0a5a53 129 SnmpInit();
d7d76e50 130
3a2f672c
VK
131 if (!DBInit())
132 return FALSE;
133
134 g_hCoreDB = DBConnect();
135 if (g_hCoreDB == 0)
136 {
137 WriteLog(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, NULL);
138 return FALSE;
139 }
140
c7ca9142
VK
141 // Initialize locks
142 if (!InitLocks(&dwAddr, szInfo))
143 {
144 if (dwAddr == UNLOCKED) // Some SQL problems
145 WriteLog(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL);
146 else // Database already locked by another server instance
147 WriteLog(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "as", dwAddr, szInfo);
148 return FALSE;
149 }
150
48b1c0ac
VK
151 // Load global configuration parameters
152 LoadGlobalConfig();
153
3a2f672c
VK
154 // Create synchronization stuff
155#ifdef _WIN32
156 m_hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
d627ae40
VK
157#else
158 pthread_cond_init(&m_hCondShutdown, NULL);
3a2f672c
VK
159#endif
160
da54bd8d
VK
161 // Load users from database
162 if (!LoadUsers())
347b5bc6
VK
163 {
164 WriteLog(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
da54bd8d 165 return FALSE;
347b5bc6 166 }
da54bd8d 167
2da1357c 168 // Initialize objects infrastructure and load objects from database
74b83361 169 ObjectsInit();
2da1357c
VK
170 if (!LoadObjects())
171 return FALSE;
74b83361 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
83f0529c
VK
215//
216// Handler for client notification
217//
218
219static void NotifyClient(ClientSession *pSession, void *pArg)
220{
221 pSession->Notify(NX_NOTIFY_SHUTDOWN);
222}
223
224
9a19737f
VK
225//
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
3a2f672c
VK
236#ifdef _WIN32
237 SetEvent(m_hEventShutdown);
d627ae40
VK
238#else /* _WIN32 */
239 pthread_cond_broadcast(&m_hCondShutdown);
3a2f672c 240#endif
c7ca9142
VK
241
242 g_pEventQueue->Put(INVALID_POINTER_VALUE); // Stop event processor
d627ae40
VK
243 ThreadSleep(5); // Give other threads a chance to terminate in a safe way
244 SaveObjects();
83f0529c 245 StopDBWriter();
c7ca9142
VK
246
247 // Remove database lock
248 DBQuery(g_hCoreDB, "UPDATE locks SET lock_status=-1,owner_info='' WHERE component_id=0");
249
250 // Disconnect from database and unload driver
3a2f672c
VK
251 if (g_hCoreDB != 0)
252 DBDisconnect(g_hCoreDB);
cc140cce 253 DBUnloadDriver();
c7ca9142 254
4385fa12 255 CloseLog();
9a19737f
VK
256}
257
258
259//
260// Common main()
261//
262
263void Main(void)
264{
3a2f672c
VK
265 WriteLog(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL);
266
267#ifdef _WIN32
268 if (IsStandalone())
269 {
270 int ch;
271
272 printf("\n*** NMS Server operational. Press ESC to terminate. ***\n");
273 while(1)
274 {
275 ch = getch();
276 if (ch == 0)
277 ch = -getch();
278
279 if (ch == 27)
280 break;
cc140cce
VK
281
282#ifdef _DEBUG
283 switch(ch)
284 {
f91fa4c2
VK
285 case 't': // Thread status
286 case 'T':
287 WatchdogPrintStatus();
be0a5a53 288 printf("*** Done ***\n");
f91fa4c2 289 break;
cc140cce
VK
290 case 'd': // Dump objects
291 case 'D':
292 {
293 DWORD i;
067f2689 294 char *pBuffer;
cc140cce
VK
295 static char *objTypes[]={ "Generic", "Subnet", "Node", "Interface", "Network" };
296
067f2689 297 pBuffer = (char *)malloc(128000);
5d0ff6bd 298 MutexLock(g_hMutexIdIndex, INFINITE);
cc140cce
VK
299 for(i = 0; i < g_dwIdIndexSize; i++)
300 {
301 printf("Object ID %d\n"
5d0ff6bd 302 " Name='%s' Type=%s Addr=%s Status=%d IsModified=%d\n",
cc140cce
VK
303 g_pIndexById[i].pObject->Id(),g_pIndexById[i].pObject->Name(),
304 objTypes[g_pIndexById[i].pObject->Type()],
067f2689 305 IpToStr(g_pIndexById[i].pObject->IpAddr(), pBuffer),
5d0ff6bd 306 g_pIndexById[i].pObject->Status(), g_pIndexById[i].pObject->IsModified());
f00307b7 307 printf(" Parents: <%s> Childs: <%s>\n",
067f2689
VK
308 g_pIndexById[i].pObject->ParentList(pBuffer),
309 g_pIndexById[i].pObject->ChildList(&pBuffer[4096]));
469b937c 310 if (g_pIndexById[i].pObject->Type() == OBJECT_NODE)
ce19c304
VK
311 printf(" IsSNMP:%d IsAgent:%d IsLocal:%d OID='%s'\n",
312 ((Node *)(g_pIndexById[i].pObject))->IsSNMPSupported(),
313 ((Node *)(g_pIndexById[i].pObject))->IsNativeAgent(),
314 ((Node *)(g_pIndexById[i].pObject))->IsLocalManagenet(),
315 ((Node *)(g_pIndexById[i].pObject))->ObjectId());
cc140cce 316 }
5d0ff6bd 317 MutexUnlock(g_hMutexIdIndex);
067f2689 318 free(pBuffer);
cc140cce
VK
319 printf("*** Object dump complete ***\n");
320 }
321 break;
9437ca82
VK
322 case 'i': // Dump interface index by IP
323 case 'I':
324 {
325 DWORD i;
326 char szBuffer[32];
9437ca82
VK
327
328 for(i = 0; i < g_dwInterfaceAddrIndexSize; i++)
329 {
330 printf("%10u %-15s -> %d [0x%08x]\n",
331 g_pInterfaceIndexByAddr[i].dwKey,
332 IpToStr(g_pInterfaceIndexByAddr[i].dwKey, szBuffer),
333 g_pInterfaceIndexByAddr[i].pObject->Id(),
334 g_pInterfaceIndexByAddr[i].pObject);
335 }
336 printf("*** Interface IP index dump complete ***\n");
337 }
338 break;
be0a5a53
VK
339 case 'm': // Print mutex status
340 case 'M':
341 printf("Mutex status:\n");
342 DbgTestMutex(g_hMutexIdIndex, "g_hMutexIdIndex");
343 DbgTestMutex(g_hMutexNodeIndex, "g_hMutexNodeIndex");
344 DbgTestMutex(g_hMutexSubnetIndex, "g_hMutexSubnetIndex");
345 DbgTestMutex(g_hMutexInterfaceIndex, "g_hMutexInterfaceIndex");
346 DbgTestMutex(g_hMutexObjectAccess, "g_hMutexObjectAccess");
347 printf("*** Done ***\n");
5811233f 348 break;
067f2689
VK
349 case 'g': // Generate test objects
350 case 'G':
129f8f7b 351 {
067f2689
VK
352 int i;
353 char szQuery[1024];
129f8f7b 354
067f2689
VK
355 for(i = 0; i < 10000; i++)
356 {
357 sprintf(szQuery, "INSERT INTO newnodes (id,ip_addr,ip_netmask,discovery_flags) VALUES (%d,%d,65535,%d)",
358 i + 1000, htonl(0x0A800001 + i), DF_DEFAULT);
359 DBQuery(g_hCoreDB, szQuery);
360 }
361 }
362 break;
363 case 'c': // Create test items
364 case 'C':
365 {
366 DWORD i, j;
367 DC_ITEM item;
368
369 item.dwId = 20000;
370 item.iDataType = DT_INTEGER;
371 item.iPollingInterval = 60;
372 item.iRetentionTime = 30;
373 item.iSource = DS_INTERNAL;
129f8f7b
VK
374 for(i = 0; i < g_dwNodeAddrIndexSize; i++)
375 {
067f2689
VK
376 for(j = 1; j <= 100; j++)
377 {
378 sprintf(item.szName, "Debug.%d", j);
379 ((Node *)g_pNodeIndexByAddr[i].pObject)->AddItem(&item);
380 item.dwId++;
381 }
129f8f7b 382 }
067f2689 383 printf("*** Done ***\n");
129f8f7b
VK
384 }
385 break;
78bf9c68
VK
386 case 'u': // Dump users
387 case 'U':
388 DumpUsers();
389 break;
ecb7e1ee
VK
390 case 's': // Dump sessions
391 case 'S':
392 DumpSessions();
393 break;
cc140cce
VK
394 default:
395 break;
396 }
397#endif
3a2f672c
VK
398 }
399
400 Shutdown();
401 }
402 else
403 {
404 WaitForSingleObject(m_hEventShutdown, INFINITE);
405 }
406#else /* _WIN32 */
407 /* TODO: insert UNIX main thread code here */
408#endif
9a19737f
VK
409}
410
411
412//
413// Startup code
414//
415
416int main(int argc, char *argv[])
417{
4385fa12 418 if (!ParseCommandLine(argc, argv))
9a19737f
VK
419 return 1;
420
4385fa12 421 if (!LoadConfig())
9a19737f
VK
422 return 1;
423
3a2f672c
VK
424#ifndef _WIN32
425 /* TODO: insert fork() here */
426#endif /* ! _WIN32 */
427
9a19737f
VK
428 if (!IsStandalone())
429 {
430 InitService();
431 }
432 else
433 {
434 if (!Initialize())
435 {
436 printf("NMS Core initialization failed\n");
437 return 1;
438 }
439 Main();
440 }
441 return 0;
442}