- Built-in syslog daemon impemented
authorVictor Kirhenshtein <victor@netxms.org>
Tue, 27 Sep 2005 11:51:13 +0000 (11:51 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Tue, 27 Sep 2005 11:51:13 +0000 (11:51 +0000)
- Other minor changes

.gitattributes
doc/db_format_change.txt
include/nms_common.h
sql/schema.in
sql/setup.in
src/server/core/hk.cpp
src/server/core/lpp.cpp [new file with mode: 0644]
src/server/core/main.cpp
src/server/core/nxcore.dsp
src/server/core/syncer.cpp
src/server/core/syslogd.cpp [new file with mode: 0644]

index 1174d2c..6872a7e 100644 (file)
@@ -762,6 +762,7 @@ src/server/core/id.cpp -text
 src/server/core/image.cpp -text
 src/server/core/interface.cpp -text
 src/server/core/locks.cpp -text
+src/server/core/lpp.cpp -text
 src/server/core/main.cpp -text
 src/server/core/modules.cpp -text
 src/server/core/netinfo.cpp -text
@@ -784,6 +785,7 @@ src/server/core/snmp.cpp -text
 src/server/core/snmptrap.cpp -text
 src/server/core/subnet.cpp -text
 src/server/core/syncer.cpp -text
+src/server/core/syslogd.cpp -text
 src/server/core/template.cpp -text
 src/server/core/tools.cpp -text
 src/server/core/tracert.cpp -text
index 3db5355..282ae41 100644 (file)
@@ -5,6 +5,27 @@
 - Added configuration variable IcmpPingSize
        INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
                VALUES ('IcmpPingSize','46',1,1);
+- Added table for storing syslog messages
+       CREATE TABLE syslog
+       (
+               msg_id SQL_BIGINT not null,
+               msg_timestamp integer not null,
+               facility integer not null,
+               severity integer not null,
+               source_object_id integer not null,
+               hostname varchar(127) not null,
+               msg_tag varchar(32) not null,
+               msg_text SQL_TEXT not null,
+               PRIMARY KEY(msg_id)
+       ) TABLE_TYPE;
+- New syslog-related parameters added:
+       INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+               VALUES ('EnableSyslogDaemon','46',1,1);
+       INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+               VALUES ('SyslogListenPort','514',1,1);
+       INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+               VALUES ('SyslogRetentionTime','5184000',1,0);
+
 
 
 *************
index f5c9680..67d24ca 100644 (file)
@@ -107,6 +107,9 @@ typedef unsigned __int64 QWORD;
 typedef __int64 INT64;
 typedef int socklen_t;
 
+#define INT64_FMT    _T("%I64d")
+#define UINT64_FMT   _T("%I64u")
+
 // Socket compatibility
 #define SHUT_RD      0
 #define SHUT_WR      1
@@ -155,6 +158,9 @@ typedef X_UINT64_X QWORD;
 #error Target system does not have unsigned 64bit integer type
 #endif
 
+#define INT64_FMT    _T("%lld")
+#define UINT64_FMT   _T("%llu")
+
 #ifndef MAX_PATH
 #define MAX_PATH 256
 #endif
@@ -250,6 +256,8 @@ typedef u_int64_t QWORD;
 #error Target system does not have unsigned 64bit integer type
 #endif
 
+#define INT64_FMT    _T("%lld")
+#define UINT64_FMT   _T("%llu")
 
 #define TRUE   1
 #define FALSE  0
index b0e864d..48523ed 100644 (file)
@@ -769,7 +769,7 @@ CREATE TABLE lpp_rules
 CREATE TABLE syslog
 (
        msg_id SQL_INT64 not null,
-       timestamp integer not null,
+       msg_timestamp integer not null,
        facility integer not null,
        severity integer not null,
        source_object_id integer not null,
index b9739d0..ed99253 100644 (file)
@@ -100,6 +100,8 @@ INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
        VALUES ('EnableSyslogDaemon','46',1,1);
 INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
        VALUES ('SyslogListenPort','514',1,1);
+INSERT INTO config (var_name,var_value,is_visible,need_server_restart)
+       VALUES ('SyslogRetentionTime','5184000',1,0);
 
 
 /*
index 931f23f..2f6d6c8 100644 (file)
@@ -1,6 +1,6 @@
 /* 
 ** NetXMS - Network Management System
-** Copyright (C) 2003, 2004 Victor Kirhenshtein
+** Copyright (C) 2003, 2004, 2005 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
@@ -104,7 +104,7 @@ THREAD_RESULT THREAD_CALL HouseKeeper(void *pArg)
 {
    time_t currTime;
    char szQuery[256];
-   DWORD i, dwEventLogRetentionTime, dwInterval;
+   DWORD i, dwRetentionTime, dwInterval;
 
    // Establish separate connection to database if needed
    if (g_dwFlags & AF_ENABLE_MULTIPLE_DB_CONN)
@@ -123,7 +123,6 @@ THREAD_RESULT THREAD_CALL HouseKeeper(void *pArg)
 
    // Load configuration
    dwInterval = ConfigReadULong("HouseKeepingInterval", 3600);
-   dwEventLogRetentionTime = ConfigReadULong("EventLogRetentionTime", 5184000);
 
    // Housekeeping loop
    while(!ShutdownInProgress())
@@ -133,9 +132,18 @@ THREAD_RESULT THREAD_CALL HouseKeeper(void *pArg)
          break;      // Shutdown has arrived
 
       // Remove outdated event log records
-      if (dwEventLogRetentionTime > 0)
+      dwRetentionTime = ConfigReadULong("EventLogRetentionTime", 5184000);
+      if (dwRetentionTime > 0)
       {
-         sprintf(szQuery, "DELETE FROM event_log WHERE event_timestamp<%ld", currTime - dwEventLogRetentionTime);
+         sprintf(szQuery, "DELETE FROM event_log WHERE event_timestamp<%ld", currTime - dwRetentionTime);
+         DBQuery(m_hdb, szQuery);
+      }
+
+      // Remove outdated syslog records
+      dwRetentionTime = ConfigReadULong("SyslogRetentionTime", 5184000);
+      if (dwRetentionTime > 0)
+      {
+         sprintf(szQuery, "DELETE FROM syslog WHERE msg_timestamp<%ld", currTime - dwRetentionTime);
          DBQuery(m_hdb, szQuery);
       }
 
diff --git a/src/server/core/lpp.cpp b/src/server/core/lpp.cpp
new file mode 100644 (file)
index 0000000..9fed7be
--- /dev/null
@@ -0,0 +1,23 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004, 2005 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** $module: lpp.cpp
+**
+**/
+
+#include "nxcore.h"
index b0f8ec8..e022310 100644 (file)
@@ -51,6 +51,7 @@ THREAD_RESULT THREAD_CALL WatchdogThread(void *pArg);
 THREAD_RESULT THREAD_CALL ClientListener(void *pArg);
 THREAD_RESULT THREAD_CALL LocalAdminListener(void *pArg);
 THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *pArg);
+THREAD_RESULT THREAD_CALL SyslogDaemon(void *pArg);
 
 
 //
@@ -439,6 +440,10 @@ BOOL NXCORE_EXPORTABLE Initialize(void)
    if (ConfigReadInt("EnableSNMPTraps", 1))
       ThreadCreate(SNMPTrapReceiver, 0, NULL);
 
+   // Start built-in syslog daemon
+   if (ConfigReadInt("EnableSyslogDaemon", 0))
+      ThreadCreate(SyslogDaemon, 0, NULL);
+
    // Start database "lazy" write thread
    StartDBWriter();
 
index d8785ac..4495afe 100644 (file)
@@ -198,6 +198,10 @@ SOURCE=.\locks.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\lpp.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\main.cpp
 # End Source File
 # Begin Source File
@@ -274,6 +278,10 @@ SOURCE=.\syncer.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\syslogd.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\template.cpp
 # End Source File
 # Begin Source File
@@ -410,6 +418,10 @@ SOURCE=..\..\..\include\nximage.h
 # End Source File
 # Begin Source File
 
+SOURCE=..\..\..\include\nxlog.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\include\nxmodule.h
 # End Source File
 # Begin Source File
index 8302f15..17246b2 100644 (file)
@@ -1,5 +1,5 @@
 /* 
-** Project X - Network Management System
+** NetXMS - Network Management System
 ** Copyright (C) 2003 Victor Kirhenshtein
 **
 ** This program is free software; you can redistribute it and/or modify
diff --git a/src/server/core/syslogd.cpp b/src/server/core/syslogd.cpp
new file mode 100644 (file)
index 0000000..d9587da
--- /dev/null
@@ -0,0 +1,301 @@
+/* 
+** NetXMS - Network Management System
+** Copyright (C) 2003, 2004, 2005 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** $module: syslogd.cpp
+**
+**/
+
+#include "nxcore.h"
+#include <nxlog.h>
+
+
+//
+// Constants
+//
+
+#define MAX_SYSLOG_MSG_LEN    1024
+
+
+//
+// Static data
+//
+
+static QWORD m_qwMsgId = 1;
+
+
+//
+// Parse timestamp field
+//
+
+static BOOL ParseTimeStamp(char **ppStart, int nMsgSize, int *pnPos, DWORD *pdwTime)
+{
+   static char psMonth[12][5] = { "Jan ", "Feb ", "Mar ", "Apr ",
+                                  "May ", "Jun ", "Jul ", "Aug ",
+                                  "Sep ", "Oct ", "Nov ", "Dec " };
+   struct tm timestamp;
+   time_t t;
+   char szBuffer[16], *pCurr = *ppStart;
+   int i;
+
+   if (nMsgSize - *pnPos < 16)
+      return FALSE;  // Timestamp cannot be shorter than 16 bytes
+
+   // Prepare local time structure
+   t = time(NULL);
+   memcpy(&timestamp, localtime(&t), sizeof(struct tm));
+
+   // Month
+   for(i = 0; i < 12; i++)
+      if (!memcmp(pCurr, psMonth[i], 4))
+      {
+         timestamp.tm_mon = i;
+         break;
+      }
+   if (i == 12)
+      return FALSE;
+   pCurr += 4;
+
+   // Day of week
+   if (isdigit(*pCurr))
+   {
+      timestamp.tm_mday = *pCurr - '0';
+   }
+   else 
+   {
+      if (*pCurr != ' ')
+         return FALSE;  // Invalid day of month
+      timestamp.tm_mday = 0;
+   }
+   pCurr++;
+   if (isdigit(*pCurr))
+   {
+      timestamp.tm_mday = timestamp.tm_mday * 10 + (*pCurr - '0');
+   }
+   else
+   {
+      return FALSE;  // Invalid day of month
+   }
+   pCurr++;
+   if (*pCurr != ' ')
+      return FALSE;
+   pCurr++;
+
+   // HH:MM:SS
+   memcpy(szBuffer, pCurr, 8);
+   szBuffer[8] = 0;
+   if (sscanf(szBuffer, "%02d:%02d:%02d", &timestamp.tm_hour,
+              &timestamp.tm_min, &timestamp.tm_sec) != 3)
+      return FALSE;  // Invalid time format
+   pCurr += 8;
+   if (*pCurr != ' ')
+      return FALSE;  // Space should follow timestamp
+   pCurr++;
+
+   // Convert to system time
+   *pdwTime = mktime(&timestamp);
+   if (*pdwTime == 0xFFFFFFFF)
+      return FALSE;
+
+   // Adjust current position
+   *pnPos += (int)(pCurr - *ppStart);
+   *ppStart = pCurr;
+   return TRUE;
+}
+
+
+//
+// Parse syslog message
+//
+
+static BOOL ParseSyslogMessage(char *psMsg, int nMsgLen, NX_LOG_RECORD *pRec)
+{
+   int i, nLen, nPos = 0;
+   char *pCurr = psMsg;
+
+   memset(pRec, 0, sizeof(NX_LOG_RECORD));
+
+   // Parse PRI part
+   if (*psMsg == '<')
+   {
+      int nPri = 0, nCount = 0;
+
+      for(pCurr++, nPos++; isdigit(*pCurr) && (nPos < nMsgLen); pCurr++, nPos++, nCount++)
+         nPri = nPri * 10 + (*pCurr - '0');
+      if (nPos >= nMsgLen)
+         return FALSE;  // Unexpected end of message
+
+      if ((*pCurr == '>') && (nCount > 0) && (nCount <4))
+      {
+         pRec->nFacility = nPri / 8;
+         pRec->nSeverity = nPri % 8;
+         pCurr++;
+         nPos++;
+      }
+      else
+      {
+         return FALSE;  // Invalid message
+      }
+   }
+   else
+   {
+      // Set default PRI of 13
+      pRec->nFacility = 1;
+      pRec->nSeverity = SYSLOG_SEVERITY_NOTICE;
+   }
+
+   // Parse HEADER part
+   if (ParseTimeStamp(&pCurr, nMsgLen, &nPos, &pRec->dwTimeStamp))
+   {
+      // Hostname
+      for(i = 0; isalnum(*pCurr) && (i < MAX_SYSLOG_HOSTNAME_LEN) && (nPos < nMsgLen); i++, nPos++, pCurr++)
+         pRec->szHostName[i] = *pCurr;
+      if ((nPos >= nMsgLen) || (*pCurr != ' '))
+         return FALSE;  // space should follow host name
+      pCurr++;
+      nPos++;
+   }
+   else
+   {
+      pRec->dwTimeStamp = time(NULL);
+   }
+
+   // Parse MSG part
+   for(i = 0; isalnum(*pCurr) && (i < MAX_SYSLOG_TAG_LEN) && (nPos < nMsgLen); i++, nPos++, pCurr++)
+      pRec->szTag[i] = *pCurr;
+   if ((i == MAX_SYSLOG_TAG_LEN) || (nPos >= nMsgLen))
+   {
+      // Too long tag, assuming that it's a part of message
+      pCurr -= i;
+      nPos -= i;
+      pRec->szTag[0] = 0;
+   }
+   else
+   {
+      if (*pCurr == ' ')
+      {
+         pCurr++;
+         nPos++;
+      }
+   }
+   nLen = min(nMsgLen - nPos, MAX_LOG_MSG_LENGTH);
+   memcpy(pRec->szMessage, pCurr, nLen);
+   pRec->szMessage[nLen] = 0;
+
+   return TRUE;
+}
+
+
+//
+// Process syslog message
+//
+
+static void ProcessSyslogMessage(char *psMsg, int nMsgLen)
+{
+   NX_LOG_RECORD record;
+   TCHAR *pszEscMsg, szQuery[4096];
+
+   if (ParseSyslogMessage(psMsg, nMsgLen, &record))
+   {
+      pszEscMsg = EncodeSQLString(record.szMessage);
+      _sntprintf(szQuery, 4096, 
+                 _T("INSERT INTO syslog (msg_id,msg_timestamp,facility,severity,")
+                 _T("source_object_id,hostname,msg_tag,msg_text) VALUES ")
+                 _T("(" UINT64_FMT ",%ld,%d,%d,%ld,'%s','%s','%s')"),
+                 m_qwMsgId++, record.dwTimeStamp, record.nFacility,
+                 record.nSeverity, record.dwSourceObject,
+                 record.szHostName, record.szTag, pszEscMsg);
+      free(pszEscMsg);
+      DBQuery(g_hCoreDB, szQuery);
+   }
+}
+
+
+//
+// Syslog messages receiver thread
+//
+
+THREAD_RESULT THREAD_CALL SyslogDaemon(void *pArg)
+{
+   SOCKET hSocket;
+   struct sockaddr_in addr;
+   int nBytes, nPort;
+   socklen_t nAddrLen;
+   char sMsg[MAX_SYSLOG_MSG_LEN];
+   DB_RESULT hResult;
+
+   // Determine first available message id
+   hResult = DBSelect(g_hCoreDB, _T("SELECT max(msg_id) FROM syslog"));
+   if (hResult != NULL)
+   {
+      if (DBGetNumRows(hResult) > 0)
+      {
+         m_qwMsgId = max(DBGetFieldUInt64(hResult, 0, 0) + 1, m_qwMsgId);
+      }
+      DBFreeResult(hResult);
+   }
+
+   hSocket = socket(AF_INET, SOCK_DGRAM, 0);
+   if (hSocket == -1)
+   {
+      WriteLog(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", "SyslogDaemon");
+      return THREAD_OK;
+   }
+
+       SetSocketReuseFlag(hSocket);
+
+   // Get listen port number
+   nPort = ConfigReadInt(_T("SyslogListenPort"), 514);
+   if ((nPort < 1) || (nPort > 65535))
+      nPort = 514;
+
+   // Fill in local address structure
+   memset(&addr, 0, sizeof(struct sockaddr_in));
+   addr.sin_family = AF_INET;
+   addr.sin_addr.s_addr = htonl(INADDR_ANY);
+   addr.sin_port = htons((WORD)nPort);
+
+   // Bind socket
+   if (bind(hSocket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0)
+   {
+      WriteLog(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", nPort, "SyslogDaemon", WSAGetLastError());
+      closesocket(hSocket);
+      return THREAD_OK;
+   }
+
+   DbgPrintf(AF_DEBUG_MISC, _T("Syslog Daemon started"));
+
+   // Wait for packets
+   while(!ShutdownInProgress())
+   {
+      nAddrLen = sizeof(struct sockaddr_in);
+      nBytes = recvfrom(hSocket, sMsg, MAX_SYSLOG_MSG_LEN, 0,
+                        (struct sockaddr *)&addr, &nAddrLen);
+      if (nBytes > 0)
+      {
+         ProcessSyslogMessage(sMsg, nBytes);
+      }
+      else
+      {
+         // Sleep on error
+         ThreadSleepMs(100);
+      }
+   }
+
+   DbgPrintf(AF_DEBUG_SNMP, _T("SNMP Trap Receiver terminated"));
+   return THREAD_OK;
+}