Implemented Debug Tag functionality
[public/netxms.git] / src / server / core / config.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 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: config.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24 #include <nxconfig.h>
25
26 /**
27 * Externals
28 */
29 extern char g_szCodePage[];
30 extern TCHAR *g_moduleLoadList;
31 extern TCHAR *g_pdsLoadList;
32 extern InetAddressList g_peerNodeAddrList;
33 extern TCHAR *g_serverCACertificatesPath;
34 extern TCHAR g_serverCertificatePath[];
35 extern TCHAR g_serverCertificateKeyPath[];
36 extern char g_serverCertificatePassword[];
37
38 /**
39 * Database connection parameters
40 */
41 TCHAR g_szDbDriver[MAX_PATH] = _T("");
42 TCHAR g_szDbDrvParams[MAX_PATH] = _T("");
43 TCHAR g_szDbServer[MAX_PATH] = _T("127.0.0.1");
44 TCHAR g_szDbLogin[MAX_DB_LOGIN] = _T("netxms");
45 TCHAR g_szDbPassword[MAX_PASSWORD] = _T("");
46 TCHAR g_szDbName[MAX_DB_NAME] = _T("netxms_db");
47 TCHAR g_szDbSchema[MAX_DB_NAME] = _T("");
48
49 /**
50 * Debug level from config
51 */
52 static UINT32 s_debugLevel = (UINT32)NXCONFIG_UNINITIALIZED_VALUE;
53
54 /**
55 * Debug tags from config
56 */
57 static TCHAR *s_debugTags = NULL;
58
59 /**
60 * Peer node information
61 */
62 static TCHAR s_peerNode[MAX_DB_STRING];
63
64 /**
65 * Config file template
66 */
67 static NX_CFG_TEMPLATE m_cfgTemplate[] =
68 {
69 { _T("BackgroundLogWriter"), CT_BOOLEAN64, 0, 0, AF_BACKGROUND_LOG_WRITER, 0, &g_flags, NULL },
70 { _T("CodePage"), CT_MB_STRING, 0, 0, 256, 0, g_szCodePage, NULL },
71 { _T("CreateCrashDumps"), CT_BOOLEAN64, 0, 0, AF_CATCH_EXCEPTIONS, 0, &g_flags, NULL },
72 { _T("DailyLogFileSuffix"), CT_STRING, 0, 0, 64, 0, g_szDailyLogFileSuffix, NULL },
73 { _T("DataDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, g_netxmsdDataDir, NULL },
74 { _T("DBDriver"), CT_STRING, 0, 0, MAX_PATH, 0, g_szDbDriver, NULL },
75 { _T("DBDrvParams"), CT_STRING, 0, 0, MAX_PATH, 0, g_szDbDrvParams, NULL },
76 { _T("DBLogin"), CT_STRING, 0, 0, MAX_DB_LOGIN, 0, g_szDbLogin, NULL },
77 { _T("DBName"), CT_STRING, 0, 0, MAX_DB_NAME, 0, g_szDbName, NULL },
78 { _T("DBPassword"), CT_STRING, 0, 0, MAX_PASSWORD, 0, g_szDbPassword, NULL },
79 { _T("DBEncryptedPassword"), CT_STRING, 0, 0, MAX_PASSWORD, 0, g_szDbPassword, NULL },
80 { _T("DBSchema"), CT_STRING, 0, 0, MAX_DB_NAME, 0, g_szDbSchema, NULL },
81 { _T("DBServer"), CT_STRING, 0, 0, MAX_PATH, 0, g_szDbServer, NULL },
82 { _T("DebugLevel"), CT_LONG, 0, 0, 0, 0, &s_debugLevel, &s_debugLevel },
83 { _T("DebugTags"), CT_STRING_LIST, ',', 0, 0, 0, &s_debugTags, NULL },
84 { _T("DumpDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, g_szDumpDir, NULL },
85 { _T("EnableServerConsole"), CT_BOOLEAN64, 0, 0, AF_ENABLE_LOCAL_CONSOLE, 0, &g_flags, NULL },
86 { _T("FullCrashDumps"), CT_BOOLEAN64, 0, 0, AF_WRITE_FULL_DUMP, 0, &g_flags, NULL },
87 { _T("LibraryDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, g_netxmsdLibDir, NULL },
88 { _T("ListenAddress"), CT_STRING, 0, 0, MAX_PATH, 0, g_szListenAddress, NULL },
89 { _T("LogFailedSQLQueries"), CT_BOOLEAN64, 0, 0, AF_LOG_SQL_ERRORS, 0, &g_flags, NULL },
90 { _T("LogFile"), CT_STRING, 0, 0, MAX_PATH, 0, g_szLogFile, NULL },
91 { _T("LogHistorySize"), CT_LONG, 0, 0, 0, 0, &g_logHistorySize, NULL },
92 { _T("LogRotationMode"), CT_LONG, 0, 0, 0, 0, &g_logRotationMode, NULL },
93 { _T("MaxLogSize"), CT_SIZE_BYTES, 0, 0, 0, 0, &g_maxLogSize, NULL },
94 { _T("Module"), CT_STRING_LIST, '\n', 0, 0, 0, &g_moduleLoadList, NULL },
95 { _T("PeerNode"), CT_STRING, 0, 0, MAX_DB_STRING, 0, s_peerNode, NULL },
96 { _T("PerfDataStorageDriver"), CT_STRING_LIST, '\n', 0, 0, 0, &g_pdsLoadList, NULL },
97 { _T("ProcessAffinityMask"), CT_LONG, 0, 0, 0, 0, &g_processAffinityMask, NULL },
98 { _T("ServerCACertificate"), CT_STRING_LIST, '\n', 0, 0, 0, &g_serverCACertificatesPath, NULL },
99 { _T("ServerCertificate"), CT_STRING, 0, 0, MAX_PATH, 0, g_serverCertificatePath, NULL },
100 { _T("ServerCertificateKey"), CT_STRING, 0, 0, MAX_PATH, 0, g_serverCertificateKeyPath, NULL },
101 { _T("ServerCertificatePassword"), CT_MB_STRING, 0, 0, MAX_PASSWORD, 0, g_serverCertificatePassword, NULL },
102 { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL, NULL }
103 };
104
105 /**
106 * Loaded server config
107 */
108 Config g_serverConfig;
109
110 /**
111 * Load and parse configuration file
112 * Returns TRUE on success and FALSE on failure
113 */
114 bool NXCORE_EXPORTABLE LoadConfig(int *debugLevel)
115 {
116 bool bSuccess = false;
117
118 if (!_tcscmp(g_szConfigFile, _T("{search}")))
119 {
120 #ifdef _WIN32
121 TCHAR path[MAX_PATH];
122 GetNetXMSDirectory(nxDirEtc, path);
123 _tcscat(path, _T("\\netxmsd.conf"));
124 if (_taccess(path, 4) == 0)
125 {
126 _tcscpy(g_szConfigFile, path);
127 }
128 else
129 {
130 _tcscpy(g_szConfigFile, _T("C:\\netxmsd.conf"));
131 }
132 #else
133 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
134 if ((homeDir != NULL) && (*homeDir != 0))
135 {
136 TCHAR config[MAX_PATH];
137 _sntprintf(config, MAX_PATH, _T("%s/etc/netxmsd.conf"), homeDir);
138 if (_taccess(config, 4) == 0)
139 {
140 _tcscpy(g_szConfigFile, config);
141 goto stop_search;
142 }
143 }
144 if (_taccess(PREFIX _T("/etc/netxmsd.conf"), 4) == 0)
145 {
146 _tcscpy(g_szConfigFile, PREFIX _T("/etc/netxmsd.conf"));
147 }
148 else if (_taccess(_T("/usr/etc/netxmsd.conf"), 4) == 0)
149 {
150 _tcscpy(g_szConfigFile, _T("/usr/etc/netxmsd.conf"));
151 }
152 else
153 {
154 _tcscpy(g_szConfigFile, _T("/etc/netxmsd.conf"));
155 }
156 stop_search:
157 ;
158 #endif
159 }
160
161 if (IsStandalone())
162 _tprintf(_T("Using configuration file \"%s\"\n"), g_szConfigFile);
163
164 if (g_serverConfig.loadConfig(g_szConfigFile, _T("server")) && g_serverConfig.parseTemplate(_T("server"), m_cfgTemplate))
165 {
166 if ((!_tcsicmp(g_szLogFile, _T("{EventLog}"))) ||
167 (!_tcsicmp(g_szLogFile, _T("{syslog}"))))
168 {
169 g_flags |= AF_USE_SYSLOG;
170 }
171 else
172 {
173 g_flags &= ~AF_USE_SYSLOG;
174 }
175 bSuccess = true;
176 }
177
178 if (*debugLevel == NXCONFIG_UNINITIALIZED_VALUE)
179 *debugLevel = (int)s_debugLevel;
180
181 int numTags = 0, lvl = 0;
182 TCHAR tagBuffer[254], lvlBuffer[2];
183 TCHAR const *ptr;
184
185 TCHAR **tagList = SplitString(s_debugTags, _T(','), &numTags);
186 if (tagList != NULL)
187 {
188 for(int i = 0; i < numTags; i++)
189 {
190 ptr = ExtractWord(tagList[i], tagBuffer);
191 ExtractWord(ptr, lvlBuffer);
192 lvl = _tcstol(lvlBuffer, NULL, 0);
193
194 if(lvl != 0 && tagBuffer != NULL)
195 nxlog_set_debug_level_tag(tagBuffer, lvl);
196 }
197 }
198
199 free(s_debugTags);
200 free(tagList);
201
202 // Decrypt password
203 DecryptPassword(g_szDbLogin, g_szDbPassword, g_szDbPassword, MAX_PASSWORD);
204
205 // Parse peer node information
206 if (s_peerNode[0] != 0)
207 {
208 int count = 0;
209 TCHAR **list = SplitString(s_peerNode, _T(','), &count);
210 for(int i = 0; i < count; i++)
211 {
212 InetAddress a = InetAddress::resolveHostName(list[i]);
213 if (a.isValidUnicast())
214 g_peerNodeAddrList.add(a);
215 free(list[i]);
216 }
217 free(list);
218 }
219 return bSuccess;
220 }
221
222 /**
223 * Metadata cache
224 */
225 static StringMap s_metadataCache;
226 static RWLOCK s_metadataCacheLock = RWLockCreate();
227
228 /**
229 * Pre-load metadata
230 */
231 void MetaDataPreLoad()
232 {
233 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
234 DB_RESULT hResult = DBSelect(hdb, _T("SELECT var_name,var_value FROM metadata"));
235 if (hResult != NULL)
236 {
237 RWLockWriteLock(s_metadataCacheLock, INFINITE);
238 s_metadataCache.clear();
239 int count = DBGetNumRows(hResult);
240 for(int i = 0; i < count; i++)
241 {
242 s_metadataCache.setPreallocated(DBGetField(hResult, i, 0, NULL, 0), DBGetField(hResult, i, 1, NULL, 0));
243 }
244 RWLockUnlock(s_metadataCacheLock);
245 DBFreeResult(hResult);
246 }
247 DBConnectionPoolReleaseConnection(hdb);
248 }
249
250 /**
251 * Read string value from metadata table
252 */
253 bool NXCORE_EXPORTABLE MetaDataReadStr(const TCHAR *name, TCHAR *buffer, int bufSize, const TCHAR *defaultValue)
254 {
255 bool bSuccess = false;
256
257 nx_strncpy(buffer, defaultValue, bufSize);
258 if (_tcslen(name) > 127)
259 return false;
260
261 RWLockReadLock(s_metadataCacheLock, INFINITE);
262 const TCHAR *value = s_metadataCache.get(name);
263 if (value != NULL)
264 {
265 nx_strncpy(buffer, value, bufSize);
266 bSuccess = true;
267 }
268 RWLockUnlock(s_metadataCacheLock);
269
270 if (!bSuccess)
271 {
272 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
273 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM metadata WHERE var_name=?"));
274 if (hStmt != NULL)
275 {
276 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, name, DB_BIND_STATIC);
277 DB_RESULT hResult = DBSelectPrepared(hStmt);
278 if (hResult != NULL)
279 {
280 if (DBGetNumRows(hResult) > 0)
281 {
282 DBGetField(hResult, 0, 0, buffer, bufSize);
283 RWLockWriteLock(s_metadataCacheLock, INFINITE);
284 s_metadataCache.setPreallocated(_tcsdup(name), DBGetField(hResult, 0, 0, NULL, 0));
285 RWLockUnlock(s_metadataCacheLock);
286 bSuccess = true;
287 }
288 DBFreeResult(hResult);
289 }
290 DBFreeStatement(hStmt);
291 }
292 DBConnectionPoolReleaseConnection(hdb);
293 }
294 return bSuccess;
295 }
296
297 /**
298 * Read integer value from metadata table
299 */
300 INT32 NXCORE_EXPORTABLE MetaDataReadInt32(const TCHAR *var, INT32 defaultValue)
301 {
302 TCHAR buffer[256];
303 if (MetaDataReadStr(var, buffer, 256, _T("")))
304 {
305 TCHAR *eptr;
306 INT32 value = _tcstol(buffer, &eptr, 0);
307 return (*eptr == 0) ? value : defaultValue;
308 }
309 else
310 {
311 return defaultValue;
312 }
313 }
314
315 /**
316 * Write string value to metadata table
317 */
318 bool NXCORE_EXPORTABLE MetaDataWriteStr(const TCHAR *varName, const TCHAR *value)
319 {
320 if (_tcslen(varName) > 63)
321 return false;
322
323 RWLockWriteLock(s_metadataCacheLock, INFINITE);
324 s_metadataCache.set(varName, value);
325 RWLockUnlock(s_metadataCacheLock);
326
327 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
328
329 // Check for variable existence
330 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM metadata WHERE var_name=?"));
331 if (hStmt == NULL)
332 {
333 DBConnectionPoolReleaseConnection(hdb);
334 return false;
335 }
336 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, varName, DB_BIND_STATIC);
337 DB_RESULT hResult = DBSelectPrepared(hStmt);
338 bool bVarExist = false;
339 if (hResult != NULL)
340 {
341 if (DBGetNumRows(hResult) > 0)
342 bVarExist = true;
343 DBFreeResult(hResult);
344 }
345 DBFreeStatement(hStmt);
346
347 // Create or update variable value
348 if (bVarExist)
349 {
350 hStmt = DBPrepare(hdb, _T("UPDATE metadata SET var_value=? WHERE var_name=?"));
351 if (hStmt == NULL)
352 {
353 DBConnectionPoolReleaseConnection(hdb);
354 return false;
355 }
356 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, value, DB_BIND_STATIC);
357 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, varName, DB_BIND_STATIC);
358 }
359 else
360 {
361 hStmt = DBPrepare(hdb, _T("INSERT INTO metadata (var_name,var_value) VALUES (?,?)"));
362 if (hStmt == NULL)
363 {
364 DBConnectionPoolReleaseConnection(hdb);
365 return false;
366 }
367 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, varName, DB_BIND_STATIC);
368 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, value, DB_BIND_STATIC);
369 }
370 bool success = DBExecute(hStmt);
371 DBFreeStatement(hStmt);
372 DBConnectionPoolReleaseConnection(hdb);
373 return success;
374 }
375
376 /**
377 * Write integer value to metadata table
378 */
379 bool NXCORE_EXPORTABLE MetaDataWriteInt32(const TCHAR *name, INT32 value)
380 {
381 TCHAR buffer[32];
382 _sntprintf(buffer, 32, _T("%d"), value);
383 return MetaDataWriteStr(name, buffer);
384 }
385
386 /**
387 * Config cache
388 */
389 static StringMap s_configCache;
390 static RWLOCK s_configCacheLock = RWLockCreate();
391
392 /**
393 * Callback for configuration variables change
394 */
395 static void OnConfigVariableChange(bool isCLOB, const TCHAR *name, const TCHAR *value)
396 {
397 RWLockWriteLock(s_configCacheLock, INFINITE);
398 s_configCache.set(name, value);
399 RWLockUnlock(s_configCacheLock);
400
401 // Restart syslog parser if configuration was changed
402 if (isCLOB && !_tcscmp(name, _T("SyslogParser")))
403 {
404 ReinitializeSyslogParser();
405 }
406 else if (!_tcscmp(name, _T("AlarmSummaryEmailSchedule")))
407 {
408 if (ConfigReadInt(_T("EnableAlarmSummaryEmails"), 0))
409 EnableAlarmSummaryEmails(); // this call will update schedule for existing task
410 }
411 else if (!_tcsncmp(name, _T("CAS"), 3))
412 {
413 CASReadSettings();
414 }
415 else if (!_tcscmp(name, _T("DefaultDCIPollingInterval")))
416 {
417 DCObject::m_defaultPollingInterval = _tcstol(value, NULL, 0);
418 }
419 else if (!_tcscmp(name, _T("DefaultDCIRetentionTime")))
420 {
421 DCObject::m_defaultRetentionTime = _tcstol(value, NULL, 0);
422 }
423 else if (!_tcscmp(name, _T("EnableAlarmSummaryEmails")))
424 {
425 if (_tcstol(value, NULL, 0))
426 EnableAlarmSummaryEmails();
427 else
428 RemoveScheduledTaskByHandlerId(ALARM_SUMMARY_EMAIL_TASK_ID);
429 }
430 else if (!_tcscmp(name, _T("StrictAlarmStatusFlow")))
431 {
432 NotifyClientSessions(NX_NOTIFY_ALARM_STATUS_FLOW_CHANGED, _tcstol(value, NULL, 0));
433 }
434 else if (!_tcsncmp(name, _T("Syslog"), 6))
435 {
436 OnSyslogConfigurationChange(name, value);
437 }
438 }
439
440 /**
441 * Read string value from configuration table
442 */
443 bool NXCORE_EXPORTABLE ConfigReadStrEx(DB_HANDLE dbHandle, const TCHAR *szVar, TCHAR *szBuffer, int iBufSize, const TCHAR *szDefault)
444 {
445 nx_strncpy(szBuffer, szDefault, iBufSize);
446 if (_tcslen(szVar) > 127)
447 return false;
448
449 RWLockReadLock(s_configCacheLock, INFINITE);
450 const TCHAR *value = s_configCache.get(szVar);
451 RWLockUnlock(s_configCacheLock);
452 if (value != NULL)
453 {
454 nx_strncpy(szBuffer, value, iBufSize);
455 DbgPrintf(8, _T("ConfigReadStr: (cached) name=%s value=\"%s\""), szVar, szBuffer);
456 return true;
457 }
458
459 bool bSuccess = false;
460 DB_HANDLE hdb = (dbHandle == NULL) ? DBConnectionPoolAcquireConnection() : dbHandle;
461 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM config WHERE var_name=?"));
462 if (hStmt != NULL)
463 {
464 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, szVar, DB_BIND_STATIC);
465 DB_RESULT hResult = DBSelectPrepared(hStmt);
466 if (hResult != NULL)
467 {
468 if (DBGetNumRows(hResult) > 0)
469 {
470 DBGetField(hResult, 0, 0, szBuffer, iBufSize);
471 DbgPrintf(8, _T("ConfigReadStr: name=%s value=\"%s\""), szVar, szBuffer);
472 bSuccess = true;
473 }
474 DBFreeResult(hResult);
475 }
476 DBFreeStatement(hStmt);
477 }
478 if (dbHandle == NULL)
479 DBConnectionPoolReleaseConnection(hdb);
480
481 if (bSuccess)
482 {
483 RWLockWriteLock(s_configCacheLock, INFINITE);
484 s_configCache.set(szVar, szBuffer);
485 RWLockUnlock(s_configCacheLock);
486 }
487
488 return bSuccess;
489 }
490
491 /**
492 * Read string value from configuration table
493 */
494 bool NXCORE_EXPORTABLE ConfigReadStr(const TCHAR *var, TCHAR *buffer, int bufferSize, const TCHAR *defaultValue)
495 {
496 return ConfigReadStrEx(NULL, var, buffer, bufferSize, defaultValue);
497 }
498
499 /**
500 * Read multibyte string from configuration table
501 */
502 #ifdef UNICODE
503
504 bool NXCORE_EXPORTABLE ConfigReadStrA(const WCHAR *szVar, char *szBuffer, int iBufSize, const char *szDefault)
505 {
506 WCHAR *wcBuffer = (WCHAR *)malloc(iBufSize * sizeof(WCHAR));
507 bool rc = ConfigReadStr(szVar, wcBuffer, iBufSize, _T(""));
508 if (rc)
509 {
510 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, wcBuffer, -1, szBuffer, iBufSize, NULL, NULL);
511 }
512 else
513 {
514 strncpy(szBuffer, szDefault, iBufSize);
515 }
516 szBuffer[iBufSize - 1] = 0;
517 free(wcBuffer);
518 return rc;
519 }
520
521 #endif
522
523 /**
524 * Read string value from configuration table as UTF8 string
525 */
526 bool NXCORE_EXPORTABLE ConfigReadStrUTF8(const TCHAR *szVar, char *szBuffer, int iBufSize, const char *szDefault)
527 {
528 DB_RESULT hResult;
529 bool bSuccess = false;
530
531 strncpy(szBuffer, szDefault, iBufSize);
532 if (_tcslen(szVar) > 127)
533 return false;
534
535 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
536 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM config WHERE var_name=?"));
537 if (hStmt != NULL)
538 {
539 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, szVar, DB_BIND_STATIC);
540 hResult = DBSelectPrepared(hStmt);
541 if (hResult != NULL)
542 {
543 if (DBGetNumRows(hResult) > 0)
544 {
545 DBGetFieldUTF8(hResult, 0, 0, szBuffer, iBufSize);
546 bSuccess = true;
547 }
548 DBFreeResult(hResult);
549 }
550 DBFreeStatement(hStmt);
551 }
552 DBConnectionPoolReleaseConnection(hdb);
553
554 return bSuccess;
555 }
556
557 /**
558 * Read integer value from configuration table
559 */
560 int NXCORE_EXPORTABLE ConfigReadInt(const TCHAR *szVar, int iDefault)
561 {
562 return ConfigReadIntEx(NULL, szVar, iDefault);
563 }
564
565 /**
566 * Read integer value from configuration table
567 */
568 int NXCORE_EXPORTABLE ConfigReadIntEx(DB_HANDLE hdb, const TCHAR *szVar, int iDefault)
569 {
570 TCHAR szBuffer[64];
571
572 if (ConfigReadStrEx(hdb, szVar, szBuffer, 64, _T("")))
573 return _tcstol(szBuffer, NULL, 0);
574 else
575 return iDefault;
576 }
577
578 /**
579 * Read unsigned long value from configuration table
580 */
581 UINT32 NXCORE_EXPORTABLE ConfigReadULong(const TCHAR *szVar, UINT32 dwDefault)
582 {
583 TCHAR szBuffer[64];
584
585 if (ConfigReadStr(szVar, szBuffer, 64, _T("")))
586 return _tcstoul(szBuffer, NULL, 0);
587 else
588 return dwDefault;
589 }
590
591 /**
592 * Read byte array (in hex form) from configuration table into integer array
593 */
594 bool NXCORE_EXPORTABLE ConfigReadByteArray(const TCHAR *pszVar, int *pnArray, int nSize, int nDefault)
595 {
596 TCHAR szBuffer[256];
597 char pbBytes[128];
598 bool bResult;
599 int i, nLen;
600
601 if (ConfigReadStr(pszVar, szBuffer, 256, _T("")))
602 {
603 StrToBin(szBuffer, (BYTE *)pbBytes, 128);
604 nLen = (int)_tcslen(szBuffer) / 2;
605 for(i = 0; (i < nSize) && (i < nLen); i++)
606 pnArray[i] = pbBytes[i];
607 for(; i < nSize; i++)
608 pnArray[i] = nDefault;
609 bResult = true;
610 }
611 else
612 {
613 for(i = 0; i < nSize; i++)
614 pnArray[i] = nDefault;
615 bResult = false;
616 }
617 return bResult;
618 }
619
620 /**
621 * Write string value to configuration table
622 */
623 bool NXCORE_EXPORTABLE ConfigWriteStr(const TCHAR *varName, const TCHAR *value, bool bCreate, bool isVisible, bool needRestart)
624 {
625 if (_tcslen(varName) > 63)
626 return false;
627
628 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
629
630 // Check for variable existence
631 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM config WHERE var_name=?"));
632 if (hStmt == NULL)
633 {
634 DBConnectionPoolReleaseConnection(hdb);
635 return false;
636 }
637 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, varName, DB_BIND_STATIC);
638 DB_RESULT hResult = DBSelectPrepared(hStmt);
639 bool bVarExist = false;
640 if (hResult != NULL)
641 {
642 if (DBGetNumRows(hResult) > 0)
643 bVarExist = true;
644 DBFreeResult(hResult);
645 }
646 DBFreeStatement(hStmt);
647
648 // Don't create non-existing variable if creation flag not set
649 if (!bCreate && !bVarExist)
650 {
651 DBConnectionPoolReleaseConnection(hdb);
652 return false;
653 }
654
655 // Create or update variable value
656 if (bVarExist)
657 {
658 hStmt = DBPrepare(hdb, _T("UPDATE config SET var_value=? WHERE var_name=?"));
659 if (hStmt == NULL)
660 {
661 DBConnectionPoolReleaseConnection(hdb);
662 return false;
663 }
664 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, value, DB_BIND_STATIC);
665 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, varName, DB_BIND_STATIC);
666 }
667 else
668 {
669 hStmt = DBPrepare(hdb, _T("INSERT INTO config (var_name,var_value,is_visible,need_server_restart) VALUES (?,?,?,?)"));
670 if (hStmt == NULL)
671 {
672 DBConnectionPoolReleaseConnection(hdb);
673 return false;
674 }
675 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, varName, DB_BIND_STATIC);
676 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, value, DB_BIND_STATIC);
677 DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (LONG)(isVisible ? 1 : 0));
678 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (LONG)(needRestart ? 1 : 0));
679 }
680 bool success = DBExecute(hStmt);
681 DBFreeStatement(hStmt);
682 DBConnectionPoolReleaseConnection(hdb);
683 if (success)
684 OnConfigVariableChange(false, varName, value);
685 return success;
686 }
687
688 /**
689 * Write integer value to configuration table
690 */
691 bool NXCORE_EXPORTABLE ConfigWriteInt(const TCHAR *szVar, int iValue, bool bCreate, bool isVisible, bool needRestart)
692 {
693 TCHAR szBuffer[64];
694
695 _sntprintf(szBuffer, 64, _T("%d"), iValue);
696 return ConfigWriteStr(szVar, szBuffer, bCreate, isVisible, needRestart);
697 }
698
699 /**
700 * Write unsigned long value to configuration table
701 */
702 bool NXCORE_EXPORTABLE ConfigWriteULong(const TCHAR *szVar, UINT32 dwValue, bool bCreate, bool isVisible, bool needRestart)
703 {
704 TCHAR szBuffer[64];
705
706 _sntprintf(szBuffer, 64, _T("%u"), dwValue);
707 return ConfigWriteStr(szVar, szBuffer, bCreate, isVisible, needRestart);
708 }
709
710 /**
711 * Write integer array to configuration table
712 */
713 bool NXCORE_EXPORTABLE ConfigWriteByteArray(const TCHAR *pszVar, int *pnArray, int nSize, bool bCreate, bool isVisible, bool needRestart)
714 {
715 TCHAR szBuffer[256];
716 int i, j;
717
718 for(i = 0, j = 0; (i < nSize) && (i < 127); i++, j += 2)
719 _sntprintf(&szBuffer[j], 256 - j, _T("%02X"), (char)((pnArray[i] > 127) ? 127 : ((pnArray[i] < -127) ? -127 : pnArray[i])));
720 return ConfigWriteStr(pszVar, szBuffer, bCreate, isVisible, needRestart);
721 }
722
723 /**
724 * Delete configuratrion variable
725 */
726 bool NXCORE_EXPORTABLE ConfigDelete(const TCHAR *name)
727 {
728 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
729
730 TCHAR query[1024];
731 _sntprintf(query, 1024, _T("DELETE FROM config WHERE var_name=%s"), (const TCHAR *)DBPrepareString(hdb, name));
732 bool success = DBQuery(hdb, query) ? true : false;
733
734 DBConnectionPoolReleaseConnection(hdb);
735
736 if (success)
737 {
738 RWLockWriteLock(s_configCacheLock, INFINITE);
739 s_configCache.remove(name);
740 RWLockUnlock(s_configCacheLock);
741 }
742
743 return success;
744 }
745
746 /**
747 * Read large string (clob) value from configuration table
748 */
749 TCHAR NXCORE_EXPORTABLE *ConfigReadCLOB(const TCHAR *var, const TCHAR *defValue)
750 {
751 TCHAR *result = NULL;
752
753 if (_tcslen(var) <= 63)
754 {
755 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
756 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM config_clob WHERE var_name=?"));
757 if (hStmt != NULL)
758 {
759 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, var, DB_BIND_STATIC);
760 DB_RESULT hResult = DBSelectPrepared(hStmt);
761 if (hResult != NULL)
762 {
763 if (DBGetNumRows(hResult) > 0)
764 {
765 result = DBGetField(hResult, 0, 0, NULL, 0);
766 }
767 DBFreeResult(hResult);
768 }
769 DBFreeStatement(hStmt);
770 }
771 DBConnectionPoolReleaseConnection(hdb);
772 }
773
774 // Return default value in case of error
775 if ((result == NULL) && (defValue != NULL))
776 result = _tcsdup(defValue);
777
778 return result;
779 }
780
781 /**
782 * Write large string (clob) value to configuration table
783 */
784 bool NXCORE_EXPORTABLE ConfigWriteCLOB(const TCHAR *var, const TCHAR *value, bool bCreate)
785 {
786 if (_tcslen(var) > 63)
787 return false;
788
789 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
790
791 // Check for variable existence
792 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT var_value FROM config_clob WHERE var_name=?"));
793 if (hStmt == NULL)
794 {
795 DBConnectionPoolReleaseConnection(hdb);
796 return false;
797 }
798 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, var, DB_BIND_STATIC);
799 DB_RESULT hResult = DBSelectPrepared(hStmt);
800 bool bVarExist = false;
801 if (hResult != NULL)
802 {
803 if (DBGetNumRows(hResult) > 0)
804 bVarExist = true;
805 DBFreeResult(hResult);
806 }
807 DBFreeStatement(hStmt);
808
809 // Don't create non-existing variable if creation flag not set
810 if (!bCreate && !bVarExist)
811 {
812 DBConnectionPoolReleaseConnection(hdb);
813 return false;
814 }
815
816 // Create or update variable value
817 if (bVarExist)
818 {
819 hStmt = DBPrepare(hdb, _T("UPDATE config_clob SET var_value=? WHERE var_name=?"));
820 if (hStmt == NULL)
821 {
822 DBConnectionPoolReleaseConnection(hdb);
823 return false;
824 }
825 DBBind(hStmt, 1, DB_SQLTYPE_TEXT, value, DB_BIND_STATIC);
826 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, var, DB_BIND_STATIC);
827 }
828 else
829 {
830 hStmt = DBPrepare(hdb, _T("INSERT INTO config_clob (var_name,var_value) VALUES (?,?)"));
831 if (hStmt == NULL)
832 {
833 DBConnectionPoolReleaseConnection(hdb);
834 return false;
835 }
836 DBBind(hStmt, 1, DB_SQLTYPE_VARCHAR, var, DB_BIND_STATIC);
837 DBBind(hStmt, 2, DB_SQLTYPE_TEXT, value, DB_BIND_STATIC);
838 }
839 bool success = DBExecute(hStmt) ? true : false;
840 DBFreeStatement(hStmt);
841 DBConnectionPoolReleaseConnection(hdb);
842 if (success)
843 OnConfigVariableChange(true, var, value);
844 return success;
845 }