- Added component locks
[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 #ifdef _WIN32
67 static HANDLE m_hEventShutdown = INVALID_HANDLE_VALUE;
68 #else /* _WIN32 */
69 static pthread_cond_t m_hCondShutdown;
70 #endif
71
72
73 //
74 // Sleep for specified number of seconds or until system shutdown arrives
75 // Function will return TRUE if shutdown event occurs
76 //
77
78 BOOL 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
88 //
89 // Load global configuration parameters
90 //
91
92 static void LoadGlobalConfig()
93 {
94 g_dwDiscoveryPollingInterval = ConfigReadInt("DiscoveryPollingInterval", 900);
95 g_dwStatusPollingInterval = ConfigReadInt("StatusPollingInterval", 60);
96 g_dwConfigurationPollingInterval = ConfigReadInt("ConfigurationPollingInterval", 3600);
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;
101 }
102
103
104 //
105 // Server initialization
106 //
107
108 BOOL Initialize(void)
109 {
110 int i, iNumThreads;
111 DWORD dwAddr;
112 char szInfo[256];
113
114 InitLog();
115
116 #ifdef _WIN32
117 WSADATA wsaData;
118 WSAStartup(0x0002, &wsaData);
119 #endif
120
121 // Initialize SSL library
122 SSL_library_init();
123 SSL_load_error_strings();
124
125 // Create queue for delayed SQL queries
126 g_pLazyRequestQueue = new Queue(64, 16);
127
128 // Initialize SNMP stuff
129 SnmpInit();
130
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
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
151 // Load global configuration parameters
152 LoadGlobalConfig();
153
154 // Create synchronization stuff
155 #ifdef _WIN32
156 m_hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
157 #else
158 pthread_cond_init(&m_hCondShutdown, NULL);
159 #endif
160
161 // Load users from database
162 if (!LoadUsers())
163 {
164 WriteLog(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL);
165 return FALSE;
166 }
167
168 // Initialize objects infrastructure and load objects from database
169 ObjectsInit();
170 if (!LoadObjects())
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 #ifdef _WIN32
237 SetEvent(m_hEventShutdown);
238 #else /* _WIN32 */
239 pthread_cond_broadcast(&m_hCondShutdown);
240 #endif
241
242 g_pEventQueue->Put(INVALID_POINTER_VALUE); // Stop event processor
243 ThreadSleep(5); // Give other threads a chance to terminate in a safe way
244 SaveObjects();
245 StopDBWriter();
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
251 if (g_hCoreDB != 0)
252 DBDisconnect(g_hCoreDB);
253 DBUnloadDriver();
254
255 CloseLog();
256 }
257
258
259 //
260 // Common main()
261 //
262
263 void Main(void)
264 {
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;
281
282 #ifdef _DEBUG
283 switch(ch)
284 {
285 case 't': // Thread status
286 case 'T':
287 WatchdogPrintStatus();
288 printf("*** Done ***\n");
289 break;
290 case 'd': // Dump objects
291 case 'D':
292 {
293 DWORD i;
294 char *pBuffer;
295 static char *objTypes[]={ "Generic", "Subnet", "Node", "Interface", "Network" };
296
297 pBuffer = (char *)malloc(128000);
298 MutexLock(g_hMutexIdIndex, INFINITE);
299 for(i = 0; i < g_dwIdIndexSize; i++)
300 {
301 printf("Object ID %d\n"
302 " Name='%s' Type=%s Addr=%s Status=%d IsModified=%d\n",
303 g_pIndexById[i].pObject->Id(),g_pIndexById[i].pObject->Name(),
304 objTypes[g_pIndexById[i].pObject->Type()],
305 IpToStr(g_pIndexById[i].pObject->IpAddr(), pBuffer),
306 g_pIndexById[i].pObject->Status(), g_pIndexById[i].pObject->IsModified());
307 printf(" Parents: <%s> Childs: <%s>\n",
308 g_pIndexById[i].pObject->ParentList(pBuffer),
309 g_pIndexById[i].pObject->ChildList(&pBuffer[4096]));
310 if (g_pIndexById[i].pObject->Type() == OBJECT_NODE)
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());
316 }
317 MutexUnlock(g_hMutexIdIndex);
318 free(pBuffer);
319 printf("*** Object dump complete ***\n");
320 }
321 break;
322 case 'i': // Dump interface index by IP
323 case 'I':
324 {
325 DWORD i;
326 char szBuffer[32];
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;
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");
348 break;
349 case 'g': // Generate test objects
350 case 'G':
351 {
352 int i;
353 char szQuery[1024];
354
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;
374 for(i = 0; i < g_dwNodeAddrIndexSize; i++)
375 {
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 }
382 }
383 printf("*** Done ***\n");
384 }
385 break;
386 case 'u': // Dump users
387 case 'U':
388 DumpUsers();
389 break;
390 case 's': // Dump sessions
391 case 'S':
392 DumpSessions();
393 break;
394 default:
395 break;
396 }
397 #endif
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
409 }
410
411
412 //
413 // Startup code
414 //
415
416 int main(int argc, char *argv[])
417 {
418 if (!ParseCommandLine(argc, argv))
419 return 1;
420
421 if (!LoadConfig())
422 return 1;
423
424 #ifndef _WIN32
425 /* TODO: insert fork() here */
426 #endif /* ! _WIN32 */
427
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 }