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