"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.8.166/src/agent/subagents/odbcquery/odbcquery.cpp" (23 Feb 2021, 8672 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "odbcquery.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.6.300_vs_3.7.95.

    1 /*
    2 ** NetXMS ODBCQUERY subagent
    3 ** Copyright (C) 2006-2018 Raden Solutions
    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: odbcquery.cpp
   20 **
   21 **/
   22 
   23 #include "odbcquery.h"
   24 #include <netxms-version.h>
   25 
   26 #ifdef _WIN32
   27 #define ODBCQUERY_EXPORTABLE __declspec(dllexport) __cdecl
   28 #else
   29 #define ODBCQUERY_EXPORTABLE
   30 #endif
   31 
   32 #define EL_WARN     EVENTLOG_WARNING_TYPE
   33 #define EL_INFO     EVENTLOG_INFORMATION_TYPE
   34 #define EL_ERROR        EVENTLOG_ERROR_TYPE
   35 #define EL_DEBUG        EVENTLOG_DEBUG_TYPE
   36 
   37 
   38 //
   39 // Static data
   40 //
   41 
   42 static CONDITION m_hCondShutdown = INVALID_CONDITION_HANDLE;
   43 static BOOL m_bShutdown = FALSE;
   44 static DWORD m_dwNumQueries = 0;
   45 static ODBC_QUERY *m_pQueryList = NULL;
   46 
   47 
   48 //
   49 // Poller thread
   50 //
   51 
   52 static THREAD_RESULT THREAD_CALL PollerThread(void *pArg)
   53 {
   54    QWORD qwTime, qwPrevTime;
   55     ODBC_QUERY* pQuery;
   56 
   57     if ((pQuery = (ODBC_QUERY *)pArg) == NULL)
   58     {
   59         AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("ODBC Internal error: NULL passed to thread"));
   60         goto thread_finish;
   61     }
   62 
   63     if ((pQuery->pSqlCtx = OdbcCtxAlloc()) == NULL)
   64     {
   65         AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("Failed to allocate ODBC context"));
   66         goto thread_finish;
   67     }
   68 
   69     qwPrevTime = 0;
   70    while(!m_bShutdown)
   71    {
   72         qwTime = GetCurrentTimeMs();
   73         if (qwTime - qwPrevTime >= ((QWORD)pQuery->dwPollInterval) * 1000)
   74         {
   75             if (OdbcConnect(pQuery->pSqlCtx, pQuery->szOdbcSrc) < 0)
   76             {
   77                 pQuery->dwCompletionCode = OdbcGetSqlErrorNumber(pQuery->pSqlCtx);
   78                 AgentWriteDebugLog(2, _T("ODBC connect error: %s (%s)"), 
   79                                         OdbcGetInfo(pQuery->pSqlCtx),
   80                                         OdbcGetSqlError(pQuery->pSqlCtx));
   81             }
   82             else
   83             {
   84                 if (OdbcQuerySelect(pQuery->pSqlCtx, pQuery->szSqlQuery, 
   85                                           pQuery->szQueryResult, (size_t)MAX_DB_STRING) < 0)
   86                 {
   87                     pQuery->dwCompletionCode = OdbcGetSqlErrorNumber(pQuery->pSqlCtx);
   88                     AgentWriteDebugLog(2, _T("ODBC query error: %s (%s)"), 
   89                                             OdbcGetInfo(pQuery->pSqlCtx),
   90                                             OdbcGetSqlError(pQuery->pSqlCtx));
   91                 }
   92                 else
   93                 {
   94                     pQuery->dwCompletionCode = 0;
   95                 }
   96                 OdbcDisconnect(pQuery->pSqlCtx);
   97             }
   98             qwPrevTime = GetCurrentTimeMs();
   99         }
  100       if (ConditionWait(m_hCondShutdown, 1000))
  101          break;
  102    }
  103 
  104 thread_finish:
  105     if (pQuery->pSqlCtx)
  106     {
  107         OdbcCtxFree(pQuery->pSqlCtx);
  108     }
  109 
  110    return THREAD_OK;
  111 }
  112 
  113 
  114 //
  115 // Handler for poller information
  116 //
  117 
  118 static LONG H_PollResult(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue, AbstractCommSession *session)
  119 {
  120    TCHAR szName[MAX_DB_STRING];
  121    DWORD i;
  122 
  123    if (!AgentGetParameterArg(pszParam, 1, szName, MAX_DB_STRING))
  124       return SYSINFO_RC_UNSUPPORTED;
  125    StrStrip(szName);
  126 
  127    for(i = 0; i < m_dwNumQueries; i++)
  128    {
  129         if (!_tcsicmp(m_pQueryList[i].szName, szName))
  130             break;
  131    }
  132 
  133    if (i == m_dwNumQueries)
  134       return SYSINFO_RC_UNSUPPORTED;   // No such target
  135 
  136     switch(*pArg)
  137     {
  138         case 'R':
  139             if (m_pQueryList[i].dwCompletionCode != 0)
  140                 return SYSINFO_RC_ERROR;
  141             ret_string(pValue, m_pQueryList[i].szQueryResult);
  142             break;
  143         case 'S':
  144             ret_uint(pValue, m_pQueryList[i].dwCompletionCode);
  145             break;
  146         case 'T':
  147             ret_string(pValue, OdbcGetInfo(m_pQueryList[i].pSqlCtx));
  148             break;
  149         default:
  150           return SYSINFO_RC_UNSUPPORTED;
  151     }
  152 
  153    return SYSINFO_RC_SUCCESS;
  154 }
  155 
  156 
  157 //
  158 // Add query string from configuration file parameter
  159 // Parameter value should be <query_name>:<sql_source>:<sql>:<poll_interval>
  160 //
  161 
  162 static BOOL AddQueryFromConfig(const TCHAR *pszCfg)
  163 {
  164    TCHAR *ptr, *pszLine = NULL, *pszName = NULL;
  165     TCHAR *pszSrc = NULL, *pszQuery = NULL, *pszPollInterval = NULL;
  166     DWORD dwPollInterval = 0;
  167    BOOL bResult = FALSE;
  168 
  169     if (pszCfg == NULL)
  170     {
  171         AgentWriteLog(EVENTLOG_WARNING_TYPE, _T("ODBC: Null config entry, ignored"));
  172         bResult = TRUE;
  173         goto finish_add_query;
  174     }
  175 
  176    if ((pszLine = _tcsdup(pszCfg)) == NULL)
  177     {
  178         AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("ODBC: String allocation failed"));
  179         goto finish_add_query;
  180     }
  181     StrStrip(pszLine);
  182 
  183     // Get query name
  184     pszName = pszLine;
  185 
  186     // Get source name
  187    ptr = _tcschr(pszLine, _T(':'));
  188    if (ptr != NULL)
  189    {
  190       *ptr = _T('\0');
  191       ptr++;
  192       StrStrip(ptr);
  193       pszSrc = ptr;
  194    }
  195     else
  196     {
  197         AgentWriteLog(EVENTLOG_WARNING_TYPE, _T("ODBC: Wrong query string format, ODBC source missing"));
  198         goto finish_add_query;
  199     }
  200 
  201     // Get SQL query
  202     ptr = _tcschr(pszSrc, _T(':'));
  203    if (ptr != NULL)
  204    {
  205       *ptr = _T('\0');
  206       ptr++;
  207       StrStrip(ptr);
  208       pszQuery = ptr;
  209    }
  210     else
  211     {
  212         AgentWriteLog(EVENTLOG_WARNING_TYPE, _T("ODBC: Wrong query string format, SQL query missing"));
  213         goto finish_add_query;
  214     }
  215 
  216     // Get poll interval
  217     ptr = _tcschr(pszQuery, _T(':'));
  218    if (ptr != NULL)
  219    {
  220       *ptr = _T('\0');
  221       ptr++;
  222       StrStrip(ptr);
  223       pszPollInterval = ptr;
  224    }
  225     else
  226     {
  227         AgentWriteLog(EVENTLOG_WARNING_TYPE, _T("ODBC: Wrong query string format, poll interval missing"));
  228         goto finish_add_query;
  229     }
  230 
  231     dwPollInterval = (DWORD)_tcstol(pszPollInterval, NULL, 0);
  232     if (dwPollInterval == (DWORD)LONG_MIN || 
  233          dwPollInterval == (DWORD)LONG_MAX ||
  234          dwPollInterval == 0)
  235     {
  236         AgentWriteLog(EVENTLOG_WARNING_TYPE, _T("ODBC: Wrong query string format, invalid poll interval"));
  237         goto finish_add_query;
  238     }
  239 
  240    m_pQueryList = (ODBC_QUERY*)realloc(m_pQueryList, 
  241                         sizeof(ODBC_QUERY) * (m_dwNumQueries + 1));
  242     if (m_pQueryList == NULL)
  243     {
  244         AgentWriteLog(EVENTLOG_ERROR_TYPE, _T("ODBC: QueryList allocation failed"));
  245         goto finish_add_query;
  246     }
  247 
  248     nx_strncpy(m_pQueryList[m_dwNumQueries].szName, pszName, MAX_DB_STRING);
  249     nx_strncpy(m_pQueryList[m_dwNumQueries].szOdbcSrc, pszSrc, MAX_DB_STRING);
  250     nx_strncpy(m_pQueryList[m_dwNumQueries].szSqlQuery, pszQuery,MAX_SQL_QUERY_LEN);
  251     m_pQueryList[m_dwNumQueries].dwPollInterval = dwPollInterval;
  252     m_pQueryList[m_dwNumQueries].pSqlCtx = NULL;
  253     m_dwNumQueries++;
  254     bResult = TRUE;
  255     AgentWriteDebugLog(1, _T("ODBC: query \"%s\" successfully registered"), pszQuery);
  256 
  257 finish_add_query:
  258    MemFree(pszLine);
  259    return bResult;
  260 }
  261 
  262 
  263 //
  264 // Subagent initialization
  265 //
  266 
  267 static bool SubAgentInit(Config *config)
  268 {
  269    int i;
  270     ConfigEntry *ql;
  271 
  272     // Add queries from config
  273     ql = config->getEntry(_T("/ODBC/Query"));
  274     if (ql != NULL)
  275     {
  276         for(i = 0; i < ql->getValueCount(); i++)
  277         {
  278             if (!AddQueryFromConfig(ql->getValue(i)))
  279             {
  280             AgentWriteLog(EVENTLOG_WARNING_TYPE,
  281                             _T("Unable to add ODBC query from configuration file. ")
  282                                      _T("Original configuration record: %s"), ql->getValue(i));
  283             }
  284         }
  285     }
  286 
  287    // Create shutdown condition and start poller threads
  288    m_hCondShutdown = ConditionCreate(TRUE);
  289    for(i = 0; i < (int)m_dwNumQueries; i++)
  290       m_pQueryList[i].hThread = ThreadCreateEx(PollerThread, 0, &m_pQueryList[i]);
  291 
  292    return true;
  293 }
  294 
  295 /**
  296  * Called by master agent at unload
  297  */
  298 static void SubAgentShutdown()
  299 {
  300    DWORD i;
  301 
  302    m_bShutdown = TRUE;
  303    if (m_hCondShutdown != INVALID_CONDITION_HANDLE)
  304       ConditionSet(m_hCondShutdown);
  305 
  306    for(i = 0; i < m_dwNumQueries; i++)
  307       ThreadJoin(m_pQueryList[i].hThread);
  308    MemFree(m_pQueryList);
  309 }
  310 
  311 
  312 //
  313 // Subagent information
  314 //
  315 
  316 static NETXMS_SUBAGENT_PARAM m_parameters[] =
  317 {
  318    { _T("ODBC.QueryResult(*)"), H_PollResult, _T("R"), DCI_DT_STRING, _T("ODBC query result") },
  319    { _T("ODBC.QueryStatus(*)"), H_PollResult, _T("S"), DCI_DT_UINT, _T("ODBC query status") },
  320    { _T("ODBC.QueryStatusText(*)"), H_PollResult, _T("T"), DCI_DT_STRING, _T("ODBC query status as text") }
  321 };
  322 
  323 static NETXMS_SUBAGENT_INFO m_info =
  324 {
  325    NETXMS_SUBAGENT_INFO_MAGIC,
  326     _T("ODBCQUERY"), NETXMS_VERSION_STRING,
  327    SubAgentInit, SubAgentShutdown, NULL, NULL,
  328     sizeof(m_parameters) / sizeof(NETXMS_SUBAGENT_PARAM),
  329     m_parameters,
  330     0, NULL,    // lists
  331     0, NULL,    // tables
  332    0, NULL, // actions
  333     0, NULL // push parameters
  334 };
  335 
  336 
  337 //
  338 // Entry point for NetXMS agent
  339 //
  340 
  341 DECLARE_SUBAGENT_ENTRY_POINT(ODBCQUERY)
  342 {
  343    *ppInfo = &m_info;
  344    return true;
  345 }
  346 
  347 //
  348 // DLL entry point
  349 //
  350 
  351 #ifdef _WIN32
  352 
  353 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  354 {
  355    if (dwReason == DLL_PROCESS_ATTACH)
  356       DisableThreadLibraryCalls(hInstance);
  357    return TRUE;
  358 }
  359 
  360 #endif