summaryrefslogtreecommitdiffstats
path: root/src/zabbix_proxy
diff options
context:
space:
mode:
authorsasha <sasha@97f52cf1-0a1b-0410-bd0e-c28be96e8082>2008-01-18 10:52:08 +0000
committersasha <sasha@97f52cf1-0a1b-0410-bd0e-c28be96e8082>2008-01-18 10:52:08 +0000
commit83c43012c9fd777e6a8d095c58f534d7de2963ad (patch)
treecb09146399616b584a71f57b7d3b54e214497548 /src/zabbix_proxy
parentaac7703069141a27b1279189c4a94bffb0a76c85 (diff)
downloadzabbix-83c43012c9fd777e6a8d095c58f534d7de2963ad.tar.gz
zabbix-83c43012c9fd777e6a8d095c58f534d7de2963ad.tar.xz
zabbix-83c43012c9fd777e6a8d095c58f534d7de2963ad.zip
- [DEV-99] New application: zabbix_proxy
git-svn-id: svn://svn.zabbix.com/trunk@5265 97f52cf1-0a1b-0410-bd0e-c28be96e8082
Diffstat (limited to 'src/zabbix_proxy')
-rw-r--r--src/zabbix_proxy/Makefile.am52
-rw-r--r--src/zabbix_proxy/dbsyncer/Makefile.am5
-rw-r--r--src/zabbix_proxy/dbsyncer/dbsyncer.c75
-rw-r--r--src/zabbix_proxy/dbsyncer/dbsyncer.h29
-rw-r--r--src/zabbix_proxy/discoverer/Makefile.am5
-rw-r--r--src/zabbix_proxy/discoverer/discoverer.c907
-rw-r--r--src/zabbix_proxy/discoverer/discoverer.h27
-rw-r--r--src/zabbix_proxy/evalfunc.c1826
-rw-r--r--src/zabbix_proxy/evalfunc.h39
-rw-r--r--src/zabbix_proxy/events.c211
-rw-r--r--src/zabbix_proxy/events.h29
-rw-r--r--src/zabbix_proxy/expression.c1631
-rw-r--r--src/zabbix_proxy/expression.h40
-rw-r--r--src/zabbix_proxy/functions.c815
-rw-r--r--src/zabbix_proxy/functions.h34
-rw-r--r--src/zabbix_proxy/housekeeper/Makefile.am5
-rw-r--r--src/zabbix_proxy/housekeeper/housekeeper.c375
-rw-r--r--src/zabbix_proxy/housekeeper/housekeeper.h29
-rw-r--r--src/zabbix_proxy/httppoller/Makefile.am8
-rw-r--r--src/zabbix_proxy/httppoller/httpmacro.c133
-rw-r--r--src/zabbix_proxy/httppoller/httpmacro.h25
-rw-r--r--src/zabbix_proxy/httppoller/httppoller.c165
-rw-r--r--src/zabbix_proxy/httppoller/httppoller.h30
-rw-r--r--src/zabbix_proxy/httppoller/httptest.c544
-rw-r--r--src/zabbix_proxy/httppoller/httptest.h51
-rw-r--r--src/zabbix_proxy/nodewatcher/Makefile.am9
-rw-r--r--src/zabbix_proxy/nodewatcher/history.c347
-rw-r--r--src/zabbix_proxy/nodewatcher/history.h25
-rw-r--r--src/zabbix_proxy/nodewatcher/nodecomms.c153
-rw-r--r--src/zabbix_proxy/nodewatcher/nodecomms.h32
-rw-r--r--src/zabbix_proxy/nodewatcher/nodesender.c673
-rw-r--r--src/zabbix_proxy/nodewatcher/nodesender.h37
-rw-r--r--src/zabbix_proxy/nodewatcher/nodewatcher.c120
-rw-r--r--src/zabbix_proxy/nodewatcher/nodewatcher.h26
-rw-r--r--src/zabbix_proxy/operations.c833
-rw-r--r--src/zabbix_proxy/operations.h36
-rw-r--r--src/zabbix_proxy/pinger/Makefile.am5
-rw-r--r--src/zabbix_proxy/pinger/pinger.c415
-rw-r--r--src/zabbix_proxy/pinger/pinger.h31
-rw-r--r--src/zabbix_proxy/poller/Makefile.am13
-rw-r--r--src/zabbix_proxy/poller/checks_agent.c133
-rw-r--r--src/zabbix_proxy/poller/checks_agent.h32
-rw-r--r--src/zabbix_proxy/poller/checks_aggregate.c369
-rw-r--r--src/zabbix_proxy/poller/checks_aggregate.h30
-rw-r--r--src/zabbix_proxy/poller/checks_db.c201
-rw-r--r--src/zabbix_proxy/poller/checks_db.h28
-rw-r--r--src/zabbix_proxy/poller/checks_external.c134
-rw-r--r--src/zabbix_proxy/poller/checks_external.h36
-rw-r--r--src/zabbix_proxy/poller/checks_internal.c93
-rw-r--r--src/zabbix_proxy/poller/checks_internal.h30
-rw-r--r--src/zabbix_proxy/poller/checks_simple.c221
-rw-r--r--src/zabbix_proxy/poller/checks_simple.h30
-rw-r--r--src/zabbix_proxy/poller/checks_snmp.c493
-rw-r--r--src/zabbix_proxy/poller/checks_snmp.h30
-rw-r--r--src/zabbix_proxy/poller/poller.c579
-rw-r--r--src/zabbix_proxy/poller/poller.h40
-rw-r--r--src/zabbix_proxy/proxy.c569
-rw-r--r--src/zabbix_proxy/trapper/Makefile.am10
-rw-r--r--src/zabbix_proxy/trapper/active.c120
-rw-r--r--src/zabbix_proxy/trapper/active.h30
-rw-r--r--src/zabbix_proxy/trapper/nodecommand.c284
-rw-r--r--src/zabbix_proxy/trapper/nodecommand.h26
-rw-r--r--src/zabbix_proxy/trapper/nodehistory.c481
-rw-r--r--src/zabbix_proxy/trapper/nodehistory.h30
-rw-r--r--src/zabbix_proxy/trapper/nodesync.c338
-rw-r--r--src/zabbix_proxy/trapper/nodesync.h26
-rw-r--r--src/zabbix_proxy/trapper/trapper.c245
-rw-r--r--src/zabbix_proxy/trapper/trapper.h31
-rw-r--r--src/zabbix_proxy/zlog.c92
69 files changed, 14606 insertions, 0 deletions
diff --git a/src/zabbix_proxy/Makefile.am b/src/zabbix_proxy/Makefile.am
new file mode 100644
index 00000000..c2bc8cb9
--- /dev/null
+++ b/src/zabbix_proxy/Makefile.am
@@ -0,0 +1,52 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = \
+ dbsyncer \
+ discoverer \
+ housekeeper \
+ httppoller \
+ nodewatcher \
+ pinger \
+ poller \
+ trapper
+
+sbin_PROGRAMS = zabbix_proxy
+
+zabbix_proxy_SOURCES = \
+ evalfunc.c evalfunc.h \
+ expression.c expression.h \
+ operations.c operations.h \
+ events.c events.h \
+ zlog.c \
+ functions.c functions.h \
+ proxy.c
+
+zabbix_proxy_LDADD = \
+ dbsyncer/libzbxdbsyncer.a \
+ discoverer/libzbxdiscoverer.a \
+ housekeeper/libzbxhousekeeper.a \
+ httppoller/libzbxhttppoller.a \
+ nodewatcher/libzbxnodewatcher.a \
+ pinger/libzbxpinger.a \
+ poller/libzbxpoller.a \
+ trapper/libzbxtrapper.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/libzbxserversysinfo.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/$(ARCH)/libspecsysinfo.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/common/libcommonsysinfo.a \
+ $(top_srcdir)/src/libs/zbxsysinfo/simple/libsimplesysinfo.a \
+ $(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
+ $(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
+ $(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
+ $(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
+ $(top_srcdir)/src/libs/zbxdbhigh/libzbxdbhigh.a \
+ $(top_srcdir)/src/libs/zbxdb/libzbxdb.a \
+ $(top_srcdir)/src/libs/zbxdbcache/libzbxdbcache.a \
+ $(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
+ $(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
+ $(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
+ @PROXY_LIBS@
+
+zabbix_proxy_LDFLAGS = \
+ @PROXY_LDFLAGS@
+
+zabbix_proxy_CFLAGS = -DZABBIX_DAEMON
diff --git a/src/zabbix_proxy/dbsyncer/Makefile.am b/src/zabbix_proxy/dbsyncer/Makefile.am
new file mode 100644
index 00000000..c81bdc5e
--- /dev/null
+++ b/src/zabbix_proxy/dbsyncer/Makefile.am
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxdbsyncer.a
+
+libzbxdbsyncer_a_SOURCES = dbsyncer.c dbsyncer.h
diff --git a/src/zabbix_proxy/dbsyncer/dbsyncer.c b/src/zabbix_proxy/dbsyncer/dbsyncer.c
new file mode 100644
index 00000000..644418da
--- /dev/null
+++ b/src/zabbix_proxy/dbsyncer/dbsyncer.c
@@ -0,0 +1,75 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "dbcache.h"
+#include "dbsyncer.h"
+
+/******************************************************************************
+ * *
+ * Function: main_dbsyncer_loop *
+ * *
+ * Purpose: periodically syncronises data in memory cache with database *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: never returns *
+ * *
+ ******************************************************************************/
+int main_dbsyncer_loop()
+{
+ int now;
+ struct timeval from;
+ struct timeval to;
+
+ zbx_setproctitle("connecting to the database");
+
+ DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+ for(;;)
+ {
+ now = time(NULL);
+
+ zabbix_log( LOG_LEVEL_WARNING, "Syncing ...");
+
+
+ gettimeofday(&from, NULL);
+
+ DCsync();
+
+ gettimeofday(&to, NULL);
+ zabbix_log( LOG_LEVEL_WARNING, "Spent " ZBX_FS_DBL " sec",
+ time_diff(&from,&to));
+
+ zbx_setproctitle("sender [sleeping for %d seconds]",
+ CONFIG_DBSYNCER_FREQUENCY);
+
+ sleep(CONFIG_DBSYNCER_FREQUENCY);
+ }
+ DBclose();
+}
diff --git a/src/zabbix_proxy/dbsyncer/dbsyncer.h b/src/zabbix_proxy/dbsyncer/dbsyncer.h
new file mode 100644
index 00000000..753ea08b
--- /dev/null
+++ b/src/zabbix_proxy/dbsyncer/dbsyncer.h
@@ -0,0 +1,29 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2007 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_DBSYNCER_H
+#define ZABBIX_DBSYNCER_H
+
+#include "db.h"
+
+extern int CONFIG_DBSYNCER_FREQUENCY;
+
+int main_dbsyncer_loop();
+
+#endif
diff --git a/src/zabbix_proxy/discoverer/Makefile.am b/src/zabbix_proxy/discoverer/Makefile.am
new file mode 100644
index 00000000..aae20ad6
--- /dev/null
+++ b/src/zabbix_proxy/discoverer/Makefile.am
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxdiscoverer.a
+
+libzbxdiscoverer_a_SOURCES = discoverer.c discoverer.h
diff --git a/src/zabbix_proxy/discoverer/discoverer.c b/src/zabbix_proxy/discoverer/discoverer.c
new file mode 100644
index 00000000..101117c4
--- /dev/null
+++ b/src/zabbix_proxy/discoverer/discoverer.c
@@ -0,0 +1,907 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "pid.h"
+#include "db.h"
+#include "log.h"
+#include "sysinfo.h"
+#include "zlog.h"
+
+#include "daemon.h"
+#include "discoverer.h"
+#include "../events.h"
+#include "../poller/checks_agent.h"
+#include "../poller/checks_snmp.h"
+
+int discoverer_num;
+
+/******************************************************************************
+ * *
+ * Function: add_host_event *
+ * *
+ * Purpose: generate host UP/DOWN event if required *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void add_host_event(char *ip)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ DB_EVENT event;
+ int now;
+ int status;
+ zbx_uint64_t dhostid;
+
+ assert(ip);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In add_host_event(ip:%s)",
+ ip);
+
+ result = DBselect("select status,dhostid from dhosts where ip='%s'",
+ ip);
+ row=DBfetch(result);
+ if(row && DBis_null(row[0])!=SUCCEED)
+ {
+ now = time(NULL);
+ status = atoi(row[0]);
+ ZBX_STR2UINT64(dhostid, row[1]);
+
+ memset(&event,0,sizeof(DB_EVENT));
+
+ event.eventid = 0;
+ event.source = EVENT_SOURCE_DISCOVERY;
+ event.object = EVENT_OBJECT_DHOST;
+ event.objectid = dhostid;
+ event.clock = now;
+ event.value = status;
+ event.acknowledged = 0;
+
+ process_event(&event);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End add_host_event()");
+}
+
+/******************************************************************************
+ * *
+ * Function: add_service_event *
+ * *
+ * Purpose: generate service UP/DOWN event if required *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void add_service_event(DB_DSERVICE *service)
+{
+ DB_EVENT event;
+ int now;
+
+ assert(service);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In add_service_event()");
+
+ now = time(NULL);
+
+ memset(&event,0,sizeof(DB_EVENT));
+
+ event.eventid = 0;
+ event.source = EVENT_SOURCE_DISCOVERY;
+ event.object = EVENT_OBJECT_DSERVICE;
+ event.objectid = service->dserviceid;
+ event.clock = now;
+ event.value = service->status;
+ event.acknowledged = 0;
+
+ process_event(&event);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End add_service_event()");
+}
+
+/******************************************************************************
+ * *
+ * Function: update_dservice *
+ * *
+ * Purpose: update descovered service details *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void update_dservice(DB_DSERVICE *service)
+{
+ char key_esc[MAX_STRING_LEN];
+
+ assert(service);
+
+ DBescape_string(service->key_, key_esc, sizeof(key_esc)-1);
+
+ DBexecute("update dservices set dhostid=" ZBX_FS_UI64 ",type=%d,port=%d,status=%d,lastup=%d,lastdown=%d,key_='%s' where dserviceid=" ZBX_FS_UI64,
+ service->dhostid,
+ service->type,
+ service->port,
+ service->status,
+ service->lastup,
+ service->lastdown,
+ key_esc,
+ service->dserviceid);
+}
+
+/******************************************************************************
+ * *
+ * Function: update_host *
+ * *
+ * Purpose: update descovered host details *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void update_dhost(DB_DHOST *host)
+{
+ assert(host);
+
+ DBexecute("update dhosts set druleid=" ZBX_FS_UI64 ",ip='%s',status=%d,lastup=%d,lastdown=%d where dhostid=" ZBX_FS_UI64,
+ host->druleid,
+ host->ip,
+ host->status,
+ host->lastup,
+ host->lastdown,
+ host->dhostid);
+}
+
+/******************************************************************************
+ * *
+ * Function: register_service *
+ * *
+ * Purpose: register service if one does not exist *
+ * *
+ * Parameters: host ip address *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void register_service(DB_DSERVICE *service,DB_DRULE *rule,DB_DCHECK *check,zbx_uint64_t dhostid,char *ip,int port)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ char value_esc[MAX_STRING_LEN];
+ char key_esc[MAX_STRING_LEN];
+
+ assert(service);
+ assert(rule);
+ assert(check);
+ assert(ip);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In register_service(ip:%s,port:%d)",
+ ip,
+ port);
+
+ DBescape_string(check->key_, key_esc, sizeof(key_esc)-1);
+
+ result = DBselect("select dserviceid,dhostid,type,port,status,lastup,lastdown,value,key_ from dservices where dhostid=" ZBX_FS_UI64 " and type=%d and port=%d and key_='%s'",
+ dhostid,
+ check->type,
+ port,
+ key_esc);
+ row=DBfetch(result);
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ /* Add host only if service is up */
+ if(check->status == DOBJECT_STATUS_UP)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "New service discovered on port %d", port);
+
+ service->dserviceid = DBget_maxid("dservices","dserviceid");
+ service->dhostid = dhostid;
+ service->type = check->type;
+ service->port = port;
+ service->status = DOBJECT_STATUS_UP;
+ service->lastup = 0;
+ service->lastdown = 0;
+ strscpy(service->value, check->value);
+ strscpy(service->key_, check->key_);
+
+ DBescape_string(service->value, value_esc, sizeof(value_esc)-1);
+ DBescape_string(service->key_, key_esc, sizeof(key_esc)-1);
+
+ DBexecute("insert into dservices (dhostid,dserviceid,type,port,status,value,key_) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d,%d,%d,'%s','%s')",
+ service->dhostid,
+ service->dserviceid,
+ check->type,
+ service->port,
+ service->status,
+ value_esc,
+ key_esc);
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Service is already in database");
+
+ ZBX_STR2UINT64(service->dserviceid, row[0]);
+ ZBX_STR2UINT64(service->dhostid, row[1]);
+ service->type = atoi(row[2]);
+ service->port = atoi(row[3]);
+ service->status = atoi(row[4]);
+ service->lastup = atoi(row[5]);
+ service->lastdown = atoi(row[6]);
+ strscpy(service->value,row[7]);
+ strscpy(service->key_,row[8]);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End register_service()");
+}
+
+/******************************************************************************
+ * *
+ * Function: register_host *
+ * *
+ * Purpose: register host if one does not exist *
+ * *
+ * Parameters: host ip address *
+ * *
+ * Return value: dhostid or 0 if we didn't add host *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void register_host(DB_DHOST *host,DB_DCHECK *check, zbx_uint64_t druleid, char *ip)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ assert(host);
+ assert(check);
+ assert(ip);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In register_host(ip:%s)",
+ ip);
+
+ host->dhostid=0;
+ result = DBselect("select dhostid,druleid,ip,status,lastup,lastdown from dhosts where ip='%s' and " ZBX_COND_NODEID,
+ ip,
+ LOCAL_NODE("dhostid"));
+ row=DBfetch(result);
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ /* Add host only if service is up */
+ if(check->status == DOBJECT_STATUS_UP)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "New host discovered at %s",
+ ip);
+ host->dhostid = DBget_maxid("dhosts","dhostid");
+ DBexecute("insert into dhosts (dhostid,druleid,ip) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 ",'%s')",
+ host->dhostid,
+ druleid,
+ ip);
+ host->druleid = druleid;
+ strscpy(host->ip,ip);
+ host->status = 0;
+ host->lastup = 0;
+ host->lastdown = 0;
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Host is already in database");
+ ZBX_STR2UINT64(host->dhostid,row[0]);
+ ZBX_STR2UINT64(host->druleid,row[1]);
+ strscpy(host->ip, row[2]);
+ host->status = atoi(row[3]);
+ host->lastup = atoi(row[4]);
+ host->lastdown = atoi(row[5]);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End register_host()");
+}
+
+/******************************************************************************
+ * *
+ * Function: update_service *
+ * *
+ * Purpose: process new service status *
+ * *
+ * Parameters: service - service info *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void update_service(DB_DRULE *rule, DB_DCHECK *check, char *ip, int port)
+{
+ int now;
+ DB_DHOST host;
+ DB_DSERVICE service;
+
+ assert(rule);
+ assert(check);
+ assert(ip);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In update_service(ip:%s, port:%d, status:%s)",
+ ip,
+ port,
+ (check->status==DOBJECT_STATUS_UP?"up":"down"));
+
+ service.dserviceid=0;
+
+ /* Register host if is not registered yet */
+ register_host(&host,check,rule->druleid,ip);
+
+ if(host.dhostid>0)
+ {
+ /* Register service if is not registered yet */
+/* dserviceid = register_service(rule,check,host.dhostid,ip,port);*/
+ register_service(&service,rule,check,host.dhostid,ip,port);
+ }
+
+ if(service.dserviceid == 0)
+ {
+ /* Service wasn't registered because we do not add down service */
+ return;
+ }
+
+ now = time(NULL);
+ if(check->status == DOBJECT_STATUS_UP)
+ {
+ /* Update host status */
+ if(host.status == DOBJECT_STATUS_DOWN || host.lastup==0)
+ {
+ host.status=DOBJECT_STATUS_UP;
+ host.lastdown=0;
+ host.lastup=now;
+ update_dhost(&host);
+ }
+ /* Update service status */
+ if(service.status == DOBJECT_STATUS_DOWN || service.lastup==0)
+ {
+ service.status=DOBJECT_STATUS_UP;
+ service.lastdown=0;
+ service.lastup=now;
+ update_dservice(&service);
+ }
+ }
+ /* DOBJECT_STATUS_DOWN */
+ else
+ {
+ if(host.status == DOBJECT_STATUS_UP || host.lastdown==0)
+ {
+ host.status=DOBJECT_STATUS_DOWN;
+ host.lastdown=now;
+ host.lastup=0;
+ update_dhost(&host);
+ }
+ /* Update service status */
+ if(service.status == DOBJECT_STATUS_UP || service.lastdown==0)
+ {
+ service.status=DOBJECT_STATUS_DOWN;
+ service.lastdown=now;
+ service.lastup=0;
+ update_dservice(&service);
+ }
+ }
+
+ add_service_event(&service);
+}
+
+/******************************************************************************
+ * *
+ * Function: discover_service *
+ * *
+ * Purpose: check if service is avaiable and update database *
+ * *
+ * Parameters: service typ,e ip address, port number *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int discover_service(DB_DCHECK *check, char *ip, int port)
+{
+ int ret = SUCCEED;
+ char key[MAX_STRING_LEN];
+ AGENT_RESULT value;
+ DB_ITEM item;
+ struct sigaction phan;
+
+ assert(check);
+ assert(ip);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In discover_service(ip:%s, port:%d, type:%d)",
+ ip,
+ port,
+ check->type);
+
+ init_result(&value);
+
+ switch(check->type) {
+ case SVC_SSH:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[ssh,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_LDAP:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[ldap,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_SMTP:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[smtp,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_FTP:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[ftp,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_HTTP:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[http,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_POP:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[pop,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_NNTP:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[nntp,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_IMAP:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[imap,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_TCP:
+ zbx_snprintf(key,sizeof(key),"net.tcp.service[tcp,%s,%d]",
+ ip,
+ port);
+ break;
+ case SVC_AGENT:
+ case SVC_SNMPv1:
+ case SVC_SNMPv2c:
+ break;
+ default:
+ ret = FAIL;
+ break;
+ }
+
+ if(ret == SUCCEED)
+ {
+ phan.sa_handler = &child_signal_handler;
+ sigemptyset(&phan.sa_mask);
+ phan.sa_flags = 0;
+ sigaction(SIGALRM, &phan, NULL);
+ alarm(10);
+
+ switch(check->type) {
+ /* Agent and SNMP checks */
+ case SVC_AGENT:
+ case SVC_SNMPv1:
+ case SVC_SNMPv2c:
+ memset(&item,0,sizeof(DB_ITEM));
+ strscpy(item.key,check->key_);
+ item.host_name = ip;
+ item.host_ip = ip;
+ item.host_dns = ip;
+ item.useip = 1;
+ item.port = port;
+
+ item.value_type = ITEM_VALUE_TYPE_STR;
+
+ if(check->type == SVC_SNMPv1)
+ {
+ item.type = ITEM_TYPE_SNMPv1;
+ }
+ else
+ {
+ item.type = ITEM_TYPE_SNMPv2c;
+ }
+
+ item.snmp_oid = check->key_;
+ item.snmp_community = check->snmp_community;
+ item.snmp_port = port;
+
+ if(check->type==SVC_AGENT)
+ {
+ if(SUCCEED == get_value_agent(&item, &value))
+ {
+ if(GET_STR_RESULT(&value))
+ {
+ strscpy(check->value, value.str);
+ }
+ else ret = FAIL;
+ }
+ else
+ {
+ ret = FAIL;
+ }
+ }
+ else
+#ifdef HAVE_SNMP
+ {
+ if(SUCCEED == get_value_snmp(&item, &value))
+ {
+ if(GET_STR_RESULT(&value))
+ {
+ strscpy(check->value, value.str);
+ }
+ else ret = FAIL;
+ }
+ else
+ {
+ ret = FAIL;
+ }
+ }
+#else
+ {
+ ret = FAIL;
+ }
+#endif
+ break;
+ /* Simple checks */
+ default:
+ if(process(key, 0, &value) == SUCCEED)
+ {
+ if(GET_UI64_RESULT(&value))
+ {
+ if(value.ui64 == 0) ret = FAIL;
+ }
+ else ret = FAIL;
+ }
+ else ret = FAIL;
+ break;
+ }
+ alarm(0);
+ }
+ free_result(&value);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End discover_service()");
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: process_check *
+ * *
+ * Purpose: check if service is avaiable and update database *
+ * *
+ * Parameters: service - service info *
+ * *
+ * Return value: *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void process_check(DB_DRULE *rule, DB_DCHECK *check, char *ip)
+{
+ int port,
+ first,
+ last;
+
+ char *curr_range = NULL,
+ *next_range = NULL,
+ *last_port = NULL;
+
+ assert(rule);
+ assert(check);
+ assert(ip);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_check(ip:%s, ports:%s, type:%d)",
+ ip,
+ check->ports,
+ check->type);
+
+ for ( curr_range = check->ports; curr_range; curr_range = next_range )
+ { /* split by ',' */
+ if ( (next_range = strchr(curr_range, ',')) )
+ {
+ *next_range = '\0';
+ }
+
+ if ( (last_port = strchr(curr_range, '-')) )
+ { /* split by '-' */
+ *last_port = '\0';
+ first = atoi(curr_range);
+ last = atoi(last_port);
+ *last_port = '-';
+ }
+ else
+ {
+ first = last = atoi(curr_range);
+ }
+
+ if ( next_range )
+ {
+ *next_range = ',';
+ next_range++;
+ }
+
+ for ( port = first; port <= last; port++)
+ {
+ check->status = discover_service(check,ip,port);
+ update_service(rule, check, ip, port);
+ }
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End process_check()");
+}
+
+/******************************************************************************
+ * *
+ * Function: process_rule *
+ * *
+ * Purpose: process single discovery rule *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void process_rule(DB_DRULE *rule)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ DB_DCHECK check;
+
+ char ip[MAX_STRING_LEN], prefix[MAX_STRING_LEN];
+ unsigned int j[9], i;
+ int first, last, ipv6;
+
+ char *curr_range = NULL,
+ *next_range = NULL,
+ *dash = NULL;
+#if defined(HAVE_IPV6)
+ char *colon;
+#endif
+
+ assert(rule);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_rule() [name:%s] [range:%s]",
+ rule->name,
+ rule->iprange);
+
+ for ( curr_range = rule->iprange; curr_range; curr_range = next_range )
+ { /* split by ',' */
+ if ( NULL != (next_range = strchr(curr_range, ',')) )
+ {
+ next_range[0] = '\0';
+ }
+
+ if ( NULL != (dash = strchr(curr_range, '-')) )
+ {
+ dash[0] = '\0';
+ }
+
+ first = last = -1;
+#if defined(HAVE_IPV6)
+ if ( SUCCEED == expand_ipv6(curr_range, ip, sizeof(ip)) )
+ {
+ ipv6 = 1;
+ if( sscanf(ip, "%x:%x:%x:%x:%x:%x:%x:%x", &j[0], &j[1], &j[2], &j[3], &j[4], &j[5], &j[6], &j[7]) == 8 )
+ {
+ first = j[7];
+
+ zbx_strlcpy( prefix, curr_range, sizeof(prefix) );
+ if( NULL != (colon = strrchr(prefix, ':')) )
+ {
+ ( colon + 1 )[0] = '\0';
+ }
+ }
+
+ if( dash != NULL )
+ {
+ if( sscanf(dash + 1, "%x", &j[8]) == 1 )
+ {
+ last = j[8];
+ }
+ }
+ else
+ {
+ last = first;
+ }
+ }
+ else
+ {
+#endif /* HAVE_IPV6 */
+ ipv6 = 0;
+ if( sscanf(curr_range, "%d.%d.%d.%d", &j[0], &j[1], &j[2], &j[3]) == 4 )
+ {
+ first = j[3];
+ }
+
+ if( dash != NULL )
+ {
+ if( sscanf(dash + 1, "%d", &j[4]) == 1 )
+ {
+ last = j[4];
+ }
+ }
+ else
+ {
+ last = first;
+ }
+#if defined(HAVE_IPV6)
+ }
+#endif /* HAVE_IPV6 */
+
+ if( dash )
+ {
+ dash[0] = '-';
+ dash = NULL;
+ }
+
+ if ( next_range )
+ {
+ next_range[0] = ',';
+ next_range ++;
+ }
+
+ if( first < 0 || last < 0 )
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "Discovery: Wrong format of IP range [%s]",
+ rule->iprange);
+ continue;
+ }
+
+ for ( i = first; i <= last; i++ )
+ {
+ switch( ipv6 )
+ {
+ case 0 : zbx_snprintf(ip, sizeof(ip), "%d.%d.%d.%d", j[0], j[1], j[2], i); break;
+ case 1 : zbx_snprintf(ip, sizeof(ip), "%s%x", prefix, i); break;
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "Discovery: process_rule() [IP:%s]", ip);
+
+ result = DBselect("select dcheckid,druleid,type,key_,snmp_community,ports from dchecks where druleid=" ZBX_FS_UI64,
+ rule->druleid);
+ while((row=DBfetch(result)))
+ {
+ memset(&check, 0, sizeof(DB_RESULT));
+
+ ZBX_STR2UINT64(check.dcheckid,row[0]);
+ ZBX_STR2UINT64(check.druleid,row[1]);
+ check.type = atoi(row[2]);
+ check.key_ = row[3];
+ check.snmp_community = row[4];
+ check.ports = row[5];
+
+ process_check(rule, &check, ip);
+ }
+ DBfree_result(result);
+
+ add_host_event(ip);
+ }
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End process_rule()");
+}
+
+/******************************************************************************
+ * *
+ * Function: main_discoverer_loop *
+ * *
+ * Purpose: periodically try to find new hosts and services *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: executes once per 30 seconds (hardcoded) *
+ * *
+ ******************************************************************************/
+void main_discoverer_loop(int num)
+{
+ int now;
+
+ DB_RESULT result;
+ DB_ROW row;
+ DB_DRULE rule;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In main_discoverer_loop(num:%d)",
+ num);
+
+ discoverer_num = num;
+
+ DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+ for(;;)
+ {
+ now=time(NULL);
+
+ result = DBselect("select druleid,iprange,delay,nextcheck,name,status from drules where status=%d and nextcheck<=%d and " ZBX_SQL_MOD(druleid,%d) "=%d and" ZBX_COND_NODEID,
+ DRULE_STATUS_MONITORED,
+ now,
+ CONFIG_DISCOVERER_FORKS,
+ discoverer_num-1,
+ LOCAL_NODE("druleid"));
+ while((row=DBfetch(result)))
+ {
+ memset(&rule, 0, sizeof(DB_DRULE));
+
+ ZBX_STR2UINT64(rule.druleid,row[0]);
+ rule.iprange = row[1];
+ rule.delay = atoi(row[2]);
+ rule.nextcheck = atoi(row[3]);
+ rule.name = row[4];
+ rule.status = atoi(row[5]);
+
+ process_rule(&rule);
+ }
+ DBfree_result(result);
+
+ zbx_setproctitle("sleeping for 30 sec");
+
+ sleep(30);
+ }
+ DBclose();
+}
diff --git a/src/zabbix_proxy/discoverer/discoverer.h b/src/zabbix_proxy/discoverer/discoverer.h
new file mode 100644
index 00000000..12f30728
--- /dev/null
+++ b/src/zabbix_proxy/discoverer/discoverer.h
@@ -0,0 +1,27 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_DISCOVERER_H
+#define ZABBIX_DISCOVERER_H
+
+extern int CONFIG_DISCOVERER_FORKS;
+
+void main_discoverer_loop(int num);
+
+#endif
diff --git a/src/zabbix_proxy/evalfunc.c b/src/zabbix_proxy/evalfunc.c
new file mode 100644
index 00000000..642913f0
--- /dev/null
+++ b/src/zabbix_proxy/evalfunc.c
@@ -0,0 +1,1826 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "evalfunc.h"
+
+/******************************************************************************
+ * *
+ * Function: evaluate_LOGSOURCE *
+ * *
+ * Purpose: evaluate function 'logsource' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - ignored *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_LOGSOURCE(char *value, DB_ITEM *item, char *parameter)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char sql[MAX_STRING_LEN];
+ int now;
+ int res = SUCCEED;
+
+ if(item->value_type != ITEM_VALUE_TYPE_LOG)
+ {
+ return FAIL;
+ }
+
+ now=time(NULL);
+
+ zbx_snprintf(sql,sizeof(sql),"select source from history_log where itemid=" ZBX_FS_UI64 " order by clock desc",
+ item->itemid);
+
+ result = DBselectN(sql,1);
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for LOGSOURCE is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ if(strcmp(row[0], parameter) == 0)
+ {
+ strcpy(value,"1");
+ }
+ else
+ {
+ strcpy(value,"0");
+ }
+ }
+ DBfree_result(result);
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_LOGSEVERITY *
+ * *
+ * Purpose: evaluate function 'logseverity' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - ignored *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_LOGSEVERITY(char *value, DB_ITEM *item, char *parameter)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char sql[MAX_STRING_LEN];
+ int now;
+ int res = SUCCEED;
+
+ if(item->value_type != ITEM_VALUE_TYPE_LOG)
+ {
+ return FAIL;
+ }
+
+ now=time(NULL);
+
+ zbx_snprintf(sql,sizeof(sql),"select severity from history_log where itemid=" ZBX_FS_UI64 " order by clock desc",
+ item->itemid);
+
+ result = DBselectN(sql,1);
+ row = DBfetch(result);
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for LOGSEVERITY is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ strcpy(value,row[0]);
+ }
+ DBfree_result(result);
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_COUNT *
+ * *
+ * Purpose: evaluate function 'count' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - number of seconds *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_COUNT(char *value, DB_ITEM *item, char *parameter)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char period[MAX_STRING_LEN+1];
+ char op[MAX_STRING_LEN+1];
+ char cmp[MAX_STRING_LEN+1];
+ char cmp_esc[MAX_STRING_LEN+1];
+
+ int now;
+ int res = SUCCEED;
+
+ char *table = NULL;
+ char table_ui64[] = "history_uint";
+ char table_float[] = "history";
+ char table_log[] = "history_log";
+ char table_str[] = "history_str";
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_COUNT(param:%s)",
+ parameter);
+
+
+ switch(item->value_type)
+ {
+ case ITEM_VALUE_TYPE_FLOAT: table = table_float; break;
+ case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break;
+ case ITEM_VALUE_TYPE_LOG: table = table_log; break;
+ case ITEM_VALUE_TYPE_STR: table = table_str; break;
+ default:
+ return FAIL;
+ }
+
+ now=time(NULL);
+
+ if(get_param(parameter, 1, period, MAX_STRING_LEN) != 0)
+ {
+ return FAIL;
+ }
+ if(get_param(parameter, 2, cmp, MAX_STRING_LEN) != 0)
+ {
+ result = DBselect("select count(value) from %s where clock>%d and itemid=" ZBX_FS_UI64,
+ table,
+ now-atoi(period),
+ item->itemid);
+
+ }
+ else
+ {
+ if(get_param(parameter, 3, op, MAX_STRING_LEN) != 0)
+ {
+ strscpy(op,"eq");
+ }
+ DBescape_string(cmp, cmp_esc, sizeof(cmp_esc));
+ /* ITEM_VALUE_TYPE_UINT64 */
+ if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"eq") == 0))
+ {
+ result = DBselect("select count(value) from history_uint where clock>%d and value=" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ zbx_atoui64(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"ne") == 0))
+ {
+ result = DBselect("select count(value) from history_uint where clock>%d and value<>" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ zbx_atoui64(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"gt") == 0))
+ {
+ result = DBselect("select count(value) from history_uint where clock>%d and value>" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ zbx_atoui64(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"lt") == 0))
+ {
+ result = DBselect("select count(value) from history_uint where clock>%d and value<" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ zbx_atoui64(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"ge") == 0))
+ {
+ result = DBselect("select count(value) from history_uint where clock>%d and value>=" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ zbx_atoui64(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_UINT64) && (strcmp(op,"le") == 0))
+ {
+ result = DBselect("select count(value) from history_uint where clock>%d and value<=" ZBX_FS_UI64 " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ zbx_atoui64(cmp_esc),
+ item->itemid);
+ }
+ /* ITEM_VALUE_TYPE_FLOAT */
+ else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"eq") == 0))
+ {
+ result = DBselect("select count(value) from history where clock>%d and value+0.00001>" ZBX_FS_DBL " and value-0.0001<" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ atof(cmp_esc),
+ atof(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"ne") == 0))
+ {
+ result = DBselect("select count(value) from history where clock>%d and ((value+0.00001<" ZBX_FS_DBL ") or (value-0.0001>" ZBX_FS_DBL ")) and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ atof(cmp_esc),
+ atof(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"gt") == 0))
+ {
+ result = DBselect("select count(value) from history where clock>%d and value>" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ atof(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"ge") == 0))
+ {
+ result = DBselect("select count(value) from history where clock>=%d and value>" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ atof(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"lt") == 0))
+ {
+ result = DBselect("select count(value) from history where clock>%d and value<" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ atof(cmp_esc),
+ item->itemid);
+ }
+ else if( (item->value_type == ITEM_VALUE_TYPE_FLOAT) && (strcmp(op,"le") == 0))
+ {
+ result = DBselect("select count(value) from history where clock>%d and value<=" ZBX_FS_DBL " and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ atof(cmp_esc),
+ item->itemid);
+ }
+ else if(item->value_type == ITEM_VALUE_TYPE_LOG)
+ {
+ result = DBselect("select count(value) from history_log where clock>%d and value like '%s' and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ cmp_esc,
+ item->itemid);
+ }
+ else
+ {
+ result = DBselect("select count(value) from history_str where clock>%d and value like '%s' and itemid=" ZBX_FS_UI64,
+ now-atoi(period),
+ cmp_esc,
+ item->itemid);
+ }
+ }
+
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for COUNT is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ strcpy(value,row[0]);
+ }
+ DBfree_result(result);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End evaluate_COUNT");
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_SUM *
+ * *
+ * Purpose: evaluate function 'sum' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - number of seconds *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_SUM(char *value, DB_ITEM *item, int parameter, int flag)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char sql[MAX_STRING_LEN];
+ int now;
+ int res = SUCCEED;
+ int rows = 0;
+ double sum=0;
+ zbx_uint64_t sum_uint64=0;
+ zbx_uint64_t value_uint64;
+
+ char *table = NULL;
+ char table_ui64[] = "history_uint";
+ char table_float[] = "history";
+
+
+ switch(item->value_type)
+ {
+ case ITEM_VALUE_TYPE_FLOAT: table = table_float; break;
+ case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break;
+ default:
+ return FAIL;
+ }
+
+ now=time(NULL);
+
+ if(flag == ZBX_FLAG_SEC)
+ {
+ result = DBselect("select sum(value) from %s where clock>%d and itemid=" ZBX_FS_UI64,
+ table,
+ now-parameter,
+ item->itemid);
+
+ row = DBfetch(result);
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for SUM is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ strcpy(value,row[0]);
+ }
+ }
+ else if(flag == ZBX_FLAG_VALUES)
+ {
+ zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc",
+ table,
+ item->itemid);
+ result = DBselectN(sql, parameter);
+ if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(value_uint64,row[0]);
+ sum_uint64+=value_uint64;
+ rows++;
+ }
+ if(rows>0) zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, sum_uint64);
+ }
+ else
+ {
+ while((row=DBfetch(result)))
+ {
+ sum+=atof(row[0]);
+ rows++;
+ }
+ if(rows>0) zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, sum);
+ }
+ if(0 == rows)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for SUM is empty" );
+ res = FAIL;
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]",
+ flag,
+ ZBX_FLAG_SEC,
+ ZBX_FLAG_VALUES);
+ return FAIL;
+ }
+
+ DBfree_result(result);
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_AVG *
+ * *
+ * Purpose: evaluate function 'avg' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - number of seconds *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_AVG(char *value,DB_ITEM *item,int parameter,int flag)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char sql[MAX_STRING_LEN];
+ int now;
+ int res = SUCCEED;
+ int rows;
+ double sum=0;
+
+ char *table = NULL;
+ char table_ui64[] = "history_uint";
+ char table_float[] = "history";
+
+
+ switch(item->value_type)
+ {
+ case ITEM_VALUE_TYPE_FLOAT: table = table_float; break;
+ case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break;
+ default:
+ return FAIL;
+ }
+
+ now=time(NULL);
+
+ if(flag == ZBX_FLAG_SEC)
+ {
+ result = DBselect("select avg(value) from %s where clock>%d and itemid=" ZBX_FS_UI64,
+ table,
+ now-parameter,
+ item->itemid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for AVG is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ strcpy(value,row[0]);
+ del_zeroes(value);
+ }
+ }
+ else if(flag == ZBX_FLAG_VALUES)
+ {
+ zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc",
+ table,
+ item->itemid);
+ result = DBselectN(sql, parameter);
+ rows=0;
+ while((row=DBfetch(result)))
+ {
+ sum+=atof(row[0]);
+ rows++;
+ }
+ if(rows == 0)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for AVG is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, sum/(double)rows);
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]",
+ flag,
+ ZBX_FLAG_SEC,
+ ZBX_FLAG_VALUES);
+ return FAIL;
+ }
+
+ DBfree_result(result);
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_MIN *
+ * *
+ * Purpose: evaluate function 'min' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - number of seconds *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_MIN(char *value,DB_ITEM *item,int parameter, int flag)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char sql[MAX_STRING_LEN];
+ int now;
+ int rows;
+ int res = SUCCEED;
+
+ char *table = NULL;
+ char table_ui64[] = "history_uint";
+ char table_float[] = "history";
+
+ zbx_uint64_t min_uint64=0;
+ zbx_uint64_t l;
+
+ double min=0;
+ double f;
+
+ switch(item->value_type)
+ {
+ case ITEM_VALUE_TYPE_FLOAT: table = table_float; break;
+ case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break;
+ default:
+ return FAIL;
+ }
+
+ now=time(NULL);
+
+
+ if(flag == ZBX_FLAG_SEC)
+ {
+ result = DBselect("select min(value) from %s where clock>%d and itemid=" ZBX_FS_UI64,
+ table,
+ now-parameter,
+ item->itemid);
+ row = DBfetch(result);
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for MIN is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ strcpy(value,row[0]);
+ del_zeroes(value);
+ }
+ }
+ else if(flag == ZBX_FLAG_VALUES)
+ {
+ zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc",
+ table,
+ item->itemid);
+ result = DBselectN(sql,parameter);
+
+ rows=0;
+ while((row=DBfetch(result)))
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ ZBX_STR2UINT64(l,row[0]);
+
+ if(rows==0) min_uint64 = l;
+ else if(l<min_uint64) min_uint64 = l;
+ }
+ else
+ {
+ f=atof(row[0]);
+ if(rows==0) min = f;
+ else if(f<min) min = f;
+ }
+ rows++;
+ }
+
+ if(rows==0)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for MIN is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, min_uint64);
+ }
+ else
+ {
+ zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, min);
+ }
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]",
+ flag,
+ ZBX_FLAG_SEC,
+ ZBX_FLAG_VALUES);
+ return FAIL;
+ }
+
+ DBfree_result(result);
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_MAX *
+ * *
+ * Purpose: evaluate function 'max' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - number of seconds *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_MAX(char *value,DB_ITEM *item,int parameter,int flag)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char sql[MAX_STRING_LEN];
+ int now;
+ int res = SUCCEED;
+ int rows;
+ double f;
+ double max = 0;
+
+ char *table = NULL;
+ char table_ui64[] = "history_uint";
+ char table_float[] = "history";
+
+ zbx_uint64_t max_uint64=0;
+ zbx_uint64_t l;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_MAX()");
+
+ switch(item->value_type)
+ {
+ case ITEM_VALUE_TYPE_FLOAT: table = table_float; break;
+ case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break;
+ default:
+ return FAIL;
+ }
+
+ now=time(NULL);
+
+ if(flag == ZBX_FLAG_SEC)
+ {
+ result = DBselect("select max(value) from %s where clock>%d and itemid=" ZBX_FS_UI64,
+ table,
+ now-parameter,
+ item->itemid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for MAX is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ strcpy(value,row[0]);
+ del_zeroes(value);
+ }
+ }
+ else if(flag == ZBX_FLAG_VALUES)
+ {
+ zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc",
+ table,
+ item->itemid);
+ result = DBselectN(sql,parameter);
+ rows=0;
+ while((row=DBfetch(result)))
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ ZBX_STR2UINT64(l,row[0]);
+
+ if(rows==0) max_uint64 = l;
+ else if(l>max_uint64) max_uint64 = l;
+ }
+ else
+ {
+ f=atof(row[0]);
+ if(rows==0) max=f;
+ else if(f>max) max=f;
+ }
+ rows++;
+ }
+ if(rows == 0)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for MAX is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, max_uint64);
+ }
+ else
+ {
+ zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, max);
+ }
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]",
+ flag,
+ ZBX_FLAG_SEC,
+ ZBX_FLAG_VALUES);
+ return FAIL;
+ }
+
+ DBfree_result(result);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End of evaluate_MAX()");
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_DELTA *
+ * *
+ * Purpose: evaluate function 'delat' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - number of seconds *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_DELTA(char *value,DB_ITEM *item,int parameter, int flag)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char sql[MAX_STRING_LEN];
+ int now;
+ int res = SUCCEED;
+ int rows;
+ double f;
+ double min = 0,max = 0;
+
+ zbx_uint64_t max_uint64=0,min_uint64=0;
+ zbx_uint64_t l;
+
+ char *table = NULL;
+ char table_ui64[] = "history_uint";
+ char table_float[] = "history";
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_DELTA()");
+
+ switch(item->value_type)
+ {
+ case ITEM_VALUE_TYPE_FLOAT: table = table_float; break;
+ case ITEM_VALUE_TYPE_UINT64: table = table_ui64; break;
+ default:
+ return FAIL;
+ }
+
+ now=time(NULL);
+
+ if(flag == ZBX_FLAG_SEC)
+ {
+ result = DBselect("select max(value)-min(value) from %s where clock>%d and itemid=" ZBX_FS_UI64,
+ table,
+ now-parameter,
+ item->itemid);
+
+ row = DBfetch(result);
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for DELTA is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ strcpy(value,row[0]);
+ del_zeroes(value);
+ }
+ }
+ else if(flag == ZBX_FLAG_VALUES)
+ {
+ zbx_snprintf(sql,sizeof(sql),"select value from %s where itemid=" ZBX_FS_UI64 " order by clock desc",
+ table,
+ item->itemid);
+ result = DBselectN(sql,parameter);
+ rows=0;
+ while((row=DBfetch(result)))
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ ZBX_STR2UINT64(l,row[0]);
+
+ if(rows==0)
+ {
+ max_uint64 = l;
+ min_uint64 = l;
+ }
+ else
+ {
+ if(l>max_uint64) max_uint64 = l;
+ if(l<min_uint64) min_uint64 = l;
+ }
+ }
+ else
+ {
+ f=atof(row[0]);
+ if(rows==0)
+ {
+ min=f;
+ max=f;
+ }
+ else
+ {
+ if(f>max) max=f;
+ if(f<min) min=f;
+ }
+ }
+ rows++;
+ }
+ if(rows==0)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result for DELTA is empty" );
+ res = FAIL;
+ }
+ else
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64, max_uint64-min_uint64);
+ }
+ else
+ {
+ zbx_snprintf(value,MAX_STRING_LEN, ZBX_FS_DBL, max-min);
+ }
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "Unknown flag [%d] Expected [%d] or [%d]",
+ flag,
+ ZBX_FLAG_SEC,
+ ZBX_FLAG_VALUES);
+ return FAIL;
+ }
+
+ DBfree_result(result);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End of evaluate_DELTA()");
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_NODATA *
+ * *
+ * Purpose: evaluate function 'nodata' for the item *
+ * *
+ * Parameters: item - item (performance metric) *
+ * parameter - number of seconds *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result is stored in 'value' *
+ * FAIL - failed to evaluate function *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int evaluate_NODATA(char *value,DB_ITEM *item,int parameter)
+{
+ int now;
+ int res = SUCCEED;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_NODATA()");
+
+ now = time(NULL);
+
+ if((CONFIG_SERVER_STARTUP_TIME + parameter > now) || (item->lastclock + parameter > now))
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End of evaluate_NODATA()");
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_function *
+ * *
+ * Purpose: evaluate function *
+ * *
+ * Parameters: item - item to calculate function for *
+ * function - function (for example, 'max') *
+ * parameter - parameter of the function) *
+ * flag - if EVALUATE_FUNCTION_SUFFIX, then include units and *
+ * suffix (K,M,G) into result value (for example, 15GB) *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, value contains its value *
+ * FAIL - evaluation failed *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int evaluate_function(char *value,DB_ITEM *item,char *function,char *parameter)
+{
+ int ret = SUCCEED;
+ time_t now;
+ struct tm *tm;
+
+ int fuzlow, fuzhig;
+
+ int day;
+ int len;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_function(%s)",
+ function);
+
+ if(strcmp(function,"last")==0)
+ {
+ if(item->lastvalue_null==1)
+ {
+ ret = FAIL;
+ }
+ else
+ {
+ switch (item->value_type) {
+ case ITEM_VALUE_TYPE_FLOAT:
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_DBL,item->lastvalue_dbl);
+ del_zeroes(value);
+ break;
+ case ITEM_VALUE_TYPE_UINT64:
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64,item->lastvalue_uint64);
+ break;
+ default:
+ strcpy(value,item->lastvalue_str);
+ break;
+ }
+ }
+ }
+ else if(strcmp(function,"prev")==0)
+ {
+ if(item->prevvalue_null==1)
+ {
+ ret = FAIL;
+ }
+ else
+ {
+ switch (item->value_type) {
+ case ITEM_VALUE_TYPE_FLOAT:
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_DBL,item->prevvalue_dbl);
+ del_zeroes(value);
+ break;
+ case ITEM_VALUE_TYPE_UINT64:
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64,item->prevvalue_uint64);
+ break;
+ default:
+ strcpy(value,item->prevvalue_str);
+ break;
+ }
+ }
+ }
+ else if(strcmp(function,"min")==0)
+ {
+ if(parameter[0]=='#')
+ ret = evaluate_MIN(value,item,atoi(parameter+1),ZBX_FLAG_VALUES);
+ else
+ ret = evaluate_MIN(value,item,atoi(parameter),ZBX_FLAG_SEC);
+ }
+ else if(strcmp(function,"max")==0)
+ {
+ if(parameter[0]=='#')
+ ret = evaluate_MAX(value,item,atoi(parameter+1),ZBX_FLAG_VALUES);
+ else
+ ret = evaluate_MAX(value,item,atoi(parameter),ZBX_FLAG_SEC);
+ }
+ else if(strcmp(function,"avg")==0)
+ {
+ if(parameter[0]=='#')
+ ret = evaluate_AVG(value,item,atoi(parameter+1),ZBX_FLAG_VALUES);
+ else
+ ret = evaluate_AVG(value,item,atoi(parameter),ZBX_FLAG_SEC);
+ }
+ else if(strcmp(function,"sum")==0)
+ {
+ if(parameter[0]=='#')
+ ret = evaluate_SUM(value,item,atoi(parameter+1),ZBX_FLAG_VALUES);
+ else
+ ret = evaluate_SUM(value,item,atoi(parameter),ZBX_FLAG_SEC);
+ }
+ else if(strcmp(function,"count")==0)
+ {
+ ret = evaluate_COUNT(value,item,parameter);
+ }
+ else if(strcmp(function,"delta")==0)
+ {
+ if(parameter[0]=='#')
+ ret = evaluate_DELTA(value,item,atoi(parameter+1),ZBX_FLAG_VALUES);
+ else
+ ret = evaluate_DELTA(value,item,atoi(parameter),ZBX_FLAG_SEC);
+ }
+ else if(strcmp(function,"nodata")==0)
+ {
+ ret = evaluate_NODATA(value,item,atoi(parameter));
+ }
+ else if(strcmp(function,"date")==0)
+ {
+ now=time(NULL);
+ tm=localtime(&now);
+ zbx_snprintf(value,MAX_STRING_LEN,"%.4d%.2d%.2d",
+ tm->tm_year+1900,
+ tm->tm_mon+1,
+ tm->tm_mday);
+ }
+ else if(strcmp(function,"dayofweek")==0)
+ {
+ now=time(NULL);
+ tm=localtime(&now);
+ /* The number of days since Sunday, in the range 0 to 6. */
+ day=tm->tm_wday;
+ if(0 == day) day=7;
+ zbx_snprintf(value,MAX_STRING_LEN,"%d",
+ day);
+ }
+ else if(strcmp(function,"time")==0)
+ {
+ now=time(NULL);
+ tm=localtime(&now);
+ zbx_snprintf(value,MAX_STRING_LEN,"%.2d%.2d%.2d",
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ }
+ else if(strcmp(function,"abschange")==0)
+ {
+ if((item->lastvalue_null==1)||(item->prevvalue_null==1))
+ {
+ ret = FAIL;
+ }
+ else
+ {
+ switch (item->value_type) {
+ case ITEM_VALUE_TYPE_FLOAT:
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_DBL,
+ (double)abs(item->lastvalue_dbl-item->prevvalue_dbl));
+ del_zeroes(value);
+ break;
+ case ITEM_VALUE_TYPE_UINT64:
+ /* To avoid overflow */
+ if(item->lastvalue_uint64>=item->prevvalue_uint64)
+ {
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64,
+ labs(item->lastvalue_uint64-item->prevvalue_uint64));
+ }
+ else
+ {
+ zbx_snprintf(value,MAX_STRING_LEN,"-" ZBX_FS_UI64,
+ labs(item->prevvalue_uint64 - item->lastvalue_uint64));
+ }
+ break;
+ default:
+ if(strcmp(item->lastvalue_str, item->prevvalue_str) == 0)
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+ break;
+ }
+ }
+ }
+ else if(strcmp(function,"change")==0)
+ {
+ if((item->lastvalue_null==1)||(item->prevvalue_null==1))
+ {
+ ret = FAIL;
+ }
+ else
+ {
+ switch (item->value_type) {
+ case ITEM_VALUE_TYPE_FLOAT:
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_DBL,
+ item->lastvalue_dbl-item->prevvalue_dbl);
+ del_zeroes(value);
+ break;
+ case ITEM_VALUE_TYPE_UINT64:
+ /* To avoid overflow */
+ if(item->lastvalue_uint64>=item->prevvalue_uint64)
+ {
+ zbx_snprintf(value,MAX_STRING_LEN,ZBX_FS_UI64,
+ item->lastvalue_uint64-item->prevvalue_uint64);
+ }
+ else
+ {
+ zbx_snprintf(value,MAX_STRING_LEN,"-" ZBX_FS_UI64,
+ item->prevvalue_uint64 - item->lastvalue_uint64);
+ }
+ break;
+ default:
+ if(strcmp(item->lastvalue_str, item->prevvalue_str) == 0)
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+ break;
+ }
+ }
+ }
+ else if(strcmp(function,"diff")==0)
+ {
+ if((item->lastvalue_null==1)||(item->prevvalue_null==1))
+ {
+ ret = FAIL;
+ }
+ else
+ {
+ switch (item->value_type) {
+ case ITEM_VALUE_TYPE_FLOAT:
+ if(cmp_double(item->lastvalue_dbl, item->prevvalue_dbl) == 0)
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+ break;
+ case ITEM_VALUE_TYPE_UINT64:
+ if(item->lastvalue_uint64 == item->prevvalue_uint64)
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+ break;
+ default:
+ if(strcmp(item->lastvalue_str, item->prevvalue_str) == 0)
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+ break;
+ }
+/* if( (item->value_type==ITEM_VALUE_TYPE_FLOAT) || (item->value_type==ITEM_VALUE_TYPE_UINT64))
+ {
+ if(cmp_double(item->lastvalue, item->prevvalue) == 0)
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+ }
+ else
+ {
+ if(strcmp(item->lastvalue_str, item->prevvalue_str) == 0)
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+ }*/
+ }
+ }
+ else if(strcmp(function,"str")==0)
+ {
+ if( (item->value_type==ITEM_VALUE_TYPE_STR) || (item->value_type==ITEM_VALUE_TYPE_LOG))
+ {
+ if(strstr(item->lastvalue_str, parameter) == NULL)
+ {
+ strcpy(value,"0");
+ }
+ else
+ {
+ strcpy(value,"1");
+ }
+
+ }
+ else
+ {
+ ret = FAIL;
+ }
+ }
+ else if(strcmp(function,"regexp")==0)
+ {
+ if( (item->value_type==ITEM_VALUE_TYPE_STR) || (item->value_type==ITEM_VALUE_TYPE_LOG))
+ {
+ if(zbx_regexp_match(item->lastvalue_str, parameter, &len) != NULL)
+ {
+ strcpy(value,"1");
+ }
+ else
+ {
+ strcpy(value,"0");
+ }
+ }
+ else
+ {
+ ret = FAIL;
+ }
+ }
+ else if(strcmp(function,"iregexp")==0)
+ {
+ if( (item->value_type==ITEM_VALUE_TYPE_STR) || (item->value_type==ITEM_VALUE_TYPE_LOG))
+ {
+ if(zbx_iregexp_match(item->lastvalue_str, parameter, &len) != NULL)
+ {
+ strcpy(value,"1");
+ }
+ else
+ {
+ strcpy(value,"0");
+ }
+ }
+ else
+ {
+ ret = FAIL;
+ }
+ }
+ else if(strcmp(function,"now")==0)
+ {
+ now=time(NULL);
+ zbx_snprintf(value,MAX_STRING_LEN,"%d",(int)now);
+ }
+ else if(strcmp(function,"fuzzytime")==0)
+ {
+ now=time(NULL);
+ fuzlow=(int)(now-atoi(parameter));
+ fuzhig=(int)(now+atoi(parameter));
+
+ if(item->lastvalue_null==1)
+ {
+ ret = FAIL;
+ }
+ else
+ {
+ switch (item->value_type) {
+ case ITEM_VALUE_TYPE_FLOAT:
+ if((item->lastvalue_dbl>=fuzlow)&&(item->lastvalue_dbl<=fuzhig))
+ {
+ strcpy(value,"1");
+ }
+ else
+ {
+ strcpy(value,"0");
+ }
+ break;
+ case ITEM_VALUE_TYPE_UINT64:
+ if((item->lastvalue_uint64>=fuzlow)&&(item->lastvalue_uint64<=fuzhig))
+ {
+ strcpy(value,"1");
+ }
+ else
+ {
+ strcpy(value,"0");
+ }
+ break;
+ default:
+ ret = FAIL;
+ break;
+ }
+ }
+ }
+ else if(strcmp(function,"logseverity")==0)
+ {
+ ret = evaluate_LOGSEVERITY(value,item,parameter);
+ }
+ else if(strcmp(function,"logsource")==0)
+ {
+ ret = evaluate_LOGSOURCE(value,item,parameter);
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Unsupported function:%s",
+ function);
+ zabbix_syslog("Unsupported function:%s",
+ function);
+ ret = FAIL;
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End of evaluate_function(result:%s)",
+ value);
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: add_value_suffix_uptime *
+ * *
+ * Purpose: Peocess suffix 'uptime' *
+ * *
+ * Parameters: value - value for adjusting *
+ * max_len - max len of the value *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void add_value_suffix_uptime(char *value, int max_len)
+{
+ double value_double;
+ double days, hours, min;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_value_suffix_uptime(%s)",
+ value);
+
+ value_double = atof(value);
+
+ if(value_double <0) return;
+
+ days=floor(value_double/(24*3600));
+ if(cmp_double(days,0) != 0)
+ {
+ value_double=value_double-days*(24*3600);
+ }
+ hours=floor(value_double/(3600));
+ if(cmp_double(hours,0) != 0)
+ {
+ value_double=value_double-hours*3600;
+ }
+ min=floor(value_double/(60));
+ if( cmp_double(min,0) !=0)
+ {
+ value_double=value_double-min*(60);
+ }
+ if(cmp_double(days,0) == 0)
+ {
+ zbx_snprintf(value, max_len, "%02d:%02d:%02d",
+ (int)hours,
+ (int)min,
+ (int)value_double);
+ }
+ else
+ {
+ zbx_snprintf(value, max_len, "%d days, %02d:%02d:%02d",
+ (int)days,
+ (int)hours,
+ (int)min,
+ (int)value_double);
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "End of add_value_suffix_uptime(%s)",
+ value);
+}
+
+/******************************************************************************
+ * *
+ * Function: add_value_suffix_s *
+ * *
+ * Purpose: Peocess suffix 's' *
+ * *
+ * Parameters: value - value for adjusting *
+ * max_len - max len of the value *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void add_value_suffix_s(char *value, int max_len)
+{
+ double value_double;
+ double t;
+ char tmp[MAX_STRING_LEN];
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_value_suffix_s(%s)",
+ value);
+
+ value_double = atof(value);
+ if(value_double <0) return;
+
+ value[0]='\0';
+
+ t=floor(value_double/(365*24*3600));
+ if(cmp_double(t,0) != 0)
+ {
+ zbx_snprintf(tmp, sizeof(tmp), "%dy", (int)t);
+ zbx_strlcat(value, tmp, max_len);
+ value_double = value_double-t*(365*24*3600);
+ }
+
+ t=floor(value_double/(30*24*3600));
+ if(cmp_double(t,0) != 0)
+ {
+ zbx_snprintf(tmp, sizeof(tmp), "%dm", (int)t);
+ zbx_strlcat(value, tmp, max_len);
+ value_double = value_double-t*(30*24*3600);
+ }
+
+ t=floor(value_double/(24*3600));
+ if(cmp_double(t,0) != 0)
+ {
+ zbx_snprintf(tmp, sizeof(tmp), "%dd", (int)t);
+ zbx_strlcat(value, tmp, max_len);
+ value_double = value_double-t*(24*3600);
+ }
+
+ t=floor(value_double/(3600));
+ if(cmp_double(t,0) != 0)
+ {
+ zbx_snprintf(tmp, sizeof(tmp), "%dh", (int)t);
+ zbx_strlcat(value, tmp, max_len);
+ value_double = value_double-t*(3600);
+ }
+
+ t=floor(value_double/(60));
+ if(cmp_double(t,0) != 0)
+ {
+ zbx_snprintf(tmp, sizeof(tmp), "%dm", (int)t);
+ zbx_strlcat(value, tmp, max_len);
+ value_double = value_double-t*(60);
+ }
+
+ zbx_snprintf(tmp, sizeof(tmp), "%02.2f", value_double);
+ zbx_rtrim(tmp,"0");
+ zbx_rtrim(tmp,".");
+ zbx_strlcat(tmp, "s", sizeof(tmp));
+ zbx_strlcat(value, tmp, max_len);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End of add_value_suffix_s(%s)",
+ value);
+}
+
+/******************************************************************************
+ * *
+ * Function: add_value_suffix_normsl *
+ * *
+ * Purpose: Peocess normal values and add K,M,G,T *
+ * *
+ * Parameters: value - value for adjusting *
+ * max_len - max len of the value *
+ * units - units (bps, b,B, etc) *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void add_value_suffix_normal(char *value, int max_len, char *units)
+{
+ double base = 1024;
+ char kmgt[MAX_STRING_LEN];
+
+ zbx_uint64_t value_uint64;
+ double value_double;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_value_normal(value:%s,units:%s)",
+ value,
+ units);
+
+ value_uint64 = labs(zbx_atoui64(value));
+
+ /* SPecial processing for bits */
+ if(strcmp(units,"b") == 0 || strcmp(units,"bps") == 0)
+ {
+ base = 1000;
+ }
+
+ if(value_uint64 < base)
+ {
+ strscpy(kmgt,"");
+ value_double = (double)value_uint64;
+ }
+ else if(value_uint64 < base*base)
+ {
+ strscpy(kmgt,"K");
+ value_double = (double)value_uint64/base;
+ }
+ else if(value_uint64 < base*base*base)
+ {
+ strscpy(kmgt,"M");
+ value_double = (double)(value_uint64/(base*base));
+ }
+ else if(value_uint64 < base*base*base*base)
+ {
+ strscpy(kmgt,"G");
+ value_double = (double)value_uint64/(base*base*base);
+ }
+ else
+ {
+ strscpy(kmgt,"T");
+ value_double = (double)value_uint64/(base*base*base*base);
+ }
+
+ if(cmp_double((int)(value_double+0.5), value_double) == 0)
+ {
+ zbx_snprintf(value, MAX_STRING_LEN, ZBX_FS_DBL_EXT(0) " %s%s",
+ value_double,
+ kmgt,
+ units);
+ }
+ else
+ {
+ zbx_snprintf(value, MAX_STRING_LEN, ZBX_FS_DBL_EXT(2) " %s%s",
+ value_double,
+ kmgt,
+ units);
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End of add_value_normal(value:%s)",
+ value);
+}
+
+/******************************************************************************
+ * *
+ * Function: add_value_suffix *
+ * *
+ * Purpose: Add suffix for value *
+ * *
+ * Parameters: value - value to replacing *
+ * valuemapid - index of value map *
+ * *
+ * Return value: SUCCEED - suffix added succesfully, value contains new value *
+ * FAIL - adding failed, value contains old value *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+
+/* Do not forget to keep it in sync wiht convert_units in config.inc.php */
+int add_value_suffix(char *value, int max_len, char *units, int value_type)
+{
+ int ret = FAIL;
+
+ struct tm *local_time = NULL;
+ time_t time;
+
+ char tmp[MAX_STRING_LEN];
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_value_suffix(value:%s,units:%s)",
+ value,
+ units);
+
+ switch(value_type)
+ {
+ case ITEM_VALUE_TYPE_FLOAT:
+ if(strcmp(units,"s") == 0)
+ {
+ add_value_suffix_s(value, max_len);
+ ret = SUCCEED;
+ }
+ else if(strcmp(units,"uptime") == 0)
+ {
+ add_value_suffix_uptime(value, max_len);
+ ret = SUCCEED;
+ }
+ else if(strlen(units) != 0)
+ {
+ add_value_suffix_normal(value, max_len, units);
+ ret = SUCCEED;
+ }
+ else
+ {
+ /* Do nothing if units not set */
+ }
+ break;
+
+ case ITEM_VALUE_TYPE_UINT64:
+ if(strcmp(units,"s") == 0)
+ {
+ add_value_suffix_s(value, max_len);
+ ret = SUCCEED;
+ }
+ else if(strcmp(units,"unixtime") == 0)
+ {
+ time = (time_t)zbx_atoui64(value);
+ local_time = localtime(&time);
+ strftime(tmp, MAX_STRING_LEN, "%Y.%m.%d %H:%M:%S",
+ local_time);
+ zbx_strlcpy(value, tmp, max_len);
+ ret = SUCCEED;
+ }
+ else if(strcmp(units,"uptime") == 0)
+ {
+ add_value_suffix_uptime(value, max_len);
+ ret = SUCCEED;
+ }
+ else if(strlen(units) != 0)
+ {
+ add_value_suffix_normal(value, max_len, units);
+ ret = SUCCEED;
+ }
+ else
+ {
+ /* Do nothing if units not set */
+ }
+ break;
+ default:
+ ret = FAIL;
+ break;
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of add_value_suffix(%s)",
+ value);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: replace_value_by_map *
+ * *
+ * Purpose: replace value by mapping value *
+ * *
+ * Parameters: value - value to replacing *
+ * valuemapid - index of value map *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, value contains new value *
+ * FAIL - evaluation failed, value contains old value *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int replace_value_by_map(char *value, zbx_uint64_t valuemapid)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char new_value[MAX_STRING_LEN];
+ char sql[MAX_STRING_LEN];
+ char *or_value;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In replace_value_by_map()" );
+
+ if(valuemapid == 0) return FAIL;
+
+ result = DBselect("select newvalue from mappings where valuemapid=" ZBX_FS_UI64 " and value='%s'",
+ valuemapid,
+ value);
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED) return FAIL;
+
+ strcpy(new_value,row[0]);
+ DBfree_result(result);
+
+ del_zeroes(new_value);
+ or_value = sql; /* sql variarbvle used as tmp - original value */
+ zbx_strlcpy(sql,value,MAX_STRING_LEN);
+
+ zbx_snprintf(value, MAX_STRING_LEN, "%s (%s)",
+ new_value,
+ or_value);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End replace_value_by_map(result:%s)",
+ value);
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_function2 *
+ * *
+ * Purpose: evaluate function *
+ * *
+ * Parameters: host - host the key belongs to *
+ * key - item's key (for example, 'max') *
+ * function - function (for example, 'max') *
+ * parameter - parameter of the function) *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, value contains its value *
+ * FAIL - evaluation failed *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: Used for evaluation of notification macros *
+ * *
+ ******************************************************************************/
+int evaluate_function2(char *value,char *host,char *key,char *function,char *parameter)
+{
+ DB_ITEM item;
+ DB_RESULT result;
+ DB_ROW row;
+
+ char host_esc[MAX_STRING_LEN];
+ char key_esc[MAX_STRING_LEN];
+
+ int res;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In evaluate_function2(%s,%s,%s,%s)",
+ host,
+ key,
+ function,
+ parameter);
+
+ DBescape_string(host, host_esc, MAX_STRING_LEN);
+ DBescape_string(key, key_esc, MAX_STRING_LEN);
+
+ result = DBselect("select %s where h.host='%s' and h.hostid=i.hostid and i.key_='%s' and" ZBX_COND_NODEID,
+ ZBX_SQL_ITEM_SELECT,
+ host_esc,
+ key_esc,
+ LOCAL_NODE("h.hostid"));
+
+ row = DBfetch(result);
+
+ if(!row)
+ {
+ DBfree_result(result);
+ zabbix_log(LOG_LEVEL_WARNING, "Query returned empty result");
+ zabbix_syslog("Query returned empty result");
+ return FAIL;
+ }
+
+ DBget_item_from_db(&item,row);
+
+ res = evaluate_function(value,&item,function,parameter);
+
+ if(replace_value_by_map(value, item.valuemapid) != SUCCEED)
+ {
+ add_value_suffix(value, MAX_STRING_LEN, item.units, item.value_type);
+ }
+
+/* Cannot call DBfree_result until evaluate_FUNC */
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End evaluate_function2(result:%s)",
+ value);
+ return res;
+}
diff --git a/src/zabbix_proxy/evalfunc.h b/src/zabbix_proxy/evalfunc.h
new file mode 100644
index 00000000..5da6b67d
--- /dev/null
+++ b/src/zabbix_proxy/evalfunc.h
@@ -0,0 +1,39 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#ifndef ZABBIX_EVALFUNC_H
+#define ZABBIX_EVALFUNC_H
+
+#include "common.h"
+#include "db.h"
+
+#define EVALUATE_FUNCTION_NORMAL 0
+#define EVALUATE_FUNCTION_SUFFIX 1
+
+#define ZBX_FLAG_SEC 0
+#define ZBX_FLAG_VALUES 1
+
+extern int CONFIG_SERVER_STARTUP_TIME;
+
+int evaluate_function(char *value,DB_ITEM *item,char *function,char *parameter);
+int evaluate_function2(char *value,char *host,char *key,char *function,char *parameter);
+int add_value_suffix(char *value, int max_len, char *units, int value_type);
+
+#endif
diff --git a/src/zabbix_proxy/events.c b/src/zabbix_proxy/events.c
new file mode 100644
index 00000000..3f514030
--- /dev/null
+++ b/src/zabbix_proxy/events.c
@@ -0,0 +1,211 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <signal.h>
+
+#include <string.h>
+
+#include <time.h>
+
+#include <sys/socket.h>
+#include <errno.h>
+
+/* Functions: pow(), round() */
+#include <math.h>
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+/*#include "actions.h"*/
+#include "functions.h"
+#include "events.h"
+
+/******************************************************************************
+ * *
+ * Function: add_trigger_info *
+ * *
+ * Purpose: add trigger info to event if required *
+ * *
+ * Parameters: event - event data (event.triggerid) *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: use 'free_trigger_info' function to clear allocated memory *
+ * *
+ ******************************************************************************/
+static void add_trigger_info(DB_EVENT *event)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_uint64_t triggerid;
+
+ int event_prev_status, event_last_status;
+
+ if(event->object==EVENT_OBJECT_TRIGGER && event->objectid != 0)
+ {
+ triggerid = event->objectid;
+
+ result = DBselect("select description,priority,comments,url,type from triggers where triggerid=" ZBX_FS_UI64,
+ triggerid);
+ row = DBfetch(result);
+ event->trigger_description[0]=0;
+ zbx_free(event->trigger_comments);
+ zbx_free(event->trigger_url);
+
+ if(row)
+ {
+ strscpy(event->trigger_description, row[0]);
+ event->trigger_priority = atoi(row[1]);
+ event->trigger_comments = strdup(row[2]);
+ event->trigger_url = strdup(row[3]);
+ event->trigger_type = atoi(row[4]);
+ }
+ DBfree_result(result);
+
+ get_latest_event_status(triggerid, &event_prev_status, &event_last_status);
+ zabbix_log(LOG_LEVEL_DEBUG,"event_prev_status %d event_last_status %d event->value %d",
+ event_prev_status,
+ event_last_status,
+ event->value);
+
+ event->skip_actions = 0;
+
+ switch(event->trigger_type)
+ {
+ case TRIGGER_TYPE_NORMAL:
+ if( (event->value == TRIGGER_VALUE_UNKNOWN) ||
+ (event_prev_status == TRIGGER_VALUE_TRUE && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_TRUE) ||
+ (event_prev_status == TRIGGER_VALUE_FALSE && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_FALSE) ||
+ (event_prev_status == TRIGGER_VALUE_UNKNOWN && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_FALSE)
+ )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG,"Skip actions");
+ event->skip_actions = 1;
+ }
+ case TRIGGER_TYPE_MULTIPLE_TRUE:
+ if( (event->value == TRIGGER_VALUE_UNKNOWN) ||
+/* (event_prev_status == TRIGGER_VALUE_TRUE && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_TRUE) ||*/
+ (event_prev_status == TRIGGER_VALUE_FALSE && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_FALSE) ||
+ (event_prev_status == TRIGGER_VALUE_UNKNOWN && event_last_status == TRIGGER_VALUE_UNKNOWN && event->value == TRIGGER_VALUE_FALSE)
+ )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG,"Skip actions");
+ event->skip_actions = 1;
+ }
+ }
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: free_trigger_info *
+ * *
+ * Purpose: clean allocated memory by function 'add_trigger_info' *
+ * *
+ * Parameters: event - event data (event.triggerid) *
+ * *
+ * Return value: *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void free_trigger_info(DB_EVENT *event)
+{
+ zbx_free(event->trigger_url);
+ zbx_free(event->trigger_comments);
+}
+
+/******************************************************************************
+ * *
+ * Function: process_event *
+ * *
+ * Purpose: process new event *
+ * *
+ * Parameters: event - event data (event.eventid - new event) *
+ * *
+ * Return value: SUCCESS - event added *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: Cannot use action->userid as it may also be groupid *
+ * *
+ ******************************************************************************/
+int process_event(DB_EVENT *event)
+{
+ zabbix_log(LOG_LEVEL_DEBUG,"In process_event(eventid:" ZBX_FS_UI64 ",object:%d,objectid:" ZBX_FS_UI64 ")",
+ event->eventid,
+ event->object,
+ event->objectid);
+
+ add_trigger_info(event);
+
+ if(event->eventid == 0)
+ {
+ event->eventid = DBget_maxid("events","eventid");
+ }
+ DBexecute("insert into events(eventid,source,object,objectid,clock,value) values(" ZBX_FS_UI64 ",%d,%d," ZBX_FS_UI64 ",%d,%d)",
+ event->eventid,
+ event->source,
+ event->object,
+ event->objectid,
+ event->clock,
+ event->value);
+
+ /* Cancel currently active alerts */
+/* if(event->value == TRIGGER_VALUE_FALSE || event->value == TRIGGER_VALUE_TRUE)
+ {
+ DBexecute("update alerts set retries=3,error='Trigger changed its status. Will not send repeats.' where triggerid=" ZBX_FS_UI64 " and repeats>0 and status=%d",
+ event->triggerid, ALERT_STATUS_NOT_SENT);
+ }*/
+/*
+ if(event->skip_actions == 0)
+ {
+ process_actions(event);
+ }
+*/
+ if(event->value == TRIGGER_VALUE_TRUE)
+ {
+ DBupdate_services(event->objectid, event->trigger_priority);
+ }
+ else
+ {
+ DBupdate_services(event->objectid, 0);
+ }
+
+ free_trigger_info(event);
+
+ zabbix_log(LOG_LEVEL_DEBUG,"End of process_event()");
+
+ return SUCCEED;
+}
diff --git a/src/zabbix_proxy/events.h b/src/zabbix_proxy/events.h
new file mode 100644
index 00000000..b56d9f77
--- /dev/null
+++ b/src/zabbix_proxy/events.h
@@ -0,0 +1,29 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#ifndef ZABBIX_EVENTS_H
+#define ZABBIX_EVENTS_H
+
+#include "common.h"
+#include "db.h"
+
+int process_event(DB_EVENT *event);
+
+#endif
diff --git a/src/zabbix_proxy/expression.c b/src/zabbix_proxy/expression.c
new file mode 100644
index 00000000..f288f754
--- /dev/null
+++ b/src/zabbix_proxy/expression.c
@@ -0,0 +1,1631 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "expression.h"
+#include "functions.h"
+#include "evalfunc.h"
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+
+
+/******************************************************************************
+ * *
+ * Function: str2double *
+ * *
+ * Purpose: convert string to double *
+ * *
+ * Parameters: str - string to convert *
+ * *
+ * Return value: converted double value *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: the function automatically processes prefixes 'K','M','G' *
+ * *
+ ******************************************************************************/
+double str2double(char *str)
+{
+ if(str[strlen(str)-1] == 'K')
+ {
+ str[strlen(str)-1] = 0;
+ return (double)1024*atof(str);
+ }
+ else if(str[strlen(str)-1] == 'M')
+ {
+ str[strlen(str)-1] = 0;
+ return (double)1024*1024*atof(str);
+ }
+ else if(str[strlen(str)-1] == 'G')
+ {
+ str[strlen(str)-1] = 0;
+ return (double)1024*1024*1024*atof(str);
+ }
+ return atof(str);
+}
+
+
+/******************************************************************************
+ * *
+ * Function: delete_spaces *
+ * *
+ * Purpose: delete all spaces *
+ * *
+ * Parameters: c - string to delete spaces *
+ * *
+ * Return value: the string wtihout spaces *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void delete_spaces(char *c)
+{
+ int i,j;
+
+ j=0;
+ for(i=0;c[i]!=0;i++)
+ {
+ if( c[i] != ' ')
+ {
+ c[j]=c[i];
+ j++;
+ }
+ }
+ c[j]=0;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_simple *
+ * *
+ * Purpose: evaluate simple expression *
+ * *
+ * Parameters: exp - expression string *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result - value of the exp *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: format: <double> or <double> <operator> <double> *
+ * *
+ * It is recursive function! *
+ * *
+ ******************************************************************************/
+int evaluate_simple(double *result,char *exp,char *error,int maxerrlen)
+{
+ double value1,value2;
+ char first[MAX_STRING_LEN],second[MAX_STRING_LEN];
+ char *p;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_simple(%s)",
+ exp);
+
+/* Remove left and right spaces */
+ lrtrim_spaces(exp);
+
+/* Compress repeating - and +. Add prefix N to negative numebrs. */
+ compress_signs(exp);
+
+ /* We should process negative prefix, i.e. N123 == -123 */
+ if( exp[0]=='N' && is_double_prefix(exp+1) == SUCCEED )
+ {
+/* str2double support prefixes */
+ *result=-str2double(exp+1);
+ return SUCCEED;
+ }
+ else if( exp[0]!='N' && is_double_prefix(exp) == SUCCEED )
+ {
+/* str2double support prefixes */
+ *result=str2double(exp);
+ return SUCCEED;
+ }
+
+ /* Operators with lowest priority come first */
+ /* HIGHEST / * - + < > # = & | LOWEST */
+ if( (p = strchr(exp,'|')) != NULL )
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s", error);
+ zabbix_syslog("%s", error);
+ return FAIL;
+ }
+ if( value1 == 1)
+ {
+ *result=value1;
+ return SUCCEED;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s", error);
+ zabbix_syslog("%s", error);
+ return FAIL;
+ }
+ if( value2 == 1)
+ {
+ *result=value2;
+ return SUCCEED;
+ }
+ *result=0;
+ return SUCCEED;
+ }
+ if( (p = strchr(exp,'&')) != NULL )
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s", error);
+ zabbix_syslog("%s", error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s", error);
+ zabbix_syslog("%s", error);
+ return FAIL;
+ }
+ if( (value1 == 1) && (value2 == 1) )
+ {
+ *result=1;
+ }
+ else
+ {
+ *result=0;
+ }
+ return SUCCEED;
+ }
+ if((p = strchr(exp,'=')) != NULL)
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( cmp_double(value1,value2) ==0 )
+ {
+ *result=1;
+ }
+ else
+ {
+ *result=0;
+ }
+ return SUCCEED;
+ }
+ if((p = strchr(exp,'#')) != NULL)
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( cmp_double(value1,value2) != 0 )
+ {
+ *result=1;
+ }
+ else
+ {
+ *result=0;
+ }
+ return SUCCEED;
+ }
+ if((p = strchr(exp,'>')) != NULL)
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s", error);
+ zabbix_syslog("%s", error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s", error);
+ zabbix_syslog("%s", error);
+ return FAIL;
+ }
+ if( value1 > value2 )
+ {
+ *result=1;
+ }
+ else
+ {
+ *result=0;
+ }
+ return SUCCEED;
+ }
+ if((p = strchr(exp,'<')) != NULL)
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( value1 < value2 )
+ {
+ *result=1;
+ }
+ else
+ {
+ *result=0;
+ }
+ zabbix_log(LOG_LEVEL_DEBUG, "Result [" ZBX_FS_DBL "]",*result );
+ return SUCCEED;
+ }
+ if((p = strchr(exp,'+')) != NULL)
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ *result=value1+value2;
+ return SUCCEED;
+ }
+ if((p = strchr(exp,'-')) != NULL)
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ *result=value1-value2;
+ return SUCCEED;
+ }
+ if((p = strchr(exp,'*')) != NULL)
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ *result=value1*value2;
+ return SUCCEED;
+ }
+ if((p = strchr(exp,'/')) != NULL)
+ {
+ *p=0;
+ strscpy( first, exp);
+ *p='|';
+ p++;
+ strscpy( second, p);
+ if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if(cmp_double(value2,0) == 0)
+ {
+ zbx_snprintf(error,maxerrlen,"Division by zero. Cannot evaluate expression [%s/%s]",
+ first,
+ second);
+ zabbix_log(LOG_LEVEL_WARNING, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ else
+ {
+ *result=value1/value2;
+ }
+ return SUCCEED;
+ }
+ else
+ {
+ zbx_snprintf(error,maxerrlen,"Format error or unsupported operator. Exp: [%s]",
+ exp);
+ zabbix_log(LOG_LEVEL_WARNING, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate *
+ * *
+ * Purpose: evaluate simplified expression *
+ * *
+ * Parameters: exp - expression string *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result - value of the exp *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: example: ({15}>10)|({123}=1) *
+ * *
+ ******************************************************************************/
+int evaluate(int *result, char *exp, char *error, int maxerrlen)
+{
+ double value;
+ char *res;
+ char simple[MAX_STRING_LEN];
+ char tmp[MAX_STRING_LEN];
+ char value_str[MAX_STRING_LEN];
+ int i,l,r;
+ char c;
+ int t;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In evaluate(%s)",
+ exp);
+
+ res = NULL;
+
+ strscpy(tmp, exp);
+ t=0;
+ while( find_char( tmp, ')' ) != FAIL )
+ {
+ l=-1;
+ r=find_char(tmp,')');
+ for(i=r;i>=0;i--)
+ {
+ if( tmp[i] == '(' )
+ {
+ l=i;
+ break;
+ }
+ }
+ if( l == -1 )
+ {
+ zbx_snprintf(error, maxerrlen, "Cannot find left bracket [(]. Expression:[%s]",
+ tmp);
+ zabbix_log(LOG_LEVEL_WARNING, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ for(i=l+1;i<r;i++)
+ {
+ simple[i-l-1]=tmp[i];
+ }
+ simple[r-l-1]=0;
+
+ if( evaluate_simple( &value, simple, error, maxerrlen ) != SUCCEED )
+ {
+ /* Changed to LOG_LEVEL_DEBUG */
+ zabbix_log( LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+
+ /* res = first+simple+second */
+ c=tmp[l]; tmp[l]='\0';
+ res = zbx_strdcat(res, tmp);
+ tmp[l]=c;
+
+ zbx_snprintf(value_str,MAX_STRING_LEN-1,"%lf",
+ value);
+ res = zbx_strdcat(res, value_str);
+ res = zbx_strdcat(res, tmp+r+1);
+
+ delete_spaces(res);
+ strscpy(tmp,res);
+
+ zbx_free(res); res = NULL;
+ }
+ if( evaluate_simple( &value, tmp, error, maxerrlen ) != SUCCEED )
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ if(cmp_double(value,0) == 0)
+ {
+ *result = TRIGGER_VALUE_FALSE;
+ }
+ else
+ {
+ *result = TRIGGER_VALUE_TRUE;
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End evaluate(result:%lf)",
+ value);
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: extract_numbers *
+ * *
+ * Purpose: Extract from string numbers with prefixes (A-Z) *
+ * *
+ * Return value: *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: !!! Don't forget sync code with PHP !!! *
+ * Use zbx_free_numbers to free allocated memory *
+ * *
+ ******************************************************************************/
+static char** extract_numbers(char *str, int *count)
+{
+ char *s = NULL;
+ char *e = NULL;
+
+ char **result = NULL;
+
+ int dot_founded = 0;
+ int len = 0;
+
+ assert(count);
+
+ *count = 0;
+
+ /* find start of number */
+ for ( s = str; *s; s++)
+ {
+ if ( !isdigit(*s) ) {
+ continue; /* for s */
+ }
+
+ if ( s != str && '{' == *(s-1) ) {
+ /* skip functions '{65432}' */
+ s = strchr(s, '}');
+ continue; /* for s */
+ }
+
+ dot_founded = 0;
+ /* find end of number */
+ for ( e = s; *e; e++ )
+ {
+ if ( isdigit(*e) ) {
+ continue; /* for e */
+ }
+ else if ( '.' == *e && !dot_founded ) {
+ dot_founded = 1;
+ continue; /* for e */
+ }
+ else if ( *e >= 'A' && *e <= 'Z' )
+ {
+ e++;
+ }
+ break; /* for e */
+ }
+
+ /* number founded */
+ len = e - s;
+ (*count)++;
+ result = zbx_realloc(result, sizeof(char*) * (*count));
+ result[(*count)-1] = zbx_malloc(NULL, len + 1);
+ memcpy(result[(*count)-1], s, len);
+ result[(*count)-1][len] = '\0';
+
+ s = e;
+ }
+
+ return result;
+}
+
+static void zbx_free_numbers(char ***numbers, int count)
+{
+ register int i = 0;
+
+ if ( !numbers ) return;
+ if ( !*numbers ) return;
+
+ for ( i = 0; i < count; i++ )
+ {
+ zbx_free((*numbers)[i]);
+ }
+
+ zbx_free(*numbers);
+}
+
+/******************************************************************************
+ * *
+ * Function: expand_trigger_description_constants *
+ * *
+ * Purpose: substitute simple macros in data string with real values *
+ * *
+ * Parameters: data - trigger description *
+ * *
+ * Return value: *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: !!! Don't forget sync code with PHP !!! *
+ * replcae ONLY $1-9 macros NOT {HOSTNAME} *
+ * *
+ ******************************************************************************/
+static void expand_trigger_description_constants(
+ char **data,
+ zbx_uint64_t triggerid
+ )
+{
+ DB_RESULT db_trigger;
+ DB_ROW db_trigger_data;
+
+ char **numbers = NULL;
+ int numbers_cnt = 0;
+
+ int i = 0;
+
+ char *new_str = NULL;
+
+ char replace[3] = "$0";
+
+ db_trigger = DBselect("select expression from triggers where triggerid=" ZBX_FS_UI64, triggerid);
+
+ if ( (db_trigger_data = DBfetch(db_trigger)) ) {
+
+ numbers = extract_numbers(db_trigger_data[0], &numbers_cnt);
+
+ for ( i = 0; i < 9; i++ )
+ {
+ replace[1] = '0' + i + 1;
+ new_str = string_replace(
+ *data,
+ replace,
+ i < numbers_cnt ?
+ numbers[i] :
+ ""
+ );
+ zbx_free(*data);
+ *data = new_str;
+ }
+
+ zbx_free_numbers(&numbers, numbers_cnt);
+ }
+
+ DBfree_result(db_trigger);
+}
+
+/******************************************************************************
+ * *
+ * Function: substitute_simple_macros *
+ * *
+ * Purpose: substitute simple macros in data string with real values *
+ * *
+ * Parameters: trigger - trigger structure *
+ * action - action structure (NULL if unknown) *
+ * data - data string *
+ * *
+ * Return value: *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: {DATE},{TIME},{HOSTNAME},{IPADDRESS},{STATUS}, *
+ * {TRIGGER.NAME}, {TRIGGER.KEY}, {TRIGGER.SEVERITY} *
+ * *
+ ******************************************************************************/
+/* definition of macros variables */
+#define MVAR_DATE "{DATE}"
+#define MVAR_EVENT_ID "{EVENT.ID}"
+#define MVAR_HOST_NAME "{HOSTNAME}"
+#define MVAR_IPADDRESS "{IPADDRESS}"
+#define MVAR_TIME "{TIME}"
+#define MVAR_ITEM_LASTVALUE "{ITEM.LASTVALUE}"
+#define MVAR_ITEM_NAME "{ITEM.NAME}"
+#define MVAR_TRIGGER_COMMENT "{TRIGGER.COMMENT}"
+#define MVAR_TRIGGER_ID "{TRIGGER.ID}"
+#define MVAR_TRIGGER_KEY "{TRIGGER.KEY}"
+#define MVAR_TRIGGER_NAME "{TRIGGER.NAME}"
+#define MVAR_TRIGGER_SEVERITY "{TRIGGER.SEVERITY}"
+#define MVAR_TRIGGER_STATUS "{TRIGGER.STATUS}"
+#define MVAR_TRIGGER_STATUS_OLD "{STATUS}"
+#define MVAR_TRIGGER_VALUE "{TRIGGER.VALUE}"
+#define MVAR_TRIGGER_URL "{TRIGGER.URL}"
+#define MVAR_PROFILE_DEVICETYPE "{PROFILE.DEVICETYPE}"
+#define MVAR_PROFILE_NAME "{PROFILE.NAME}"
+#define MVAR_PROFILE_OS "{PROFILE.OS}"
+#define MVAR_PROFILE_SERIALNO "{PROFILE.SERIALNO}"
+#define MVAR_PROFILE_TAG "{PROFILE.TAG}"
+#define MVAR_PROFILE_MACADDRESS "{PROFILE.MACADDRESS}"
+#define MVAR_PROFILE_HARDWARE "{PROFILE.HARDWARE}"
+#define MVAR_PROFILE_SOFTWARE "{PROFILE.SOFTWARE}"
+#define MVAR_PROFILE_CONTACT "{PROFILE.CONTACT}"
+#define MVAR_PROFILE_LOCATION "{PROFILE.LOCATION}"
+#define MVAR_PROFILE_NOTES "{PROFILE.NOTES}"
+
+#define STR_UNKNOWN_VARIABLE "*UNKNOWN*"
+
+void substitute_simple_macros(DB_EVENT *event, DB_ACTION *action, char **data, int macro_type)
+{
+
+ char
+ *pl = NULL,
+ *pr = NULL,
+ *str_out = NULL,
+ *replace_to = NULL;
+
+ char tmp[MAX_STRING_LEN];
+
+ int var_len;
+
+ time_t now;
+ struct tm *tm;
+
+ DB_RESULT result;
+ DB_ROW row;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In substitute_simple_macros()");
+
+ if(!data || !*data) return;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In substitute_simple_macros (data:%s)",
+ *data);
+
+ if('\0' == *data[0]) return;
+
+ if ( macro_type & MACRO_TYPE_TRIGGER_DESCRIPTION ) {
+ expand_trigger_description_constants(data, event->objectid);
+ }
+
+ pl = *data;
+ while((pr = strchr(pl, '{')))
+ {
+ pr[0] = '\0';
+zabbix_log(LOG_LEVEL_DEBUG, "str_out1 [%s] pl [%s]", str_out, pl);
+ str_out = zbx_strdcat(str_out, pl);
+zabbix_log(LOG_LEVEL_DEBUG, "str_out1 [%s] pl [%s]", str_out, pl);
+ pr[0] = '{';
+
+ replace_to = zbx_dsprintf(replace_to, "{");
+ var_len = 1;
+
+ if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_TRIGGER_NAME, strlen(MVAR_TRIGGER_NAME)) == 0)
+ {
+ var_len = strlen(MVAR_TRIGGER_NAME);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "Before replace_to [%s]", replace_to);
+
+ replace_to = zbx_dsprintf(replace_to, "%s", event->trigger_description);
+ /* Why it was here? *//* For substituting macros in trigger description :) */
+ substitute_simple_macros(event, action, &replace_to, MACRO_TYPE_TRIGGER_DESCRIPTION);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "After replace_to [%s]", replace_to);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_TRIGGER_COMMENT, strlen(MVAR_TRIGGER_COMMENT)) == 0)
+ {
+ var_len = strlen(MVAR_TRIGGER_COMMENT);
+
+ replace_to = zbx_dsprintf(replace_to, "%s", event->trigger_comments);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_DEVICETYPE, strlen(MVAR_PROFILE_DEVICETYPE)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_DEVICETYPE);
+
+ result = DBselect("select distinct p.devicetype from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.DEVECETYPE in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_NAME, strlen(MVAR_PROFILE_NAME)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_NAME);
+
+ result = DBselect("select distinct p.name from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.NAME in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_OS, strlen(MVAR_PROFILE_OS)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_OS);
+
+ result = DBselect("select distinct p.os from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.OS in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_SERIALNO, strlen(MVAR_PROFILE_SERIALNO)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_SERIALNO);
+
+ result = DBselect("select distinct p.serialno from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.SERIALNO in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_TAG, strlen(MVAR_PROFILE_TAG)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_TAG);
+
+ result = DBselect("select distinct p.tag from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.TAG in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_MACADDRESS, strlen(MVAR_PROFILE_MACADDRESS)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_MACADDRESS);
+
+ result = DBselect("select distinct p.macaddress from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.MACADDRESS in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_HARDWARE, strlen(MVAR_PROFILE_HARDWARE)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_HARDWARE);
+
+ result = DBselect("select distinct p.hardware from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.HARDWARE in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_SOFTWARE, strlen(MVAR_PROFILE_SOFTWARE)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_SOFTWARE);
+
+ result = DBselect("select distinct p.software from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.SOFTWARE in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_CONTACT, strlen(MVAR_PROFILE_CONTACT)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_CONTACT);
+
+ result = DBselect("select distinct p.contact from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.CONTACT in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_LOCATION, strlen(MVAR_PROFILE_LOCATION)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_LOCATION);
+
+ result = DBselect("select distinct p.location from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.LOCATION in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_PROFILE_NOTES, strlen(MVAR_PROFILE_NOTES)) == 0)
+ {
+ var_len = strlen(MVAR_PROFILE_NOTES);
+
+ result = DBselect("select distinct p.notes from triggers t, functions f,items i, hosts h, hosts_profiles p"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and p.hostid=h.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No PROFILE.NOTES in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY | MACRO_TYPE_TRIGGER_DESCRIPTION) &&
+ strncmp(pr, MVAR_HOST_NAME, strlen(MVAR_HOST_NAME)) == 0)
+ {
+ var_len = strlen(MVAR_HOST_NAME);
+
+ result = DBselect("select distinct h.host from triggers t, functions f,items i, hosts h "
+ "where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No hostname in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_ITEM_NAME, strlen(MVAR_ITEM_NAME)) == 0)
+ {
+ var_len = strlen(MVAR_ITEM_NAME);
+
+ result = DBselect("select distinct i.description from triggers t, functions f,items i, hosts h"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid"
+ " order by i.description",
+ event->objectid);
+
+ row=DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No ITEM.NAME in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY | MACRO_TYPE_TRIGGER_DESCRIPTION) &&
+ strncmp(pr, MVAR_ITEM_LASTVALUE, strlen(MVAR_ITEM_LASTVALUE)) == 0)
+ {
+ var_len = strlen(MVAR_ITEM_LASTVALUE);
+
+ result = DBselect("select distinct i.lastvalue,i.units,i.value_type"
+ " from triggers t, functions f,items i, hosts h"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid",
+ event->objectid);
+
+ row=DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No ITEM.LASTVALUE in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ strscpy(tmp, row[0]);
+
+ add_value_suffix(tmp, sizeof(tmp), row[1], atoi(row[2]));
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ tmp);
+ }
+
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_TRIGGER_KEY, strlen(MVAR_TRIGGER_KEY)) == 0)
+ {
+ var_len = strlen(MVAR_TRIGGER_KEY);
+
+ result = DBselect("select distinct i.key_ from triggers t, functions f,items i, hosts h"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid"
+ " order by i.key_",
+ event->objectid);
+
+ row=DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No TRIGGER.KEY in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_IPADDRESS, strlen(MVAR_IPADDRESS)) == 0)
+ {
+ var_len = strlen(MVAR_IPADDRESS);
+
+ result = DBselect("select distinct h.ip from triggers t, functions f,items i, hosts h"
+ " where t.triggerid=" ZBX_FS_UI64 " and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid",
+ event->objectid);
+
+ row = DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No hostname in substitute_simple_macros. Triggerid [" ZBX_FS_UI64 "]",
+ event->objectid);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ STR_UNKNOWN_VARIABLE);
+ }
+ else
+ {
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ row[0]);
+ }
+ DBfree_result(result);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_DATE, strlen(MVAR_DATE)) == 0)
+ {
+ var_len = strlen(MVAR_TIME);
+
+ now = time(NULL);
+ tm = localtime(&now);
+ replace_to = zbx_dsprintf(replace_to, "%.4d.%.2d.%.2d",
+ tm->tm_year+1900,
+ tm->tm_mon+1,
+ tm->tm_mday);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY)&&
+ strncmp(pr, MVAR_TIME, strlen(MVAR_TIME)) == 0)
+ {
+ var_len = strlen(MVAR_TIME);
+
+ now = time(NULL);
+ tm = localtime(&now);
+ replace_to = zbx_dsprintf(replace_to, "%.2d:%.2d:%.2d",
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_TRIGGER_STATUS, strlen(MVAR_TRIGGER_STATUS)) == 0)
+ {
+ /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS_OLD block */
+ var_len = strlen(MVAR_TRIGGER_STATUS);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ event->value == TRIGGER_VALUE_TRUE ? "ON" : "OFF");
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_TRIGGER_STATUS_OLD, strlen(MVAR_TRIGGER_STATUS_OLD)) == 0)
+ {
+ /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS block */
+ var_len = strlen(MVAR_TRIGGER_STATUS_OLD);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ event->value == TRIGGER_VALUE_TRUE ? "ON" : "OFF");
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_TRIGGER_ID, strlen(MVAR_TRIGGER_ID)) == 0)
+ {
+ /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS block */
+ var_len = strlen(MVAR_TRIGGER_ID);
+
+ replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64,
+ event->objectid);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY | MACRO_TYPE_TRIGGER_EXPRESSION) &&
+ strncmp(pr, MVAR_TRIGGER_VALUE, strlen(MVAR_TRIGGER_VALUE)) == 0)
+ {
+ var_len = strlen(MVAR_TRIGGER_VALUE);
+
+ replace_to = zbx_dsprintf(replace_to, "%d",
+ event->value);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_TRIGGER_URL, strlen(MVAR_TRIGGER_URL)) == 0)
+ {
+ /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS block */
+ var_len = strlen(MVAR_TRIGGER_URL);
+
+ replace_to = zbx_dsprintf(replace_to, "%s",
+ event->trigger_url);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_EVENT_ID, strlen(MVAR_EVENT_ID)) == 0)
+ {
+ /* NOTE: if you make changes for this bloc, don't forgot MVAR_TRIGGER_STATUS block */
+ var_len = strlen(MVAR_EVENT_ID);
+
+ replace_to = zbx_dsprintf(replace_to, ZBX_FS_UI64,
+ event->eventid);
+ }
+ else if(macro_type & (MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY) &&
+ strncmp(pr, MVAR_TRIGGER_SEVERITY, strlen(MVAR_TRIGGER_SEVERITY)) == 0)
+ {
+ var_len = strlen(MVAR_TRIGGER_SEVERITY);
+
+ if(event->trigger_priority == 0) replace_to = zbx_dsprintf(replace_to, "Not classified");
+ else if(event->trigger_priority == 1) replace_to = zbx_dsprintf(replace_to, "Information");
+ else if(event->trigger_priority == 2) replace_to = zbx_dsprintf(replace_to, "Warning");
+ else if(event->trigger_priority == 3) replace_to = zbx_dsprintf(replace_to, "Average");
+ else if(event->trigger_priority == 4) replace_to = zbx_dsprintf(replace_to, "High");
+ else if(event->trigger_priority == 5) replace_to = zbx_dsprintf(replace_to, "Disaster");
+ else replace_to = zbx_dsprintf(replace_to, "Unknown");
+ }
+
+zabbix_log(LOG_LEVEL_DEBUG, "str_out2 [%s] replace_to [%s]", str_out, replace_to);
+ str_out = zbx_strdcat(str_out, replace_to);
+zabbix_log(LOG_LEVEL_DEBUG, "str_out2 [%s] replace_to [%s]", str_out, replace_to);
+ pl = pr + var_len;
+
+ zbx_free(replace_to);
+ }
+zabbix_log(LOG_LEVEL_DEBUG, "str_out3 [%s] pl [%s]", str_out, pl);
+ str_out = zbx_strdcat(str_out, pl);
+zabbix_log(LOG_LEVEL_DEBUG, "str_out3 [%s] pl [%s]", str_out, pl);
+
+ zbx_free(*data);
+
+ *data = str_out;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End substitute_simple_macros ()");
+ zabbix_log(LOG_LEVEL_DEBUG, "End substitute_simple_macros (result:%s)",
+ *data);
+}
+
+/******************************************************************************
+ * *
+ * Function: substitute_macros *
+ * *
+ * Purpose: substitute macros in data string with real values *
+ * *
+ * Parameters: trigger - trigger structure *
+ * action - action structure *
+ * data - data string *
+ * *
+ * Return value: *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: example: "{127.0.0.1:system[procload].last(0)}" to "1.34" *
+ * *
+ ******************************************************************************/
+void substitute_macros(DB_EVENT *event, DB_ACTION *action, char **data)
+{
+ char
+ *str_out = NULL,
+ *replace_to = NULL,
+ *pl = NULL,
+ *pr = NULL,
+ *pms = NULL,
+ *pme = NULL,
+ *p = NULL;
+ char
+ host[MAX_STRING_LEN],
+ key[MAX_STRING_LEN],
+ function[MAX_STRING_LEN],
+ parameter[MAX_STRING_LEN];
+
+ if(!data || !*data) return;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In substitute_macros(data:%s)",
+ *data);
+
+ if('\0' == *data[0]) return;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "Before substitute_simple_macros(%s)", *data);
+ substitute_simple_macros(event, action, data, MACRO_TYPE_MESSAGE_SUBJECT | MACRO_TYPE_MESSAGE_BODY);
+ zabbix_log(LOG_LEVEL_DEBUG, "After substitute_simple_macros(%s)", *data);
+
+ pl = *data;
+ while((pr = strchr(pl, '{')))
+ {
+ if((pme = strchr(pr, '}')) == NULL)
+ break;
+
+ pme[0] = '\0';
+
+ pr = strrchr(pr, '{'); /* find '{' near '}' */
+
+ /* copy left side */
+ pr[0] = '\0';
+ str_out = zbx_strdcat(str_out, pl);
+ pr[0] = '{';
+
+
+ /* copy original name of variable */
+ replace_to = zbx_dsprintf(replace_to, "%s}", pr); /* in format used '}' */
+ /* cose in 'pr' string symbol '}' is changed to '\0' by 'pme'*/
+ pl = pr + strlen(replace_to);
+
+ pms = pr + 1;
+
+ if(NULL != (p = strchr(pms, ':')))
+ {
+ *p = '\0';
+ zbx_snprintf(host, sizeof(host), "%s", pms);
+ *p = ':';
+ pms = p + 1;
+ if(NULL != (p = strrchr(pms, '.')))
+ {
+ *p = '\0';
+ zbx_snprintf(key, sizeof(key), "%s", pms);
+ *p = '.';
+ pms = p + 1;
+ if(NULL != (p = strchr(pms, '(')))
+ {
+ *p = '\0';
+ zbx_snprintf(function, sizeof(function), "%s", pms);
+ *p = '(';
+ pms = p + 1;
+ if(NULL != (p = strchr(pms, ')')))
+ {
+ *p = '\0';
+ zbx_snprintf(parameter, sizeof(parameter), "%s", pms);
+ *p = ')';
+ pms = p + 1;
+
+ /* function 'evaluate_function2' require 'replace_to' with size 'MAX_STRING_LEN' */
+ zbx_free(replace_to);
+ replace_to = zbx_malloc(replace_to, MAX_STRING_LEN);
+
+ if(evaluate_function2(replace_to,host,key,function,parameter) != SUCCEED)
+ zbx_snprintf(replace_to, MAX_STRING_LEN, "%s", STR_UNKNOWN_VARIABLE);
+ }
+ }
+ }
+
+ }
+ pme[0] = '}';
+
+ str_out = zbx_strdcat(str_out, replace_to);
+ zbx_free(replace_to);
+ }
+ str_out = zbx_strdcat(str_out, pl);
+
+ zbx_free(*data);
+
+ *data = str_out;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End substitute_macros(result:%s)",
+ *data );
+}
+
+/******************************************************************************
+ * *
+ * Function: substitute_functions *
+ * *
+ * Purpose: substitute expression functions with theirs values *
+ * *
+ * Parameters: exp - expression string *
+ * error - place error message here if any *
+ * maxerrlen - max length of error msg *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, exp - updated expression *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: example: "({15}>10)|({123}=0)" => "(6.456>10)|(0=0) *
+ * *
+ ******************************************************************************/
+int substitute_functions(char **exp, char *error, int maxerrlen)
+{
+ char *value;
+ char functionid[MAX_STRING_LEN];
+ int i,j;
+ int len;
+ char *out = NULL;
+ char c;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In substitute_functions(%s)",
+ *exp);
+
+ i = 0;
+ len = strlen(*exp);
+ while(i<len)
+ {
+ if((*exp)[i] == '{')
+ {
+ for(j=i+1;((*exp)[j]!='}')&&((*exp)[j]!='\0');j++)
+ {
+ functionid[j-i-1]=(*exp)[j];
+ }
+ functionid[j-i-1]='\0';
+ if( DBget_function_result( &value, functionid ) != SUCCEED )
+ {
+/* It may happen because of functions.lastvalue is NULL, so this is not warning */
+ zbx_snprintf(error,maxerrlen, "Unable to get value for functionid [%s]",
+ functionid);
+ zabbix_log( LOG_LEVEL_DEBUG, "%s",
+ error);
+ zabbix_syslog("%s",
+ error);
+ return FAIL;
+ }
+ out = zbx_strdcat(out,value);
+ zbx_free(value);
+ i=j+1;
+ }
+ else
+ {
+ c=(*exp)[i+1]; (*exp)[i+1]='\0';
+ out = zbx_strdcat(out, (*exp+i));
+ (*exp)[i+1]=c;
+ i++;
+ }
+ }
+ zbx_free(*exp);
+
+ *exp = out;
+ zabbix_log( LOG_LEVEL_DEBUG, "End substitute_functions [%s]",
+ *exp);
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: evaluate_expression *
+ * *
+ * Purpose: evaluate expression *
+ * *
+ * Parameters: exp - expression string *
+ * error - place rrror message if any *
+ * maxerrlen - max length of error message *
+ * *
+ * Return value: SUCCEED - evaluated succesfully, result - value of the exp *
+ * FAIL - otherwise *
+ * error - error message *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: example: ({a0:system[procload].last(0)}>1)| *
+ * ({a0:system[procload].max(300)}>3) *
+ * *
+ ******************************************************************************/
+int evaluate_expression(int *result,char **expression, int trigger_value, char *error, int maxerrlen)
+{
+ /* Required for substitution of macros */
+ DB_EVENT event;
+ DB_ACTION action;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In evaluate_expression(%s)",
+ *expression);
+
+ /* Substitute macros first */
+ memset(&event,0,sizeof(DB_EVENT));
+ memset(&action,0,sizeof(DB_ACTION));
+ event.value = trigger_value;
+
+ substitute_simple_macros(&event, &action, expression, MACRO_TYPE_TRIGGER_EXPRESSION);
+
+ /* Evaluate expression */
+ delete_spaces(*expression);
+ if( substitute_functions(expression, error, maxerrlen) == SUCCEED)
+ {
+ if( evaluate(result, *expression, error, maxerrlen) == SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "End evaluate_expression(result:%d)",
+ *result);
+ return SUCCEED;
+ }
+ }
+ zabbix_log(LOG_LEVEL_DEBUG, "Evaluation of expression [%s] failed [%s]",
+ *expression,
+ error);
+ zabbix_syslog("Evaluation of expression [%s] failed [%s]",
+ *expression,
+ error);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End evaluate_expression(result:FAIL)");
+ return FAIL;
+}
diff --git a/src/zabbix_proxy/expression.h b/src/zabbix_proxy/expression.h
new file mode 100644
index 00000000..d3808fcc
--- /dev/null
+++ b/src/zabbix_proxy/expression.h
@@ -0,0 +1,40 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#ifndef ZABBIX_EXPRESSION_H
+#define ZABBIX_EXPRESSION_H
+
+#include "common.h"
+#include "db.h"
+
+int cmp_double(double a,double b);
+int find_char(char *str,char c);
+int evaluate_expression(int *result,char **expression, int triggger_value, char *error, int maxerrlen);
+void substitute_macros(DB_EVENT *event, DB_ACTION *action, char **data);
+void delete_reol(char *c);
+
+#define MACRO_TYPE_TRIGGER_DESCRIPTION 1
+#define MACRO_TYPE_MESSAGE_SUBJECT 2
+#define MACRO_TYPE_MESSAGE_BODY 4
+#define MACRO_TYPE_TRIGGER_EXPRESSION 5
+
+void substitute_simple_macros(DB_EVENT *event, DB_ACTION *action, char **data, int macro_type);
+
+#endif
diff --git a/src/zabbix_proxy/functions.c b/src/zabbix_proxy/functions.c
new file mode 100644
index 00000000..53d3a2f4
--- /dev/null
+++ b/src/zabbix_proxy/functions.c
@@ -0,0 +1,815 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include "common.h"
+
+#include "comms.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "evalfunc.h"
+#include "functions.h"
+#include "expression.h"
+
+/******************************************************************************
+ * *
+ * Function: update_functions *
+ * *
+ * Purpose: re-calculate and updates values of functions related to the item *
+ * *
+ * Parameters: item - item to update functions for *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void update_functions(DB_ITEM *item)
+{
+ DB_FUNCTION function;
+ DB_RESULT result;
+ DB_ROW row;
+ char value[MAX_STRING_LEN];
+ char value_esc[MAX_STRING_LEN];
+ char *lastvalue;
+ int ret=SUCCEED;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In update_functions(" ZBX_FS_UI64 ")",
+ item->itemid);
+
+/* Oracle does'n support this */
+/* zbx_snprintf(sql,sizeof(sql),"select function,parameter,itemid,lastvalue from functions where itemid=%d group by function,parameter,itemid order by function,parameter,itemid",item->itemid);*/
+ result = DBselect("select distinct function,parameter,itemid,lastvalue from functions where itemid=" ZBX_FS_UI64,
+ item->itemid);
+
+ while((row=DBfetch(result)))
+ {
+ function.function=row[0];
+ function.parameter=row[1];
+ ZBX_STR2UINT64(function.itemid,row[2]);
+/* function.itemid=atoi(row[2]); */
+ lastvalue=row[3];
+
+ zabbix_log( LOG_LEVEL_DEBUG, "ItemId:" ZBX_FS_UI64 " Evaluating %s(%s)",
+ function.itemid,
+ function.function,
+ function.parameter);
+
+ ret = evaluate_function(value,item,function.function,function.parameter);
+ if( FAIL == ret)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "Evaluation failed for function:%s",
+ function.function);
+ continue;
+ }
+ if (ret == SUCCEED)
+ {
+ /* Update only if lastvalue differs from new one */
+ if( (lastvalue == NULL) || (strcmp(lastvalue,value) != 0))
+ {
+ DBescape_string(value,value_esc,MAX_STRING_LEN);
+ DBexecute("update functions set lastvalue='%s' where itemid=" ZBX_FS_UI64 " and function='%s' and parameter='%s'",
+ value_esc,
+ function.itemid,
+ function.function,
+ function.parameter );
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "Do not update functions, same value");
+ }
+ }
+ }
+
+ DBfree_result(result);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End update_functions()");
+}
+
+/******************************************************************************
+ * *
+ * Function: update_triggers *
+ * *
+ * Purpose: re-calculate and updates values of triggers related to the item *
+ * *
+ * Parameters: itemid - item to update trigger values for *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void update_triggers(zbx_uint64_t itemid)
+{
+ char *exp;
+ char error[MAX_STRING_LEN];
+ int exp_value;
+ DB_TRIGGER trigger;
+ DB_RESULT result;
+ DB_ROW row;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In update_triggers [itemid:" ZBX_FS_UI64 "]",
+ itemid);
+
+ result = DBselect("select distinct t.triggerid,t.expression,t.description,t.url,t.comments,t.status,t.value,t.priority,t.type from triggers t,functions f,items i where i.status<>%d and i.itemid=f.itemid and t.status=%d and f.triggerid=t.triggerid and f.itemid=" ZBX_FS_UI64,
+ ITEM_STATUS_NOTSUPPORTED,
+ TRIGGER_STATUS_ENABLED,
+ itemid);
+
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(trigger.triggerid,row[0]);
+ strscpy(trigger.expression,row[1]);
+ strscpy(trigger.description,row[2]);
+ trigger.url = row[3];
+ trigger.comments = row[4];
+ trigger.status = atoi(row[5]);
+ trigger.value = atoi(row[6]);
+ trigger.priority = atoi(row[7]);
+ trigger.type = atoi(row[8]);
+
+ exp = strdup(trigger.expression);
+ if( evaluate_expression(&exp_value, &exp, trigger.value, error, sizeof(error)) != 0 )
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Expression [%s] cannot be evaluated [%s]",
+ trigger.expression,
+ error);
+ zabbix_syslog("Expression [%s] cannot be evaluated [%s]",
+ trigger.expression,
+ error);
+/* DBupdate_trigger_value(&trigger, exp_value, time(NULL), error);*//* We shouldn't update triggervalue if expressions failed */
+ }
+ else
+ {
+ DBupdate_trigger_value(&trigger, exp_value, time(NULL), NULL);
+ }
+ zbx_free(exp);
+ }
+ DBfree_result(result);
+ zabbix_log( LOG_LEVEL_DEBUG, "End update_triggers [" ZBX_FS_UI64 "]",
+ itemid);
+}
+
+void calc_timestamp(char *line,int *timestamp, char *format)
+{
+ int hh=0,mm=0,ss=0,yyyy=0,dd=0,MM=0;
+ int hhc=0,mmc=0,ssc=0,yyyyc=0,ddc=0,MMc=0;
+ int i,num;
+ struct tm tm;
+ time_t t;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In calc_timestamp()");
+
+ hh=mm=ss=yyyy=dd=MM=0;
+
+ for(i=0;(format[i]!=0)&&(line[i]!=0);i++)
+ {
+ if(isdigit(line[i])==0) continue;
+ num=(int)line[i]-48;
+
+ switch ((char) format[i]) {
+ case 'h':
+ hh=10*hh+num;
+ hhc++;
+ break;
+ case 'm':
+ mm=10*mm+num;
+ mmc++;
+ break;
+ case 's':
+ ss=10*ss+num;
+ ssc++;
+ break;
+ case 'y':
+ yyyy=10*yyyy+num;
+ yyyyc++;
+ break;
+ case 'd':
+ dd=10*dd+num;
+ ddc++;
+ break;
+ case 'M':
+ MM=10*MM+num;
+ MMc++;
+ break;
+ }
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "hh [%d] mm [%d] ss [%d] yyyy [%d] dd [%d] MM [%d]",
+ hh,
+ mm,
+ ss,
+ yyyy,
+ dd,
+ MM);
+
+ /* Seconds can be ignored. No ssc here. */
+ if(hhc!=0&&mmc!=0&&yyyyc!=0&&ddc!=0&&MMc!=0)
+ {
+ tm.tm_sec=ss;
+ tm.tm_min=mm;
+ tm.tm_hour=hh;
+ tm.tm_mday=dd;
+ tm.tm_mon=MM-1;
+ tm.tm_year=yyyy-1900;
+
+ t=mktime(&tm);
+ if(t>0)
+ {
+ *timestamp=t;
+ }
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End timestamp [%d]",
+ *timestamp);
+}
+
+/******************************************************************************
+ * *
+ * Function: process_data *
+ * *
+ * Purpose: process new item value *
+ * *
+ * Parameters: sockfd - descriptor of agent-server socket connection *
+ * server - server name *
+ * key - item's key *
+ * value - new value of server:key *
+ * lastlogsize - if key=log[*], last size of log file *
+ * *
+ * Return value: SUCCEED - new value processed sucesfully *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: for trapper server process *
+ * *
+ ******************************************************************************/
+int process_data(zbx_sock_t *sock,char *server,char *key,char *value,char *lastlogsize, char *timestamp,
+ char *source, char *severity)
+{
+ AGENT_RESULT agent;
+
+ DB_RESULT result;
+ DB_ROW row;
+ DB_ITEM item;
+
+ char server_esc[MAX_STRING_LEN];
+ char key_esc[MAX_STRING_LEN];
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In process_data([%s],[%s],[%s],[%s])",
+ server,
+ key,
+ value,
+ lastlogsize);
+
+ init_result(&agent);
+
+ DBescape_string(server, server_esc, MAX_STRING_LEN);
+ DBescape_string(key, key_esc, MAX_STRING_LEN);
+
+ result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and h.host='%s' and i.key_='%s' and i.status in (%d,%d) and i.type in (%d,%d) and" ZBX_COND_NODEID,
+ ZBX_SQL_ITEM_SELECT,
+ HOST_STATUS_MONITORED,
+ server_esc,
+ key_esc,
+ ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED,
+ ITEM_TYPE_TRAPPER,
+ ITEM_TYPE_ZABBIX_ACTIVE,
+ LOCAL_NODE("h.hostid"));
+
+ row=DBfetch(result);
+
+ if(!row)
+ {
+ DBfree_result(result);
+ return FAIL;
+/*
+ zabbix_log( LOG_LEVEL_DEBUG, "Before checking autoregistration for [%s]",
+ server);
+
+ if(autoregister(server) == SUCCEED)
+ {
+ DBfree_result(result);
+
+ result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and h.host='%s' and i.key_='%s' and i.status=%d and i.type in (%d,%d) and" ZBX_COND_NODEID,
+ ZBX_SQL_ITEM_SELECT,
+ HOST_STATUS_MONITORED,
+ server_esc,
+ key_esc,
+ ITEM_STATUS_ACTIVE,
+ ITEM_TYPE_TRAPPER,
+ ITEM_TYPE_ZABBIX_ACTIVE,
+ LOCAL_NODE("h.hostid"));
+ row = DBfetch(result);
+ if(!row)
+ {
+ DBfree_result(result);
+ return FAIL;
+ }
+ }
+ else
+ {
+ DBfree_result(result);
+ return FAIL;
+ }
+*/
+ }
+
+ DBget_item_from_db(&item,row);
+
+ if( (item.type==ITEM_TYPE_ZABBIX_ACTIVE) && (zbx_tcp_check_security(sock,item.trapper_hosts,1) == FAIL))
+ {
+ DBfree_result(result);
+ return FAIL;
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "Processing [%s]",
+ value);
+
+ if(strcmp(value,"ZBX_NOTSUPPORTED") ==0)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Active parameter [%s] is not supported by agent on host [%s]",
+ item.key,
+ item.host_name);
+ zabbix_syslog("Active parameter [%s] is not supported by agent on host [%s]",
+ item.key,
+ item.host_name);
+ DBupdate_item_status_to_notsupported(item.itemid, "Not supported by ZABBIX agent");
+ }
+ else
+ {
+ if( (strncmp(item.key,"log[",4)==0) ||
+ (strncmp(item.key,"eventlog[",9)==0)
+ )
+ {
+ item.lastlogsize=atoi(lastlogsize);
+ item.timestamp=atoi(timestamp);
+
+ calc_timestamp(value,&item.timestamp,item.logtimefmt);
+
+ item.eventlog_severity=atoi(severity);
+ item.eventlog_source=source;
+ zabbix_log(LOG_LEVEL_DEBUG, "Value [%s] Lastlogsize [%s] Timestamp [%s]",
+ value,
+ lastlogsize,
+ timestamp);
+ }
+
+ if(set_result_type(&agent, item.value_type, value) == SUCCEED)
+ {
+ process_new_value(&item,&agent);
+ update_triggers(item.itemid);
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Type of received value [%s] is not suitable for [%s@%s]",
+ value,
+ item.key,
+ item.host_name);
+ zabbix_syslog("Type of received value [%s] is not suitable for [%s@%s]",
+ value,
+ item.key,
+ item.host_name);
+ }
+ }
+
+ DBfree_result(result);
+
+ free_result(&agent);
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: add_history *
+ * *
+ * Purpose: add new value to history *
+ * *
+ * Parameters: item - item data *
+ * value - new value of the item *
+ * now - new value of the item *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int add_history(DB_ITEM *item, AGENT_RESULT *value, int now)
+{
+ int ret = SUCCEED;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_history(key:%s,value_type:%X,type:%X)",
+ item->key,
+ item->value_type,
+ value->type);
+
+ if (value->type & AR_UINT64)
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_history(itemid:"ZBX_FS_UI64",UINT64:"ZBX_FS_UI64")",
+ item->itemid,
+ value->ui64);
+ if (value->type & AR_STRING)
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_history(itemid:"ZBX_FS_UI64",STRING:%s)",
+ item->itemid,
+ value->str);
+ if (value->type & AR_DOUBLE)
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_history(itemid:"ZBX_FS_UI64",DOUBLE:"ZBX_FS_DBL")",
+ item->itemid,
+ value->dbl);
+ if (value->type & AR_TEXT)
+ zabbix_log( LOG_LEVEL_DEBUG, "In add_history(itemid:"ZBX_FS_UI64",TEXT:[%s])",
+ item->itemid,
+ value->text);
+
+ if(item->history>0)
+ {
+ if( (item->value_type==ITEM_VALUE_TYPE_FLOAT) || (item->value_type==ITEM_VALUE_TYPE_UINT64))
+ {
+ /* Should we store delta or original value? */
+ if(item->delta == ITEM_STORE_AS_IS)
+ {
+ if(item->value_type==ITEM_VALUE_TYPE_UINT64)
+ {
+ if(GET_UI64_RESULT(value))
+ DBadd_history_uint(item->itemid,value->ui64,now);
+ }
+ else if(item->value_type==ITEM_VALUE_TYPE_FLOAT)
+ {
+ if(GET_DBL_RESULT(value))
+ DBadd_history(item->itemid,value->dbl,now);
+ }
+ }
+ /* Delta as speed of change */
+ else if(item->delta == ITEM_STORE_SPEED_PER_SECOND)
+ {
+ /* Save delta */
+ if( ITEM_VALUE_TYPE_FLOAT == item->value_type )
+ {
+ if(GET_DBL_RESULT(value) && (item->prevorgvalue_null == 0) && (item->prevorgvalue_dbl <= value->dbl) && (now != item->lastclock))
+ {
+ DBadd_history(
+ item->itemid,
+ (value->dbl - item->prevorgvalue_dbl)/(now-item->lastclock),
+ now);
+ }
+ }
+ else if( ITEM_VALUE_TYPE_UINT64 == item->value_type )
+ {
+ if(GET_UI64_RESULT(value) && (item->prevorgvalue_null == 0) && (item->prevorgvalue_uint64 <= value->ui64) && (now != item->lastclock))
+ {
+ DBadd_history_uint(
+ item->itemid,
+ (zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64)/(now-item->lastclock),
+ now);
+ }
+ }
+ }
+ /* Real delta: simple difference between values */
+ else if(item->delta == ITEM_STORE_SIMPLE_CHANGE)
+ {
+ /* Save delta */
+ if( ITEM_VALUE_TYPE_FLOAT == item->value_type )
+ {
+ if(GET_DBL_RESULT(value) && (item->prevorgvalue_null == 0) && (item->prevorgvalue_dbl <= value->dbl) )
+ {
+ DBadd_history(item->itemid, (value->dbl - item->prevorgvalue_dbl), now);
+ }
+ }
+ else if(item->value_type==ITEM_VALUE_TYPE_UINT64)
+ {
+ if(GET_UI64_RESULT(value) && (item->prevorgvalue_null == 0) && (item->prevorgvalue_uint64 <= value->ui64) )
+ {
+ DBadd_history_uint(item->itemid, value->ui64 - item->prevorgvalue_uint64, now);
+ }
+ }
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Value not stored for itemid [%d]. Unknown delta [%d]",
+ item->itemid,
+ item->delta);
+ zabbix_syslog("Value not stored for itemid [%d]. Unknown delta [%d]",
+ item->itemid,
+ item->delta);
+ ret = FAIL;
+ }
+ }
+ else if(item->value_type==ITEM_VALUE_TYPE_STR)
+ {
+ if(GET_STR_RESULT(value))
+ DBadd_history_str(item->itemid,value->str,now);
+ }
+ else if(item->value_type==ITEM_VALUE_TYPE_LOG)
+ {
+ if(GET_STR_RESULT(value))
+ DBadd_history_log(0, item->itemid,value->str,now,item->timestamp,item->eventlog_source,item->eventlog_severity);
+ }
+ else if(item->value_type==ITEM_VALUE_TYPE_TEXT)
+ {
+ if(GET_TEXT_RESULT(value))
+ DBadd_history_text(item->itemid,value->text,now);
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Unknown value type [%d] for itemid [" ZBX_FS_UI64 "]",
+ item->value_type,
+ item->itemid);
+ }
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End of add_history");
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: update_item *
+ * *
+ * Purpose: update item info after new value is received *
+ * *
+ * Parameters: item - item data *
+ * value - new value of the item *
+ * now - current timestamp *
+ * *
+ * Author: Alexei Vladishev, Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void update_item(DB_ITEM *item, AGENT_RESULT *value, time_t now)
+{
+ char value_esc[MAX_STRING_LEN];
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In update_item()");
+
+ value_esc[0] = '\0';
+
+ if(item->delta == ITEM_STORE_AS_IS)
+ {
+ if(GET_STR_RESULT(value))
+ {
+ DBescape_string(value->str, value_esc, sizeof(value_esc));
+ }
+
+ if (item->value_type == ITEM_VALUE_TYPE_LOG) {
+ DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,lastvalue='%s',lastclock=%d,lastlogsize=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay, item->delay_flex, now),
+ value_esc,
+ (int)now,
+ item->lastlogsize,
+ item->itemid);
+ } else {
+ DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,lastvalue='%s',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay, item->delay_flex, now),
+ value_esc,
+ (int)now,
+ item->itemid);
+ }
+ }
+ /* Logic for delta as speed of change */
+ else if(item->delta == ITEM_STORE_SPEED_PER_SECOND)
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_FLOAT)
+ {
+ if(GET_DBL_RESULT(value))
+ {
+ if((item->prevorgvalue_null == 0) && (item->prevorgvalue_dbl <= value->dbl) )
+ {
+ /* In order to continue normal processing, we assume difference 1 second
+ Otherwise function update_functions and update_triggers won't work correctly*/
+ if(now != item->lastclock)
+ {
+ DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_DBL "',"
+ "lastvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now),
+ value->dbl,
+ (value->dbl - item->prevorgvalue_dbl)/(now-item->lastclock),
+ (int)now,
+ item->itemid);
+ SET_DBL_RESULT(value, (double)(value->dbl - item->prevorgvalue_dbl)/(now-item->lastclock));
+ }
+ else
+ {
+ DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_DBL "',"
+ "lastvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now),
+ value->dbl,
+ value->dbl - item->prevorgvalue_dbl,
+ (int)now,
+ item->itemid);
+ SET_DBL_RESULT(value, (double)(value->dbl - item->prevorgvalue_dbl));
+ }
+ }
+ else
+ {
+ DBexecute("update items set nextcheck=%d,prevorgvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now),
+ value->dbl,
+ (int)now,
+ item->itemid);
+ }
+ }
+ }
+ else if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ if(GET_UI64_RESULT(value))
+ {
+ if((item->prevorgvalue_null == 0) && (item->prevorgvalue_uint64 <= value->ui64) )
+ {
+ if(now != item->lastclock)
+ {
+ DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_UI64 "',"
+ "lastvalue='" ZBX_FS_UI64 "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now),
+ value->ui64,
+ ((zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64))/(now-item->lastclock),
+ (int)now,
+ item->itemid);
+ SET_UI64_RESULT(value, (zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64)/(now-item->lastclock));
+ }
+ else
+ {
+ DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_UI64 "',"
+ "lastvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now),
+ value->ui64,
+ (double)(value->ui64 - item->prevorgvalue_uint64),
+ (int)now,
+ item->itemid);
+ SET_UI64_RESULT(value, (zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64));
+ }
+ }
+ else
+ {
+ DBexecute("update items set nextcheck=%d,prevorgvalue='" ZBX_FS_UI64 "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now),
+ value->ui64,
+ (int)now,
+ item->itemid);
+ }
+ }
+ }
+ }
+ /* Real delta: simple difference between values */
+ else if(item->delta == ITEM_STORE_SIMPLE_CHANGE)
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_FLOAT)
+ {
+ if(GET_DBL_RESULT(value))
+ {
+ if((item->prevorgvalue_null == 0) && (item->prevorgvalue_dbl <= value->dbl))
+ {
+ DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_DBL "',"
+ "lastvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now),
+ value->dbl,
+ (value->dbl - item->prevorgvalue_dbl),
+ (int)now,
+ item->itemid);
+ SET_DBL_RESULT(value, (double)(value->dbl - item->prevorgvalue_dbl));
+ }
+ else
+ {
+ DBexecute("update items set nextcheck=%d,prevorgvalue='" ZBX_FS_DBL "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex, now),
+ value->dbl,
+ (int)now,
+ item->itemid);
+ }
+ }
+ }
+ else if(item->value_type == ITEM_VALUE_TYPE_UINT64)
+ {
+ if(GET_UI64_RESULT(value))
+ {
+ if((item->prevorgvalue_null == 0) && (item->prevorgvalue_uint64 <= value->ui64))
+ {
+ DBexecute("update items set nextcheck=%d,prevvalue=lastvalue,prevorgvalue='" ZBX_FS_UI64 "',"
+ "lastvalue='" ZBX_FS_UI64 "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex,now),
+ value->ui64,
+ (value->ui64 - item->prevorgvalue_uint64),
+ (int)now,
+ item->itemid);
+ SET_UI64_RESULT(value, (zbx_uint64_t)(value->ui64 - item->prevorgvalue_uint64));
+ }
+ else
+ {
+ DBexecute("update items set nextcheck=%d,prevorgvalue='" ZBX_FS_UI64 "',lastclock=%d where itemid=" ZBX_FS_UI64,
+ calculate_item_nextcheck(item->itemid, item->type, item->delay,item->delay_flex, now),
+ value->ui64,
+ (int)now,
+ item->itemid);
+ }
+ }
+ }
+ }
+
+ item->prevvalue_str = item->lastvalue_str;
+ item->prevvalue_dbl = item->lastvalue_dbl;
+ item->prevvalue_uint64 = item->lastvalue_uint64;
+ item->prevvalue_null = item->lastvalue_null;
+
+ item->lastvalue_uint64 = value->ui64;
+ item->lastvalue_dbl = value->dbl;
+ item->lastvalue_str = value->str;
+ item->lastvalue_null = 0;
+
+/* Update item status if required */
+ if(item->status == ITEM_STATUS_NOTSUPPORTED)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Parameter [%s] became supported by agent on host [%s]",
+ item->key,
+ item->host_name);
+ zabbix_syslog("Parameter [%s] became supported by agent on host [%s]",
+ item->key,
+ item->host_name);
+ item->status = ITEM_STATUS_ACTIVE;
+ DBexecute("update items set status=%d where itemid=" ZBX_FS_UI64,
+ ITEM_STATUS_ACTIVE,
+ item->itemid);
+ }
+
+ /* Required for nodata() */
+ item->lastclock = now;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End update_item()");
+}
+
+/******************************************************************************
+ * *
+ * Function: process_new_value *
+ * *
+ * Purpose: process new item value *
+ * *
+ * Parameters: item - item data *
+ * value - new value of the item *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: for trapper poller process *
+ * *
+ ******************************************************************************/
+void process_new_value(DB_ITEM *item, AGENT_RESULT *value)
+{
+ time_t now;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In process_new_value(%s)",
+ item->key);
+
+ now = time(NULL);
+
+ if( ITEM_MULTIPLIER_USE == item->multiplier )
+ {
+ if( ITEM_VALUE_TYPE_FLOAT == item->value_type )
+ {
+ if(GET_DBL_RESULT(value))
+ {
+ UNSET_RESULT_EXCLUDING(value, AR_DOUBLE);
+ SET_DBL_RESULT(value, value->dbl * strtod(item->formula, NULL));
+ }
+ }
+ else if( ITEM_VALUE_TYPE_UINT64 == item->value_type )
+ {
+ if(GET_UI64_RESULT(value))
+ {
+ UNSET_RESULT_EXCLUDING(value, AR_UINT64);
+ if(is_uint(item->formula) == SUCCEED)
+ {
+ SET_UI64_RESULT(value, value->ui64 * zbx_atoui64((item->formula)));
+ }
+ else
+ {
+ SET_UI64_RESULT(value, (zbx_uint64_t)((double)value->ui64 * strtod(item->formula, NULL)));
+ }
+ }
+ }
+ }
+
+ add_history(item, value, now);
+ update_item(item, value, now);
+ update_functions( item );
+}
diff --git a/src/zabbix_proxy/functions.h b/src/zabbix_proxy/functions.h
new file mode 100644
index 00000000..79d64bbd
--- /dev/null
+++ b/src/zabbix_proxy/functions.h
@@ -0,0 +1,34 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_FUNCTIONS_H
+#define ZABBIX_FUNCTIONS_H
+
+#include "common.h"
+#include "comms.h"
+#include "db.h"
+#include "sysinfo.h"
+
+void update_triggers (zbx_uint64_t itemid);
+void update_functions(DB_ITEM *item);
+int process_data(zbx_sock_t *sock,char *server,char *key, char *value,char *lastlogsize,char *timestamp,
+ char *source, char *severity);
+void process_new_value(DB_ITEM *item, AGENT_RESULT *value);
+
+#endif
diff --git a/src/zabbix_proxy/housekeeper/Makefile.am b/src/zabbix_proxy/housekeeper/Makefile.am
new file mode 100644
index 00000000..315f0d24
--- /dev/null
+++ b/src/zabbix_proxy/housekeeper/Makefile.am
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxhousekeeper.a
+
+libzbxhousekeeper_a_SOURCES = housekeeper.c housekeeper.h
diff --git a/src/zabbix_proxy/housekeeper/housekeeper.c b/src/zabbix_proxy/housekeeper/housekeeper.c
new file mode 100644
index 00000000..048ac76e
--- /dev/null
+++ b/src/zabbix_proxy/housekeeper/housekeeper.c
@@ -0,0 +1,375 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+#include "cfg.h"
+#include "db.h"
+#include "log.h"
+
+#include "housekeeper.h"
+
+/******************************************************************************
+ * *
+ * Function: housekeeping_process_log *
+ * *
+ * Purpose: process table 'housekeeper' and remove data if required *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - information removed succesfully *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int housekeeping_process_log()
+{
+ DB_HOUSEKEEPER housekeeper;
+
+ DB_RESULT result;
+ DB_ROW row;
+ int res = SUCCEED;
+
+ long deleted;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_process_log()");
+
+ /* order by tablename to effectively use DB cache */
+ result = DBselect("select housekeeperid, tablename, field, value from housekeeper order by tablename");
+
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(housekeeper.housekeeperid,row[0]);
+ housekeeper.tablename=row[1];
+ housekeeper.field=row[2];
+ ZBX_STR2UINT64(housekeeper.value,row[3]);
+
+#ifdef HAVE_ORACLE
+ deleted = DBexecute("delete from %s where %s=" ZBX_FS_UI64 " and rownum<500",
+ housekeeper.tablename,
+ housekeeper.field,
+ housekeeper.value);
+#elif defined(HAVE_POSTGRESQL)
+ deleted = DBexecute("delete from %s where oid in (select oid from %s where %s=" ZBX_FS_UI64 " limit 500)",
+ housekeeper.tablename,
+ housekeeper.tablename,
+ housekeeper.field,
+ housekeeper.value);
+#else
+ deleted = DBexecute("delete from %s where %s=" ZBX_FS_UI64 " limit 500",
+ housekeeper.tablename,
+ housekeeper.field,
+ housekeeper.value);
+#endif
+ if(deleted == 0)
+ {
+ DBexecute("delete from housekeeper where housekeeperid=" ZBX_FS_UI64,
+ housekeeper.housekeeperid);
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "Deleted [%ld] records from table [%s]",
+ deleted,
+ housekeeper.tablename);
+ }
+ }
+ DBfree_result(result);
+
+ return res;
+}
+
+
+static int housekeeping_sessions(int now)
+{
+ int deleted;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_sessions(%d)",
+ now);
+
+ deleted = DBexecute("delete from sessions where lastaccess<%d",
+ now-24*3600);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "Deleted [%ld] records from table [sessions]",
+ deleted);
+
+ return SUCCEED;
+}
+
+static int housekeeping_alerts(int now)
+{
+ int alert_history;
+ DB_RESULT result;
+ DB_ROW row;
+ int res = SUCCEED;
+ int deleted;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_alerts(%d)",
+ now);
+
+ result = DBselect("select alert_history from config");
+
+ row=DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_ERR, "No records in table 'config'.");
+ res = FAIL;
+ }
+ else
+ {
+ alert_history=atoi(row[0]);
+
+ deleted = DBexecute("delete from alerts where clock<%d",
+ now-24*3600*alert_history);
+ zabbix_log( LOG_LEVEL_DEBUG, "Deleted [%ld] records from table [alerts]",
+ deleted);
+ }
+
+ DBfree_result(result);
+ return res;
+}
+
+static int housekeeping_events(int now)
+{
+ int event_history;
+ DB_RESULT result;
+ DB_RESULT result2;
+ DB_ROW row1;
+ DB_ROW row2;
+ zbx_uint64_t eventid;
+ int res = SUCCEED;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_events(%d)",
+ now);
+
+ result = DBselect("select event_history from config");
+
+ row1=DBfetch(result);
+
+ if(!row1 || DBis_null(row1[0])==SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_ERR, "No records in table 'config'.");
+ res = FAIL;
+ }
+ else
+ {
+ event_history=atoi(row1[0]);
+
+ result2 = DBselect("select eventid from events where clock<%d",
+ now-24*3600*event_history);
+ while((row2=DBfetch(result2)))
+ {
+ ZBX_STR2UINT64(eventid,row2[0]);
+
+ DBexecute("delete from acknowledges where eventid=" ZBX_FS_UI64,
+ eventid);
+
+ DBexecute("delete from events where eventid=" ZBX_FS_UI64,
+ eventid);
+ }
+ DBfree_result(result2);
+
+ }
+
+ DBfree_result(result);
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: delete_history *
+ * *
+ * Purpose: remove outdated information from historical table *
+ * *
+ * Parameters: now - current timestamp *
+ * *
+ * Return value: number of rows deleted *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int delete_history(char *table, zbx_uint64_t itemid, int keep_history, int now)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ int min_clock;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In delete_history(%s," ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d)",
+ table,
+ itemid,
+ keep_history,
+ now);
+
+ result = DBselect("select min(clock) from %s where itemid=" ZBX_FS_UI64,
+ table,
+ itemid);
+
+ row=DBfetch(result);
+
+ if(!row || DBis_null(row[0]) == SUCCEED)
+ {
+ DBfree_result(result);
+ return 0;
+ }
+
+ min_clock = atoi(row[0]);
+ DBfree_result(result);
+
+/* zabbix_log( LOG_LEVEL_DEBUG, "Now %d keep_history %d Itemid " ZBX_FS_UI64 " min %d new min %d",
+ now,
+ keep_history,
+ itemid,
+ min_clock,
+ MIN(now-24*3600*keep_history, min_clock+4*3600*CONFIG_HOUSEKEEPING_FREQUENCY));*/
+
+ return DBexecute("delete from %s where itemid=" ZBX_FS_UI64 " and clock<%d",
+ table,
+ itemid,
+ MIN(now-24*3600*keep_history, min_clock+4*3600*CONFIG_HOUSEKEEPING_FREQUENCY)
+ );
+}
+
+/******************************************************************************
+ * *
+ * Function: housekeeping_history_and_trends *
+ * *
+ * Purpose: remove outdated information from history and trends *
+ * *
+ * Parameters: now - current timestamp *
+ * *
+ * Return value: SUCCEED - information removed succesfully *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int housekeeping_history_and_trends(int now)
+{
+ DB_ITEM item;
+
+ DB_RESULT result;
+ DB_ROW row;
+
+ int deleted = 0;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In housekeeping_history_and_trends(%d)",
+ now);
+
+ result = DBselect("select itemid,history,trends from items");
+
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(item.itemid,row[0]);
+ item.history=atoi(row[1]);
+ item.trends=atoi(row[2]);
+
+ deleted += delete_history("history", item.itemid, item.history, now);
+ deleted += delete_history("history_uint", item.itemid, item.history, now);
+ deleted += delete_history("history_str", item.itemid, item.history, now);
+ deleted += delete_history("history_text", item.itemid, item.history, now);
+ deleted += delete_history("history_log", item.itemid, item.history, now);
+ deleted += delete_history("trends", item.itemid, item.trends, now);
+ }
+ DBfree_result(result);
+ return deleted;
+}
+
+int main_housekeeper_loop()
+{
+ int now;
+ int d;
+
+ if(CONFIG_DISABLE_HOUSEKEEPING == 1)
+ {
+ for(;;)
+ {
+/* Do nothing */
+ zbx_setproctitle("do nothing");
+
+ sleep(3600);
+ }
+ }
+
+ for(;;)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Executing housekeeper");
+ now = time(NULL);
+
+ zbx_setproctitle("connecting to the database");
+
+ DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+/* Transaction is not required here. It causes timeouts under MySQL */
+/* DBbegin();*/
+
+/* zbx_setproctitle("housekeeper [removing deleted hosts]");*/
+
+/* housekeeping_hosts();*/
+
+/* zbx_setproctitle("housekeeper [removing deleted items]");*/
+
+/* housekeeping_items();*/
+
+/* zbx_setproctitle("housekeeper [removing old history]");*/
+
+ d = housekeeping_history_and_trends(now);
+ zabbix_log( LOG_LEVEL_WARNING, "Deleted %d records from history and trends",
+ d);
+
+ zbx_setproctitle("housekeeper [removing old history]");
+
+ housekeeping_process_log(now);
+
+ zbx_setproctitle("housekeeper [removing old events]");
+
+ housekeeping_events(now);
+
+ zbx_setproctitle("housekeeper [removing old alerts]");
+
+ housekeeping_alerts(now);
+
+ zbx_setproctitle("housekeeper [removing old sessions]");
+
+ housekeeping_sessions(now);
+
+ zbx_setproctitle("housekeeper [vacuuming database]");
+
+/* Transaction is not required here. It causes timeouts under MySQL */
+/* DBcommit();*/
+
+ DBvacuum();
+
+ zabbix_log( LOG_LEVEL_DEBUG, "Sleeping for %d hours",
+ CONFIG_HOUSEKEEPING_FREQUENCY);
+
+ zbx_setproctitle("housekeeper [sleeping for %d hour(s)]",
+ CONFIG_HOUSEKEEPING_FREQUENCY);
+
+ DBclose();
+ zabbix_log( LOG_LEVEL_DEBUG, "Next housekeeper run is after %dh",
+ CONFIG_HOUSEKEEPING_FREQUENCY);
+ sleep(3660*CONFIG_HOUSEKEEPING_FREQUENCY);
+ }
+}
diff --git a/src/zabbix_proxy/housekeeper/housekeeper.h b/src/zabbix_proxy/housekeeper/housekeeper.h
new file mode 100644
index 00000000..ecb9bb52
--- /dev/null
+++ b/src/zabbix_proxy/housekeeper/housekeeper.h
@@ -0,0 +1,29 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_HOUSEKEEPER_H
+#define ZABBIX_HOUSEKEEPER_H
+
+extern int CONFIG_DISABLE_HOUSEKEEPING;
+extern int CONFIG_HOUSEKEEPING_FREQUENCY;
+extern char *CONFIG_FPING_LOCATION;
+
+int main_housekeeper_loop();
+
+#endif
diff --git a/src/zabbix_proxy/httppoller/Makefile.am b/src/zabbix_proxy/httppoller/Makefile.am
new file mode 100644
index 00000000..07706687
--- /dev/null
+++ b/src/zabbix_proxy/httppoller/Makefile.am
@@ -0,0 +1,8 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxhttppoller.a
+
+libzbxhttppoller_a_SOURCES = \
+ httpmacro.c httpmacro.h \
+ httptest.c httptest.h \
+ httppoller.c httppoller.h
diff --git a/src/zabbix_proxy/httppoller/httpmacro.c b/src/zabbix_proxy/httppoller/httpmacro.c
new file mode 100644
index 00000000..4e14fe9b
--- /dev/null
+++ b/src/zabbix_proxy/httppoller/httpmacro.c
@@ -0,0 +1,133 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "pid.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "httpmacro.h"
+
+/******************************************************************************
+ * *
+ * Function: http_substitute_macros *
+ * *
+ * Purpose: substitute macros in input string by value from http test config *
+ * *
+ * Parameters: httptest - http test data, data - string to substitute macros *
+ * *
+ * Return value: - *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void http_substitute_macros(DB_HTTPTEST *httptest, char *data, int data_max_len)
+{
+ char
+ *pl = NULL,
+ *pr = NULL,
+ str_out[MAX_STRING_LEN],
+ replace_to[MAX_STRING_LEN],
+ *c,*c2, save,*replacement,save2;
+ int
+ outlen,
+ var_len;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In http_substitute_macros(httptestid:" ZBX_FS_UI64 ", data:%s)",
+ httptest->httptestid,
+ data);
+
+ assert(data);
+
+ *str_out = '\0';
+ outlen = sizeof(str_out) - 1;
+ pl = data;
+ while((pr = strchr(pl, '{')) && outlen > 0)
+ {
+ pr[0] = '\0';
+ zbx_strlcat(str_out, pl, outlen);
+ outlen -= MIN(strlen(pl), outlen);
+ pr[0] = '{';
+
+ zbx_snprintf(replace_to, sizeof(replace_to), "{");
+ var_len = 1;
+
+
+ if(NULL!=(c=strchr(pr,'}')))
+ {
+ /* Macro in pr */
+ save = c[1]; c[1]=0;
+
+ if(NULL != (c2 = strstr(httptest->macros,pr)))
+ {
+ if(NULL != (replacement = strchr(c2,'=')))
+ {
+ replacement++;
+ if(NULL != (c2 = strchr(replacement,'\r')))
+ {
+ save2 = c2[0]; c2[0]=0;
+ var_len = strlen(pr);
+ zbx_snprintf(replace_to, sizeof(replace_to), "%s", replacement);
+ c2[0] = save2;
+ }
+ else
+ {
+ var_len = strlen(pr);
+ zbx_snprintf(replace_to, sizeof(replace_to), "%s", replacement);
+ }
+ }
+
+ }
+/* result = DBselect("select value from httpmacro where macro='%s' and httptestid=" ZBX_FS_UI64,
+ pr, httptest->httptestid);
+ row = DBfetch(result);
+ if(row)
+ {
+ var_len = strlen(pr);
+ zbx_snprintf(replace_to, sizeof(replace_to), "%s", row[0]);
+ }
+ DBfree_result(result);*/
+ /* Restore pr */
+ c[1]=save;
+ }
+
+/* if(strncmp(pr, "TRIGGER.NAME", strlen("TRIGGER.NAME")) == 0)
+ {
+ var_len = strlen("TRIGGER.NAME");
+
+ zbx_snprintf(replace_to, sizeof(replace_to), "%s", event->trigger_description);
+ substitute_simple_macros(event, action, replace_to, sizeof(replace_to), MACRO_TYPE_TRIGGER_DESCRIPTION);
+ }*/
+ zbx_strlcat(str_out, replace_to, outlen);
+ outlen -= MIN(strlen(replace_to), outlen);
+ pl = pr + var_len;
+ }
+ zbx_strlcat(str_out, pl, outlen);
+ outlen -= MIN(strlen(pl), outlen);
+
+ zbx_snprintf(data, data_max_len, "%s", str_out);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "Result expression [%s]",
+ data);
+}
diff --git a/src/zabbix_proxy/httppoller/httpmacro.h b/src/zabbix_proxy/httppoller/httpmacro.h
new file mode 100644
index 00000000..3a3a2abf
--- /dev/null
+++ b/src/zabbix_proxy/httppoller/httpmacro.h
@@ -0,0 +1,25 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_HTTPMACRO_H
+#define ZABBIX_HTTPMACRO_H
+
+void http_substitute_macros(DB_HTTPTEST *httptest, char *data, int data_max_len);
+
+#endif
diff --git a/src/zabbix_proxy/httppoller/httppoller.c b/src/zabbix_proxy/httppoller/httppoller.c
new file mode 100644
index 00000000..ef07fa05
--- /dev/null
+++ b/src/zabbix_proxy/httppoller/httppoller.c
@@ -0,0 +1,165 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "pid.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "../functions.h"
+#include "../expression.h"
+#include "httptest.h"
+#include "httppoller.h"
+
+#include "daemon.h"
+
+int httppoller_num;
+
+/******************************************************************************
+ * *
+ * Function: get_minnextcheck *
+ * *
+ * Purpose: calculate when we have to process earliest httptest *
+ * *
+ * Parameters: now - current timestamp *
+ * *
+ * Return value: timestamp of earliest check or -1 if not found *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: never returns *
+ * *
+ ******************************************************************************/
+static int get_minnextcheck(int now)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ int res;
+
+ result = DBselect("select count(*),min(nextcheck) from httptest t where t.status=%d and " ZBX_SQL_MOD(t.httptestid,%d) "=%d and " ZBX_COND_NODEID,
+ HTTPTEST_STATUS_MONITORED,
+ CONFIG_HTTPPOLLER_FORKS,
+ httppoller_num-1,
+ LOCAL_NODE("t.httptestid"));
+
+ row=DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED || DBis_null(row[1])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "No httptests to process in get_minnextcheck.");
+ res = FAIL;
+ }
+ else
+ {
+ if( atoi(row[0]) == 0)
+ {
+ res = FAIL;
+ }
+ else
+ {
+ res = atoi(row[1]);
+ }
+ }
+ DBfree_result(result);
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: main_httppoller_loop *
+ * *
+ * Purpose: main loop of processing of httptests *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: never returns *
+ * *
+ ******************************************************************************/
+void main_httppoller_loop(int num)
+{
+ int now;
+ int nextcheck,sleeptime;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In main_httppoller_loop(num:%d)",
+ num);
+
+ httppoller_num = num;
+
+ DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+ for(;;)
+ {
+ zbx_setproctitle("http poller [getting values]");
+
+ now=time(NULL);
+ process_httptests(now);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "Spent %d seconds while processing HTTP tests",
+ (int)time(NULL)-now);
+
+ nextcheck=get_minnextcheck(now);
+ zabbix_log( LOG_LEVEL_DEBUG, "Nextcheck:%d Time:%d",
+ nextcheck,
+ (int)time(NULL));
+
+ if( FAIL == nextcheck)
+ {
+ sleeptime=POLLER_DELAY;
+ }
+ else
+ {
+ sleeptime=nextcheck-time(NULL);
+ if(sleeptime<0)
+ {
+ sleeptime=0;
+ }
+ }
+ if(sleeptime>0)
+ {
+ if(sleeptime > POLLER_DELAY)
+ {
+ sleeptime = POLLER_DELAY;
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "Sleeping for %d seconds",
+ sleeptime );
+
+ zbx_setproctitle("http poller [sleeping for %d seconds]",
+ sleeptime);
+
+ sleep( sleeptime );
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No sleeping" );
+ }
+
+#ifdef ZABBIX_TEST
+ break;
+#endif /* ZABBIX_TEST */
+ }
+}
diff --git a/src/zabbix_proxy/httppoller/httppoller.h b/src/zabbix_proxy/httppoller/httppoller.h
new file mode 100644
index 00000000..eb0d63e0
--- /dev/null
+++ b/src/zabbix_proxy/httppoller/httppoller.h
@@ -0,0 +1,30 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_HTTPPOLLER_H
+#define ZABBIX_HTTPPOLLER_H
+
+extern void signal_handler(int);
+extern int server_num;
+
+extern int CONFIG_HTTPPOLLER_FORKS;
+
+void main_httppoller_loop(int num);
+
+#endif
diff --git a/src/zabbix_proxy/httppoller/httptest.c b/src/zabbix_proxy/httppoller/httptest.c
new file mode 100644
index 00000000..cc7fefc4
--- /dev/null
+++ b/src/zabbix_proxy/httppoller/httptest.c
@@ -0,0 +1,544 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "pid.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "../functions.h"
+#include "httpmacro.h"
+#include "httptest.h"
+
+#ifdef HAVE_LIBCURL
+
+static S_ZBX_HTTPPAGE page;
+
+/******************************************************************************
+ * *
+ * Function: process_value *
+ * *
+ * Purpose: process new item value *
+ * *
+ * Parameters: key - item key *
+ * host - host name *
+ * value - new value of the item *
+ * *
+ * Return value: SUCCEED - new value sucesfully processed *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: can be done in process_data() *
+ * *
+ ******************************************************************************/
+static int process_value(zbx_uint64_t itemid, AGENT_RESULT *value)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ DB_ITEM item;
+
+ INIT_CHECK_MEMORY();
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In process_value(itemid:" ZBX_FS_UI64 ")",
+ itemid);
+
+ result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and i.status=%d and i.type=%d and i.itemid=" ZBX_FS_UI64 " and " ZBX_COND_NODEID,
+ ZBX_SQL_ITEM_SELECT,
+ HOST_STATUS_MONITORED,
+ ITEM_STATUS_ACTIVE,
+ ITEM_TYPE_HTTPTEST,
+ itemid,
+ LOCAL_NODE("h.hostid"));
+ row=DBfetch(result);
+
+ if(!row)
+ {
+ DBfree_result(result);
+ zabbix_log( LOG_LEVEL_DEBUG, "End process_value(result:FAIL)");
+ return FAIL;
+ }
+
+ DBget_item_from_db(&item,row);
+
+ DBbegin();
+ process_new_value(&item,value);
+ update_triggers(item.itemid);
+ DBcommit();
+
+ DBfree_result(result);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End process_value()");
+
+ CHECK_MEMORY("process_value", "end");
+
+ return SUCCEED;
+}
+
+static size_t WRITEFUNCTION2( void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ size_t r_size = size*nmemb;
+
+ /* First piece of data */
+ if(page.data == NULL)
+ {
+ page.allocated=MAX(8096, r_size);
+ page.offset=0;
+ page.data=malloc(page.allocated);
+ }
+
+ zbx_snprintf_alloc(&page.data, &page.allocated, &page.offset, MAX(8096, r_size), "%s", ptr);
+
+ return r_size;
+}
+
+static size_t HEADERFUNCTION2( void *ptr, size_t size, size_t nmemb, void *stream)
+{
+/*
+ ZBX_LIM_PRINT("HEADERFUNCTION", size*nmemb, ptr, 300);
+ zabbix_log(LOG_LEVEL_WARNING, "In HEADERFUNCTION");
+*/
+
+ return size*nmemb;
+}
+
+static void process_test_data(DB_HTTPTEST *httptest, S_ZBX_HTTPSTAT *stat)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ DB_HTTPTESTITEM httptestitem;
+
+ AGENT_RESULT value;
+
+ INIT_CHECK_MEMORY();
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_test_data(test:%s,time:" ZBX_FS_DBL ",last step:%d)",
+ httptest->name,
+ stat->test_total_time,
+ stat->test_last_step);
+
+ result = DBselect("select httptestitemid,httptestid,itemid,type from httptestitem where httptestid=" ZBX_FS_UI64,
+ httptest->httptestid);
+
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(httptestitem.httptestitemid, row[0]);
+ ZBX_STR2UINT64(httptestitem.httptestid, row[1]);
+ ZBX_STR2UINT64(httptestitem.itemid, row[2]);
+ httptestitem.type=atoi(row[3]);
+
+ init_result(&value);
+
+ switch (httptestitem.type) {
+ case ZBX_HTTPITEM_TYPE_TIME:
+ SET_DBL_RESULT(&value, stat->test_total_time);
+ process_value(httptestitem.itemid,&value);
+ break;
+ case ZBX_HTTPITEM_TYPE_LASTSTEP:
+ SET_UI64_RESULT(&value, stat->test_last_step);
+ process_value(httptestitem.itemid,&value);
+ break;
+ default:
+ break;
+ }
+
+ free_result(&value);
+ }
+
+ DBfree_result(result);
+ zabbix_log(LOG_LEVEL_DEBUG, "End process_test_data()");
+
+ CHECK_MEMORY("process_test_data", "end");
+}
+
+
+static void process_step_data(DB_HTTPTEST *httptest, DB_HTTPSTEP *httpstep, S_ZBX_HTTPSTAT *stat)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ DB_HTTPSTEPITEM httpstepitem;
+
+ AGENT_RESULT value;
+
+ INIT_CHECK_MEMORY();
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_step_data(step:%s,url:%s,rsp:%d,time:" ZBX_FS_DBL ",speed:" ZBX_FS_DBL ")",
+ httpstep->name,
+ httpstep->url,
+ stat->rspcode,
+ stat->total_time,
+ stat->speed_download);
+
+ result = DBselect("select httpstepitemid,httpstepid,itemid,type from httpstepitem where httpstepid=" ZBX_FS_UI64,
+ httpstep->httpstepid);
+
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(httpstepitem.httpstepitemid, row[0]);
+ ZBX_STR2UINT64(httpstepitem.httpstepid, row[1]);
+ ZBX_STR2UINT64(httpstepitem.itemid, row[2]);
+ httpstepitem.type=atoi(row[3]);
+
+ init_result(&value);
+
+ switch (httpstepitem.type) {
+ case ZBX_HTTPITEM_TYPE_RSPCODE:
+ SET_UI64_RESULT(&value, stat->rspcode);
+ process_value(httpstepitem.itemid,&value);
+ break;
+ case ZBX_HTTPITEM_TYPE_TIME:
+ SET_DBL_RESULT(&value, stat->total_time);
+ process_value(httpstepitem.itemid,&value);
+ break;
+ case ZBX_HTTPITEM_TYPE_SPEED:
+ SET_DBL_RESULT(&value, stat->speed_download);
+ process_value(httpstepitem.itemid,&value);
+ break;
+ default:
+ break;
+ }
+
+ free_result(&value);
+ }
+
+ DBfree_result(result);
+ zabbix_log(LOG_LEVEL_DEBUG, "End process_step_data()");
+
+ CHECK_MEMORY("process_step_data", "end");
+}
+
+/******************************************************************************
+ * *
+ * Function: process_httptest *
+ * *
+ * Purpose: process single scenario of http test *
+ * *
+ * Parameters: httptestid - ID of http test *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: SUCCEED or FAIL *
+ * *
+ ******************************************************************************/
+static void process_httptest(DB_HTTPTEST *httptest)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ DB_HTTPSTEP httpstep;
+ int err;
+ char *err_str = NULL, *esc_err_str = NULL;
+ int now;
+ int lastfailedstep;
+
+ S_ZBX_HTTPSTAT stat;
+
+ CURL *easyhandle = NULL;
+
+ INIT_CHECK_MEMORY();
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_httptest(httptestid:" ZBX_FS_UI64 ",name:%s)",
+ httptest->httptestid,
+ httptest->name);
+
+ now = time(NULL);
+
+ DBexecute("update httptest set lastcheck=%d where httptestid=" ZBX_FS_UI64,
+ now,
+ httptest->httptestid);
+
+ easyhandle = curl_easy_init();
+ if(easyhandle == NULL)
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot init CURL");
+
+ return;
+ }
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_COOKIEFILE, "")))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_COOKIEFILE [%s]",
+ curl_easy_strerror(err));
+ (void)curl_easy_cleanup(easyhandle);
+ return;
+ }
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, httptest->agent)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_USERAGENT [%s]",
+ curl_easy_strerror(err));
+ (void)curl_easy_cleanup(easyhandle);
+ return;
+ }
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_FOLLOWLOCATION [%s]",
+ curl_easy_strerror(err));
+ (void)curl_easy_cleanup(easyhandle);
+ return;
+ }
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle,CURLOPT_WRITEFUNCTION ,WRITEFUNCTION2)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_WRITEFUNCTION [%s]",
+ curl_easy_strerror(err));
+ (void)curl_easy_cleanup(easyhandle);
+ return;
+ }
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle,CURLOPT_HEADERFUNCTION ,HEADERFUNCTION2)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_WRITEFUNCTION [%s]",
+ curl_easy_strerror(err));
+ (void)curl_easy_cleanup(easyhandle);
+ return;
+ }
+ /* Process self-signed certificates. Do not verify certificate. */
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle,CURLOPT_SSL_VERIFYPEER , 0)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_SSL_VERIFYPEER [%s]",
+ curl_easy_strerror(err));
+ (void)curl_easy_cleanup(easyhandle);
+ return;
+ }
+
+ /* Process certs whose hostnames do not match the queried hostname. */
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle,CURLOPT_SSL_VERIFYHOST , 0)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set CURLOPT_SSL_VERIFYHOST [%s]",
+ curl_easy_strerror(err));
+ (void)curl_easy_cleanup(easyhandle);
+ return;
+ }
+
+ lastfailedstep=0;
+ httptest->time = 0;
+ result = DBselect("select httpstepid,httptestid,no,name,url,timeout,posts,required,status_codes from httpstep where httptestid=" ZBX_FS_UI64 " order by no",
+ httptest->httptestid);
+ now=time(NULL);
+ while((row=DBfetch(result)) && !err_str)
+ {
+ /* NOTE: do not use break or return for this block!
+ * process_step_data calling required!
+ */
+ ZBX_STR2UINT64(httpstep.httpstepid, row[0]);
+ ZBX_STR2UINT64(httpstep.httptestid, row[1]);
+ httpstep.no=atoi(row[2]);
+ httpstep.name=row[3];
+ strscpy(httpstep.url,row[4]);
+ httpstep.timeout=atoi(row[5]);
+ strscpy(httpstep.posts,row[6]);
+ strscpy(httpstep.required,row[7]);
+ strscpy(httpstep.status_codes,row[8]);
+
+ DBexecute("update httptest set curstep=%d,curstate=%d where httptestid=" ZBX_FS_UI64,
+ httpstep.no,
+ HTTPTEST_STATE_BUSY,
+ httptest->httptestid);
+
+ memset(&stat,0,sizeof(stat));
+
+ /* Substitute macros */
+ http_substitute_macros(httptest,httpstep.url, sizeof(httpstep.url));
+
+ http_substitute_macros(httptest,httpstep.posts, sizeof(httpstep.posts));
+ /* zabbix_log(LOG_LEVEL_WARNING, "POSTS [%s]", httpstep.posts); */
+ if(httpstep.posts[0] != 0)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: use post [%s]", httpstep.posts);
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, httpstep.posts)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set POST vars [%s]",
+ curl_easy_strerror(err));
+ err_str = strdup(curl_easy_strerror(err));
+ lastfailedstep = httpstep.no;
+ }
+ }
+ if( !err_str )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: Go to URL [%s]", httpstep.url);
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_URL, httpstep.url)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set URL [%s]",
+ curl_easy_strerror(err));
+ err_str = strdup(curl_easy_strerror(err));
+ lastfailedstep = httpstep.no;
+ }
+ }
+ if( !err_str )
+ {
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_TIMEOUT, httpstep.timeout)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set TIMEOUT [%s]",
+ curl_easy_strerror(err));
+ err_str = strdup(curl_easy_strerror(err));
+ lastfailedstep = httpstep.no;
+ }
+ }
+ if( !err_str )
+ {
+ if(CURLE_OK != (err = curl_easy_setopt(easyhandle, CURLOPT_CONNECTTIMEOUT, httpstep.timeout)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Cannot set CONNECTTIMEOUT [%s]",
+ curl_easy_strerror(err));
+ err_str = strdup(curl_easy_strerror(err));
+ lastfailedstep = httpstep.no;
+ }
+ }
+
+ if( !err_str )
+ {
+ memset(&page, 0, sizeof(page));
+ if(CURLE_OK != (err = curl_easy_perform(easyhandle)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Error doing curl_easy_perform [%s]",
+ curl_easy_strerror(err));
+ err_str = strdup(curl_easy_strerror(err));
+ lastfailedstep = httpstep.no;
+ }
+ else
+ {
+ if(httpstep.required[0]!='\0' && zbx_regexp_match(page.data,httpstep.required,NULL) == NULL)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Page didn't match [%s]", httpstep.required);
+ err_str = strdup("Page didn't match");
+ lastfailedstep = httpstep.no;
+ }
+ }
+ free(page.data);
+
+ if( !err_str )
+ {
+ if(CURLE_OK != (err = curl_easy_getinfo(easyhandle,CURLINFO_RESPONSE_CODE ,&stat.rspcode)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Error getting CURLINFO_RESPONSE_CODE [%s]",
+ curl_easy_strerror(err));
+ err_str = strdup(curl_easy_strerror(err));
+ lastfailedstep = httpstep.no;
+ }
+ else if(httpstep.status_codes[0]!='\0' && (int_in_list(httpstep.status_codes,stat.rspcode) == FAIL))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Status code didn't match [%s]", httpstep.status_codes);
+ err_str = strdup("Status code didn't match");
+ lastfailedstep = httpstep.no;
+ }
+ }
+
+ if( !err_str && CURLE_OK != (err = curl_easy_getinfo(easyhandle,CURLINFO_TOTAL_TIME ,&stat.total_time)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Error getting CURLINFO_TOTAL_TIME [%s]",
+ curl_easy_strerror(err));
+ err_str = strdup(curl_easy_strerror(err));
+ lastfailedstep = httpstep.no;
+ }
+
+ if( !err_str && CURLE_OK != (err = curl_easy_getinfo(easyhandle,CURLINFO_SPEED_DOWNLOAD ,&stat.speed_download)))
+ {
+ zabbix_log(LOG_LEVEL_ERR, "Error getting CURLINFO_SPEED_DOWNLOAD [%s]",
+ curl_easy_strerror(err));
+ err_str = strdup(curl_easy_strerror(err));
+ lastfailedstep = httpstep.no;
+ }
+ }
+
+ httptest->time+=stat.total_time;
+ process_step_data(httptest, &httpstep, &stat);
+ }
+ DBfree_result(result);
+
+ esc_err_str = DBdyn_escape_string(err_str);
+ zbx_free(err_str);
+
+ (void)curl_easy_cleanup(easyhandle);
+
+ DBexecute("update httptest set curstep=0,curstate=%d,lastcheck=%d,nextcheck=%d+delay,lastfailedstep=%d,"
+ "time=" ZBX_FS_DBL ",error='%s' where httptestid=" ZBX_FS_UI64,
+ HTTPTEST_STATE_IDLE,
+ now,
+ now,
+ lastfailedstep,
+ httptest->time,
+ esc_err_str,
+ httptest->httptestid);
+
+ zbx_free(esc_err_str);
+
+ stat.test_total_time = httptest->time;
+ stat.test_last_step = lastfailedstep;
+
+ process_test_data(httptest, &stat);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End process_httptest(total time:" ZBX_FS_DBL ")",
+ httptest->time);
+
+ CHECK_MEMORY("process_httptest", "end");
+}
+
+/******************************************************************************
+ * *
+ * Function: process_httptests *
+ * *
+ * Purpose: process httptests *
+ * *
+ * Parameters: now - current timestamp *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: always SUCCEED *
+ * *
+ ******************************************************************************/
+void process_httptests(int now)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ DB_HTTPTEST httptest;
+
+ INIT_CHECK_MEMORY();
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_httptests()");
+
+ result = DBselect("select httptestid,name,applicationid,nextcheck,status,delay,macros,agent from httptest where status=%d and nextcheck<=%d and " ZBX_SQL_MOD(httptestid,%d) "=%d and " ZBX_COND_NODEID,
+ HTTPTEST_STATUS_MONITORED,
+ now,
+ CONFIG_HTTPPOLLER_FORKS,
+ httppoller_num-1,
+ LOCAL_NODE("httptestid"));
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(httptest.httptestid, row[0]);
+ httptest.name=row[1];
+ ZBX_STR2UINT64(httptest.applicationid, row[2]);
+ httptest.nextcheck=atoi(row[3]);
+ httptest.status=atoi(row[4]);
+ httptest.delay=atoi(row[5]);
+ httptest.macros=row[6];
+ httptest.agent=row[7];
+
+ process_httptest(&httptest);
+ }
+ DBfree_result(result);
+ zabbix_log(LOG_LEVEL_DEBUG, "End process_httptests()");
+
+ CHECK_MEMORY("process_httptests", "end");
+}
+
+#endif /* HAVE_LIBCURL */
diff --git a/src/zabbix_proxy/httppoller/httptest.h b/src/zabbix_proxy/httppoller/httptest.h
new file mode 100644
index 00000000..fef92849
--- /dev/null
+++ b/src/zabbix_proxy/httppoller/httptest.h
@@ -0,0 +1,51 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_HTTPTEST_H
+#define ZABBIX_HTTPTEST_H
+
+#define S_ZBX_HTTPPAGE struct s_zbx_httppage_t
+S_ZBX_HTTPPAGE
+{
+ char *data;
+ int allocated;
+ int offset;
+};
+
+#define S_ZBX_HTTPSTAT struct s_zbx_httpstat_t
+S_ZBX_HTTPSTAT
+{
+ long rspcode;
+ double total_time;
+ double speed_download;
+ double test_total_time;
+ int test_last_step;
+};
+
+#ifdef HAVE_LIBCURL
+ void process_httptests(int now);
+#else
+# define process_httptests(now)
+#endif /* HAVE_LIBCURL */
+
+extern int httppoller_num;
+
+extern int CONFIG_HTTPPOLLER_FORKS;
+
+#endif
diff --git a/src/zabbix_proxy/nodewatcher/Makefile.am b/src/zabbix_proxy/nodewatcher/Makefile.am
new file mode 100644
index 00000000..5d7387a7
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/Makefile.am
@@ -0,0 +1,9 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxnodewatcher.a
+
+libzbxnodewatcher_a_SOURCES = \
+ nodewatcher.c nodewatcher.h \
+ nodesender.c nodesender.h \
+ nodecomms.c nodecomms.h \
+ history.c history.h
diff --git a/src/zabbix_proxy/nodewatcher/history.c b/src/zabbix_proxy/nodewatcher/history.c
new file mode 100644
index 00000000..edcdd69c
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/history.c
@@ -0,0 +1,347 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2006 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "history.h"
+#include "nodewatcher.h"
+#include "nodecomms.h"
+
+/******************************************************************************
+ * *
+ * Function: get_history_lastid: *
+ * *
+ * Purpose: get last history id from master node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int get_history_lastid(int master_nodeid, int nodeid, ZBX_TABLE *table, zbx_uint64_t *lastid)
+{
+ zbx_sock_t sock;
+ char data[MAX_STRING_LEN], *answer;
+ int res = FAIL;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In get_history_lastid()");
+
+ if (SUCCEED == connect_to_node(master_nodeid, &sock)) {
+ zbx_snprintf(data, sizeof(data), "ZBX_GET_HISTORY_LAST_ID%c%d%c%d\n%s%c%s",
+ ZBX_DM_DELIMITER, CONFIG_NODEID,
+ ZBX_DM_DELIMITER, nodeid,
+ table->table, ZBX_DM_DELIMITER, table->recid);
+
+ if (FAIL == send_data_to_node(master_nodeid, &sock, data))
+ goto disconnect;
+
+ if (FAIL == recv_data_from_node(master_nodeid, &sock, &answer))
+ goto disconnect;
+
+ if (0 == strncmp(answer, "FAIL", 4)) {
+ zabbix_log( LOG_LEVEL_ERR, "NODE %d: get_history_lastid() FAIL from node %d for node %d",
+ CONFIG_NODEID,
+ master_nodeid,
+ nodeid);
+ goto disconnect;
+ }
+
+ ZBX_STR2UINT64(*lastid, answer);
+ res = SUCCEED;
+disconnect:
+ disconnect_node(&sock);
+ }
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: get_trends_lastid: *
+ * *
+ * Purpose: get last history lastid and lastclock from master node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int get_trends_lastid(int master_nodeid, int nodeid, ZBX_TABLE *table, zbx_uint64_t *lastid, int *lastclock)
+{
+ zbx_sock_t sock;
+ char data[MAX_STRING_LEN], *answer, *ptr;
+ int res = FAIL;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In get_trends_lastclock()");
+
+ if (SUCCEED == connect_to_node(master_nodeid, &sock)) {
+ zbx_snprintf(data, sizeof(data), "ZBX_GET_TRENDS_LAST_ID%c%d%c%d\n%s",
+ ZBX_DM_DELIMITER, CONFIG_NODEID,
+ ZBX_DM_DELIMITER, nodeid,
+ table->table);
+
+ if (FAIL == send_data_to_node(master_nodeid, &sock, data))
+ goto disconnect;
+
+ if (FAIL == recv_data_from_node(master_nodeid, &sock, &answer))
+ goto disconnect;
+
+ if (0 == strncmp(answer, "FAIL", 4)) {
+ zabbix_log( LOG_LEVEL_ERR, "NODE %d: get_trends_lastid() FAIL from node %d for node %d",
+ CONFIG_NODEID,
+ master_nodeid,
+ nodeid);
+ goto disconnect;
+ }
+
+ if (NULL != (ptr = strchr(answer, ZBX_DM_DELIMITER))) {
+ *ptr++ = '\0';
+
+ ZBX_STR2UINT64(*lastid, answer);
+ *lastclock = atoi(ptr);
+
+ res = SUCCEED;
+ }
+disconnect:
+ disconnect_node(&sock);
+ }
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function : process_hstory_table_data: *
+ * *
+ * Purpose: process new history data *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void process_history_table_data(ZBX_TABLE *table, int master_nodeid, int nodeid)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ char *data = NULL, *tmp = NULL;
+ int data_allocated = 1024*1024, tmp_allocated = 4096, tmp_offset, data_offset, f, fld, len;
+ int data_found = 0;
+ zbx_uint64_t lastid;
+ int lastclock = 0, clock;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In process_history_table_data()");
+
+ DBbegin();
+
+ if ((table->flags & ZBX_HISTORY) && FAIL == get_history_lastid(master_nodeid, nodeid, table, &lastid))
+ return;
+ if ((table->flags & ZBX_HISTORY_TRENDS) && FAIL == get_trends_lastid(master_nodeid, nodeid, table, &lastid, &lastclock))
+ return;
+
+ data = zbx_malloc(data, data_allocated);
+ tmp = zbx_malloc(tmp, tmp_allocated);
+
+ data_offset = 0;
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "History%c%d%c%d%c%s",
+ ZBX_DM_DELIMITER, CONFIG_NODEID,
+ ZBX_DM_DELIMITER, nodeid,
+ ZBX_DM_DELIMITER, table->table);
+
+ /* Do not send history for current node if CONFIG_NODE_NOHISTORY is set */
+/* if ((CONFIG_NODE_NOHISTORY != 0) && (CONFIG_NODEID == nodeid))
+ goto exit;*/
+
+ tmp_offset = 0;
+ if (table->flags & ZBX_HISTORY_SYNC) {
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "select %s,",
+ table->recid);
+ } else { /* ZBX_HISTORY, ZBX_HISTORY_TRENDS */
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 16, "select ");
+ }
+
+ for (f = 0; table->fields[f].name != 0; f++) {
+ if ((table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC))
+ continue;
+
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "%s,",
+ table->fields[f].name);
+ }
+ tmp_offset--;
+
+ if (table->flags & ZBX_HISTORY_SYNC) {
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where nodeid=%d order by %s",
+ table->table,
+ nodeid,
+ table->recid);
+ } else if (table->flags & ZBX_HISTORY_TRENDS) {
+ clock = time(NULL) - 600; /* -10min */
+ clock -= clock % 3600;
+
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where"
+ " (itemid>"ZBX_FS_UI64" or (itemid="ZBX_FS_UI64" and clock>%d)) and clock<%d"
+ " and"ZBX_COND_NODEID"order by itemid,clock",
+ table->table,
+ lastid, lastid, lastclock, clock,
+ ZBX_NODE("itemid", nodeid));
+ } else { /* ZBX_HISTORY */
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 1024, " from %s where %s>"ZBX_FS_UI64
+ " and"ZBX_COND_NODEID"order by %2$s",
+ table->table,
+ table->recid,
+ lastid,
+ ZBX_NODE(table->recid, nodeid));
+ }
+
+ result = DBselectN(tmp, 10000);
+ while (NULL != (row = DBfetch(result))) {
+ if (table->flags & ZBX_HISTORY_SYNC) {
+ ZBX_STR2UINT64(lastid, row[0]);
+ fld = 1;
+ } else
+ fld = 0;
+
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n");
+
+ for (f = 0; table->fields[f].name != 0; f++) {
+ if ((table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC))
+ continue;
+
+ if (table->fields[f].type == ZBX_TYPE_INT ||
+ table->fields[f].type == ZBX_TYPE_UINT ||
+ table->fields[f].type == ZBX_TYPE_ID ||
+ table->fields[f].type == ZBX_TYPE_FLOAT)
+ {
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s%c",
+ row[fld], ZBX_DM_DELIMITER);
+ } else { /* ZBX_TYPE_CHAR ZBX_TYPE_BLOB ZBX_TYPE_TEXT */
+ len = (int)strlen(row[fld]);
+ len = zbx_binary2hex((u_char *)row[fld], len, &tmp, &tmp_allocated);
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, len + 8, "%s%c",
+ tmp, ZBX_DM_DELIMITER);
+ }
+ fld++;
+ }
+ data_offset--;
+ data_found = 1;
+ }
+ DBfree_result(result);
+
+ data[data_offset] = '\0';
+
+ if (1 == data_found && SUCCEED == send_to_node(table->table, master_nodeid, nodeid, data)) {
+ if (table->flags & ZBX_HISTORY_SYNC) {
+ DBexecute("delete from %s where nodeid=%d and %s<="ZBX_FS_UI64,
+ table->table,
+ nodeid,
+ table->recid,
+ lastid);
+ }
+ }
+
+ DBcommit();
+
+ zbx_free(tmp);
+ zbx_free(data);
+}
+
+/******************************************************************************
+ * *
+ * Function: process_history_tables *
+ * *
+ * Purpose: process new history data from tables with ZBX_HISTORY* flags *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static void process_history_tables(int master_nodeid, int nodeid)
+{
+ int t;
+ int start = time(NULL);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_history_tables()");
+
+ for (t = 0; tables[t].table != 0; t++) {
+ if (tables[t].flags & (ZBX_HISTORY | ZBX_HISTORY_SYNC | ZBX_HISTORY_TRENDS))
+ process_history_table_data(&tables[t], master_nodeid, nodeid);
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "NODE %d: Spent %d seconds for node %d in process_history_tables",
+ CONFIG_NODEID,
+ time(NULL) - start,
+ nodeid);
+}
+/******************************************************************************
+ * *
+ * Function: main_historysender *
+ * *
+ * Purpose: periodically sends historical data to master node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void main_historysender()
+{
+ DB_RESULT result;
+ DB_ROW row;
+ int master_nodeid, nodeid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In main_historysender()");
+
+ master_nodeid = CONFIG_MASTER_NODEID;
+ if (0 == master_nodeid)
+ return;
+
+ result = DBselect("select nodeid from nodes");
+ while ((row = DBfetch(result))) {
+ nodeid = atoi(row[0]);
+ if (SUCCEED == is_master_node(CONFIG_NODEID, nodeid))
+ continue;
+
+ process_history_tables(master_nodeid, nodeid);
+ }
+ DBfree_result(result);
+}
diff --git a/src/zabbix_proxy/nodewatcher/history.h b/src/zabbix_proxy/nodewatcher/history.h
new file mode 100644
index 00000000..cf064cc3
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/history.h
@@ -0,0 +1,25 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_NODEWATCHER_HISTORY_H
+#define ZABBIX_NODEWATCHER_HISTORY_H
+
+void main_historysender();
+
+#endif
diff --git a/src/zabbix_proxy/nodewatcher/nodecomms.c b/src/zabbix_proxy/nodewatcher/nodecomms.c
new file mode 100644
index 00000000..7f87befc
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/nodecomms.c
@@ -0,0 +1,153 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2006 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "comms.h"
+#include "nodecomms.h"
+
+int connect_to_node(int nodeid, zbx_sock_t *sock)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ unsigned short port;
+ int res = FAIL;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In connect_to_node(nodeid:%d)", nodeid);
+
+ result = DBselect("select ip,port from nodes where nodeid=%d",
+ nodeid);
+
+ if (NULL != (row = DBfetch(result))) {
+ port = (unsigned short)atoi(row[1]);
+
+ if (SUCCEED == zbx_tcp_connect(sock, row[0], port, 0))
+ res = SUCCEED;
+ else
+ zabbix_log(LOG_LEVEL_ERR, "NODE %d: Unable to connect to Node [%d] error: %s",
+ CONFIG_NODEID,
+ nodeid,
+ zbx_tcp_strerror());
+ } else
+ zabbix_log(LOG_LEVEL_ERR, "NODE %d: Node [%d] is unknown",
+ CONFIG_NODEID,
+ nodeid);
+ DBfree_result(result);
+
+ return res;
+}
+
+int send_data_to_node(int nodeid, zbx_sock_t *sock, const char *data)
+{
+ int res;
+
+ if (FAIL == (res = zbx_tcp_send_ext(sock, data, ZBX_TCP_NEW_PROTOCOL))) {
+ zabbix_log(LOG_LEVEL_ERR, "NODE %d: Error while sending data to Node [%d] error: %s",
+ CONFIG_NODEID,
+ nodeid,
+ zbx_tcp_strerror());
+ } else
+ zabbix_log(LOG_LEVEL_DEBUG, "NODE %d: Sending [%s] to Node [%d]",
+ CONFIG_NODEID,
+ data,
+ nodeid);
+
+ return res;
+}
+
+int recv_data_from_node(int nodeid, zbx_sock_t *sock, char **data)
+{
+ int res;
+
+ if (FAIL == (res = zbx_tcp_recv_ext(sock, data, 0))) {
+ zabbix_log(LOG_LEVEL_ERR, "NODE %d: Error while receiving answer from Node [%d] error: %s",
+ CONFIG_NODEID,
+ nodeid,
+ zbx_tcp_strerror());
+ } else
+ zabbix_log(LOG_LEVEL_DEBUG, "NODE %d: Receiving [%s] from Node [%d]",
+ CONFIG_NODEID,
+ *data,
+ nodeid);
+
+ return res;
+}
+
+void disconnect_node(zbx_sock_t *sock)
+{
+ zbx_tcp_close(sock);
+}
+
+/******************************************************************************
+ * *
+ * Function: send_to_node *
+ * *
+ * Purpose: send configuration changes to required node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCESS - processed succesfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int send_to_node(const char *name, int dest_nodeid, int nodeid, char *data)
+{
+ int ret = FAIL;
+ zbx_sock_t sock;
+ char *answer;
+
+ zabbix_log( LOG_LEVEL_WARNING, "NODE %d: Sending %s of node %d to node %d datalen %zd",
+ CONFIG_NODEID,
+ name,
+ nodeid,
+ dest_nodeid,
+ strlen(data));
+
+ if (FAIL == connect_to_node(dest_nodeid, &sock))
+ return FAIL;
+
+ if (FAIL == send_data_to_node(dest_nodeid, &sock, data))
+ goto disconnect;
+
+ if (FAIL == recv_data_from_node(dest_nodeid, &sock, &answer))
+ goto disconnect;
+
+ if (0 == strcmp(answer, "OK"))
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "OK");
+ ret = SUCCEED;
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "NOT OK");
+ }
+disconnect:
+ disconnect_node(&sock);
+
+ return ret;
+}
diff --git a/src/zabbix_proxy/nodewatcher/nodecomms.h b/src/zabbix_proxy/nodewatcher/nodecomms.h
new file mode 100644
index 00000000..88303cf1
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/nodecomms.h
@@ -0,0 +1,32 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_NODECOMMS_H
+#define ZABBIX_NODECOMMS_H
+
+#include "comms.h"
+
+int connect_to_node(int nodeid, zbx_sock_t *sock);
+int send_data_to_node(int nodeid, zbx_sock_t *sock, const char *data);
+int recv_data_from_node(int nodeid, zbx_sock_t *sock, char **data);
+void disconnect_node(zbx_sock_t *sock);
+
+int send_to_node(const char *name, int dest_nodeid, int nodeid, char *data);
+
+#endif
diff --git a/src/zabbix_proxy/nodewatcher/nodesender.c b/src/zabbix_proxy/nodewatcher/nodesender.c
new file mode 100644
index 00000000..0e49e60b
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/nodesender.c
@@ -0,0 +1,673 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2006 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "nodesender.h"
+#include "nodewatcher.h"
+#include "nodecomms.h"
+#include "../trapper/nodesync.h"
+
+
+/******************************************************************************
+ * *
+ * Function: calculate_checksums *
+ * *
+ * Purpose: calculate check sums of configuration data *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCESS - calculated succesfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int calculate_checksums(int nodeid, const char *tablename, const zbx_uint64_t id)
+{
+ char *sql = NULL;
+ int sql_allocated = 16*1024, sql_offset = 0;
+ int t, f, res = SUCCEED;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In calculate_checksums");
+
+ sql = zbx_malloc(sql, sql_allocated);
+
+ for (t = 0; tables[t].table != 0; t++) {
+ /* Do not sync some of tables */
+ if ((tables[t].flags & ZBX_SYNC) == 0)
+ continue;
+
+ if (NULL != tablename && 0 != strcmp(tablename, tables[t].table))
+ continue;
+
+#ifdef HAVE_MYSQL
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 512,
+ "%s select %d,'%s',%s,%d,concat_ws(',',",
+ sql_offset > 0 ? "union all" : "insert into node_cksum (nodeid,tablename,recordid,cksumtype,cksum)",
+ nodeid,
+ tables[t].table,
+ tables[t].recid,
+ NODE_CKSUM_TYPE_NEW);
+#else
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 512,
+ "%s select %d,'%s',%s,%d,",
+ sql_offset > 0 ? "union all" : "insert into node_cksum (nodeid,tablename,recordid,cksumtype,cksum)",
+ nodeid,
+ tables[t].table,
+ tables[t].recid,
+ NODE_CKSUM_TYPE_NEW);
+#endif
+
+ for (f = 0; tables[t].fields[f].name != 0; f ++) {
+ if ((tables[t].fields[f].flags & ZBX_SYNC) == 0)
+ continue;
+
+ if (tables[t].fields[f].flags & ZBX_NOTNULL) {
+ switch ( tables[t].fields[f].type ) {
+ case ZBX_TYPE_ID :
+ case ZBX_TYPE_INT :
+ case ZBX_TYPE_UINT :
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128,
+ "%s",
+ tables[t].fields[f].name);
+ break;
+ default :
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128,
+ "md5(%s)",
+ tables[t].fields[f].name);
+ break;
+ }
+ } else {
+ switch ( tables[t].fields[f].type ) {
+ case ZBX_TYPE_ID :
+ case ZBX_TYPE_INT :
+ case ZBX_TYPE_UINT :
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128,
+ "case when %s is null then 'NULL' else %1$s end",
+ tables[t].fields[f].name);
+ break;
+ default :
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128,
+ "case when %s is null then 'NULL' else md5(%1$s) end",
+ tables[t].fields[f].name);
+ break;
+ }
+ }
+#ifdef HAVE_MYSQL
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 16,
+ ","
+ );
+#else
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 16,
+ "||','||"
+ );
+#endif
+ }
+
+ /* remove last delimiter */
+ if (f > 0) {
+#ifdef HAVE_MYSQL
+ sql_offset --;
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 16, ")");
+#else
+ sql_offset -= 7;
+#endif
+ }
+
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 512,
+ " from %s where"ZBX_COND_NODEID,
+ tables[t].table,
+ ZBX_NODE(tables[t].recid,nodeid));
+
+ if (0 != id) {
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128,
+ "and %s="ZBX_FS_UI64,
+ tables[t].recid,
+ id);
+ }
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "\n");
+ }
+ if (SUCCEED == res && DBexecute("delete from node_cksum where nodeid=%d and cksumtype=%d",
+ nodeid,
+ NODE_CKSUM_TYPE_NEW) < ZBX_DB_OK)
+ res = FAIL;
+ if (SUCCEED == res && DBexecute("%s", sql) < ZBX_DB_OK)
+ res = FAIL;
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: send_config_data *
+ * *
+ * Purpose: send configuration changes to required node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCESS - processed succesfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+char *get_config_data(int nodeid, int dest_nodetype)
+{
+ DB_RESULT result;
+ DB_RESULT result2;
+ DB_ROW row;
+ DB_ROW row2;
+
+ char *data = NULL, *hex = NULL, *sql = NULL, c, sync[129], *s, *r[2], *d[2];
+ int data_offset=0, sql_offset = 0;
+ int data_allocated=1024, hex_allocated=1024, sql_allocated=8*1024;
+ int t, f, j, rowlen;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_config_data(node:%d,dest_nodetype:%s)",
+ nodeid,
+ dest_nodetype == ZBX_NODE_MASTER ? "MASTER" : "SLAVE");
+
+ data = zbx_malloc(data, data_allocated);
+ hex = zbx_malloc(hex, hex_allocated);
+ sql = zbx_malloc(sql, sql_allocated);
+ c = '1';
+
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "Data%c%d%c%d\n",
+ ZBX_DM_DELIMITER,
+ CONFIG_NODEID,
+ ZBX_DM_DELIMITER,
+ nodeid);
+
+ /* Find updated records */
+ result = DBselect("select curr.tablename,curr.recordid,prev.cksum,curr.cksum,prev.sync "
+ "from node_cksum curr, node_cksum prev "
+ "where curr.nodeid=%1$d and prev.nodeid=%1$d and "
+ "curr.tablename=prev.tablename and curr.recordid=prev.recordid and "
+ "curr.cksumtype=%3$d and prev.cksumtype=%2$d "
+ /*" and curr.tablename='hosts' "*/
+ "union all "
+ /* Find new records */
+ "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,curr.sync "
+ "from node_cksum curr left join node_cksum prev "
+ "on prev.nodeid=%1$d and prev.tablename=curr.tablename and "
+ "prev.recordid=curr.recordid and prev.cksumtype=%2$d "
+ "where curr.nodeid=%1$d and curr.cksumtype=%3$d and prev.tablename is null "
+ /*" and curr.tablename='hosts' "*/
+ "union all "
+ /* Find deleted records */
+ "select prev.tablename,prev.recordid,prev.cksum,curr.cksum,prev.sync "
+ "from node_cksum prev left join node_cksum curr "
+ "on prev.nodeid=curr.nodeid and curr.nodeid=%1$d and curr.tablename=prev.tablename and "
+ "curr.recordid=prev.recordid and curr.cksumtype=%3$d "
+ "where prev.nodeid=%1$d and prev.cksumtype=%2$d and curr.tablename is null"
+ /*" and prev.tablename='hosts' "*/,
+ nodeid,
+ NODE_CKSUM_TYPE_OLD, /* prev */
+ NODE_CKSUM_TYPE_NEW); /* curr */
+
+ while (NULL != (row = DBfetch(result))) {
+ for (t = 0; tables[t].table != 0 && strcmp(tables[t].table, row[0]) != 0; t++)
+ ;
+
+ /* Found table */
+ if (tables[t].table == 0) {
+ zabbix_log( LOG_LEVEL_WARNING, "Cannot find table [%s]",
+ row[0]);
+ continue;
+ }
+
+ if (DBis_null(row[4]) == FAIL)
+ strcpy(sync, row[4]);
+ else
+ memset(sync, ' ', sizeof(sync));
+ s = sync;
+
+ /* Special (simpler) processing for operation DELETE */
+ if (DBis_null(row[2]) == FAIL && DBis_null(row[3]) == SUCCEED &&
+ ((dest_nodetype == ZBX_NODE_SLAVE && *s != c) ||
+ (dest_nodetype == ZBX_NODE_MASTER && *(s+1) != c))) {
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s%c%s%c%d\n",
+ row[0],
+ ZBX_DM_DELIMITER,
+ row[1],
+ ZBX_DM_DELIMITER,
+ NODE_CONFIGLOG_OP_DELETE);
+ continue;
+ }
+
+ r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2];
+ r[1] = DBis_null(row[3]) == SUCCEED ? NULL : row[3];
+ f = 0;
+ sql_offset = 0;
+
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "select ");
+ do {
+ while ((tables[t].fields[f].flags & ZBX_SYNC) == 0)
+ f++;
+
+ d[0] = NULL;
+ d[1] = NULL;
+ if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ',')))
+ *d[0] = '\0';
+ if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ',')))
+ *d[1] = '\0';
+
+ if (r[0] == NULL || r[1] == NULL || (dest_nodetype == ZBX_NODE_SLAVE && *s != c) ||
+ (dest_nodetype == ZBX_NODE_MASTER && *(s+1) != c) || strcmp(r[0], r[1]) != 0) {
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "%s,length(%1$s),",
+ tables[t].fields[f].name);
+ }
+ s += 2;
+ f++;
+
+ if (d[0] != NULL) {
+ *d[0] = ',';
+ r[0] = d[0] + 1;
+ } else
+ r[0] = NULL;
+ if (d[1] != NULL) {
+ *d[1] = ',';
+ r[1] = d[1] + 1;
+ } else
+ r[1] = NULL;
+ } while (d[0] != NULL || d[1] != NULL);
+
+ if (sql[sql_offset-1] != ',')
+ continue;
+
+ sql_offset--;
+ zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, " from %s where %s=%s",
+ row[0],
+ tables[t].recid,
+ row[1]);
+
+ result2 = DBselect("%s", sql);
+ if (NULL == (row2=DBfetch(result2)))
+ goto out;
+
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s%c%s%c%d",
+ row[0],
+ ZBX_DM_DELIMITER,
+ row[1],
+ ZBX_DM_DELIMITER,
+ NODE_CONFIGLOG_OP_UPDATE);
+
+ r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2];
+ r[1] = DBis_null(row[3]) == SUCCEED ? NULL : row[3];
+ s = sync;
+ f = 0;
+ j = 0;
+
+ do {
+ while ((tables[t].fields[f].flags & ZBX_SYNC) == 0)
+ f++;
+
+ d[0] = NULL;
+ d[1] = NULL;
+ if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ',')))
+ *d[0] = '\0';
+ if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ',')))
+ *d[1] = '\0';
+
+ if (r[0] == NULL || r[1] == NULL || (dest_nodetype == ZBX_NODE_SLAVE && *s != c) ||
+ (dest_nodetype == ZBX_NODE_MASTER && *(s+1) != c) || strcmp(r[0], r[1]) != 0) {
+
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%c%s%c%d%c",
+ ZBX_DM_DELIMITER,
+ tables[t].fields[f].name,
+ ZBX_DM_DELIMITER,
+ tables[t].fields[f].type,
+ ZBX_DM_DELIMITER);
+
+ /* Fieldname, type, value */
+ if (DBis_null(row2[j*2]) == SUCCEED) {
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "NULL");
+ } else if(tables[t].fields[f].type == ZBX_TYPE_INT ||
+ tables[t].fields[f].type == ZBX_TYPE_UINT ||
+ tables[t].fields[f].type == ZBX_TYPE_ID ||
+ tables[t].fields[f].type == ZBX_TYPE_FLOAT) {
+
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s", row2[j*2]);
+ } else {
+ rowlen = atoi(row2[j*2+1]);
+ zbx_binary2hex((u_char *)row2[j*2], rowlen, &hex, &hex_allocated);
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, strlen(hex)+128, "%s", hex);
+/*zabbix_log(LOG_LEVEL_CRIT, "----- [field:%s][type:%d][row:%s][hex:%s]",tables[t].fields[f].name,tables[t].fields[f].type,row2[j*2],hex);*/
+ }
+ j++;
+ }
+ s += 2;
+ f++;
+
+ if (d[0] != NULL) {
+ *d[0] = ',';
+ r[0] = d[0] + 1;
+ } else
+ r[0] = NULL;
+ if (d[1] != NULL) {
+ *d[1] = ',';
+ r[1] = d[1] + 1;
+ } else
+ r[1] = NULL;
+ } while (d[0] != NULL || d[1] != NULL);
+ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n");
+out:
+ DBfree_result(result2);
+ }
+ DBfree_result(result);
+
+ zbx_free(hex);
+ zbx_free(sql);
+
+ return data;
+}
+
+/******************************************************************************
+ * *
+ * Function: update_checksums *
+ * *
+ * Purpose: overwrite old checksums with new ones *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCESS - calculated succesfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int update_checksums(int nodeid, int synked_nodetype, int synked, const char *tablename, const zbx_uint64_t id, char *fields)
+{
+ char *r[2], *d[2], sync[129], *s;
+ char c, sql[2][256];
+ char cksum[32*64+32], *ck;
+ DB_RESULT result;
+ DB_ROW row;
+ int t, f;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In update_checksums");
+
+ c = synked == SUCCEED ? '1' : ' ';
+
+ if (NULL != tablename) {
+ zbx_snprintf(sql[0], sizeof(sql[0]), " and curr.tablename='%s' and curr.recordid="ZBX_FS_UI64,
+ tablename, id);
+ zbx_snprintf(sql[1], sizeof(sql[1]), " and prev.tablename='%s' and prev.recordid="ZBX_FS_UI64,
+ tablename, id);
+ } else {
+ *sql[0] = '\0';
+ *sql[1] = '\0';
+ }
+
+ /* Find updated records */
+ result = DBselect("select curr.tablename,curr.recordid,prev.cksum,curr.cksum,prev.sync "
+ "from node_cksum curr, node_cksum prev "
+ "where curr.nodeid=%1$d and prev.nodeid=%1$d and "
+ "curr.tablename=prev.tablename and curr.recordid=prev.recordid and "
+ "curr.cksumtype=%3$d and prev.cksumtype=%2$d%4$s "
+ "union all "
+ /* Find new records */
+ "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,NULL "
+ "from node_cksum curr left join node_cksum prev "
+ "on prev.nodeid=%1$d and prev.tablename=curr.tablename and "
+ "prev.recordid=curr.recordid and prev.cksumtype=%2$d "
+ "where curr.nodeid=%1$d and curr.cksumtype=%3$d and prev.tablename is null%4$s "
+ "union all "
+ /* Find deleted records */
+ "select prev.tablename,prev.recordid,prev.cksum,curr.cksum,prev.sync "
+ "from node_cksum prev left join node_cksum curr "
+ "on prev.nodeid=curr.nodeid and curr.nodeid=%1$d and curr.tablename=prev.tablename and "
+ "curr.recordid=prev.recordid and curr.cksumtype=%3$d "
+ "where prev.nodeid=%1$d and prev.cksumtype=%2$d and curr.tablename is null%5$s",
+ nodeid,
+ NODE_CKSUM_TYPE_OLD, /* prev */
+ NODE_CKSUM_TYPE_NEW, /* curr */
+ sql[0],
+ sql[1]);
+
+ while (NULL != (row = DBfetch(result))) {
+ for (t = 0; tables[t].table != 0 && strcmp(tables[t].table, row[0]) != 0; t++)
+ ;
+
+ /* Found table */
+ if (tables[t].table == 0) {
+ zabbix_log(LOG_LEVEL_WARNING, "Cannot find table [%s]",
+ row[0]);
+ continue;
+ }
+
+ if (DBis_null(row[4]) == FAIL)
+ strcpy(sync, row[4]);
+ else
+ memset(sync, ' ', sizeof(sync));
+ s = sync;
+ ck = cksum;
+ *ck = '\0';
+
+ /* Special (simpler) processing for operation DELETE */
+ if (DBis_null(row[3]) == SUCCEED) {
+ if (*(s+2) != '\0') {
+ *s = ' ';
+ *(s+1) = ' ';
+ }
+ if (synked == SUCCEED) {
+ if (synked_nodetype == ZBX_NODE_SLAVE)
+ *s = c;
+ else if (synked_nodetype == ZBX_NODE_MASTER)
+ *(s+1) = c;
+ }
+ s += 2;
+ } else {
+ r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2];
+ r[1] = DBis_null(row[3]) == SUCCEED ? NULL : row[3];
+ f = 0;
+
+ do {
+ while ((tables[t].fields[f].flags & ZBX_SYNC) == 0)
+ f++;
+
+ d[0] = NULL;
+ d[1] = NULL;
+ if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ',')))
+ *d[0] = '\0';
+ if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ',')))
+ *d[1] = '\0';
+
+ if (NULL == tablename || SUCCEED == str_in_list(fields, tables[t].fields[f].name, ',')) {
+ ck += zbx_snprintf(ck, 64, "%s,", NULL != r[1] ? r[1] : r[0]);
+
+ if (r[0] == NULL || r[1] == NULL || strcmp(r[0], r[1]) != 0) {
+ if (synked_nodetype == ZBX_NODE_SLAVE) {
+ *s = c;
+ *(s+1) = ' ';
+ } else if (synked_nodetype == ZBX_NODE_MASTER) {
+ *s = ' ';
+ *(s+1) = c;
+ }
+ } else {
+ if (synked == SUCCEED) {
+ if (synked_nodetype == ZBX_NODE_SLAVE)
+ *s = c;
+ else if (synked_nodetype == ZBX_NODE_MASTER)
+ *(s+1) = c;
+ }
+ }
+ } else
+ ck += zbx_snprintf(ck, 64, "%s,", NULL != r[0] ? r[0] : "");
+ s += 2;
+ f++;
+
+ if (d[0] != NULL) {
+ *d[0] = ',';
+ r[0] = d[0] + 1;
+ } else
+ r[0] = NULL;
+ if (d[1] != NULL) {
+ *d[1] = ',';
+ r[1] = d[1] + 1;
+ } else
+ r[1] = NULL;
+ } while (d[0] != NULL || d[1] != NULL);
+ }
+ *s = '\0';
+ *--ck = '\0';
+
+ if (DBis_null(row[2]) == SUCCEED || DBis_null(row[3]) == SUCCEED ||
+ strcmp(row[4], sync) != 0 || strcmp(row[2], row[3]) != 0)
+ {
+ DBexecute("update node_cksum set cksumtype=%d,cksum=\'%s\',sync=\'%s\' "
+ "where nodeid=%d and tablename=\'%s\' and recordid=%s and cksumtype=%d",
+ NODE_CKSUM_TYPE_OLD,
+ cksum,
+ sync,
+ nodeid,
+ row[0],
+ row[1],
+ DBis_null(row[2]) == SUCCEED ? NODE_CKSUM_TYPE_NEW : NODE_CKSUM_TYPE_OLD);
+ }
+ }
+ DBfree_result(result);
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: node_sync_lock *
+ * *
+ * Purpose: *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void node_sync_lock(int nodeid)
+{
+ zbx_mutex_lock(&node_sync_access);
+}
+
+/******************************************************************************
+ * *
+ * Function: node_sync_unlock *
+ * *
+ * Purpose: *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void node_sync_unlock(int nodeid)
+{
+ zbx_mutex_unlock(&node_sync_access);
+}
+
+/******************************************************************************
+ * *
+ * Function: process_nodes *
+ * *
+ * Purpose: calculates checks sum of config data *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: never returns *
+ * *
+ ******************************************************************************/
+void process_nodes()
+{
+ DB_RESULT result;
+ DB_ROW row;
+ int nodeid;
+ int master_nodeid;
+ char *data, *answer;
+ zbx_sock_t sock;
+ int res;
+/* int now = time(NULL);*/
+ int sender_nodeid;
+
+ master_nodeid = CONFIG_MASTER_NODEID;
+ if (0 == master_nodeid)
+ return;
+
+ result = DBselect("select nodeid from nodes");
+ while (NULL != (row=DBfetch(result))) {
+ nodeid = atoi(row[0]);
+ if (SUCCEED == is_master_node(CONFIG_NODEID, nodeid))
+ continue;
+
+ node_sync_lock(nodeid);
+
+/* DBbegin();*/
+
+ res = calculate_checksums(nodeid, NULL, 0);
+ if (SUCCEED == res && NULL != (data = get_config_data(nodeid, ZBX_NODE_MASTER))) {
+ zabbix_log( LOG_LEVEL_WARNING, "NODE %d: Sending configuration changes to master node %d for node %d datalen %d",
+ CONFIG_NODEID,
+ master_nodeid,
+ nodeid,
+ strlen(data));
+ if (SUCCEED == (res = connect_to_node(master_nodeid, &sock))) {
+ if (SUCCEED == res)
+ res = send_data_to_node(master_nodeid, &sock, data);
+ if (SUCCEED == res)
+ res = recv_data_from_node(master_nodeid, &sock, &answer);
+ if (SUCCEED == res && 0 == strncmp(answer, "Data", 4)) {
+ res = update_checksums(nodeid, ZBX_NODE_MASTER, SUCCEED, NULL, 0, NULL);
+ if (SUCCEED == res)
+ res = node_sync(answer, &sender_nodeid, &nodeid);
+ send_data_to_node(master_nodeid, &sock, SUCCEED == res ? "OK" : "FAIL");
+ }
+ disconnect_node(&sock);
+ }
+ zbx_free(data);
+ }
+
+/* DBcommit();*/
+
+ node_sync_unlock(nodeid);
+ }
+ DBfree_result(result);
+
+/* zabbix_log(LOG_LEVEL_CRIT, "<-----> process_nodes [Selected records in %d seconds]", time(NULL)-now);*/
+}
diff --git a/src/zabbix_proxy/nodewatcher/nodesender.h b/src/zabbix_proxy/nodewatcher/nodesender.h
new file mode 100644
index 00000000..7f64e5da
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/nodesender.h
@@ -0,0 +1,37 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_NODESENDER_H
+#define ZABBIX_NODESENDER_H
+
+#include "mutexs.h"
+
+#define ZBX_NODE_MASTER 0
+#define ZBX_NODE_SLAVE 1
+
+extern ZBX_MUTEX node_sync_access;
+
+int calculate_checksums(int nodeid, const char *tablename, const zbx_uint64_t id);
+char *get_config_data(int nodeid, int dest_nodetype);
+int update_checksums(int nodeid, int synked_nodetype, int synked, const char *tablename, const zbx_uint64_t id, char *fields);
+void node_sync_lock(int nodeid);
+void node_sync_unlock(int nodeid);
+void process_nodes();
+
+#endif
diff --git a/src/zabbix_proxy/nodewatcher/nodewatcher.c b/src/zabbix_proxy/nodewatcher/nodewatcher.c
new file mode 100644
index 00000000..951bc871
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/nodewatcher.c
@@ -0,0 +1,120 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2006 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+#include "cfg.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "nodewatcher.h"
+#include "nodesender.h"
+#include "history.h"
+
+/******************************************************************************
+ * *
+ * Function: is_master_node *
+ * *
+ * Purpose: *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - nodeid is master node *
+ * FAIL - nodeid is slave node *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int is_master_node(int current_nodeid, int nodeid)
+{
+ DB_RESULT dbresult;
+ DB_ROW dbrow;
+ int res = FAIL;
+
+ dbresult = DBselect("select masterid from nodes where nodeid=%d",
+ current_nodeid);
+
+ if (NULL != (dbrow = DBfetch(dbresult))) {
+ current_nodeid = atoi(dbrow[0]);
+ if (current_nodeid == nodeid)
+ res = SUCCEED;
+ else if (0 != current_nodeid)
+ res = is_master_node(current_nodeid, nodeid);
+ }
+ DBfree_result(dbresult);
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: main_nodewatcher_loop *
+ * *
+ * Purpose: periodically calculates checks sum of config data *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: never returns *
+ * *
+ ******************************************************************************/
+int main_nodewatcher_loop()
+{
+ int start, end;
+ int lastrun = 0;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In main_nodeupdater_loop()");
+ for(;;)
+ {
+ start = time(NULL);
+
+ zbx_setproctitle("connecting to the database");
+ zabbix_log( LOG_LEVEL_DEBUG, "Starting sync with nodes");
+
+ DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+ if(lastrun + 120 < start)
+ {
+ process_nodes();
+
+ lastrun = start;
+ }
+
+ /* Send new history data to master node */
+ main_historysender();
+
+ DBclose();
+
+ end = time(NULL);
+
+ if(end-start<10)
+ {
+ zbx_setproctitle("sender [sleeping for %d seconds]",
+ 10-(end-start));
+ zabbix_log( LOG_LEVEL_DEBUG, "Sleeping %d seconds",
+ 10-(end-start));
+ sleep(10-(end-start));
+ }
+ }
+}
diff --git a/src/zabbix_proxy/nodewatcher/nodewatcher.h b/src/zabbix_proxy/nodewatcher/nodewatcher.h
new file mode 100644
index 00000000..60285d0f
--- /dev/null
+++ b/src/zabbix_proxy/nodewatcher/nodewatcher.h
@@ -0,0 +1,26 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_NODEWATCHER_H
+#define ZABBIX_NODEWATCHER_H
+
+int main_nodewatcher_loop();
+int is_master_node(int current_nodeid, int nodeid);
+
+#endif
diff --git a/src/zabbix_proxy/operations.c b/src/zabbix_proxy/operations.c
new file mode 100644
index 00000000..e2f11a78
--- /dev/null
+++ b/src/zabbix_proxy/operations.c
@@ -0,0 +1,833 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <signal.h>
+
+#include <string.h>
+
+#include <time.h>
+
+#include "common.h"
+#include "comms.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "poller/poller.h"
+#include "poller/checks_agent.h"
+
+/******************************************************************************
+ * *
+ * Function: send_to_user_medias *
+ * *
+ * Purpose: send notifications to user's medias (email, sms, whatever) *
+ * *
+ * Parameters: trigger - trigger data *
+ * action - action data *
+ * userid - user id *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: Cannot use action->userid as it may also be groupid *
+ * *
+ ******************************************************************************/
+static void send_to_user_medias(DB_EVENT *event,DB_OPERATION *operation, zbx_uint64_t userid)
+{
+ DB_MEDIA media;
+ DB_RESULT result;
+ DB_ROW row;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In send_to_user_medias(objectid:" ZBX_FS_UI64 ")",
+ event->objectid);
+
+ result = DBselect("select mediatypeid,sendto,active,severity,period from media where active=%d and userid=" ZBX_FS_UI64,
+ MEDIA_STATUS_ACTIVE,
+ userid);
+
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(media.mediatypeid, row[0]);
+
+ media.sendto = row[1];
+ media.active = atoi(row[2]);
+ media.severity = atoi(row[3]);
+ media.period = row[4];
+
+ zabbix_log( LOG_LEVEL_DEBUG, "Trigger severity [%d] Media severity [%d] Period [%s]",
+ event->trigger_priority,
+ media.severity,
+ media.period);
+ if(((1<<event->trigger_priority)&media.severity)==0)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "Won't send message (severity)");
+ continue;
+ }
+ if(check_time_period(media.period, (time_t)NULL) == 0)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "Won't send message (period)");
+ continue;
+ }
+
+ DBadd_alert(operation->actionid, userid, event->objectid, media.mediatypeid,media.sendto,operation->shortdata,operation->longdata);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End send_to_user_medias()");
+}
+
+/******************************************************************************
+ * *
+ * Function: op_notify_user *
+ * *
+ * Purpose: send notifications to user or user groupd *
+ * *
+ * Parameters: trigger - trigger data *
+ * action - action data *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: action->recipient specifies user or group *
+ * *
+ ******************************************************************************/
+void op_notify_user(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_uint64_t userid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In send_to_user()");
+
+ if(operation->object == OPERATION_OBJECT_USER)
+ {
+ result = DBselect("SELECT count(u.userid) as user_cnt FROM users u WHERE u.userid= " ZBX_FS_UI64 " and u.status=%d",
+ operation->objectid, USER_STATUS_ACTIVE);
+ row = DBfetch(result);
+ if(row && (DBis_null(row[0])!=SUCCEED) && (atoi(row[0])>0))
+ {
+ send_to_user_medias(event, operation, operation->objectid);
+ }
+ DBfree_result(result);
+ }
+ else if(operation->object == OPERATION_OBJECT_GROUP)
+ {
+ result = DBselect("select u.userid from users u, users_groups ug where ug.usrgrpid=" ZBX_FS_UI64 " and ug.userid=u.userid and u.status=%d",
+ operation->objectid,USER_STATUS_ACTIVE);
+ while((row=DBfetch(result)))
+ {
+ ZBX_STR2UINT64(userid, row[0]);
+ send_to_user_medias(event, operation, userid);
+ }
+ DBfree_result(result);
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Unknown object type [%d] for operationid [" ZBX_FS_UI64 "]",
+ operation->object,
+ operation->operationid);
+ zabbix_syslog("Unknown object type [%d] for operationid [" ZBX_FS_UI64 "]",
+ operation->object,
+ operation->operationid);
+ }
+ zabbix_log(LOG_LEVEL_DEBUG, "End send_to_user()");
+}
+
+
+/******************************************************************************
+ * *
+ * Function: run_remote_commands *
+ * *
+ * Purpose: run remote command on specific host *
+ * *
+ * Parameters: host_name - host name *
+ * command - remote command *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+
+static void run_remote_command(char* host_name, char* command)
+{
+ int ret = 9;
+
+ AGENT_RESULT agent_result;
+ DB_ITEM item;
+ DB_RESULT result;
+ DB_ROW row;
+
+ assert(host_name);
+ assert(command);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In run_remote_command(hostname:%s,command:%s)",
+ host_name,
+ command);
+
+ result = DBselect("select distinct host,ip,useip,port,dns from hosts where host='%s' and " ZBX_COND_NODEID,
+ host_name,
+ LOCAL_NODE("hostid"));
+ row = DBfetch(result);
+ if(row)
+ {
+ item.host_name = row[0];
+ item.host_ip=row[1];
+ item.useip=atoi(row[2]);
+ item.port=atoi(row[3]);
+ item.host_dns=row[4];
+
+ zbx_snprintf(item.key,ITEM_KEY_LEN_MAX,"system.run[%s,nowait]",command);
+
+ alarm(CONFIG_TIMEOUT);
+
+ ret = get_value_agent(&item, &agent_result);
+
+ alarm(0);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End run_remote_command(result:%d)",
+ ret);
+}
+
+/******************************************************************************
+ * *
+ * Function: get_next_command *
+ * *
+ * Purpose: parse action script on remote commands *
+ * *
+ * Parameters: command_list - command list *
+ * alias - (output) of host name or group name *
+ * is_group - (output) 0 if alias is a host name *
+ * 1 if alias is a group name *
+ * command - (output) remote command *
+ * *
+ * Return value: 0 - correct comand is readed *
+ * 1 - EOL *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+
+#define CMD_ALIAS 0
+#define CMD_REM_COMMAND 1
+
+static int get_next_command(char** command_list, char** alias, int* is_group, char** command)
+{
+ int state = CMD_ALIAS;
+ int len = 0;
+ int i = 0;
+
+ assert(alias);
+ assert(is_group);
+ assert(command);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In get_next_command(command_list:%s)",
+ *command_list);
+
+ *alias = NULL;
+ *is_group = 0;
+ *command = NULL;
+
+
+ if((*command_list)[0] == '\0' || (*command_list)==NULL) {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result get_next_command [EOL]");
+ return 1;
+ }
+
+ *alias = *command_list;
+ len = strlen(*command_list);
+
+ for(i=0; i < len; i++)
+ {
+ if(state == CMD_ALIAS)
+ {
+ if((*command_list)[i] == '#'){
+ *is_group = 1;
+ (*command_list)[i] = '\0';
+ state = CMD_REM_COMMAND;
+ *command = &(*command_list)[i+1];
+ }else if((*command_list)[i] == ':'){
+ *is_group = 0;
+ (*command_list)[i] = '\0';
+ state = CMD_REM_COMMAND;
+ *command = &(*command_list)[i+1];
+ }
+ } else if(state == CMD_REM_COMMAND) {
+ if((*command_list)[i] == '\r')
+ {
+ (*command_list)[i] = '\0';
+ } else if((*command_list)[i] == '\n')
+ {
+ (*command_list)[i] = '\0';
+ (*command_list) = &(*command_list)[i+1];
+ break;
+ }
+ }
+ if((*command_list)[i+1] == '\0')
+ {
+ (*command_list) = &(*command_list)[i+1];
+ break;
+ }
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End get_next_command(alias:%s,is_group:%i,command:%s)",
+ *alias,
+ *is_group,
+ *command);
+
+ return 0;
+}
+
+/******************************************************************************
+ * *
+ * Function: run_commands *
+ * *
+ * Purpose: run remote commandlist for specific action *
+ * *
+ * Parameters: trigger - trigger data *
+ * action - action data *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: commands devided with newline *
+ * *
+ ******************************************************************************/
+void op_run_commands(DB_EVENT *event, DB_OPERATION *operation)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ char *cmd_list = NULL;
+ char *alias = NULL;
+ char *command = NULL;
+ int is_group = 0;
+
+ assert(event);
+ assert(operation);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In run_commands(operationid:" ZBX_FS_UI64 ")",
+ operation->operationid);
+
+ cmd_list = operation->longdata;
+ while(get_next_command(&cmd_list,&alias,&is_group,&command)!=1)
+ {
+ if(!alias || !command) continue;
+ if(alias == '\0' || command == '\0') continue;
+ if(is_group)
+ {
+ result = DBselect("select distinct h.host from hosts_groups hg,hosts h, groups g where hg.hostid=h.hostid and hg.groupid=g.groupid and g.name='%s' and" ZBX_COND_NODEID,
+ alias,
+ LOCAL_NODE("h.hostid"));
+ while((row=DBfetch(result)))
+ {
+ run_remote_command(row[0], command);
+ }
+
+ DBfree_result(result);
+ }
+ else
+ {
+ run_remote_command(alias, command);
+ }
+/* DBadd_alert(action->actionid,trigger->triggerid, userid, media.mediatypeid,media.sendto,action->subject,action->scripts); */ /* TODO !!! Add alert for remote commands !!! */
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "End run_commands()");
+}
+
+/******************************************************************************
+ * *
+ * Function: select dhostid by dserviceid *
+ * *
+ * Purpose: select discovered host id *
+ * *
+ * Parameters: dserviceid - servce id *
+ * *
+ * Return value: dhostid - existing dhostid, 0 - if not found *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static zbx_uint64_t select_dhostid_by_dserviceid(zbx_uint64_t dserviceid)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_uint64_t dhostid = 0;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In select_dhostid_by_dserviceid(dserviceid:" ZBX_FS_UI64 ")",
+ dserviceid);
+
+ result = DBselect("select dhostid from dservices where dserviceid=" ZBX_FS_UI64,
+ dserviceid);
+ row = DBfetch(result);
+ if(row && DBis_null(row[0]) != SUCCEED)
+ {
+ ZBX_STR2UINT64(dhostid, row[0]);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End select_dhostid_by_dserviceid()");
+
+ return dhostid;
+}
+
+/******************************************************************************
+ * *
+ * Function: select hostid of discovered host *
+ * *
+ * Purpose: select discovered host *
+ * *
+ * Parameters: dhostid - discovered host id *
+ * *
+ * Return value: hostid - existing hostid, o - if not found *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static zbx_uint64_t select_discovered_host(zbx_uint64_t dhostid)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_uint64_t hostid = 0;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In select_discovered_host(dhostid:" ZBX_FS_UI64 ")",
+ dhostid);
+
+ result = DBselect("select h.hostid from dhosts d,hosts h where h.ip=d.ip and d.dhostid=" ZBX_FS_UI64,
+ dhostid);
+ row = DBfetch(result);
+ if(row && DBis_null(row[0]) != SUCCEED)
+ {
+ ZBX_STR2UINT64(hostid, row[0]);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End select_discovered_host()");
+
+ return hostid;
+}
+
+/******************************************************************************
+ * *
+ * Function: add host if not added already *
+ * *
+ * Purpose: add discovered host *
+ * *
+ * Parameters: dhostid - discovered host id *
+ * *
+ * Return value: hostid - new/existing hostid *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static zbx_uint64_t add_discovered_host(zbx_uint64_t dhostid)
+{
+ DB_RESULT result;
+ DB_RESULT result2;
+ DB_ROW row;
+ DB_ROW row2;
+ zbx_uint64_t hostid = 0;
+ char *ip;
+ char host[MAX_STRING_LEN], host_esc[MAX_STRING_LEN];
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In add_discovered_host(dhostid:" ZBX_FS_UI64 ")",
+ dhostid);
+
+ result = DBselect("select ip from dhosts where dhostid=" ZBX_FS_UI64,
+ dhostid);
+ row = DBfetch(result);
+ if(row && DBis_null(row[0]) != SUCCEED)
+ {
+ ip=row[0];
+
+ alarm(CONFIG_TIMEOUT);
+ zbx_gethost_by_ip(ip, host, sizeof(host));
+ alarm(0);
+
+ DBescape_string(host, host_esc, sizeof(host_esc));
+
+ result2 = DBselect("select hostid from hosts where ip='%s' and " ZBX_COND_NODEID,
+ ip,
+ LOCAL_NODE("hostid"));
+ row2 = DBfetch(result2);
+ if(!row2 || DBis_null(row2[0]) == SUCCEED)
+ {
+ hostid = DBget_maxid("hosts","hostid");
+ DBexecute("insert into hosts (hostid,host,useip,ip,dns) values (" ZBX_FS_UI64 ",'%s',1,'%s','%s')",
+ hostid,
+ (host[0] != '\0' ? host_esc : ip), /* Use host name if exists, IP otherwise */
+ ip,
+ host_esc);
+ }
+ else
+ {
+ ZBX_STR2UINT64(hostid, row2[0]);
+ if(host_esc[0] != '\0')
+ {
+ DBexecute("update hosts set dns='%s' where hostid=" ZBX_FS_UI64,
+ host_esc,
+ hostid);
+ }
+ }
+ DBfree_result(result2);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End add_discovered_host()");
+
+ return hostid;
+}
+
+/******************************************************************************
+ * *
+ * Function: op_host_add *
+ * *
+ * Purpose: add discovered host *
+ * *
+ * Parameters: trigger - trigger data *
+ * action - action data *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void op_host_add(DB_EVENT *event)
+{
+ zbx_uint64_t hostid;
+ zbx_uint64_t dhostid = 0;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In op_host_add()");
+
+ if(event->object == EVENT_OBJECT_DHOST)
+ {
+ dhostid = event->objectid;
+ }
+ else if(event->object == EVENT_OBJECT_DSERVICE)
+ {
+ dhostid = select_dhostid_by_dserviceid(event->objectid);
+ }
+
+ hostid = add_discovered_host(dhostid);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End op_host_add()");
+}
+
+/******************************************************************************
+ * *
+ * Function: op_host_del *
+ * *
+ * Purpose: delete host *
+ * *
+ * Parameters: *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void op_host_del(DB_EVENT *event)
+{
+ zbx_uint64_t hostid, dhostid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In op_host_del()");
+
+ if(event->object == EVENT_OBJECT_DSERVICE)
+ {
+ dhostid = select_dhostid_by_dserviceid(event->objectid);
+ }
+ else
+ {
+ dhostid = event->objectid;
+ }
+
+ hostid = select_discovered_host(dhostid);
+ if(hostid != 0)
+ {
+ DBdelete_host(hostid);
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End op_host_del()");
+}
+
+/******************************************************************************
+ * *
+ * Function: op_group_add *
+ * *
+ * Purpose: add group to discovered host *
+ * *
+ * Parameters: trigger - trigger data *
+ * action - action data *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void op_group_add(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_uint64_t hostgroupid, groupid, hostid, dhostid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In op_group_add(object:%d)",
+ event->object);
+
+ if(operation->operationtype != OPERATION_TYPE_GROUP_ADD) return;
+ if(event->object != EVENT_OBJECT_DHOST && event->object != EVENT_OBJECT_DSERVICE) return;
+
+
+ if(event->object == EVENT_OBJECT_DSERVICE)
+ {
+ dhostid = select_dhostid_by_dserviceid(event->objectid);
+ }
+ else
+ {
+ dhostid = event->objectid;
+ }
+
+ hostid = add_discovered_host(dhostid);
+ if(hostid != 0)
+ {
+ groupid = operation->objectid;
+ result = DBselect("select hostgroupid from hosts_groups where groupid=" ZBX_FS_UI64 " and hostid=" ZBX_FS_UI64,
+ groupid,
+ hostid);
+ row = DBfetch(result);
+ if(!row || DBis_null(row[0]) == SUCCEED)
+ {
+ hostgroupid = DBget_maxid("hosts_groups","hostgroupid");
+ DBexecute("insert into hosts_groups (hostgroupid,hostid,groupid) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 ")",
+ hostgroupid,
+ hostid,
+ groupid);
+ }
+ DBfree_result(result);
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End op_group_add()");
+}
+
+/******************************************************************************
+ * *
+ * Function: op_group_del *
+ * *
+ * Purpose: delete group from discovered host *
+ * *
+ * Parameters: trigger - trigger data *
+ * action - action data *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void op_group_del(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation)
+{
+ zbx_uint64_t groupid, hostid, dhostid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In op_group_del()");
+
+ if(operation->operationtype != OPERATION_TYPE_GROUP_REMOVE) return;
+ if(event->object != EVENT_OBJECT_DHOST && event->object != EVENT_OBJECT_DSERVICE) return;
+
+ if(event->object == EVENT_OBJECT_DSERVICE)
+ {
+ dhostid = select_dhostid_by_dserviceid(event->objectid);
+ }
+ else
+ {
+ dhostid = event->objectid;
+ }
+
+ hostid = select_discovered_host(dhostid);
+ if(hostid != 0)
+ {
+ groupid = operation->objectid;
+ DBexecute("delete from hosts_groups where hostid=" ZBX_FS_UI64 " and groupid=" ZBX_FS_UI64,
+ hostid,
+ groupid);
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End op_group_del()");
+}
+
+/******************************************************************************
+ * *
+ * Function: op_template_add *
+ * *
+ * Purpose: link host with template *
+ * *
+ * Parameters: *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void op_template_add(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_uint64_t hosttemplateid, templateid, hostid, dhostid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In op_template_add(object:%d)",
+ event->object);
+
+ if(operation->operationtype != OPERATION_TYPE_TEMPLATE_ADD) return;
+ if(event->object != EVENT_OBJECT_DHOST && event->object != EVENT_OBJECT_DSERVICE) return;
+
+
+ if(event->object == EVENT_OBJECT_DSERVICE)
+ {
+ dhostid = select_dhostid_by_dserviceid(event->objectid);
+ }
+ else
+ {
+ dhostid = event->objectid;
+ }
+
+ hostid = add_discovered_host(dhostid);
+ if(hostid != 0)
+ {
+ templateid = operation->objectid;
+
+ result = DBselect("select hosttemplateid from hosts_templates where templateid=" ZBX_FS_UI64 " and hostid=" ZBX_FS_UI64,
+ templateid,
+ hostid);
+ row = DBfetch(result);
+ if(!row || DBis_null(row[0]) == SUCCEED)
+ {
+ hosttemplateid = DBget_maxid("hosts_templates","hosttemplateid");
+ DBexecute("begin;");
+
+ DBexecute("insert into hosts_templates (hosttemplateid,hostid,templateid) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 ")",
+ hosttemplateid,
+ hostid,
+ templateid);
+
+ DBsync_host_with_template(hostid, templateid);
+
+ DBexecute("commit;");
+ }
+ DBfree_result(result);
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End op_template_add()");
+}
+
+/******************************************************************************
+ * *
+ * Function: op_template_del *
+ * *
+ * Purpose: unlink and clear host from template *
+ * *
+ * Parameters: *
+ * *
+ * Return value: nothing *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void op_template_del(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_uint64_t templateid, hostid, dhostid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In op_template_del(object:%d)",
+ event->object);
+
+ if(operation->operationtype != OPERATION_TYPE_TEMPLATE_REMOVE) return;
+ if(event->object != EVENT_OBJECT_DHOST && event->object != EVENT_OBJECT_DSERVICE) return;
+
+
+ if(event->object == EVENT_OBJECT_DSERVICE)
+ {
+ dhostid = select_dhostid_by_dserviceid(event->objectid);
+ }
+ else
+ {
+ dhostid = event->objectid;
+ }
+
+ hostid = select_discovered_host(dhostid);
+ if(hostid != 0)
+ {
+ templateid = operation->objectid;
+
+ result = DBselect("select hosttemplateid from hosts_templates where templateid=" ZBX_FS_UI64 " and hostid=" ZBX_FS_UI64,
+ templateid,
+ hostid);
+
+ if( (row = DBfetch(result)) )
+ {
+ DBexecute("begin;");
+
+ DBdelete_template_elements(hostid, templateid, 0 /* not a unlink mode */);
+
+ DBexecute("delete from hosts_templates where "
+ "hostid=" ZBX_FS_UI64 " and templateid=" ZBX_FS_UI64,
+ hostid,
+ templateid);
+
+ DBexecute("commit;");
+ }
+ DBfree_result(result);
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End op_template_del()");
+}
+
diff --git a/src/zabbix_proxy/operations.h b/src/zabbix_proxy/operations.h
new file mode 100644
index 00000000..523f03c3
--- /dev/null
+++ b/src/zabbix_proxy/operations.h
@@ -0,0 +1,36 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#ifndef ZABBIX_OPERATIONS_H
+#define ZABBIX_OPERATIONS_H
+
+#include "common.h"
+#include "db.h"
+
+void op_template_add(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation);
+void op_template_del(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation);
+void op_group_add(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation);
+void op_group_del(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation);
+void op_host_add(DB_EVENT *event);
+void op_host_del(DB_EVENT *event);
+void op_run_commands(DB_EVENT *event, DB_OPERATION *operation);
+void op_notify_user(DB_EVENT *event, DB_ACTION *action, DB_OPERATION *operation);
+
+#endif
diff --git a/src/zabbix_proxy/pinger/Makefile.am b/src/zabbix_proxy/pinger/Makefile.am
new file mode 100644
index 00000000..589d6d19
--- /dev/null
+++ b/src/zabbix_proxy/pinger/Makefile.am
@@ -0,0 +1,5 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxpinger.a
+
+libzbxpinger_a_SOURCES = pinger.c pinger.h
diff --git a/src/zabbix_proxy/pinger/pinger.c b/src/zabbix_proxy/pinger/pinger.c
new file mode 100644
index 00000000..01620be1
--- /dev/null
+++ b/src/zabbix_proxy/pinger/pinger.c
@@ -0,0 +1,415 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "db.h"
+#include "../functions.h"
+#include "log.h"
+#include "zlog.h"
+#include "threads.h"
+
+#include "pinger.h"
+
+int pinger_num;
+
+/******************************************************************************
+ * *
+ * Function: is_ip *
+ * *
+ * Purpose: is string IP address *
+ * *
+ * Parameters: ip - string *
+ * *
+ * Return value: SUCCEED - is IP address *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: could be improved *
+ * *
+ ******************************************************************************/
+static int is_ip(char *ip)
+{
+ int i;
+ char c;
+ int dots=0;
+ int res = SUCCEED;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In process_ip([%s])",
+ ip);
+
+ for(i=0;ip[i]!=0;i++)
+ {
+ c=ip[i];
+ if( (c>='0') && (c<='9'))
+ {
+ continue;
+ }
+ else if(c=='.')
+ {
+ dots++;
+ }
+ else
+ {
+ res = FAIL;
+ break;
+ }
+ }
+ if( dots!=3)
+ {
+ res = FAIL;
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "End of process_ip(result:%d)",
+ res);
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: process_new_value *
+ * *
+ * Purpose: process new item value *
+ * *
+ * Parameters: key - item key *
+ * host - host name *
+ * value - new value of the item *
+ * *
+ * Return value: SUCCEED - new value sucesfully processed *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: can be done in process_data() *
+ * *
+ ******************************************************************************/
+static int process_value(char *key, char *host, AGENT_RESULT *value)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ DB_ITEM item;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In process_value(%s@%s)",
+ key,
+ host);
+
+ /* IP address? */
+ if(is_ip(host) == SUCCEED)
+ {
+ result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and h.ip='%s' and i.key_='%s' and i.status=%d and i.type=%d and" ZBX_COND_NODEID,
+ ZBX_SQL_ITEM_SELECT,
+ HOST_STATUS_MONITORED,
+ host,
+ key,
+ ITEM_STATUS_ACTIVE,
+ ITEM_TYPE_SIMPLE,
+ LOCAL_NODE("h.hostid"));
+ }
+ else
+ {
+ result = DBselect("select %s where h.status=%d and h.hostid=i.hostid and h.dns='%s' and i.key_='%s' and i.status=%d and i.type=%d and" ZBX_COND_NODEID,
+ ZBX_SQL_ITEM_SELECT,
+ HOST_STATUS_MONITORED,
+ host,
+ key,
+ ITEM_STATUS_ACTIVE,
+ ITEM_TYPE_SIMPLE,
+ LOCAL_NODE("h.hostid"));
+ }
+ row=DBfetch(result);
+
+ if(!row)
+ {
+ DBfree_result(result);
+ return FAIL;
+ }
+
+ DBget_item_from_db(&item,row);
+
+ DBbegin();
+ process_new_value(&item,value);
+ update_triggers(item.itemid);
+ DBcommit();
+
+ DBfree_result(result);
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: create_host_file *
+ * *
+ * Purpose: creates file which contains list of hosts to ping *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - the file was created succesfully *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int create_host_file(void)
+{
+ FILE *f;
+ int now;
+
+ DB_HOST host;
+ DB_RESULT result;
+ DB_ROW row;
+ char str[MAX_STRING_LEN];
+
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In create_host_file()");
+
+ zbx_snprintf(str,sizeof(str),"/tmp/zabbix_server_%li.pinger",
+ zbx_get_thread_id());
+
+ if(NULL == (f = fopen(str, "w") ))
+ {
+ zabbix_log( LOG_LEVEL_ERR, "Cannot open file [%s] [%s]",
+ str,
+ strerror(errno));
+ zabbix_syslog("Cannot open file [%s] [%s]",
+ str,
+ strerror(errno));
+ return FAIL;
+ }
+
+ now=time(NULL);
+ /* Select hosts monitored by IP */
+ result = DBselect("select distinct h.ip from hosts h,items i where " ZBX_SQL_MOD(h.hostid,%d) "=%d and i.hostid=h.hostid and h.status=%d and (i.key_='%s' or i.key_='%s') and i.type=%d and i.status=%d and h.useip=1 and" ZBX_COND_NODEID,
+ CONFIG_PINGER_FORKS,
+ pinger_num-1,
+ HOST_STATUS_MONITORED,
+ SERVER_ICMPPING_KEY,
+ SERVER_ICMPPINGSEC_KEY,
+ ITEM_TYPE_SIMPLE,
+ ITEM_STATUS_ACTIVE,
+ LOCAL_NODE("h.hostid"));
+
+ while((row=DBfetch(result)))
+ {
+ strscpy(host.ip,row[0]);
+/* host.host=DBget_field(result,i,2);*/
+
+ fprintf(f,"%s\n",host.ip);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "IP [%s]", host.ip);
+ }
+ DBfree_result(result);
+
+ /* Select hosts monitored by hostname */
+ result = DBselect("select distinct h.dns from hosts h,items i where " ZBX_SQL_MOD(h.hostid,%d) "=%d and i.hostid=h.hostid and h.status=%d and (i.key_='%s' or i.key_='%s') and i.type=%d and i.status=%d and h.useip=0 and" ZBX_COND_NODEID,
+ CONFIG_PINGER_FORKS,
+ pinger_num-1,
+ HOST_STATUS_MONITORED,
+ SERVER_ICMPPING_KEY,
+ SERVER_ICMPPINGSEC_KEY,
+ ITEM_TYPE_SIMPLE,
+ ITEM_STATUS_ACTIVE,
+ LOCAL_NODE("h.hostid"));
+
+ while((row=DBfetch(result)))
+ {
+ strscpy(host.dns,row[0]);
+
+ fprintf(f,"%s\n",
+ host.dns);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "DNS name [%s]",
+ host.dns);
+ }
+ DBfree_result(result);
+
+ zbx_fclose(f);
+
+ return SUCCEED;
+}
+
+
+/******************************************************************************
+ * *
+ * Function: do_ping *
+ * *
+ * Purpose: ping hosts listed in the host files *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - successfully processed *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: use external binary 'fping' to avoid superuser priviledges *
+ * *
+ ******************************************************************************/
+static int do_ping(void)
+{
+ FILE *f;
+ char ip[MAX_STRING_LEN];
+ char str[MAX_STRING_LEN];
+ char tmp[MAX_STRING_LEN];
+ double mseconds;
+ char *c;
+ int alive;
+ AGENT_RESULT value;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In do_ping()");
+
+ zbx_snprintf(str,sizeof(str),"cat /tmp/zabbix_server_%li.pinger | %s -e 2>/dev/null",
+ zbx_get_thread_id(),
+ CONFIG_FPING_LOCATION);
+
+ f=popen(str,"r");
+ if(f==0)
+ {
+ zabbix_log( LOG_LEVEL_ERR, "Cannot execute [%s] [%s]",
+ CONFIG_FPING_LOCATION,
+ strerror(errno));
+ zabbix_syslog("Cannot execute [%s] [%s]",
+ CONFIG_FPING_LOCATION,
+ strerror(errno));
+ return FAIL;
+ }
+
+ while(NULL!=fgets(ip,MAX_STRING_LEN,f))
+ {
+/* zabbix_log( LOG_LEVEL_WARNING, "PING: [%s]", ip);*/
+
+ ip[strlen(ip)-1]=0;
+ zabbix_log( LOG_LEVEL_DEBUG, "Update IP [%s]",
+ ip);
+
+ if(strstr(ip,"alive") != NULL)
+ {
+ alive=1;
+ sscanf(ip,"%s is alive (%lf ms)",
+ tmp,
+ &mseconds);
+ zabbix_log( LOG_LEVEL_DEBUG, "Mseconds [%lf]",
+ mseconds);
+ }
+ else
+ {
+ alive=0;
+ }
+ c=strstr(ip," ");
+ if(c != NULL)
+ {
+ *c=0;
+ zabbix_log( LOG_LEVEL_DEBUG, "IP [%s] alive [%d]",
+ ip,
+ alive);
+
+ if(0 == alive)
+ {
+ init_result(&value);
+ SET_UI64_RESULT(&value, 0);
+ process_value(SERVER_ICMPPING_KEY,ip,&value);
+ free_result(&value);
+
+ init_result(&value);
+ SET_DBL_RESULT(&value, 0);
+ process_value(SERVER_ICMPPINGSEC_KEY,ip,&value);
+ free_result(&value);
+ }
+ else
+ {
+ init_result(&value);
+ SET_UI64_RESULT(&value, 1);
+ process_value(SERVER_ICMPPING_KEY,ip,&value);
+ free_result(&value);
+
+ init_result(&value);
+ SET_DBL_RESULT(&value, mseconds/1000);
+ process_value(SERVER_ICMPPINGSEC_KEY,ip,&value);
+ free_result(&value);
+ }
+ }
+ }
+
+ pclose(f);
+
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: main_pinger_loop *
+ * *
+ * Purpose: periodically perform ICMP pings *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: never returns *
+ * *
+ ******************************************************************************/
+void main_pinger_loop(int num)
+{
+ int ret = SUCCEED;
+
+ char str[MAX_STRING_LEN];
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In main_pinger_loop(num:%d)",
+ num);
+
+ pinger_num = num;
+
+ for(;;)
+ {
+ zbx_setproctitle("connecting to the database");
+
+ DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+/* zabbix_set_log_level(LOG_LEVEL_DEBUG);*/
+
+ ret = create_host_file();
+
+ if( SUCCEED == ret)
+ {
+ zbx_setproctitle("pinging hosts");
+
+ ret = do_ping();
+ }
+ zbx_snprintf(str,sizeof(str),"/tmp/zabbix_server_%li.pinger",
+ zbx_get_thread_id());
+ unlink(str);
+
+/* zabbix_set_log_level(LOG_LEVEL_WARNING); */
+
+ DBclose();
+
+ zbx_setproctitle("pinger [sleeping for %d seconds]",
+ CONFIG_PINGER_FREQUENCY);
+
+ sleep(CONFIG_PINGER_FREQUENCY);
+ }
+
+ /* Never reached */
+}
diff --git a/src/zabbix_proxy/pinger/pinger.h b/src/zabbix_proxy/pinger/pinger.h
new file mode 100644
index 00000000..bf52b8d7
--- /dev/null
+++ b/src/zabbix_proxy/pinger/pinger.h
@@ -0,0 +1,31 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_PINGER_H
+#define ZABBIX_PINGER_H
+
+extern int CONFIG_PINGER_FORKS;
+extern int CONFIG_PINGER_FREQUENCY;
+extern char *CONFIG_FPING_LOCATION;
+
+extern void signal_handler( int sig );
+
+void main_pinger_loop(int num);
+
+#endif
diff --git a/src/zabbix_proxy/poller/Makefile.am b/src/zabbix_proxy/poller/Makefile.am
new file mode 100644
index 00000000..5d6ebe0a
--- /dev/null
+++ b/src/zabbix_proxy/poller/Makefile.am
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxpoller.a
+
+libzbxpoller_a_SOURCES = \
+ checks_agent.c checks_agent.h \
+ checks_internal.c checks_internal.h \
+ checks_simple.c checks_simple.h \
+ checks_snmp.c checks_snmp.h \
+ checks_db.c checks_db.h \
+ checks_aggregate.c checks_aggregate.h \
+ checks_external.c checks_external.h \
+ poller.c poller.h
diff --git a/src/zabbix_proxy/poller/checks_agent.c b/src/zabbix_proxy/poller/checks_agent.c
new file mode 100644
index 00000000..a9a5fe80
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_agent.c
@@ -0,0 +1,133 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+#include "common.h"
+#include "comms.h"
+
+#include "checks_agent.h"
+
+/******************************************************************************
+ * *
+ * Function: get_value_agent *
+ * *
+ * Purpose: retrieve data from ZABBIX agent *
+ * *
+ * Parameters: item - item we are interested in *
+ * *
+ * Return value: SUCCEED - data succesfully retrieved and stored in result *
+ * and result_str (as string) *
+ * NETWORK_ERROR - network related error occured *
+ * NOTSUPPORTED - item not supported by the agent *
+ * AGENT_ERROR - uncritical error on agent side occured *
+ * FAIL - otherwise *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: error will contain error message *
+ * *
+ ******************************************************************************/
+int get_value_agent(DB_ITEM *item, AGENT_RESULT *result)
+{
+ zbx_sock_t s;
+
+ char
+ *buf,
+ packet[MAX_STRING_LEN],
+ error[MAX_STRING_LEN];
+
+ int ret = SUCCEED;
+
+ init_result(result);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_agent(host:%s,ip:%s,key:%s",
+ item->host_name,
+ item->host_ip,
+ item->key );
+
+ if (SUCCEED == (ret = zbx_tcp_connect(&s, item->useip==1 ? item->host_ip : item->host_dns, item->port, 0))) {
+ zbx_snprintf(packet, sizeof(packet), "%s\n",item->key);
+ zabbix_log(LOG_LEVEL_DEBUG, "Sending [%s]", packet);
+
+ /* Send requests using old protocol */
+ if( SUCCEED == (ret = zbx_tcp_send_raw(&s, packet)) )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Before read");
+
+ ret = zbx_tcp_recv_ext(&s, &buf, ZBX_TCP_READ_UNTIL_CLOSE);
+ }
+ }
+
+ if( SUCCEED == ret )
+ {
+ zbx_rtrim(buf, " \r\n\0");
+ zbx_ltrim(buf, " ");
+
+ if( strcmp(buf,"ZBX_NOTSUPPORTED") == 0)
+ {
+ zbx_snprintf(error,sizeof(error),"Not supported by ZABBIX agent");
+ SET_MSG_RESULT(result, strdup(error));
+ ret = NOTSUPPORTED;
+ }
+ else if( strcmp(buf,"ZBX_ERROR") == 0)
+ {
+ zbx_snprintf(error,sizeof(error),"ZABBIX agent non-critical error");
+ SET_MSG_RESULT(result, strdup(error));
+ ret = AGENT_ERROR;
+ }
+ /* The section should be improved */
+ else if(buf[0]==0)
+ {
+ zbx_snprintf(error,sizeof(error),"Got empty string from [%s] IP [%s] Parameter [%s]",
+ item->host_name,
+ item->host_ip,
+ item->key);
+ zabbix_log( LOG_LEVEL_WARNING, "%s",
+ error);
+ zabbix_log( LOG_LEVEL_WARNING, "Assuming that agent dropped connection because of access permissions");
+ SET_MSG_RESULT(result, strdup(error));
+ ret = NETWORK_ERROR;
+ }
+ else if(set_result_type(result, item->value_type, buf) == FAIL)
+ {
+ zbx_snprintf(error,sizeof(error), "Type of received value [%s] is not sutable for [%s@%s] having type [%d]",
+ buf,
+ item->key,
+ item->host_name,
+ item->value_type);
+ zabbix_log( LOG_LEVEL_WARNING, "%s",
+ error);
+ zabbix_log( LOG_LEVEL_WARNING, "Returning NOTSUPPORTED");
+ result->msg=strdup(error);
+ ret = NOTSUPPORTED;
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End get_value_agent(result:%s)",
+ buf);
+
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "Get value from agent failed. Error: %s", zbx_tcp_strerror());
+ SET_MSG_RESULT(result, strdup(zbx_tcp_strerror()));
+ ret = NETWORK_ERROR;
+
+ }
+ zbx_tcp_close(&s);
+
+ return ret;
+}
diff --git a/src/zabbix_proxy/poller/checks_agent.h b/src/zabbix_proxy/poller/checks_agent.h
new file mode 100644
index 00000000..f890eee7
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_agent.h
@@ -0,0 +1,32 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_CHECKS_AGENT_H
+#define ZABBIX_CHECKS_AGENT_H
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "sysinfo.h"
+
+extern int CONFIG_NOTIMEWAIT;
+
+extern int get_value_agent(DB_ITEM *item, AGENT_RESULT *result);
+
+#endif
diff --git a/src/zabbix_proxy/poller/checks_aggregate.c b/src/zabbix_proxy/poller/checks_aggregate.c
new file mode 100644
index 00000000..29e56cb7
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_aggregate.c
@@ -0,0 +1,369 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+#include "checks_aggregate.h"
+
+static int evaluate_one(double *result, int *num, char *grpfunc, char const *value_str, int valuetype)
+{
+ int ret = SUCCEED;
+ double value = 0;
+
+ if(valuetype == ITEM_VALUE_TYPE_FLOAT)
+ {
+ value = zbx_atod(value_str);
+ }
+ else if(valuetype == ITEM_VALUE_TYPE_UINT64)
+ {
+ value = (double)zbx_atoui64(value_str);
+ }
+
+ if(strcmp(grpfunc,"grpsum") == 0)
+ {
+ *result+=value;
+ *num+=1;
+ }
+ else if(strcmp(grpfunc,"grpavg") == 0)
+ {
+ *result+=value;
+ *num+=1;
+ }
+ else if(strcmp(grpfunc,"grpmin") == 0)
+ {
+ if(*num==0)
+ {
+ *result=value;
+ }
+ else if(value<*result)
+ {
+ *result=value;
+ }
+ *num+=1;
+ }
+ else if(strcmp(grpfunc,"grpmax") == 0)
+ {
+ if(*num==0)
+ {
+ *result=value;
+ }
+ else if(value>*result)
+ {
+ *result=value;
+ }
+ *num+=1;
+ }
+ else
+ {
+ ret = FAIL;
+ }
+
+ return ret;
+}
+
+/*
+ * grpfunc: grpmax, grpmin, grpsum, grpavg
+ * itemfunc: last, min, max, avg, sum,count
+ */
+static int evaluate_aggregate(AGENT_RESULT *res,char *grpfunc, char *hostgroup, char *itemkey, char *itemfunc, char *param)
+{
+ char sql[MAX_STRING_LEN];
+ char sql2[MAX_STRING_LEN];
+ char hostgroup_esc[MAX_STRING_LEN],itemkey_esc[MAX_STRING_LEN];
+
+ DB_RESULT result;
+ DB_ROW row;
+
+ int valuetype;
+ double d = 0;
+ const char *value;
+ int num = 0;
+ int now;
+ char items[MAX_STRING_LEN],items2[MAX_STRING_LEN];
+
+ now=time(NULL);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In evaluate_aggregate('%s','%s','%s','%s','%s')",
+ grpfunc,
+ hostgroup,
+ itemkey,
+ itemfunc,
+ param);
+
+ init_result(res);
+
+ DBescape_string(itemkey,itemkey_esc,MAX_STRING_LEN);
+ DBescape_string(hostgroup,hostgroup_esc,MAX_STRING_LEN);
+/* Get list of affected item IDs */
+ strscpy(items,"0");
+ result = DBselect("select itemid from items i,hosts_groups hg,hosts h,groups g where hg.groupid=g.groupid and i.hostid=h.hostid and hg.hostid=h.hostid and g.name='%s' and i.key_='%s' and i.status=%d and h.status=%d and" ZBX_COND_NODEID,
+ hostgroup_esc,
+ itemkey_esc,
+ ITEM_STATUS_ACTIVE,
+ HOST_STATUS_MONITORED,
+ LOCAL_NODE("h.hostid"));
+
+ while((row=DBfetch(result)))
+ {
+ zbx_snprintf(items2,sizeof(items2),"%s,%s",
+ items,
+ row[0]);
+/* zabbix_log( LOG_LEVEL_WARNING, "ItemIDs items2[%s])",items2);*/
+ strscpy(items,items2);
+/* zabbix_log( LOG_LEVEL_WARNING, "ItemIDs items[%s])",items2);*/
+ }
+ DBfree_result(result);
+
+ if(strcmp(itemfunc,"last") == 0)
+ {
+ zbx_snprintf(sql,sizeof(sql),"select itemid,value_type,lastvalue from items where lastvalue is not NULL and items.itemid in (%s)",
+ items);
+ zbx_snprintf(sql2,sizeof(sql2),"select itemid,value_type,lastvalue from items where 0=1");
+ }
+ /* The SQL works very very slow on MySQL 4.0. That's why it has been split into two. */
+/* zbx_snprintf(sql,sizeof(sql),"select items.itemid,items.value_type,min(history.value) from items,hosts_groups,hosts,groups,history where history.itemid=items.itemid and hosts_groups.groupid=groups.groupid and items.hostid=hosts.hostid and hosts_groups.hostid=hosts.hostid and groups.name='%s' and items.key_='%s' and history.clock>%d group by 1,2",hostgroup_esc, itemkey_esc, now - atoi(param));*/
+ else if( (strcmp(itemfunc,"min") == 0) ||
+ (strcmp(itemfunc,"max") == 0) ||
+ (strcmp(itemfunc,"avg") == 0) ||
+ (strcmp(itemfunc,"count") == 0) ||
+ (strcmp(itemfunc,"sum") == 0)
+ )
+ {
+ zbx_snprintf(sql,sizeof(sql),"select h.itemid,i.value_type,%s(h.value) from items i,history h where h.itemid=i.itemid and h.itemid in (%s) and h.clock>%d group by h.itemid,i.value_type",
+ itemfunc,
+ items,
+ now - atoi(param));
+ zbx_snprintf(sql2,sizeof(sql),"select h.itemid,i.value_type,%s(h.value) from items i,history_uint h where h.itemid=i.itemid and h.itemid in (%s) and h.clock>%d group by h.itemid,i.value_type",
+ itemfunc,
+ items,
+ now - atoi(param));
+ }
+ else
+ {
+ SET_MSG_RESULT(res, strdup("Unsupported item function"));
+ zabbix_log( LOG_LEVEL_WARNING, "Unsupported item function [%s])",
+ itemfunc);
+ return FAIL;
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "SQL [%s]",sql);
+ zabbix_log( LOG_LEVEL_DEBUG, "SQL2 [%s]",sql2);
+
+ result = DBselect("%s",sql);
+ while((row=DBfetch(result)))
+ {
+ valuetype = atoi(row[1]);
+ value = row[2];
+ if(FAIL == evaluate_one(&d, &num, grpfunc, value, valuetype))
+ {
+ SET_MSG_RESULT(res, strdup("Unsupported group function"));
+ zabbix_log( LOG_LEVEL_WARNING, "Unsupported group function [%s])",
+ grpfunc);
+ DBfree_result(result);
+ return FAIL;
+ }
+ }
+ DBfree_result(result);
+
+ result = DBselect("%s",sql2);
+ while((row=DBfetch(result)))
+ {
+ valuetype = atoi(row[1]);
+ value = row[2];
+ if(FAIL == evaluate_one(&d, &num, grpfunc, value, valuetype))
+ {
+ SET_MSG_RESULT(res, strdup("Unsupported group function"));
+ zabbix_log( LOG_LEVEL_WARNING, "Unsupported group function [%s])",
+ grpfunc);
+ DBfree_result(result);
+ return FAIL;
+ }
+ }
+ DBfree_result(result);
+
+ if(num==0)
+ {
+ SET_MSG_RESULT(res, strdup("No values"));
+ zabbix_log( LOG_LEVEL_WARNING, "No values for group[%s] key[%s])",
+ hostgroup,
+ itemkey);
+ return FAIL;
+ }
+
+ if(strcmp(grpfunc,"grpavg") == 0)
+ {
+ SET_DBL_RESULT(res, d/num);
+ }
+ else
+ {
+ SET_DBL_RESULT(res, d);
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "End evaluate_aggregate(result:" ZBX_FS_DBL ")",
+ d);
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: get_value_aggregate *
+ * *
+ * Purpose: retrieve data from ZABBIX server (aggregate items) *
+ * *
+ * Parameters: item - item we are interested in *
+ * *
+ * Return value: SUCCEED - data succesfully retrieved and stored in result *
+ * and result_str (as string) *
+ * NOTSUPPORTED - requested item is not supported *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int get_value_aggregate(DB_ITEM *item, AGENT_RESULT *result)
+{
+ char function_grp[MAX_STRING_LEN];
+ char key[MAX_STRING_LEN];
+ char group[MAX_STRING_LEN];
+ char itemkey[MAX_STRING_LEN];
+ char function_item[MAX_STRING_LEN];
+ char parameter[MAX_STRING_LEN];
+ char *p,*p2;
+
+ int ret = SUCCEED;
+
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_aggregate([%s])",
+ item->key);
+
+ init_result(result);
+
+ strscpy(key, item->key);
+ if((p=strchr(key,'[')) != NULL)
+ {
+ *p=0;
+ strscpy(function_grp,key);
+ *p='[';
+ p++;
+ }
+ else ret = NOTSUPPORTED;
+
+ if(ret == SUCCEED)
+ {
+ if((p2=strchr(p,'"')) != NULL)
+ {
+ p2++;
+ }
+ else ret = NOTSUPPORTED;
+
+ if((ret == SUCCEED) && (p=strchr(p2,'"')) != NULL)
+ {
+ *p=0;
+ strscpy(group,p2);
+ *p='"';
+ p++;
+ }
+ else ret = NOTSUPPORTED;
+ }
+
+ if(ret == SUCCEED)
+ {
+ if(*p != ',') ret = NOTSUPPORTED;
+ }
+
+ if(ret == SUCCEED)
+ {
+ if((p2=strchr(p,'"')) != NULL)
+ {
+ p2++;
+ }
+ else ret = NOTSUPPORTED;
+
+ if((ret == SUCCEED) && (p=strchr(p2,'"')) != NULL)
+ {
+ *p=0;
+ strscpy(itemkey,p2);
+ *p='"';
+ p++;
+ }
+ else ret = NOTSUPPORTED;
+ }
+
+ if(ret == SUCCEED)
+ {
+ if(*p != ',') ret = NOTSUPPORTED;
+ }
+
+ if(ret == SUCCEED)
+ {
+ if((p2=strchr(p,'"')) != NULL)
+ {
+ p2++;
+ }
+ else ret = NOTSUPPORTED;
+
+ if((ret == SUCCEED) && (p=strchr(p2,'"')) != NULL)
+ {
+ *p=0;
+ strscpy(function_item,p2);
+ *p='"';
+ p++;
+ }
+ else ret = NOTSUPPORTED;
+ }
+
+ if(ret == SUCCEED)
+ {
+ if(*p != ',') ret = NOTSUPPORTED;
+ }
+
+ if(ret == SUCCEED)
+ {
+ if((p2=strchr(p,'"')) != NULL)
+ {
+ p2++;
+ }
+ else ret = NOTSUPPORTED;
+
+ if((ret == SUCCEED) && (p=strchr(p2,'"')) != NULL)
+ {
+ *p=0;
+ strscpy(parameter,p2);
+ *p='"';
+ p++;
+ }
+ else ret = NOTSUPPORTED;
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "Evaluating aggregate[%s] grpfunc[%s] group[%s] itemkey[%s] itemfunc [%s] parameter [%s]",
+ item->key,
+ function_grp,
+ group,
+ itemkey,
+ function_item,
+ parameter);
+
+ if( (ret == SUCCEED) &&
+ (evaluate_aggregate(result,function_grp, group, itemkey, function_item, parameter) != SUCCEED)
+ )
+ {
+ ret = NOTSUPPORTED;
+ }
+
+ return ret;
+}
diff --git a/src/zabbix_proxy/poller/checks_aggregate.h b/src/zabbix_proxy/poller/checks_aggregate.h
new file mode 100644
index 00000000..0d42b2bd
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_aggregate.h
@@ -0,0 +1,30 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_CHECKS_AGGREGATE_H
+#define ZABBIX_CHECKS_AGGREGATE_H
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "sysinfo.h"
+
+extern int get_value_aggregate(DB_ITEM *item, AGENT_RESULT *result);
+
+#endif
diff --git a/src/zabbix_proxy/poller/checks_db.c b/src/zabbix_proxy/poller/checks_db.c
new file mode 100644
index 00000000..bd3b9cf7
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_db.c
@@ -0,0 +1,201 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#ifdef HAVE_ODBC
+# include "zbxodbc.h"
+#endif /* HAVE_ODBC */
+
+#include "checks_db.h"
+#include "log.h"
+
+#ifdef HAVE_ODBC
+/******************************************************************************
+ * *
+ * Function: get_param_value *
+ * *
+ * Purpose: retrieve parameter value by name *
+ * *
+ * Parameters: params - list of params *
+ * param_name - name of requested parameter *
+ * *
+ * Return value: NULL - if parameter missedparam_name, *
+ * else return value in new allocated memory *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: this function allocate memory, required zbx_free for result!!! *
+ * one parameter format: param1_name=param1_value *
+ * parameters splited by '\n' *
+ * *
+ ******************************************************************************/
+static char* get_param_value(char* params, const char* param_name)
+{
+ char
+ *p = NULL,
+ *l = NULL,
+ *n = NULL,
+ *r = NULL,
+ *buf = NULL;
+
+ for(p = params; p && *p; p++)
+ {
+ r = NULL;
+
+ /* trim left spaces */
+ for(; *p == ' '; p++);
+
+ /* find '=' symbol */
+ for(n = p; *n && *n != '\n'; n++)
+ {
+ if(*n == '=')
+ {
+ /* trim right spaces */
+ for(l = n - 1; *l == ' '; l--);
+ l++;
+
+ /* compare parameter name */
+ if(l - p != strlen(param_name)) break;
+ if(strncmp(p, param_name, l - p)) break;
+
+ r = n+1;
+ break;
+ }
+ }
+
+ /* find EOL */
+ for(p = n; *p && *p != '\n'; p++);
+
+ /* allocate result */
+ if(r)
+ {
+ /* trim right EOL symbols */
+ while(*p == '\r' || *p == '\n' || *p == '\0') p--;
+ p++;
+
+ /* allocate result */
+ buf = zbx_malloc(buf, p - r + 1);
+ memmove(buf, r, p - r);
+ buf[p - r] = '\0';
+
+ break;
+ }
+ }
+
+ if(buf == NULL)
+ {
+ /* allocate result */
+ buf = zbx_malloc(buf, 1);
+ *buf = '\0';
+ }
+ return buf;
+}
+#endif /* HAVE_ODBC */
+
+/******************************************************************************
+ * *
+ * Function: get_value_db *
+ * *
+ * Purpose: retrieve data from database *
+ * *
+ * Parameters: item - item we are interested in *
+ * *
+ * Return value: SUCCEED - data succesfully retrieved and stored in result *
+ * NOTSUPPORTED - requested item is not supported *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int get_value_db(DB_ITEM *item, AGENT_RESULT *result)
+{
+#ifdef HAVE_ODBC
+ ZBX_ODBC_DBH dbh;
+ ZBX_ODBC_ROW row;
+
+ char
+ *db_dsn = NULL,
+ *db_user = NULL,
+ *db_pass = NULL,
+ *db_sql = NULL;
+#endif /* HAVE_ODBC */
+
+ int ret = NOTSUPPORTED;
+
+ init_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In database monitor: %s", item->key);
+
+#ifdef HAVE_ODBC
+
+ #define DB_ODBC_SELECT_KEY "db.odbc.select["
+
+ if(strncmp(item->key, DB_ODBC_SELECT_KEY, strlen(DB_ODBC_SELECT_KEY)) == 0)
+ {
+ db_dsn = get_param_value(item->params,"DSN");
+ db_user = get_param_value(item->params,"user");
+ db_pass = get_param_value(item->params,"password");
+ db_sql = get_param_value(item->params,"sql");
+
+ if( SUCCEED == odbc_DBconnect(&dbh, db_dsn, db_user, db_pass) )
+ {
+ if( NULL != (row = odbc_DBfetch(odbc_DBselect(&dbh, db_sql))) )
+ {
+ if( SUCCEED == set_result_type(result, item->value_type, row[0]) )
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Result accepted with type 0x%02X [%s]", item->value_type, row[0]);
+ ret = SUCCEED;
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "Cant determine result type [%s]", row[0]);
+ }
+ }
+ else
+ {
+ SET_MSG_RESULT(result, strdup(get_last_odbc_strerror()));
+ }
+ odbc_DBclose(&dbh);
+ }
+ else
+ {
+ SET_MSG_RESULT(result, strdup(get_last_odbc_strerror()));
+ }
+
+ zbx_free(db_dsn);
+ zbx_free(db_user);
+ zbx_free(db_pass);
+ zbx_free(db_sql);
+ }
+
+#endif /* HAVE_ODBC */
+
+ /*
+ * TODO:
+ *
+ * db.*.select[]
+ * db.*.ping
+ * ...
+ *
+ */
+
+ return ret;
+}
diff --git a/src/zabbix_proxy/poller/checks_db.h b/src/zabbix_proxy/poller/checks_db.h
new file mode 100644
index 00000000..e3b07d21
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_db.h
@@ -0,0 +1,28 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_CHECKS_DB_H
+#define ZABBIX_CHECKS_DB_H
+
+#include "db.h"
+#include "sysinfo.h"
+
+int get_value_db(DB_ITEM *item, AGENT_RESULT *result);
+
+#endif /* ZABBIX_CHECKS_DB_H */
diff --git a/src/zabbix_proxy/poller/checks_external.c b/src/zabbix_proxy/poller/checks_external.c
new file mode 100644
index 00000000..a4a164b7
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_external.c
@@ -0,0 +1,134 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+#include "checks_external.h"
+
+/******************************************************************************
+ * *
+ * Function: get_value_external *
+ * *
+ * Purpose: retrieve data from script executed on ZABBIX server *
+ * *
+ * Parameters: item - item we are interested in *
+ * *
+ * Return value: SUCCEED - data succesfully retrieved and stored in result *
+ * and result_str (as string) *
+ * NOTSUPPORTED - requested item is not supported *
+ * *
+ * Author: Mike Nestor *
+ * *
+ * Comments: *
+ * *
+ ************************************************** ****************************/
+int get_value_external(DB_ITEM *item, AGENT_RESULT *result)
+{
+ FILE* fp;
+ char scriptname[MAX_STRING_LEN];
+ char key[MAX_STRING_LEN];
+ char params[MAX_STRING_LEN];
+ char error[MAX_STRING_LEN];
+ char cmd[MAX_STRING_LEN];
+ char msg[MAX_STRING_LEN];
+ char *p,*p2;
+ int i;
+
+ int ret = SUCCEED;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_external([%s])",item->key);
+
+ init_result(result);
+
+ strscpy(key, item->key);
+ if((p2=strchr(key,'[')) != NULL)
+ {
+ *p2=0;
+ strscpy(scriptname,key);
+ zabbix_log( LOG_LEVEL_DEBUG, "scriptname [%s]",scriptname);
+ *p2='[';
+ p2++;
+ }
+ else ret = NOTSUPPORTED;
+
+ if(ret == SUCCEED)
+ {
+ if((ret == SUCCEED) && (p=strchr(p2,']')) != NULL)
+ {
+ *p=0;
+ strscpy(params,p2);
+ zabbix_log( LOG_LEVEL_DEBUG, "params [%s]",params);
+ *p=']';
+ p++;
+ }
+ else ret = NOTSUPPORTED;
+ }
+ else
+ {
+ zbx_snprintf(error,MAX_STRING_LEN-1,"External check [%s] is not supported", item->key);
+ zabbix_log( LOG_LEVEL_DEBUG, "%s", error);
+ SET_STR_RESULT(result, strdup(error));
+ return NOTSUPPORTED;
+ }
+
+ zbx_snprintf(cmd, MAX_STRING_LEN-1, "%s/%s %s %s",
+ CONFIG_EXTERNALSCRIPTS,
+ scriptname,
+/* item->host_name,*/
+ item->useip == 1 ? item->host_ip : item->host_dns,
+ params);
+ zabbix_log( LOG_LEVEL_DEBUG, "%s", cmd );
+ if (NULL == (fp = popen(cmd, "r")))
+ {
+ zbx_snprintf(error,MAX_STRING_LEN-1,"External check [%s] is not supported, failed execution", item->key);
+ zabbix_log( LOG_LEVEL_DEBUG, "%s", error);
+ SET_STR_RESULT(result, strdup(error));
+ return NOTSUPPORTED;
+ }
+
+ /* we only care about the first line */
+ memset(msg,0,sizeof(msg));
+ if(NULL != fgets(msg, sizeof(msg)-1, fp))
+ {
+ for (i = 0; i < MAX_STRING_LEN && msg[i] != 0; ++i)
+ {
+ if (msg[i] == '\n')
+ {
+ msg[i] = 0;
+ break;
+ }
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "Result [%s]", msg);
+
+ set_result_type(result,item->value_type,strdup(msg));
+ }
+ else
+ {
+ zbx_snprintf(error,MAX_STRING_LEN-1,"Script %s/%s returned nothing.",
+ CONFIG_EXTERNALSCRIPTS,
+ scriptname);
+ zabbix_log( LOG_LEVEL_WARNING, "%s", error);
+ SET_STR_RESULT(result, strdup(error));
+ ret = NOTSUPPORTED;
+ }
+
+ /* cleanup */
+ pclose(fp);
+
+ return ret;
+}
diff --git a/src/zabbix_proxy/poller/checks_external.h b/src/zabbix_proxy/poller/checks_external.h
new file mode 100644
index 00000000..cdabbaab
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_external.h
@@ -0,0 +1,36 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_CHECKS_EXTERNAL_H
+#define ZABBIX_CHECKS_EXTERNAL_H
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "sysinfo.h"
+
+extern char *CONFIG_EXTERNALSCRIPTS;
+
+extern int get_value_external(DB_ITEM *item, AGENT_RESULT *result);
+
+#endif
diff --git a/src/zabbix_proxy/poller/checks_internal.c b/src/zabbix_proxy/poller/checks_internal.c
new file mode 100644
index 00000000..ed53c36e
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_internal.c
@@ -0,0 +1,93 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+#include "checks_internal.h"
+
+/******************************************************************************
+ * *
+ * Function: get_value_internal *
+ * *
+ * Purpose: retrieve data from ZABBIX server (internally supported intems) *
+ * *
+ * Parameters: item - item we are interested in *
+ * *
+ * Return value: SUCCEED - data succesfully retrieved and stored in result *
+ * and result_str (as string) *
+ * NOTSUPPORTED - requested item is not supported *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int get_value_internal(DB_ITEM *item, AGENT_RESULT *result)
+{
+ zbx_uint64_t i;
+ char error[MAX_STRING_LEN];
+
+ init_result(result);
+
+ if(strcmp(item->key,"zabbix[triggers]")==0)
+ {
+ i = (zbx_uint64_t)DBget_triggers_count();
+ SET_UI64_RESULT(result, i);
+ }
+ else if(strcmp(item->key,"zabbix[items]")==0)
+ {
+ i = (zbx_uint64_t)DBget_items_count();
+ SET_UI64_RESULT(result, i);
+ }
+ else if(strcmp(item->key,"zabbix[items_unsupported]")==0)
+ {
+ i=DBget_items_unsupported_count();
+ SET_UI64_RESULT(result, i);
+ }
+ else if(strcmp(item->key,"zabbix[history]")==0)
+ {
+ i=DBget_history_count();
+ SET_UI64_RESULT(result, i);
+ }
+ else if(strcmp(item->key,"zabbix[history_str]")==0)
+ {
+ i=DBget_history_str_count();
+ SET_UI64_RESULT(result, i);
+ }
+ else if(strcmp(item->key,"zabbix[trends]")==0)
+ {
+ i=DBget_trends_count();
+ SET_UI64_RESULT(result, i);
+ }
+ else if(strcmp(item->key,"zabbix[queue]")==0)
+ {
+ i=DBget_queue_count();
+ SET_UI64_RESULT(result, i);
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"Internal check [%s] is not supported",
+ item->key);
+ zabbix_log( LOG_LEVEL_WARNING, "%s",
+ error);
+ SET_STR_RESULT(result, strdup(error));
+ return NOTSUPPORTED;
+ }
+
+ return SUCCEED;
+}
diff --git a/src/zabbix_proxy/poller/checks_internal.h b/src/zabbix_proxy/poller/checks_internal.h
new file mode 100644
index 00000000..da2bdf75
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_internal.h
@@ -0,0 +1,30 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_CHECKS_INTERNAL_H
+#define ZABBIX_CHECKS_INTERNAL_H
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "sysinfo.h"
+
+extern int get_value_internal(DB_ITEM *item, AGENT_RESULT *result);
+
+#endif
diff --git a/src/zabbix_proxy/poller/checks_simple.c b/src/zabbix_proxy/poller/checks_simple.c
new file mode 100644
index 00000000..bce26b2f
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_simple.c
@@ -0,0 +1,221 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "checks_simple.h"
+
+int get_value_simple(DB_ITEM *item, AGENT_RESULT *result)
+{
+ char *t;
+ char c[MAX_STRING_LEN];
+ char param[MAX_STRING_LEN];
+ char error[MAX_STRING_LEN];
+ char service[MAX_STRING_LEN];
+ char service_sysinfo[MAX_STRING_LEN];
+ char ip[MAX_STRING_LEN];
+ char port[MAX_STRING_LEN];
+ int port_int=0;
+ int ret = SUCCEED;
+ char *l,*r;
+ /* Assumption: host name does not contain '_perf' */
+
+ init_result(result);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_simple([%s]",
+ item->key);
+
+ if(0 == strncmp(item->key,"service.ntp",11))
+ {
+ l=strchr(item->key,'[');
+ r=strrchr(item->key,']');
+ if(l==NULL || r==NULL)
+ zbx_snprintf(c,sizeof(c),"net.tcp.service[%s]",
+ item->key);
+ else
+ {
+ zbx_strlcpy( param,l+1, r-l-1);
+ if(item->useip==1)
+ {
+ zbx_snprintf(c,sizeof(c),"net.tcp.service[%s,%s]",
+ item->key,
+ item->host_ip);
+ }
+ else
+ {
+ zbx_snprintf(c,sizeof(c),"net.tcp.service[%s,%s]",
+ item->key,
+ item->host_ip);
+ }
+ }
+ }
+ else if(0 == strncmp(item->key,"dns",3))
+ {
+ if(item->useip==1)
+ {
+ l=strchr(item->key,'[');
+ r=strrchr(item->key,']');
+ if(l==NULL || r==NULL)
+ zbx_snprintf(c,sizeof(c),"%s",
+ item->key);
+ else
+ {
+ zbx_strlcpy( param,l+1, r-l-1);
+/* zbx_snprintf(c,sizeof(c),"dns[%s,%s]",item->ip,param);*/
+ zbx_snprintf(c,sizeof(c),"dns[%s]",
+ param);
+ }
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"You must use IP address in Host %s definition",
+ item->host_name);
+ zabbix_log( LOG_LEVEL_WARNING, "%s",
+ error);
+ result->str=strdup(error);
+ return NOTSUPPORTED;
+ }
+ }
+ else
+ {
+ ip[0]=0;
+ port[0]=0;
+ service[0]=0;
+ if(num_param(item->key) == 1)
+ {
+ if(get_param(item->key, 1, service, MAX_STRING_LEN) != 0)
+ {
+ ret = NOTSUPPORTED;
+ }
+ }
+ else if(num_param(item->key) == 2)
+ {
+ if(get_param(item->key, 1, service, MAX_STRING_LEN) != 0)
+ {
+ ret = NOTSUPPORTED;
+ }
+ if(get_param(item->key, 2, port, MAX_STRING_LEN) != 0)
+ {
+ ret = NOTSUPPORTED;
+ }
+ else if(is_uint(port)==SUCCEED)
+ {
+ port_int=atoi(port);
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"Port number must be numeric in [%s]",
+ item->key);
+ zabbix_log( LOG_LEVEL_WARNING, "%s",
+ error);
+ result->str=strdup(error);
+ ret = NOTSUPPORTED;
+ }
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"Too many parameters in [%s]",
+ item->key);
+ zabbix_log( LOG_LEVEL_WARNING, "%s",
+ error);
+ result->str=strdup(error);
+ ret = NOTSUPPORTED;
+ }
+
+ if(ret == SUCCEED)
+ {
+ if(item->useip==1)
+ {
+ strscpy(ip,item->host_ip);
+ }
+ else
+ {
+ strscpy(ip,item->host_dns);
+ }
+
+ t = strstr(service,"_perf");
+ if(t != NULL)
+ {
+ t[0]=0;
+ strscpy(service_sysinfo,"net.tcp.service.perf");
+ }
+ else strscpy(service_sysinfo,"net.tcp.service");
+
+ if(port_int == 0)
+ {
+ zbx_snprintf(c,sizeof(c),"%s[%s,%s]",
+ service_sysinfo,
+ service,
+ ip);
+ }
+ else
+ {
+ zbx_snprintf(c,sizeof(c),"%s[%s,%s,%d]",
+ service_sysinfo,
+ service,
+ ip,
+ port_int);
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "Sysinfo [%s]",
+ c);
+ }
+ else
+ {
+ return ret;
+ }
+ }
+/*
+ else if(NULL == strstr(item->key,"_perf"))
+ {
+ if(item->useip==1)
+ {
+ zbx_snprintf(c,sizeof(c),"net.tcp.service[%s,%s]",item->key,item->ip);
+ }
+ else
+ {
+ zbx_snprintf(c,sizeof(c),"net.tcp.service[%s,%s]",item->key,item->host);
+ }
+ }
+ else
+ {
+ strscpy(s,item->key);
+ t=strstr(s,"_perf");
+ t[0]=0;
+
+ if(item->useip==1)
+ {
+ zbx_snprintf(c,sizeof(c),"net.tcp.service.perf[%s,%s]",s,item->ip);
+ }
+ else
+ {
+ zbx_snprintf(c,sizeof(c),"net.tcp.service.perf[%s,%s]",s,item->host);
+ }
+ }
+*/
+
+ if(process(c, 0, result) == NOTSUPPORTED)
+ {
+ zbx_snprintf(error,sizeof(error),"Simple check [%s] is not supported",
+ c);
+ zabbix_log( LOG_LEVEL_WARNING, "%s",
+ error);
+ result->str=strdup(error);
+ ret = NOTSUPPORTED;
+ }
+
+ return ret;
+}
diff --git a/src/zabbix_proxy/poller/checks_simple.h b/src/zabbix_proxy/poller/checks_simple.h
new file mode 100644
index 00000000..3b327214
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_simple.h
@@ -0,0 +1,30 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_CHECKS_SIMPLE_H
+#define ZABBIX_CHECKS_SIMPLE_H
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "sysinfo.h"
+
+extern int get_value_simple(DB_ITEM *item, AGENT_RESULT *result);
+
+#endif
diff --git a/src/zabbix_proxy/poller/checks_snmp.c b/src/zabbix_proxy/poller/checks_snmp.c
new file mode 100644
index 00000000..b289a1bc
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_snmp.c
@@ -0,0 +1,493 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "checks_snmp.h"
+
+#ifdef HAVE_SNMP
+int get_value_snmp(DB_ITEM *item, AGENT_RESULT *value)
+{
+
+ #define NEW_APPROACH
+
+ struct snmp_session session, *ss;
+ struct snmp_pdu *pdu;
+ struct snmp_pdu *response;
+
+#ifdef NEW_APPROACH
+ char temp[MAX_STRING_LEN];
+#endif
+
+ oid anOID[MAX_OID_LEN];
+ size_t anOID_len = MAX_OID_LEN;
+
+ struct variable_list *vars;
+ int status;
+
+ char *p, *c;
+
+ unsigned char *ip;
+
+ char error[MAX_STRING_LEN];
+
+ int ret=SUCCEED;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP()");
+
+ init_result(value);
+
+/* assert((item->type == ITEM_TYPE_SNMPv1)||(item->type == ITEM_TYPE_SNMPv2c)); */
+ assert((item->type == ITEM_TYPE_SNMPv1)||(item->type == ITEM_TYPE_SNMPv2c)||(item->type == ITEM_TYPE_SNMPv3));
+
+ snmp_sess_init( &session );
+/* session.version = version;*/
+ if(item->type == ITEM_TYPE_SNMPv1)
+ {
+ session.version = SNMP_VERSION_1;
+ }
+ else if(item->type == ITEM_TYPE_SNMPv2c)
+ {
+ session.version = SNMP_VERSION_2c;
+ }
+ else if(item->type == ITEM_TYPE_SNMPv3)
+ {
+ session.version = SNMP_VERSION_3;
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"Error in get_value_SNMP. Wrong item type [%d]. Must be SNMP.",
+ item->type);
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ return NOTSUPPORTED;
+ }
+
+
+ if(item->useip == 1)
+ {
+ #ifdef NEW_APPROACH
+ zbx_snprintf(temp,sizeof(temp),"%s:%d",
+ item->host_ip,
+ item->snmp_port);
+ session.peername = temp;
+ session.remote_port = item->snmp_port;
+ #else
+ session.peername = item->host_ip;
+ session.remote_port = item->snmp_port;
+ #endif
+ }
+ else
+ {
+ #ifdef NEW_APPROACH
+ zbx_snprintf(temp, sizeof(temp), "%s:%d",
+ item->host_dns,
+ item->snmp_port);
+ session.peername = temp;
+ session.remote_port = item->snmp_port;
+ #else
+ session.peername = item->host_dns;
+ session.remote_port = item->snmp_port;
+ #endif
+ }
+
+ if( (session.version == SNMP_VERSION_1) || (item->type == ITEM_TYPE_SNMPv2c))
+ {
+ session.community = (u_char *)item->snmp_community;
+ session.community_len = strlen((void *)session.community);
+ zabbix_log( LOG_LEVEL_DEBUG, "SNMP [%s@%s:%d]",
+ session.community,
+ session.peername,
+ session.remote_port);
+ }
+ else if(session.version == SNMP_VERSION_3)
+ {
+ /* set the SNMPv3 user name */
+ session.securityName = item->snmpv3_securityname;
+ session.securityNameLen = strlen(session.securityName);
+
+ /* set the security level to authenticated, but not encrypted */
+
+ if(item->snmpv3_securitylevel == ITEM_SNMPV3_SECURITYLEVEL_NOAUTHNOPRIV)
+ {
+ session.securityLevel = SNMP_SEC_LEVEL_NOAUTH;
+ }
+ else if(item->snmpv3_securitylevel == ITEM_SNMPV3_SECURITYLEVEL_AUTHNOPRIV)
+ {
+ session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
+
+ /* set the authentication method to MD5 */
+ session.securityAuthProto = usmHMACMD5AuthProtocol;
+ session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
+ session.securityAuthKeyLen = USM_AUTH_KU_LEN;
+
+ if (generate_Ku(session.securityAuthProto,
+ session.securityAuthProtoLen,
+ (u_char *) item->snmpv3_authpassphrase, strlen(item->snmpv3_authpassphrase),
+ session.securityAuthKey,
+ &session.securityAuthKeyLen) != SNMPERR_SUCCESS)
+ {
+ zbx_snprintf(error,sizeof(error),"Error generating Ku from authentication pass phrase.");
+
+ zabbix_log( LOG_LEVEL_ERR, "%s", error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ return NOTSUPPORTED;
+ }
+ }
+ else if(item->snmpv3_securitylevel == ITEM_SNMPV3_SECURITYLEVEL_AUTHPRIV)
+ {
+ session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;
+
+ /* set the authentication method to MD5 */
+ session.securityAuthProto = usmHMACMD5AuthProtocol;
+ session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
+ session.securityAuthKeyLen = USM_AUTH_KU_LEN;
+
+ if (generate_Ku(session.securityAuthProto,
+ session.securityAuthProtoLen,
+ (u_char *) item->snmpv3_authpassphrase, strlen(item->snmpv3_authpassphrase),
+ session.securityAuthKey,
+ &session.securityAuthKeyLen) != SNMPERR_SUCCESS)
+ {
+ zbx_snprintf(error,sizeof(error),"Error generating Ku from authentication pass phrase.");
+
+ zabbix_log( LOG_LEVEL_ERR, "%s", error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ return NOTSUPPORTED;
+ }
+
+ /* set the private method to DES */
+ session.securityPrivProto = usmDESPrivProtocol;
+ session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
+ session.securityPrivKeyLen = USM_PRIV_KU_LEN;
+
+ if (generate_Ku(session.securityAuthProto,
+ session.securityAuthProtoLen,
+ (u_char *) item->snmpv3_privpassphrase, strlen(item->snmpv3_privpassphrase),
+ session.securityPrivKey,
+ &session.securityPrivKeyLen) != SNMPERR_SUCCESS)
+ {
+ zbx_snprintf(error,sizeof(error),"Error generating Ku from priv pass phrase.");
+
+ zabbix_log( LOG_LEVEL_ERR, "%s", error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ return NOTSUPPORTED;
+ }
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "SNMPv3 [%s@%s:%d]",
+ session.securityName,
+ session.peername,
+ session.remote_port);
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"Error in get_value_SNMP. Unsupported session.version [%d]",
+ (int)session.version);
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ return NOTSUPPORTED;
+ }
+
+ zabbix_log( LOG_LEVEL_DEBUG, "OID [%s]",
+ item->snmp_oid);
+
+ SOCK_STARTUP;
+ ss = snmp_open(&session);
+
+ if(ss == NULL)
+ {
+ SOCK_CLEANUP;
+
+ zbx_snprintf(error,sizeof(error),"Error doing snmp_open()");
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ return NOTSUPPORTED;
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 0.2");
+
+ pdu = snmp_pdu_create(SNMP_MSG_GET);
+/* Changed to snmp_parse_oid */
+/* read_objid(item->snmp_oid, anOID, &anOID_len);*/
+ snmp_parse_oid(item->snmp_oid, anOID, &anOID_len);
+
+#if OTHER_METHODS
+ get_node("sysDescr.0", anOID, &anOID_len);
+ read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len);
+ read_objid("system.sysDescr.0", anOID, &anOID_len);
+#endif
+
+ snmp_add_null_var(pdu, anOID, anOID_len);
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 0.3");
+
+ status = snmp_synch_response(ss, pdu, &response);
+ zabbix_log( LOG_LEVEL_DEBUG, "Status send [%d]", status);
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 0.4");
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 1");
+
+ if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR)
+ {
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_value_SNMP() 2");
+/* for(vars = response->variables; vars; vars = vars->next_variable)
+ {
+ print_variable(vars->name, vars->name_length, vars);
+ }*/
+
+ for(vars = response->variables; vars; vars = vars->next_variable)
+ {
+ int count=1;
+ zabbix_log( LOG_LEVEL_DEBUG, "AV loop(%d)", vars->type);
+
+/* if( (vars->type == ASN_INTEGER) ||*/
+ if( (vars->type == ASN_UINTEGER)||
+ (vars->type == ASN_COUNTER) ||
+#ifdef OPAQUE_SPECIAL_TYPES
+ (vars->type == ASN_UNSIGNED64) ||
+#endif
+ (vars->type == ASN_TIMETICKS) ||
+ (vars->type == ASN_GAUGE)
+ )
+ {
+/* *result=(long)*vars->val.integer;*/
+ /*
+ * This solves situation when large numbers are stored as negative values
+ * http://sourceforge.net/tracker/index.php?func=detail&aid=700145&group_id=23494&atid=378683
+ */
+ /*zbx_snprintf(result_str,sizeof(result_str),"%ld",(long)*vars->val.integer);*/
+/* zbx_snprintf(result_str,sizeof(result_str),"%lu",(long)*vars->val.integer);*/
+
+ /* Not correct. Returns huge values. */
+/* SET_UI64_RESULT(value, (zbx_uint64_t)*vars->val.integer);*/
+ SET_UI64_RESULT(value, (unsigned long)*vars->val.integer);
+ zabbix_log( LOG_LEVEL_DEBUG, "OID [%s] Type [%d] UI64[" ZBX_FS_UI64 "]",
+ item->snmp_oid,
+ vars->type,
+ (zbx_uint64_t)*vars->val.integer);
+ zabbix_log( LOG_LEVEL_DEBUG, "OID [%s] Type [%d] ULONG[%lu]",
+ item->snmp_oid,
+ vars->type,
+ (zbx_uint64_t)(unsigned long)*vars->val.integer);
+ }
+ else if(vars->type == ASN_COUNTER64)
+ {
+ /* Incorrect code for 32 bit platforms */
+/* SET_UI64_RESULT(value, ((vars->val.counter64->high)<<32)+(vars->val.counter64->low));*/
+ SET_UI64_RESULT(value, (((zbx_uint64_t)vars->val.counter64->high)<<32)+((zbx_uint64_t)vars->val.counter64->low));
+ }
+ else if(vars->type == ASN_INTEGER
+#define ASN_FLOAT (ASN_APPLICATION | 8)
+#define ASN_DOUBLE (ASN_APPLICATION | 9)
+
+#ifdef OPAQUE_SPECIAL_TYPES
+ || (vars->type == ASN_INTEGER64)
+#endif
+ )
+ {
+ /* Negative integer values are converted to double */
+ if(*vars->val.integer<0)
+ {
+ SET_DBL_RESULT(value, (double)*vars->val.integer);
+ }
+ else
+ {
+ SET_UI64_RESULT(value, (zbx_uint64_t)*vars->val.integer);
+ }
+ }
+#ifdef OPAQUE_SPECIAL_TYPES
+ else if(vars->type == ASN_FLOAT)
+ {
+ SET_DBL_RESULT(value, *vars->val.floatVal);
+ }
+ else if(vars->type == ASN_DOUBLE)
+ {
+ SET_DBL_RESULT(value, *vars->val.doubleVal);
+ }
+#endif
+ else if(vars->type == ASN_OCTET_STR)
+ {
+ if(item->value_type == ITEM_VALUE_TYPE_FLOAT)
+ {
+ SET_DBL_RESULT(value, strtod((char*)vars->val.string,0));
+ }
+ else if(item->value_type != ITEM_VALUE_TYPE_STR)
+ {
+ zbx_snprintf(error,sizeof(error),"Cannot store SNMP string value (ASN_OCTET_STR) in item having numeric type");
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ ret = NOTSUPPORTED;
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "ASN_OCTET_STR [%s]", vars->val.string);
+ zabbix_log( LOG_LEVEL_DEBUG, "ASN_OCTET_STR [%d]", vars->val_len);
+
+ p = malloc(1024);
+ if(p)
+ {
+ memset(p,0,1024);
+ snprint_value(p, 1023, vars->name, vars->name_length, vars);
+ /* Skip STRING: and STRING_HEX: */
+ c=strchr(p,':');
+ if(c==NULL)
+ {
+ SET_STR_RESULT(value, strdup(p));
+ }
+ else
+ {
+ SET_STR_RESULT(value, strdup(c+1));
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "ASN_OCTET_STR [%s]", p);
+ free(p);
+ }
+ else
+ {
+ zbx_snprintf(error,MAX_STRING_LEN-1,"Cannot allocate required memory");
+ zabbix_log( LOG_LEVEL_ERR, "%s", error);
+ SET_MSG_RESULT(value, strdup(error));
+ }
+
+/* p = malloc(vars->val_len+1);
+ if(p)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Result [%s] len [%d]",vars->val.string,vars->val_len);
+ memcpy(p, vars->val.string, vars->val_len);
+ p[vars->val_len] = '\0';
+
+ SET_STR_RESULT(value, p);
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"Cannot allocate required memory");
+ zabbix_log( LOG_LEVEL_ERR, "%s", error);
+ SET_MSG_RESULT(value, strdup(error));
+ }*/
+ }
+ }
+ else if(vars->type == ASN_IPADDRESS)
+ {
+ if(item->value_type != ITEM_VALUE_TYPE_STR)
+ {
+ zbx_snprintf(error,sizeof(error),"Cannot store SNMP string value (ASN_IPADDRESS) in item having numeric type");
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+ ret = NOTSUPPORTED;
+ }
+ else
+ {
+ ip = vars->val.string;
+ SET_STR_RESULT(value, zbx_dsprintf(NULL, "%d.%d.%d.%d",
+ ip[0],
+ ip[1],
+ ip[2],
+ ip[3]));
+ }
+ }
+ else
+ {
+/* count is not really used. Has to be removed */
+ count++;
+
+ zbx_snprintf(error,sizeof(error),"OID [%s] value #%d has unknow type [%X]",
+ item->snmp_oid,
+ count,
+ vars->type);
+
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ ret = NOTSUPPORTED;
+ }
+ }
+ }
+ else
+ {
+ if (status == STAT_SUCCESS)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "SNMP error in packet. Reason: %s\n",
+ snmp_errstring(response->errstat));
+ if(response->errstat == SNMP_ERR_NOSUCHNAME)
+ {
+ zbx_snprintf(error,sizeof(error),"SNMP error [%s]",
+ snmp_errstring(response->errstat));
+
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ ret=NOTSUPPORTED;
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"SNMP error [%s]",
+ snmp_errstring(response->errstat));
+
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ ret=NOTSUPPORTED;
+ }
+ }
+ else if(status == STAT_TIMEOUT)
+ {
+ zbx_snprintf(error,sizeof(error),"Timeout while connecting to [%s]",
+ session.peername);
+
+/* snmp_sess_perror("snmpget", ss);*/
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ ret = NETWORK_ERROR;
+ }
+ else
+ {
+ zbx_snprintf(error,sizeof(error),"SNMP error [%d]",
+ status);
+
+ zabbix_log( LOG_LEVEL_ERR, "%s",
+ error);
+ SET_MSG_RESULT(value, strdup(error));
+
+ ret=NOTSUPPORTED;
+ }
+ }
+
+ if (response)
+ {
+ snmp_free_pdu(response);
+ }
+ snmp_close(ss);
+
+ SOCK_CLEANUP;
+ return ret;
+}
+#endif
diff --git a/src/zabbix_proxy/poller/checks_snmp.h b/src/zabbix_proxy/poller/checks_snmp.h
new file mode 100644
index 00000000..c574c874
--- /dev/null
+++ b/src/zabbix_proxy/poller/checks_snmp.h
@@ -0,0 +1,30 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_CHECKS_SNMP_H
+#define ZABBIX_CHECKS_SNMP_H
+
+#include "common.h"
+#include "log.h"
+#include "db.h"
+#include "sysinfo.h"
+
+int get_value_snmp(DB_ITEM *item, AGENT_RESULT *value);
+
+#endif
diff --git a/src/zabbix_proxy/poller/poller.c b/src/zabbix_proxy/poller/poller.c
new file mode 100644
index 00000000..8435d15e
--- /dev/null
+++ b/src/zabbix_proxy/poller/poller.c
@@ -0,0 +1,579 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "zlog.h"
+
+#include "../functions.h"
+#include "../expression.h"
+#include "poller.h"
+
+#include "db.h"
+#include "sysinfo.h"
+
+#include "checks_agent.h"
+#include "checks_aggregate.h"
+#include "checks_external.h"
+#include "checks_internal.h"
+#include "checks_simple.h"
+#include "checks_snmp.h"
+#include "checks_db.h"
+
+#include "daemon.h"
+
+AGENT_RESULT result;
+
+int poller_type;
+int poller_num;
+
+int get_value(DB_ITEM *item, AGENT_RESULT *result)
+{
+ int res=FAIL;
+
+ struct sigaction phan;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In get_value(key:%s)",
+ item->key);
+
+ phan.sa_handler = &child_signal_handler;
+ sigemptyset(&phan.sa_mask);
+ phan.sa_flags = 0;
+ sigaction(SIGALRM, &phan, NULL);
+
+ alarm(CONFIG_TIMEOUT);
+
+ if(item->type == ITEM_TYPE_ZABBIX)
+ {
+ res=get_value_agent(item, result);
+ }
+ else if( (item->type == ITEM_TYPE_SNMPv1) || (item->type == ITEM_TYPE_SNMPv2c) || (item->type == ITEM_TYPE_SNMPv3))
+ {
+#ifdef HAVE_SNMP
+ res=get_value_snmp(item, result);
+#else
+ zabbix_log(LOG_LEVEL_WARNING, "Support of SNMP parameters was not compiled in");
+ zabbix_syslog("Support of SNMP parameters was not compiled in. Cannot process [%s:%s]",
+ item->host_name,
+ item->key);
+ res=NOTSUPPORTED;
+#endif
+ }
+ else if(item->type == ITEM_TYPE_SIMPLE)
+ {
+ res=get_value_simple(item, result);
+ }
+ else if(item->type == ITEM_TYPE_INTERNAL)
+ {
+ res=get_value_internal(item, result);
+ }
+ else if(item->type == ITEM_TYPE_DB_MONITOR)
+ {
+ res=get_value_db(item, result);
+ }
+ else if(item->type == ITEM_TYPE_AGGREGATE)
+ {
+ res=get_value_aggregate(item, result);
+ }
+ else if(item->type == ITEM_TYPE_EXTERNAL)
+ {
+ res=get_value_external(item, result);
+ }
+ else
+ {
+ zabbix_log(LOG_LEVEL_WARNING, "Not supported item type:%d",
+ item->type);
+ zabbix_syslog("Not supported item type:%d",
+ item->type);
+ res=NOTSUPPORTED;
+ }
+ alarm(0);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End get_value()");
+ return res;
+}
+
+static int get_minnextcheck(int now)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ int res;
+
+/* Host status 0 == MONITORED
+ 1 == NOT MONITORED
+ 2 == UNREACHABLE */
+ if(poller_type == ZBX_POLLER_TYPE_UNREACHABLE)
+ {
+ result = DBselect("select count(*),min(nextcheck) as nextcheck from items i,hosts h where " ZBX_SQL_MOD(h.hostid,%d) "=%d and i.nextcheck<=%d and i.status in (%d) and i.type not in (%d,%d,%d) and h.status=%d and h.disable_until<=%d and h.errors_from!=0 and h.hostid=i.hostid and i.key_ not in ('%s','%s','%s','%s') and " ZBX_COND_NODEID "order by nextcheck",
+ CONFIG_UNREACHABLE_POLLER_FORKS,
+ poller_num-1,
+ now,
+ ITEM_STATUS_ACTIVE,
+ ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST,
+ HOST_STATUS_MONITORED,
+ now,
+ SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY,
+ LOCAL_NODE("h.hostid"));
+ }
+ else
+ {
+ if(CONFIG_REFRESH_UNSUPPORTED != 0)
+ {
+ result = DBselect("select count(*),min(nextcheck) from items i,hosts h where h.status=%d and h.disable_until<%d and h.errors_from=0 and h.hostid=i.hostid and i.status in (%d,%d) and i.type not in (%d,%d,%d) and " ZBX_SQL_MOD(i.itemid,%d) "=%d and i.key_ not in ('%s','%s','%s','%s') and" ZBX_COND_NODEID,
+ HOST_STATUS_MONITORED,
+ now,
+ ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED,
+ ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST,
+ CONFIG_POLLER_FORKS,
+ poller_num-1,
+ SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY,
+ LOCAL_NODE("h.hostid"));
+ }
+ else
+ {
+ result = DBselect("select count(*),min(nextcheck) from items i,hosts h where h.status=%d and h.disable_until<%d and h.errors_from=0 and h.hostid=i.hostid and i.status in (%d) and i.type not in (%d,%d,%d) and " ZBX_SQL_MOD(i.itemid,%d) "=%d and i.key_ not in ('%s','%s','%s','%s') and" ZBX_COND_NODEID,
+ HOST_STATUS_MONITORED,
+ now,
+ ITEM_STATUS_ACTIVE,
+ ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST,
+ CONFIG_POLLER_FORKS,
+ poller_num-1,
+ SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY,
+ LOCAL_NODE("h.hostid"));
+ }
+ }
+
+ row=DBfetch(result);
+
+ if(!row || DBis_null(row[0])==SUCCEED || DBis_null(row[1])==SUCCEED)
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "No items to update for minnextcheck.");
+ res = FAIL;
+ }
+ else
+ {
+ if( atoi(row[0]) == 0)
+ {
+ res = FAIL;
+ }
+ else
+ {
+ res = atoi(row[1]);
+ }
+ }
+ DBfree_result(result);
+
+ return res;
+}
+
+/* Update special host's item - "status" */
+static void update_key_status(zbx_uint64_t hostid,int host_status)
+{
+/* char value_str[MAX_STRING_LEN];*/
+ AGENT_RESULT agent;
+
+ DB_ITEM item;
+ DB_RESULT result;
+ DB_ROW row;
+
+ int update;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In update_key_status(" ZBX_FS_UI64 ",%d)",
+ hostid,
+ host_status);
+
+ result = DBselect("select %s where h.hostid=i.hostid and h.hostid=" ZBX_FS_UI64 " and i.key_='%s'",
+ ZBX_SQL_ITEM_SELECT,
+ hostid,
+ SERVER_STATUS_KEY);
+
+ row = DBfetch(result);
+
+ if(row)
+ {
+ DBget_item_from_db(&item,row);
+
+/* Do not process new value for status, if previous status is the same */
+ update = (item.lastvalue_null==1);
+ update = update || ((item.value_type == ITEM_VALUE_TYPE_FLOAT) &&(cmp_double(item.lastvalue_dbl, (double)host_status) == 1));
+ update = update || ((item.value_type == ITEM_VALUE_TYPE_UINT64) &&(item.lastvalue_uint64 != host_status));
+
+ if(update)
+ {
+ init_result(&agent);
+ SET_UI64_RESULT(&agent, host_status);
+ process_new_value(&item,&agent);
+ free_result(&agent);
+
+ update_triggers(item.itemid);
+ }
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No items to update.");
+ }
+
+ DBfree_result(result);
+}
+
+/******************************************************************************
+ * *
+ * Function: get_values *
+ * *
+ * Purpose: retrieve values of metrics from monitored hosts *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: always SUCCEED *
+ * *
+ ******************************************************************************/
+int get_values(void)
+{
+ DB_RESULT result;
+ DB_RESULT result2;
+ DB_ROW row;
+ DB_ROW row2;
+
+ int now;
+ int delay;
+ int res;
+ DB_ITEM item;
+ AGENT_RESULT agent;
+ int stop=0;
+
+ char *unreachable_hosts = NULL;
+ char tmp[MAX_STRING_LEN];
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In get_values()");
+
+ now = time(NULL);
+
+ zbx_snprintf(tmp,sizeof(tmp)-1,ZBX_FS_UI64,0);
+ unreachable_hosts=zbx_strdcat(unreachable_hosts,tmp);
+
+ /* Poller for unreachable hosts */
+ if(poller_type == ZBX_POLLER_TYPE_UNREACHABLE)
+ {
+ result = DBselect("select h.hostid,min(i.itemid) from hosts h,items i where " ZBX_SQL_MOD(h.hostid,%d) "=%d and i.nextcheck<=%d and i.status in (%d) and i.type not in (%d,%d,%d) and h.status=%d and h.disable_until<=%d and h.errors_from!=0 and h.hostid=i.hostid and i.key_ not in ('%s','%s','%s','%s') and " ZBX_COND_NODEID " group by h.hostid",
+ CONFIG_UNREACHABLE_POLLER_FORKS,
+ poller_num-1,
+ now,
+ ITEM_STATUS_ACTIVE,
+ ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST,
+ HOST_STATUS_MONITORED,
+ now,
+ SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY,
+ LOCAL_NODE("h.hostid"));
+ }
+ else
+ {
+ if(CONFIG_REFRESH_UNSUPPORTED != 0)
+ {
+ result = DBselect("select %s where i.nextcheck<=%d and i.status in (%d,%d) and i.type not in (%d,%d,%d) and h.status=%d and h.disable_until<=%d and h.errors_from=0 and h.hostid=i.hostid and " ZBX_SQL_MOD(i.itemid,%d) "=%d and i.key_ not in ('%s','%s','%s','%s') and " ZBX_COND_NODEID " order by i.nextcheck",
+ ZBX_SQL_ITEM_SELECT,
+ now,
+ ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED,
+ ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST,
+ HOST_STATUS_MONITORED,
+ now,
+ CONFIG_POLLER_FORKS,
+ poller_num-1,
+ SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY,
+ LOCAL_NODE("h.hostid"));
+ }
+ else
+ {
+ result = DBselect("select %s where i.nextcheck<=%d and i.status in (%d) and i.type not in (%d,%d,%d) and h.status=%d and h.disable_until<=%d and h.errors_from=0 and h.hostid=i.hostid and " ZBX_SQL_MOD(i.itemid,%d) "=%d and i.key_ not in ('%s','%s','%s','%s') and " ZBX_COND_NODEID " order by i.nextcheck",
+ ZBX_SQL_ITEM_SELECT,
+ now,
+ ITEM_STATUS_ACTIVE,
+ ITEM_TYPE_TRAPPER, ITEM_TYPE_ZABBIX_ACTIVE, ITEM_TYPE_HTTPTEST,
+ HOST_STATUS_MONITORED,
+ now,
+ CONFIG_POLLER_FORKS,
+ poller_num-1,
+ SERVER_STATUS_KEY, SERVER_ICMPPING_KEY, SERVER_ICMPPINGSEC_KEY,SERVER_ZABBIXLOG_KEY,
+ LOCAL_NODE("h.hostid"));
+ }
+ }
+
+ /* Do not stop when select is made by poller for unreachable hosts */
+ while((row=DBfetch(result))&&(stop==0 || poller_type == ZBX_POLLER_TYPE_UNREACHABLE))
+ {
+ /* This code is just to avoid compilation warining about use of uninitialized result2 */
+ result2 = result;
+ /* */
+
+ /* Poller for unreachable hosts */
+ if(poller_type == ZBX_POLLER_TYPE_UNREACHABLE)
+ {
+ result2 = DBselect("select %s where h.hostid=i.hostid and i.itemid=%s and" ZBX_COND_NODEID,
+ ZBX_SQL_ITEM_SELECT,
+ row[1],
+ LOCAL_NODE("h.hostid"));
+
+ row2 = DBfetch(result2);
+
+ if(!row2)
+ {
+ DBfree_result(result2);
+ continue;
+ }
+ DBget_item_from_db(&item,row2);
+ }
+ else
+ {
+ DBget_item_from_db(&item,row);
+ /* Skip unreachable hosts but do not break the loop. */
+ if(uint64_in_list(unreachable_hosts,item.hostid) == SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "Host " ZBX_FS_UI64 " is unreachable. Skipping [%s]",
+ item.hostid,item.key);
+ continue;
+ }
+ }
+
+ init_result(&agent);
+ res = get_value(&item, &agent);
+
+ DBbegin();
+
+ if(res == SUCCEED )
+ {
+
+ process_new_value(&item,&agent);
+
+ if(HOST_AVAILABLE_TRUE != item.host_available)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Enabling host [%s]",
+ item.host_name);
+ zabbix_syslog("Enabling host [%s]",
+ item.host_name);
+
+ now = time(NULL);
+ DBupdate_host_availability(item.hostid,HOST_AVAILABLE_TRUE,now,agent.msg);
+
+ update_key_status(item.hostid, HOST_STATUS_MONITORED); /* 0 */
+ item.host_available=HOST_AVAILABLE_TRUE;
+
+ stop=1;
+ }
+ if(item.host_errors_from!=0)
+ {
+ DBexecute("update hosts set errors_from=0 where hostid=" ZBX_FS_UI64,
+ item.hostid);
+
+ stop=1;
+ }
+ update_triggers(item.itemid);
+ }
+ else if(res == NOTSUPPORTED || res == AGENT_ERROR)
+ {
+ now = time(NULL);
+ if(item.status == ITEM_STATUS_NOTSUPPORTED)
+ {
+ /* It is not correct */
+/* snprintf(sql,sizeof(sql)-1,"update items set nextcheck=%d, lastclock=%d where itemid=%d",calculate_item_nextcheck(item.itemid, CONFIG_REFRESH_UNSUPPORTED,now), now, item.itemid);*/
+ DBexecute("update items set nextcheck=%d, lastclock=%d where itemid=" ZBX_FS_UI64,
+ CONFIG_REFRESH_UNSUPPORTED+now,
+ now,
+ item.itemid);
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Parameter [%s] is not supported by agent on host [%s] Old status [%d]",
+ item.key,
+ item.host_name,
+ item.status);
+ zabbix_syslog("Parameter [%s] is not supported by agent on host [%s]",
+ item.key,
+ item.host_name);
+ DBupdate_item_status_to_notsupported(item.itemid, agent.msg);
+ /* if(HOST_STATUS_UNREACHABLE == item.host_status)*/
+ if(HOST_AVAILABLE_TRUE != item.host_available)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Enabling host [%s]",
+ item.host_name);
+ zabbix_syslog("Enabling host [%s]",
+ item.host_name);
+ DBupdate_host_availability(item.hostid,HOST_AVAILABLE_TRUE,now,agent.msg);
+ update_key_status(item.hostid, HOST_STATUS_MONITORED); /* 0 */
+ item.host_available=HOST_AVAILABLE_TRUE;
+
+ stop=1;
+ }
+ }
+ }
+ else if(res == NETWORK_ERROR)
+ {
+ now = time(NULL);
+
+ /* First error */
+ if(item.host_errors_from==0)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Host [%s]: first network error, wait for %d seconds",
+ item.host_name,
+ CONFIG_UNREACHABLE_DELAY);
+ zabbix_syslog("Host [%s]: first network error, wait for %d seconds",
+ item.host_name,
+ CONFIG_UNREACHABLE_DELAY);
+
+ item.host_errors_from=now;
+ DBexecute("update hosts set errors_from=%d,disable_until=%d where hostid=" ZBX_FS_UI64,
+ now,
+ now+CONFIG_UNREACHABLE_DELAY,
+ item.hostid);
+
+ delay = MIN(4*item.delay, 300);
+ zabbix_log( LOG_LEVEL_WARNING, "Parameter [%s] will be checked after %d seconds on host [%s]",
+ item.key,
+ delay,
+ item.host_name);
+ DBexecute("update items set nextcheck=%d where itemid=" ZBX_FS_UI64,
+ now + delay,
+ item.itemid);
+ }
+ else
+ {
+ if(now-item.host_errors_from>CONFIG_UNREACHABLE_PERIOD)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Host [%s] will be checked after %d seconds",
+ item.host_name,
+ CONFIG_UNAVAILABLE_DELAY);
+ zabbix_syslog("Host [%s] will be checked after %d seconds",
+ item.host_name,
+ CONFIG_UNAVAILABLE_DELAY);
+
+ DBupdate_host_availability(item.hostid,HOST_AVAILABLE_FALSE,now,agent.msg);
+ update_key_status(item.hostid,HOST_AVAILABLE_FALSE); /* 2 */
+ item.host_available=HOST_AVAILABLE_FALSE;
+
+ DBexecute("update hosts set disable_until=%d where hostid=" ZBX_FS_UI64,
+ now+CONFIG_UNAVAILABLE_DELAY,
+ item.hostid);
+ }
+ /* Still unavailable, but won't change status to UNAVAILABLE yet */
+ else
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Host [%s]: another network error, wait for %d seconds",
+ item.host_name,
+ CONFIG_UNREACHABLE_DELAY);
+ zabbix_syslog("Host [%s]: another network error, wait for %d seconds",
+ item.host_name,
+ CONFIG_UNREACHABLE_DELAY);
+
+ DBexecute("update hosts set disable_until=%d where hostid=" ZBX_FS_UI64,
+ now+CONFIG_UNREACHABLE_DELAY,
+ item.hostid);
+ }
+ }
+
+ zbx_snprintf(tmp,sizeof(tmp)-1,"," ZBX_FS_UI64,item.hostid);
+ unreachable_hosts=zbx_strdcat(unreachable_hosts,tmp);
+
+/* stop=1;*/
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_CRIT, "Unknown response code returned.");
+ assert(0==1);
+ }
+ /* Poller for unreachable hosts */
+ if(poller_type == ZBX_POLLER_TYPE_UNREACHABLE)
+ {
+ /* We cannot freeit earlier because items has references to the structure */
+ DBfree_result(result2);
+ }
+ free_result(&agent);
+ DBcommit();
+ }
+
+ zbx_free(unreachable_hosts);
+
+ DBfree_result(result);
+ zabbix_log( LOG_LEVEL_DEBUG, "End get_values()");
+ return SUCCEED;
+}
+
+void main_poller_loop(int type, int num)
+{
+ int now;
+ int nextcheck,sleeptime;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In main_poller_loop(type:%d,num:%d)",
+ type,
+ num);
+
+ poller_type = type;
+ poller_num = num;
+
+ DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+ for(;;)
+ {
+ zbx_setproctitle("poller [getting values]");
+
+ now=time(NULL);
+ get_values();
+
+ zabbix_log( LOG_LEVEL_DEBUG, "Spent %d seconds while updating values",
+ (int)time(NULL)-now );
+
+ nextcheck=get_minnextcheck(now);
+ zabbix_log( LOG_LEVEL_DEBUG, "Nextcheck:%d Time:%d",
+ nextcheck,
+ (int)time(NULL) );
+
+ if( FAIL == nextcheck)
+ {
+ sleeptime=POLLER_DELAY;
+ }
+ else
+ {
+ sleeptime=nextcheck-time(NULL);
+ if(sleeptime<0)
+ {
+ sleeptime=0;
+ }
+ }
+ if(sleeptime>0)
+ {
+ if(sleeptime > POLLER_DELAY)
+ {
+ sleeptime = POLLER_DELAY;
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "Sleeping for %d seconds",
+ sleeptime );
+
+ zbx_setproctitle("poller [sleeping for %d seconds]",
+ sleeptime);
+
+ sleep( sleeptime );
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "No sleeping" );
+ }
+ }
+}
diff --git a/src/zabbix_proxy/poller/poller.h b/src/zabbix_proxy/poller/poller.h
new file mode 100644
index 00000000..6f08111c
--- /dev/null
+++ b/src/zabbix_proxy/poller/poller.h
@@ -0,0 +1,40 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_POLLER_H
+#define ZABBIX_POLLER_H
+
+extern void signal_handler(int);
+extern int server_num;
+
+extern int CONFIG_TIMEOUT;
+extern int CONFIG_POLLER_FORKS;
+extern int CONFIG_UNREACHABLE_POLLER_FORKS;
+extern int CONFIG_UNAVAILABLE_DELAY;
+extern int CONFIG_UNREACHABLE_PERIOD;
+extern int CONFIG_UNREACHABLE_DELAY;
+
+void main_poller_loop(int type, int num);
+
+#include "db.h"
+#include "sysinfo.h"
+
+int get_value(DB_ITEM *item, AGENT_RESULT *result);
+
+#endif
diff --git a/src/zabbix_proxy/proxy.c b/src/zabbix_proxy/proxy.c
new file mode 100644
index 00000000..7c69860a
--- /dev/null
+++ b/src/zabbix_proxy/proxy.c
@@ -0,0 +1,569 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "pid.h"
+#include "db.h"
+#include "dbcache.h"
+#include "log.h"
+#include "zlog.h"
+#include "zbxgetopt.h"
+#include "mutexs.h"
+
+#include "functions.h"
+#include "expression.h"
+#include "sysinfo.h"
+
+#include "daemon.h"
+
+#include "dbsyncer/dbsyncer.h"
+#include "discoverer/discoverer.h"
+#include "httppoller/httppoller.h"
+#include "housekeeper/housekeeper.h"
+#include "pinger/pinger.h"
+#include "poller/poller.h"
+#include "poller/checks_snmp.h"
+#include "trapper/trapper.h"
+#include "nodewatcher/nodewatcher.h"
+
+/*
+#define LISTENQ 1024
+*/
+char *progname = NULL;
+char title_message[] = "ZABBIX Proxy (daemon)";
+char usage_message[] = "[-hV] [-c <file>]";
+
+#ifndef HAVE_GETOPT_LONG
+char *help_message[] = {
+ "Options:",
+ " -c <file> Specify configuration file",
+ " -h give this help",
+ " -V display version number",
+ 0 /* end of text */
+};
+#else
+char *help_message[] = {
+ "Options:",
+ " -c --config <file> Specify configuration file",
+ " -h --help give this help",
+ " -V --version display version number",
+ 0 /* end of text */
+};
+#endif
+
+/* COMMAND LINE OPTIONS */
+
+/* long options */
+
+static struct zbx_option longopts[] =
+{
+ {"config", 1, 0, 'c'},
+ {"help", 0, 0, 'h'},
+ {"version", 0, 0, 'V'},
+
+#if defined (_WINDOWS)
+
+ {"install", 0, 0, 'i'},
+ {"uninstall", 0, 0, 'd'},
+
+ {"start", 0, 0, 's'},
+ {"stop", 0, 0, 'x'},
+
+#endif /* _WINDOWS */
+
+ {0,0,0,0}
+};
+
+/* short options */
+
+static char shortopts[] =
+ "c:n:hV"
+#if defined (_WINDOWS)
+ "idsx"
+#endif /* _WINDOWS */
+ ;
+
+/* end of COMMAND LINE OPTIONS*/
+
+pid_t *threads=NULL;
+
+int CONFIG_DBSYNCER_FORKS = 0;//1;
+int CONFIG_DISCOVERER_FORKS = 1;
+int CONFIG_HOUSEKEEPER_FORKS = 1;
+int CONFIG_NODEWATCHER_FORKS = 1;
+int CONFIG_PINGER_FORKS = 1;
+int CONFIG_POLLER_FORKS = 5;
+int CONFIG_HTTPPOLLER_FORKS = 5;
+int CONFIG_TRAPPERD_FORKS = 5;
+int CONFIG_UNREACHABLE_POLLER_FORKS = 1;
+
+int CONFIG_LISTEN_PORT = 10051;
+char *CONFIG_LISTEN_IP = NULL;
+int CONFIG_TRAPPER_TIMEOUT = TRAPPER_TIMEOUT;
+/**/
+/*int CONFIG_NOTIMEWAIT =0;*/
+int CONFIG_HOUSEKEEPING_FREQUENCY = 1;
+int CONFIG_SENDER_FREQUENCY = 30;
+int CONFIG_DBSYNCER_FREQUENCY = 5;
+int CONFIG_PINGER_FREQUENCY = 60;
+/*int CONFIG_DISABLE_PINGER = 0;*/
+int CONFIG_DISABLE_HOUSEKEEPING = 0;
+int CONFIG_UNREACHABLE_PERIOD = 45;
+int CONFIG_UNREACHABLE_DELAY = 15;
+int CONFIG_UNAVAILABLE_DELAY = 60;
+int CONFIG_LOG_LEVEL = LOG_LEVEL_WARNING;
+char *CONFIG_ALERT_SCRIPTS_PATH = NULL;
+char *CONFIG_EXTERNALSCRIPTS = NULL;
+char *CONFIG_FPING_LOCATION = NULL;
+char *CONFIG_DBHOST = NULL;
+char *CONFIG_DBNAME = NULL;
+char *CONFIG_DBUSER = NULL;
+char *CONFIG_DBPASSWORD = NULL;
+char *CONFIG_DBSOCKET = NULL;
+int CONFIG_DBPORT = 0;
+int CONFIG_ENABLE_REMOTE_COMMANDS = 0;
+
+int CONFIG_NODEID = 0;
+int CONFIG_MASTER_NODEID = 0;
+int CONFIG_NODE_NOEVENTS = 0;
+int CONFIG_NODE_NOHISTORY = 0;
+
+/* Global variable to control if we should write warnings to log[] */
+int CONFIG_ENABLE_LOG = 1;
+
+/* From table config */
+int CONFIG_REFRESH_UNSUPPORTED = 0;
+
+/* Zabbix server sturtup time */
+int CONFIG_SERVER_STARTUP_TIME = 0;
+
+/* Mutex for node syncs */
+ZBX_MUTEX node_sync_access;
+
+/******************************************************************************
+ * *
+ * Function: init_config *
+ * *
+ * Purpose: parse config file and update configuration parameters *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: will terminate process if parsing fails *
+ * *
+ ******************************************************************************/
+void init_config(void)
+{
+ static struct cfg_line cfg[]=
+ {
+/* PARAMETER ,VAR ,FUNC, TYPE(0i,1s),MANDATORY,MIN,MAX */
+/* {"StartDBSyncers",&CONFIG_DBSYNCER_FORKS,0,TYPE_INT,PARM_OPT,0,1},*/
+ {"StartDiscoverers",&CONFIG_DISCOVERER_FORKS,0,TYPE_INT,PARM_OPT,0,255},
+ {"StartHTTPPollers",&CONFIG_HTTPPOLLER_FORKS,0,TYPE_INT,PARM_OPT,0,255},
+ {"StartPingers",&CONFIG_PINGER_FORKS,0,TYPE_INT,PARM_OPT,0,255},
+ {"StartPollers",&CONFIG_POLLER_FORKS,0,TYPE_INT,PARM_OPT,0,255},
+ {"StartPollersUnreachable",&CONFIG_UNREACHABLE_POLLER_FORKS,0,TYPE_INT,PARM_OPT,0,255},
+ {"StartTrappers",&CONFIG_TRAPPERD_FORKS,0,TYPE_INT,PARM_OPT,0,255},
+ {"HousekeepingFrequency",&CONFIG_HOUSEKEEPING_FREQUENCY,0,TYPE_INT,PARM_OPT,1,24},
+ {"SenderFrequency",&CONFIG_SENDER_FREQUENCY,0,TYPE_INT,PARM_OPT,5,3600},
+ {"PingerFrequency",&CONFIG_PINGER_FREQUENCY,0,TYPE_INT,PARM_OPT,1,3600},
+ {"FpingLocation",&CONFIG_FPING_LOCATION,0,TYPE_STRING,PARM_OPT,0,0},
+ {"Timeout",&CONFIG_TIMEOUT,0,TYPE_INT,PARM_OPT,1,30},
+ {"TrapperTimeout",&CONFIG_TRAPPER_TIMEOUT,0,TYPE_INT,PARM_OPT,1,30},
+ {"UnreachablePeriod",&CONFIG_UNREACHABLE_PERIOD,0,TYPE_INT,PARM_OPT,1,3600},
+ {"UnreachableDelay",&CONFIG_UNREACHABLE_DELAY,0,TYPE_INT,PARM_OPT,1,3600},
+ {"UnavailableDelay",&CONFIG_UNAVAILABLE_DELAY,0,TYPE_INT,PARM_OPT,1,3600},
+ {"ListenIP",&CONFIG_LISTEN_IP,0,TYPE_STRING,PARM_OPT,0,0},
+ {"ListenPort",&CONFIG_LISTEN_PORT,0,TYPE_INT,PARM_OPT,1024,32768},
+/* {"NoTimeWait",&CONFIG_NOTIMEWAIT,0,TYPE_INT,PARM_OPT,0,1},*/
+/* {"DisablePinger",&CONFIG_DISABLE_PINGER,0,TYPE_INT,PARM_OPT,0,1},*/
+ {"DisableHousekeeping",&CONFIG_DISABLE_HOUSEKEEPING,0,TYPE_INT,PARM_OPT,0,1},
+ {"DebugLevel",&CONFIG_LOG_LEVEL,0,TYPE_INT,PARM_OPT,0,4},
+ {"PidFile",&APP_PID_FILE,0,TYPE_STRING,PARM_OPT,0,0},
+ {"LogFile",&CONFIG_LOG_FILE,0,TYPE_STRING,PARM_OPT,0,0},
+ {"LogFileSize",&CONFIG_LOG_FILE_SIZE,0,TYPE_INT,PARM_OPT,0,1024},
+ {"AlertScriptsPath",&CONFIG_ALERT_SCRIPTS_PATH,0,TYPE_STRING,PARM_OPT,0,0},
+ {"ExternalScripts",&CONFIG_EXTERNALSCRIPTS,0,TYPE_STRING,PARM_OPT,0,0},
+ {"DBHost",&CONFIG_DBHOST,0,TYPE_STRING,PARM_OPT,0,0},
+ {"DBName",&CONFIG_DBNAME,0,TYPE_STRING,PARM_MAND,0,0},
+ {"DBUser",&CONFIG_DBUSER,0,TYPE_STRING,PARM_OPT,0,0},
+ {"DBPassword",&CONFIG_DBPASSWORD,0,TYPE_STRING,PARM_OPT,0,0},
+ {"DBSocket",&CONFIG_DBSOCKET,0,TYPE_STRING,PARM_OPT,0,0},
+ {"DBPort",&CONFIG_DBPORT,0,TYPE_INT,PARM_OPT,1024,65535},
+ {"NodeID",&CONFIG_NODEID,0,TYPE_INT,PARM_OPT,0,65535},
+ {"NodeNoEvents",&CONFIG_NODE_NOEVENTS,0,TYPE_INT,PARM_OPT,0,1},
+ {"NodeNoHistory",&CONFIG_NODE_NOHISTORY,0,TYPE_INT,PARM_OPT,0,1},
+ {0}
+ };
+
+ CONFIG_SERVER_STARTUP_TIME = time(NULL);
+
+
+ parse_cfg_file(CONFIG_FILE,cfg);
+
+ if(CONFIG_DBNAME == NULL)
+ {
+ zabbix_log( LOG_LEVEL_CRIT, "DBName not in config file");
+ exit(1);
+ }
+ if(APP_PID_FILE == NULL)
+ {
+ APP_PID_FILE=strdup("/tmp/zabbix_server.pid");
+ }
+ if(CONFIG_ALERT_SCRIPTS_PATH == NULL)
+ {
+ CONFIG_ALERT_SCRIPTS_PATH=strdup("/home/zabbix/bin");
+ }
+ if(CONFIG_FPING_LOCATION == NULL)
+ {
+ CONFIG_FPING_LOCATION=strdup("/usr/sbin/fping");
+ }
+ if(CONFIG_EXTERNALSCRIPTS == NULL)
+ {
+ CONFIG_EXTERNALSCRIPTS=strdup("/etc/zabbix/externalscripts");
+ }
+#ifndef HAVE_LIBCURL
+ CONFIG_HTTPPOLLER_FORKS = 0;
+#endif
+}
+
+/******************************************************************************
+ * *
+ * Function: main *
+ * *
+ * Purpose: executes server processes *
+ * *
+ * Parameters: *
+ * *
+ * Return value: *
+ * *
+ * Author: Eugene Grigorjev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int main(int argc, char **argv)
+{
+ zbx_task_t task = ZBX_TASK_START;
+ char ch = '\0';
+
+ int nodeid;
+
+ progname = argv[0];
+
+ /* Parse the command-line. */
+ while ((ch = (char)zbx_getopt_long(argc, argv, shortopts, longopts,NULL)) != (char)EOF)
+ switch (ch) {
+ case 'c':
+ CONFIG_FILE = strdup(zbx_optarg);
+ break;
+ case 'h':
+ help();
+ exit(-1);
+ break;
+ case 'V':
+ version();
+ exit(-1);
+ break;
+ default:
+ usage();
+ exit(-1);
+ break;
+ }
+
+ if(CONFIG_FILE == NULL)
+ {
+ CONFIG_FILE=strdup("/etc/zabbix/zabbix_proxy.conf");
+ }
+
+ /* Required for simple checks */
+ init_metrics();
+
+ init_config();
+
+ if(CONFIG_DBSYNCER_FORKS!=0)
+ {
+ init_database_cache();
+ }
+
+ return daemon_start(CONFIG_ALLOW_ROOT);
+}
+
+int MAIN_ZABBIX_ENTRY(void)
+{
+ DB_RESULT result;
+ DB_ROW row;
+
+ int i;
+ pid_t pid;
+
+ zbx_sock_t listen_sock;
+
+ int server_num = 0;
+
+ if(CONFIG_LOG_FILE == NULL)
+ {
+ zabbix_open_log(LOG_TYPE_SYSLOG,CONFIG_LOG_LEVEL,NULL);
+ }
+ else
+ {
+ zabbix_open_log(LOG_TYPE_FILE,CONFIG_LOG_LEVEL,CONFIG_LOG_FILE);
+ }
+
+#ifdef HAVE_SNMP
+# define SNMP_FEATURE_STATUS "YES"
+#else
+# define SNMP_FEATURE_STATUS " NO"
+#endif
+#ifdef HAVE_LIBCURL
+# define LIBCURL_FEATURE_STATUS "YES"
+#else
+# define LIBCURL_FEATURE_STATUS " NO"
+#endif
+#ifdef HAVE_ODBC
+# define ODBC_FEATURE_STATUS "YES"
+#else
+# define ODBC_FEATURE_STATUS " NO"
+#endif
+#ifdef HAVE_IPV6
+# define IPV6_FEATURE_STATUS "YES"
+#else
+# define IPV6_FEATURE_STATUS " NO"
+#endif
+
+/* zabbix_log( LOG_LEVEL_WARNING, "INFO [%s]", ZBX_SQL_MOD(a,%d)); */
+ zabbix_log( LOG_LEVEL_WARNING, "Starting zabbix_proxy. ZABBIX %s.", ZABBIX_VERSION);
+
+ zabbix_log( LOG_LEVEL_WARNING, "**** Enabled features ****");
+ zabbix_log( LOG_LEVEL_WARNING, "SNMP monitoring: " SNMP_FEATURE_STATUS );
+ zabbix_log( LOG_LEVEL_WARNING, "WEB monitoring: " LIBCURL_FEATURE_STATUS );
+ zabbix_log( LOG_LEVEL_WARNING, "ODBC: " ODBC_FEATURE_STATUS );
+ zabbix_log( LOG_LEVEL_WARNING, "IPv6 support: " IPV6_FEATURE_STATUS );
+ zabbix_log( LOG_LEVEL_WARNING, "**************************");
+
+ DBconnect(ZBX_DB_CONNECT_EXIT);
+
+ result = DBselect("select refresh_unsupported from config where " ZBX_COND_NODEID,
+ LOCAL_NODE("configid"));
+ row = DBfetch(result);
+
+ if( (row != NULL) && DBis_null(row[0]) != SUCCEED)
+ {
+ CONFIG_REFRESH_UNSUPPORTED = atoi(row[0]);
+ }
+ DBfree_result(result);
+
+ result = DBselect("select masterid from nodes where nodeid=%d",
+ CONFIG_NODEID);
+ row = DBfetch(result);
+
+ if( (row != NULL) && DBis_null(row[0]) != SUCCEED)
+ {
+ CONFIG_MASTER_NODEID = atoi(row[0]);
+ }
+ DBfree_result(result);
+
+/* Need to set trigger status to UNKNOWN since last run */
+/* DBconnect() already made in init_config() */
+/* DBconnect();*/
+ DBupdate_triggers_status_after_restart();
+ DBclose();
+
+/* To make sure that we can connect to the database before forking new processes */
+/* DBconnect(ZBX_DB_CONNECT_EXIT);*/
+/* Do not close database. It is required for database cache */
+/* DBclose();*/
+
+ if (ZBX_MUTEX_ERROR == zbx_mutex_create_force(&node_sync_access, ZBX_MUTEX_NODE_SYNC)) {
+ zbx_error("Unable to create mutex for node syncs");
+ exit(FAIL);
+ }
+
+ threads = calloc(1+CONFIG_POLLER_FORKS+CONFIG_TRAPPERD_FORKS+CONFIG_PINGER_FORKS
+ +CONFIG_HOUSEKEEPER_FORKS+CONFIG_UNREACHABLE_POLLER_FORKS
+ +CONFIG_NODEWATCHER_FORKS+CONFIG_HTTPPOLLER_FORKS+CONFIG_DISCOVERER_FORKS,
+ sizeof(pid_t));
+
+ if(CONFIG_TRAPPERD_FORKS > 0)
+ {
+ if( FAIL == zbx_tcp_listen(&listen_sock, CONFIG_LISTEN_IP, (unsigned short)CONFIG_LISTEN_PORT) )
+ {
+ zabbix_log(LOG_LEVEL_CRIT, "Listener failed with error: %s.", zbx_tcp_strerror());
+ exit(1);
+ }
+ }
+
+ for( i=1;
+ i<=CONFIG_POLLER_FORKS+CONFIG_TRAPPERD_FORKS+CONFIG_PINGER_FORKS+CONFIG_HOUSEKEEPER_FORKS+CONFIG_UNREACHABLE_POLLER_FORKS+CONFIG_NODEWATCHER_FORKS+CONFIG_HTTPPOLLER_FORKS+CONFIG_DISCOVERER_FORKS+CONFIG_DBSYNCER_FORKS;
+ i++)
+ {
+ if((pid = zbx_fork()) == 0)
+ {
+ server_num = i;
+ break;
+ }
+ else
+ {
+ threads[i]=pid;
+ }
+ }
+
+/* zabbix_log( LOG_LEVEL_WARNING, "zabbix_server #%d started",server_num); */
+ /* Main process */
+ if(server_num == 0)
+ {
+ init_main_process();
+/* zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Watchdog]",
+ server_num);
+ main_watchdog_loop();*/
+/* for(;;) zbx_sleep(3600);*/
+ }
+
+
+ if (server_num <= CONFIG_POLLER_FORKS) {
+#ifdef HAVE_SNMP
+ init_snmp("zabbix_server");
+#endif /* HAVE_SNMP */
+ zabbix_log(LOG_LEVEL_WARNING, "server #%d started [Poller. SNMP:%s]",
+ server_num,
+ SNMP_FEATURE_STATUS);
+ main_poller_loop(ZBX_POLLER_TYPE_NORMAL, server_num);
+ } else if (server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS) {
+/* Run trapper processes then do housekeeping */
+ child_trapper_main(server_num, &listen_sock);
+
+/* threads[i] = child_trapper_make(i, listenfd, addrlen); */
+/* child_trapper_make(server_num, listenfd, addrlen); */
+ } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "server #%d started [ICMP pinger]",
+ server_num);
+ main_pinger_loop(server_num-(CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS));
+ } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS
+ +CONFIG_HOUSEKEEPER_FORKS)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Housekeeper]",
+ server_num);
+ main_housekeeper_loop();
+ } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS
+ +CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS)
+ {
+#ifdef HAVE_SNMP
+ init_snmp("zabbix_server");
+#endif /* HAVE_SNMP */
+ zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Poller for unreachable hosts. SNMP:%s]",
+ server_num,
+ SNMP_FEATURE_STATUS);
+ main_poller_loop(ZBX_POLLER_TYPE_UNREACHABLE,
+ server_num - (CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS + CONFIG_HOUSEKEEPER_FORKS));
+ } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS
+ + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS
+ + CONFIG_NODEWATCHER_FORKS)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Node watcher. Node ID:%d]",
+ server_num,
+ CONFIG_NODEID);
+ main_nodewatcher_loop();
+ } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS
+ + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS
+ + CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "server #%d started [HTTP Poller]",
+ server_num);
+ main_httppoller_loop(server_num - CONFIG_POLLER_FORKS - CONFIG_TRAPPERD_FORKS -CONFIG_PINGER_FORKS
+ - CONFIG_HOUSEKEEPER_FORKS
+ - CONFIG_UNREACHABLE_POLLER_FORKS - CONFIG_NODEWATCHER_FORKS);
+ } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS
+ + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS
+ + CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS)
+ {
+#ifdef HAVE_SNMP
+ init_snmp("zabbix_server");
+#endif /* HAVE_SNMP */
+ zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Discoverer. SNMP:%s]",
+ server_num,
+ SNMP_FEATURE_STATUS);
+ main_discoverer_loop(server_num - CONFIG_POLLER_FORKS - CONFIG_TRAPPERD_FORKS -CONFIG_PINGER_FORKS
+ - CONFIG_HOUSEKEEPER_FORKS
+ - CONFIG_UNREACHABLE_POLLER_FORKS - CONFIG_NODEWATCHER_FORKS - CONFIG_HTTPPOLLER_FORKS);
+ } else if(server_num <= CONFIG_POLLER_FORKS + CONFIG_TRAPPERD_FORKS + CONFIG_PINGER_FORKS
+ + CONFIG_HOUSEKEEPER_FORKS + CONFIG_UNREACHABLE_POLLER_FORKS
+ + CONFIG_NODEWATCHER_FORKS + CONFIG_HTTPPOLLER_FORKS + CONFIG_DISCOVERER_FORKS + CONFIG_DBSYNCER_FORKS)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "server #%d started [DB Syncer]",
+ server_num);
+ main_dbsyncer_loop();
+ }
+
+ return SUCCEED;
+}
+
+void zbx_on_exit()
+{
+#if !defined(_WINDOWS)
+
+ int i = 0;
+
+ if(threads != NULL)
+ {
+ for(i = 1; i <= CONFIG_POLLER_FORKS+CONFIG_TRAPPERD_FORKS+CONFIG_PINGER_FORKS+CONFIG_HOUSEKEEPER_FORKS+CONFIG_UNREACHABLE_POLLER_FORKS+CONFIG_NODEWATCHER_FORKS+CONFIG_HTTPPOLLER_FORKS+CONFIG_DISCOVERER_FORKS+CONFIG_DBSYNCER_FORKS; i++)
+ {
+ if(threads[i]) {
+ kill(threads[i],SIGTERM);
+ threads[i] = (ZBX_THREAD_HANDLE)NULL;
+ }
+ }
+ }
+
+#endif /* not _WINDOWS */
+
+#ifdef USE_PID_FILE
+
+ daemon_stop();
+
+#endif /* USE_PID_FILE */
+
+ free_metrics();
+
+ zbx_sleep(2); /* wait for all threads closing */
+
+ DBconnect(ZBX_DB_CONNECT_EXIT);
+
+ if(CONFIG_DBSYNCER_FORKS!=0)
+ {
+ free_database_cache();
+ }
+ DBclose();
+ zbx_mutex_destroy(&node_sync_access);
+ zabbix_close_log();
+
+#ifdef HAVE_SQLITE3
+ php_sem_remove(&sqlite_access);
+#endif /* HAVE_SQLITE3 */
+
+ zabbix_log(LOG_LEVEL_INFORMATION, "ZABBIX Server stopped");
+
+ exit(SUCCEED);
+}
+
diff --git a/src/zabbix_proxy/trapper/Makefile.am b/src/zabbix_proxy/trapper/Makefile.am
new file mode 100644
index 00000000..dc09025f
--- /dev/null
+++ b/src/zabbix_proxy/trapper/Makefile.am
@@ -0,0 +1,10 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LIBRARIES = libzbxtrapper.a
+
+libzbxtrapper_a_SOURCES = \
+ active.c active.h \
+ trapper.c trapper.h \
+ nodesync.c nodesync.h \
+ nodehistory.c nodehistory.h \
+ nodecommand.c nodecommand.h
diff --git a/src/zabbix_proxy/trapper/active.c b/src/zabbix_proxy/trapper/active.c
new file mode 100644
index 00000000..0500e81d
--- /dev/null
+++ b/src/zabbix_proxy/trapper/active.c
@@ -0,0 +1,120 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <string.h>
+
+#include <time.h>
+
+#include <sys/socket.h>
+#include <errno.h>
+
+/* Functions: pow(), round() */
+#include <math.h>
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "active.h"
+
+/******************************************************************************
+ * *
+ * Function: send_list_of_active_checks *
+ * *
+ * Purpose: send list of active checks to the host *
+ * *
+ * Parameters: sockfd - open socket of server-agent connection *
+ * host - hostname *
+ * *
+ * Return value: SUCCEED - list of active checks sent succesfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: format of the list: key:delay:last_log_size *
+ * *
+ ******************************************************************************/
+int send_list_of_active_checks(zbx_sock_t *sock, const char *host)
+{
+ char s[MAX_STRING_LEN];
+ DB_RESULT result;
+ DB_ROW row;
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In send_list_of_active_checks()");
+
+ if (0 != CONFIG_REFRESH_UNSUPPORTED) {
+ result = DBselect("select i.key_,i.delay,i.lastlogsize from items i,hosts h "
+ "where i.hostid=h.hostid and h.status=%d and i.type=%d and h.host='%s' "
+ "and (i.status=%d or (i.status=%d and i.nextcheck<=%d)) and"ZBX_COND_NODEID,
+ HOST_STATUS_MONITORED,
+ ITEM_TYPE_ZABBIX_ACTIVE,
+ host,
+ ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED, time(NULL),
+ LOCAL_NODE("h.hostid"));
+ } else {
+ result = DBselect("select i.key_,i.delay,i.lastlogsize from items i,hosts h "
+ "where i.hostid=h.hostid and h.status=%d and i.type=%d and h.host='%s' "
+ "and i.status=%d and"ZBX_COND_NODEID,
+ HOST_STATUS_MONITORED,
+ ITEM_TYPE_ZABBIX_ACTIVE,
+ host,
+ ITEM_STATUS_ACTIVE,
+ LOCAL_NODE("h.hostid"));
+ }
+
+ while((row=DBfetch(result)))
+ {
+ zbx_snprintf(s,sizeof(s),"%s:%s:%s\n",
+ row[0],
+ row[1],
+ row[2]);
+ zabbix_log( LOG_LEVEL_DEBUG, "Sending [%s]",
+ s);
+
+ if( zbx_tcp_send_raw(sock,s) != SUCCEED )
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Error while sending list of active checks");
+ return FAIL;
+ }
+ }
+ DBfree_result(result);
+
+ zbx_snprintf(s,sizeof(s),"%s\n",
+ "ZBX_EOF");
+ zabbix_log( LOG_LEVEL_DEBUG, "Sending [%s]",
+ s);
+
+ if( zbx_tcp_send_raw(sock,s) != SUCCEED )
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Error while sending list of active checks");
+ return FAIL;
+ }
+
+ return SUCCEED;
+}
diff --git a/src/zabbix_proxy/trapper/active.h b/src/zabbix_proxy/trapper/active.h
new file mode 100644
index 00000000..3b31ea74
--- /dev/null
+++ b/src/zabbix_proxy/trapper/active.h
@@ -0,0 +1,30 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#ifndef ZABBIX_TRAPPER_ACTIVE_H
+#define ZABBIX_TRAPPER_ACTIVE_H
+
+#include "common.h"
+#include "db.h"
+#include "comms.h"
+
+int send_list_of_active_checks(zbx_sock_t *sock, const char *host);
+
+#endif
diff --git a/src/zabbix_proxy/trapper/nodecommand.c b/src/zabbix_proxy/trapper/nodecommand.c
new file mode 100644
index 00000000..7fbc645e
--- /dev/null
+++ b/src/zabbix_proxy/trapper/nodecommand.c
@@ -0,0 +1,284 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <string.h>
+
+#include <time.h>
+
+#include <sys/socket.h>
+#include <errno.h>
+
+#include "comms.h"
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#define MVAR_HOST_NAME "{HOSTNAME}"
+#define MVAR_IPADDRESS "{IPADDRESS}"
+#define MVAR_HOST_CONN "{HOST.CONN}"
+
+
+/******************************************************************************
+ * *
+ * Function: execute_script *
+ * *
+ * Purpose: executing command *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void execute_script(const char *command, char **result, int *result_allocated)
+{
+ int result_offset = 0;
+ char buffer[MAX_STRING_LEN];
+ FILE *f;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In execute_script(command:%s)", command);
+
+ if(0 != (f = popen(command, "r"))) {
+ zbx_snprintf_alloc(result, result_allocated, &result_offset, 8, "%d%c",
+ SUCCEED,
+ ZBX_DM_DELIMITER);
+
+ while (NULL != fgets(buffer, sizeof(buffer)-1, f)) {
+ zbx_snprintf_alloc(result, result_allocated, &result_offset, sizeof(buffer),
+ "%s",
+ buffer);
+ }
+ (*result)[result_offset] = '\0';
+
+ pclose(f);
+ } else {
+ zbx_snprintf_alloc(result, result_allocated, &result_offset, 128,
+ "%d%cNODE %d: Cannot execute [%s] error:%s",
+ FAIL,
+ ZBX_DM_DELIMITER,
+ CONFIG_NODEID,
+ command,
+ strerror(errno));
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: send_script *
+ * *
+ * Purpose: sending command to slave node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+void send_script(int nodeid, const char *data, char **result, int *result_allocated)
+{
+ DB_RESULT dbresult;
+ DB_ROW dbrow;
+ int result_offset = 0;
+ zbx_sock_t sock;
+ char *answer;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In send_script(nodeid:%d)", nodeid);
+
+ dbresult = DBselect("select ip,port from nodes where nodeid=%d",
+ nodeid);
+
+ if (NULL != (dbrow = DBfetch(dbresult))) {
+ if (SUCCEED == zbx_tcp_connect(&sock, dbrow[0], atoi(dbrow[1]), 0)) {
+ if (FAIL == zbx_tcp_send(&sock, data)) {
+ zbx_snprintf_alloc(result, result_allocated, &result_offset, 128,
+ "%d%cNODE %d: Error while sending data to Node [%d] error: %s",
+ FAIL,
+ ZBX_DM_DELIMITER,
+ CONFIG_NODEID,
+ nodeid,
+ zbx_tcp_strerror());
+ goto exit_sock;
+ }
+
+ if (SUCCEED == zbx_tcp_recv(&sock, &answer/*, ZBX_TCP_READ_UNTIL_CLOSE*/)) {
+ zbx_snprintf_alloc(result, result_allocated, &result_offset, strlen(answer)+1,
+ "%s",
+ answer);
+ } else {
+
+ zbx_snprintf_alloc(result, result_allocated, &result_offset, 128,
+ "%d%cNODE %d: Error while receiving answer from Node [%d] error: %s",
+ FAIL,
+ ZBX_DM_DELIMITER,
+ CONFIG_NODEID,
+ nodeid,
+ zbx_tcp_strerror());
+ goto exit_sock;
+ }
+exit_sock:
+ zbx_tcp_close(&sock);
+ } else {
+ zbx_snprintf_alloc(result, result_allocated, &result_offset, 128,
+ "%d%cNODE %d: Unable to connect to Node [%d] error: %s",
+ FAIL,
+ ZBX_DM_DELIMITER,
+ CONFIG_NODEID,
+ nodeid,
+ zbx_tcp_strerror());
+ }
+ } else {
+ zbx_snprintf_alloc(result, result_allocated, &result_offset, 128,
+ "%d%cNODE %d: Node [%d] is unknown",
+ FAIL,
+ ZBX_DM_DELIMITER,
+ CONFIG_NODEID,
+ nodeid);
+ }
+ DBfree_result(dbresult);
+}
+
+/******************************************************************************
+ * *
+ * Function: get_next_point_to_node *
+ * *
+ * Purpose: find next point to slave node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int get_next_point_to_node(int current_nodeid, int slave_nodeid, int *nodeid)
+{
+ DB_RESULT dbresult;
+ DB_ROW dbrow;
+ int id, res = FAIL;
+
+ dbresult = DBselect("select nodeid from nodes where masterid=%d",
+ current_nodeid);
+
+ while (NULL != (dbrow = DBfetch(dbresult))) {
+ id = atoi(dbrow[0]);
+ if (id == slave_nodeid || SUCCEED == get_next_point_to_node(id, slave_nodeid, NULL)) {
+ if (NULL != nodeid)
+ *nodeid = id;
+ res = SUCCEED;
+ break;
+ }
+ }
+ DBfree_result(dbresult);
+
+ return res;
+}
+
+/******************************************************************************
+ * *
+ * Function: node_process_command *
+ * *
+ * Purpose: process command received from a master node or php *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int node_process_command(zbx_sock_t *sock, const char *data)
+{
+ const char *r;
+ char *tmp = NULL, *result = NULL;
+ int tmp_allocated = 64, result_allocated = 1024;
+ int datalen;
+ int nodeid, next_nodeid;
+ int result_offset = 0;
+
+ result = zbx_malloc(result, result_allocated);
+ tmp = zbx_malloc(tmp, tmp_allocated);
+ datalen = strlen(data);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In node_process_command(datalen:%d)",
+ datalen);
+
+ r = data;
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* Constant 'Command' */
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* NodeID */
+ nodeid = atoi(tmp);
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER);
+
+ if (nodeid == CONFIG_NODEID) {
+ zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Received command \"%s\"",
+ CONFIG_NODEID,
+ tmp);
+
+ execute_script(tmp, &result, &result_allocated);
+ } else if (SUCCEED == get_next_point_to_node(CONFIG_NODEID, nodeid, &next_nodeid)) {
+ zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Sending command \"%s\" for nodeid %d"
+ "to node %d",
+ CONFIG_NODEID,
+ tmp,
+ nodeid,
+ next_nodeid);
+
+ send_script(next_nodeid, data, &result, &result_allocated);
+ } else {
+ zbx_snprintf_alloc(&result, &result_allocated, &result_offset, 128,
+ "%d%cNODE %d: Node [%d] is unknown",
+ FAIL,
+ ZBX_DM_DELIMITER,
+ CONFIG_NODEID,
+ nodeid);
+ }
+
+ if (zbx_tcp_send_raw(sock, result) != SUCCEED) {
+ zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Error sending result of command to node %d",
+ CONFIG_NODEID,
+ nodeid);
+ }
+ zbx_free(tmp);
+ zbx_free(result);
+
+ return SUCCEED;
+}
diff --git a/src/zabbix_proxy/trapper/nodecommand.h b/src/zabbix_proxy/trapper/nodecommand.h
new file mode 100644
index 00000000..0c92e05b
--- /dev/null
+++ b/src/zabbix_proxy/trapper/nodecommand.h
@@ -0,0 +1,26 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#ifndef ZABBIX_NODECOMMAND_H
+#define ZABBIX_NODECOMMAND_H
+
+int node_process_command(zbx_sock_t *sock, const char *data);
+
+#endif
diff --git a/src/zabbix_proxy/trapper/nodehistory.c b/src/zabbix_proxy/trapper/nodehistory.c
new file mode 100644
index 00000000..51fec678
--- /dev/null
+++ b/src/zabbix_proxy/trapper/nodehistory.c
@@ -0,0 +1,481 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "../events.h"
+#include "../nodewatcher/nodecomms.h"
+
+/******************************************************************************
+ * *
+ * Function: send_history_last_id *
+ * *
+ * Purpose: send list of last historical tables ids *
+ * *
+ * Parameters: sock - opened socket of node-node connection *
+ * record *
+ * *
+ * Return value: SUCCEED - sent succesfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int send_history_last_id(zbx_sock_t *sock, const char *data)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ const char *r;
+ char *tmp = NULL, tablename[MAX_STRING_LEN], fieldname[MAX_STRING_LEN];
+ int tmp_allocated = 256, tmp_offset;
+ int sender_nodeid, nodeid, res;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In send_list_of_history_ids()");
+
+ tmp = zbx_malloc(tmp, tmp_allocated);
+
+ r = data;
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* constant 'ZBX_GET_HISTORY_LAST_ID' */
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* sender_nodeid */
+ sender_nodeid=atoi(tmp);
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, '\n'); /* nodeid */
+ nodeid=atoi(tmp);
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* table name */
+ strcpy(tablename, tmp);
+
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* field name */
+ strcpy(fieldname, tmp);
+
+ tmp_offset= 0;
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 256, "select MAX(%s) "
+ "from %s where"ZBX_COND_NODEID,
+ fieldname,
+ tablename,
+ ZBX_NODE(fieldname, nodeid));
+
+ tmp_offset= 0;
+ result = DBselect("%s", tmp);
+ if (NULL != (row = DBfetch(result)))
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "%s",
+ SUCCEED == DBis_null(row[0]) ? "0" : row[0]);
+ DBfree_result(result);
+
+ if (tmp_offset == 0)
+ goto error;
+
+ res = send_data_to_node(sender_nodeid, sock, tmp);
+
+ zbx_free(tmp);
+
+ return res;
+error:
+ tmp_offset= 0;
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "FAIL");
+
+ res = send_data_to_node(sender_nodeid, sock, tmp);
+
+ zbx_free(tmp);
+
+ zabbix_log( LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]",
+ CONFIG_NODEID,
+ sender_nodeid,
+ nodeid,
+ data);
+
+ return FAIL;
+}
+
+/******************************************************************************
+ * *
+ * Function: send_trends_last_id *
+ * *
+ * Purpose: send last historical tables ids *
+ * *
+ * Parameters: sock - opened socket of node-node connection *
+ * record *
+ * *
+ * Return value: SUCCEED - sent succesfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Aleksander Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int send_trends_last_id(zbx_sock_t *sock, const char *data)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ const char *r;
+ char *tmp = NULL, tablename[MAX_STRING_LEN];
+ int tmp_allocated = 256, tmp_offset;
+ int sender_nodeid, nodeid, res;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In send_list_of_history_ids()");
+
+ tmp = zbx_malloc(tmp, tmp_allocated);
+
+ r = data;
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* constant 'ZBX_GET_HISTORY_LAST_ID' */
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* sender_nodeid */
+ sender_nodeid=atoi(tmp);
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, '\n'); /* nodeid */
+ nodeid=atoi(tmp);
+ if (NULL == r)
+ goto error;
+
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* table name */
+ strcpy(tablename, tmp);
+
+ tmp_offset= 0;
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 256, "select itemid,clock "
+ "from %s where"ZBX_COND_NODEID"order by itemid desc,clock desc",
+ tablename,
+ ZBX_NODE("itemid", nodeid));
+
+ tmp_offset= 0;
+ result = DBselectN(tmp, 1);
+ if (NULL == (row = DBfetch(result)))
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 64, "0%c0",
+ ZBX_DM_DELIMITER);
+ else
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "%s%c%s",
+ SUCCEED == DBis_null(row[0]) ? "0" : row[0],
+ ZBX_DM_DELIMITER,
+ SUCCEED == DBis_null(row[1]) ? "0" : row[1]);
+ DBfree_result(result);
+
+ res = send_data_to_node(sender_nodeid, sock, tmp);
+
+ zbx_free(tmp);
+
+ return res;
+error:
+ tmp_offset= 0;
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 128, "FAIL");
+
+ res = send_data_to_node(sender_nodeid, sock, tmp);
+
+ zbx_free(tmp);
+
+ zabbix_log( LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]",
+ CONFIG_NODEID,
+ sender_nodeid,
+ nodeid,
+ data);
+
+ return FAIL;
+}
+
+/******************************************************************************
+ * *
+ * Function: process_record_event *
+ * *
+ * Purpose: process record update *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int process_record_event(int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record, char **tmp, int *tmp_allocated)
+{
+ const char *r;
+ int f, len;
+ DB_EVENT event;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_record_event ()");
+
+ memset(&event, 0, sizeof(event));
+
+ r = record;
+ for (f = 0; table->fields[f].name != 0; f++) {
+ if (NULL == r)
+ goto error;
+
+ len = zbx_get_next_field(&r, tmp, tmp_allocated, ZBX_DM_DELIMITER);
+
+ if (0 == strcmp(table->fields[f].name, "eventid")) {
+ ZBX_STR2UINT64(event.eventid, *tmp);
+ } else if (0 == strcmp(table->fields[f].name, "source")) {
+ event.source = atoi(*tmp);
+ } else if (0 == strcmp(table->fields[f].name, "object")) {
+ event.object = atoi(*tmp);
+ } else if (0 == strcmp(table->fields[f].name, "objectid")) {
+ ZBX_STR2UINT64(event.objectid, *tmp);
+ } else if (0 == strcmp(table->fields[f].name, "clock")) {
+ event.clock=atoi(*tmp);
+ } else if (0 == strcmp(table->fields[f].name, "value")) {
+ event.value=atoi(*tmp);
+ } else if (0 == strcmp(table->fields[f].name, "acknowledged")) {
+ event.acknowledged=atoi(*tmp);
+ }
+ }
+
+ return process_event(&event);
+error:
+ zabbix_log( LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]",
+ CONFIG_NODEID,
+ sender_nodeid,
+ nodeid,
+ record);
+
+ return FAIL;
+}
+
+/******************************************************************************
+ * *
+ * Function: process_record *
+ * *
+ * Purpose: process record update *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int process_record(int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record, char **tmp, int *tmp_allocated, char **sql, int *sql_allocated, int lastrecord)
+{
+ const char *r;
+ int f, len, sql_offset, lastvalue_type;
+ int res = FAIL;
+ char lastvalue[MAX_STRING_LEN], lastclock[MAX_STRING_LEN];
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In process_record ()");
+
+ r = record;
+
+ sql_offset = 0;
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 128, "insert into %s (",
+ table->table);
+
+ if (0 != (table->flags & ZBX_HISTORY_SYNC))
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 128, "nodeid,");
+
+ for (f = 0; table->fields[f].name != 0; f++) {
+ if (0 != (table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC))
+ continue;
+
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 128, "%s,",
+ table->fields[f].name);
+ }
+
+ sql_offset--;
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 64, ") values (");
+
+ if (0 != (table->flags & ZBX_HISTORY_SYNC))
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 128, "%d,",
+ nodeid);
+
+ for (f = 0; table->fields[f].name != 0; f++) {
+ if ((table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC))
+ continue;
+
+ if (NULL == r)
+ goto error;
+
+ len = zbx_get_next_field(&r, tmp, tmp_allocated, ZBX_DM_DELIMITER);
+
+ if (table->fields[f].type == ZBX_TYPE_INT ||
+ table->fields[f].type == ZBX_TYPE_UINT ||
+ table->fields[f].type == ZBX_TYPE_ID ||
+ table->fields[f].type == ZBX_TYPE_FLOAT)
+ {
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, len + 8, "%s,",
+ *tmp);
+ } else { /* ZBX_TYPE_CHAR ZBX_TYPE_BLOB ZBX_TYPE_TEXT */
+ if (0 == len)
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 8, "'',");
+ else
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, len + 8, "0x%s,",
+ *tmp);
+ }
+
+ if (lastrecord && 0 != (table->flags & ZBX_HISTORY_SYNC)) {
+ if (0 == strcmp(table->fields[f].name, "clock")) {
+ strcpy(lastclock, *tmp);
+ } else if (0 == strcmp(table->fields[f].name, "value")) {
+ strcpy(lastvalue, *tmp);
+ lastvalue_type = table->fields[f].type;
+ }
+ }
+ }
+
+ sql_offset--;
+ zbx_snprintf_alloc(sql, sql_allocated, &sql_offset, 8, ")");
+
+ if (DBexecute("%s", *sql) >= ZBX_DB_OK)
+ res = SUCCEED;
+
+ return res;
+error:
+ zabbix_log( LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]",
+ CONFIG_NODEID,
+ sender_nodeid,
+ nodeid,
+ record);
+
+ return FAIL;
+}
+
+/******************************************************************************
+ * *
+ * Function: node_history *
+ * *
+ * Purpose: process new history received from a salve node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int node_history(char *data, size_t datalen)
+{
+ const char *r;
+ char *newline = NULL, *tmp = NULL, *sql = NULL;
+ char *pos;
+ int tmp_allocated = 4096, sql_allocated = 8192;
+ int sender_nodeid = 0, nodeid = 0, firstline = 1, events = 0;
+ const ZBX_TABLE *table_sync = NULL, *table = NULL;
+ int res = SUCCEED;
+
+ assert(data);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In node_history()");
+
+ tmp = zbx_malloc(tmp, tmp_allocated);
+ sql = zbx_malloc(sql, sql_allocated);
+
+ DBbegin();
+
+ for (r = data; *r != '\0' && res == SUCCEED;) {
+ if (NULL != (newline = strchr(r, '\n')))
+ *newline = '\0';
+
+ if (1 == firstline) {
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* constant 'History' */
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* sender_nodeid */
+ sender_nodeid=atoi(tmp);
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* nodeid */
+ nodeid=atoi(tmp);
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* tablename */
+
+ table = DBget_table(tmp);
+ if (0 == (table->flags & (ZBX_HISTORY | ZBX_HISTORY_SYNC | ZBX_HISTORY_TRENDS)))
+ table = NULL;
+
+ if (NULL != table && 0 != (table->flags & ZBX_HISTORY_SYNC)) {
+ table_sync = table;
+ if (NULL != (pos = strstr(tmp, "_sync"))) {
+ *pos = '\0';
+ table = DBget_table(tmp);
+ }
+ }
+
+ if (NULL != table && 0 == strcmp(table->table, "events"))
+ events = 1;
+
+ if (NULL == table) {
+ zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Invalid received data: unknown tablename \"%s\"",
+ CONFIG_NODEID,
+ tmp);
+ }
+ if (NULL != newline) {
+ zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Received %s from node %d for node %d datalen %zd",
+ CONFIG_NODEID,
+ tmp,
+ sender_nodeid,
+ nodeid,
+ datalen);
+ }
+ firstline = 0;
+ } else if (NULL != table) {
+ if (events) {
+ res = process_record_event(sender_nodeid, nodeid, table, r, &tmp, &tmp_allocated);
+ } else {
+ res = process_record(sender_nodeid, nodeid, table, r, &tmp, &tmp_allocated, &sql, &sql_allocated, NULL == newline);
+ if (SUCCEED == res && NULL != table_sync && 0 != CONFIG_MASTER_NODEID)
+ res = process_record(sender_nodeid, nodeid, table_sync, r, &tmp, &tmp_allocated, &sql, &sql_allocated, 0);
+ }
+ }
+
+ if (newline != NULL) {
+ *newline = '\n';
+ r = newline + 1;
+ } else
+ break;
+ }
+ if (res == SUCCEED)
+ DBcommit();
+ else
+ DBrollback();
+
+ zbx_free(sql);
+ zbx_free(tmp);
+
+ return res;
+}
diff --git a/src/zabbix_proxy/trapper/nodehistory.h b/src/zabbix_proxy/trapper/nodehistory.h
new file mode 100644
index 00000000..bfcf3e01
--- /dev/null
+++ b/src/zabbix_proxy/trapper/nodehistory.h
@@ -0,0 +1,30 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#ifndef ZABBIX_NODEHISTORY_H
+#define ZABBIX_NODEHISTORY_H
+
+#include "comms.h"
+
+int send_history_last_id(zbx_sock_t *sock, const char *data);
+int send_trends_last_id(zbx_sock_t *sock, const char *data);
+int node_history(char *data, size_t datalen);
+
+#endif
diff --git a/src/zabbix_proxy/trapper/nodesync.c b/src/zabbix_proxy/trapper/nodesync.c
new file mode 100644
index 00000000..6535d2a3
--- /dev/null
+++ b/src/zabbix_proxy/trapper/nodesync.c
@@ -0,0 +1,338 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <string.h>
+
+#include <time.h>
+
+#include <sys/socket.h>
+#include <errno.h>
+
+/* Functions: pow(), round() */
+#include <math.h>
+
+#include "common.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "nodesync.h"
+#include "../nodewatcher/nodesender.h"
+
+/******************************************************************************
+ * *
+ * Function: process_record *
+ * *
+ * Purpose: process record update *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+static int process_record(int nodeid, const char *record, int sender_nodetype)
+{
+ char tablename[MAX_STRING_LEN];
+ char fieldname[MAX_STRING_LEN];
+ zbx_uint64_t recid;
+ int op, res = SUCCEED;
+ int valuetype;
+ char value_esc[MAX_STRING_LEN];
+ int i;
+ char *key=NULL;
+ DB_RESULT result;
+ DB_ROW row;
+ const char *r;
+ char *buffer = NULL, *tmp = NULL, *fields_update = NULL, *fields = NULL, *values = NULL;
+ int buffer_allocated = 16*1024;
+ int tmp_allocated = 16*1024, tmp_offset = 0;
+ int fields_update_allocated = 16*1024, fields_update_offset = 0;
+ int fields_allocated = 4*1024, fields_offset = 0;
+ int values_allocated = 16*1024, values_offset = 0;
+#if defined(HAVE_POSTGRESQL)
+ int len;
+#endif /* HAVE_POSTGRESQL */
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In process_record [%s]", record);
+
+ r = record;
+ buffer = zbx_malloc(buffer, buffer_allocated);
+ tmp = zbx_malloc(tmp, tmp_allocated);
+
+ zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER);
+ strcpy(tablename, buffer);
+
+ zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER);
+ ZBX_STR2UINT64(recid, buffer);
+
+ zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER);
+ op = atoi(buffer);
+
+ for(i=0;tables[i].table!=0;i++)
+ {
+ if(strcmp(tables[i].table, tablename)==0)
+ {
+ key=tables[i].recid;
+ break;
+ }
+ }
+
+ if(key == NULL)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Cannot find key field for table [%s]",
+ tablename);
+ res = FAIL;
+ goto out;
+ }
+ if(op==NODE_CONFIGLOG_OP_DELETE)
+ {
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 256, "delete from %s where %s="ZBX_FS_UI64,
+ tablename,
+ key,
+ recid);
+ DBexecute("%s", tmp);
+ goto out;
+ }
+
+ fields_update = zbx_malloc(fields_update, fields_update_allocated);
+ fields = zbx_malloc(fields, fields_allocated);
+ values = zbx_malloc(values, values_allocated);
+
+ zbx_snprintf_alloc(&fields, &fields_allocated, &fields_offset, 128, "%s,", key);
+ zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, ZBX_FS_UI64",", recid);
+
+ while(r != NULL)
+ {
+ zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER);
+ strcpy(fieldname, buffer);
+
+ zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER);
+ valuetype=atoi(buffer);
+
+ zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER);
+ if(op==NODE_CONFIGLOG_OP_UPDATE)
+ {
+ if(strcmp(buffer, "NULL") == 0)
+ {
+ zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, 128, "%s=NULL,",
+ fieldname);
+ zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, "NULL,");
+ }
+ else
+ {
+ if(valuetype == ZBX_TYPE_INT || valuetype == ZBX_TYPE_UINT || valuetype == ZBX_TYPE_ID || valuetype == ZBX_TYPE_FLOAT)
+ {
+ zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, 256, "%s=%s,",
+ fieldname,
+ buffer);
+ zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, "%s,",
+ buffer);
+ }
+ else if(valuetype == ZBX_TYPE_BLOB)
+ {
+ if(*buffer == '\0')
+ {
+ zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, 128, "%s='',",
+ fieldname);
+ zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, "'',");
+ }
+ else
+ {
+#if defined(HAVE_POSTGRESQL)
+ len = zbx_hex2binary(buffer);
+ zbx_pg_escape_bytea((u_char *)buffer, len, &tmp, &tmp_allocated);
+ zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, strlen(tmp)+256, "%s='%s',",
+ fieldname,
+ tmp);
+ zbx_snprintf_alloc(&values, &values_allocated, &values_offset, strlen(tmp)+256, "'%s',",
+ tmp);
+#else
+ zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, strlen(buffer)+256, "%s=0x%s,",
+ fieldname,
+ buffer);
+ zbx_snprintf_alloc(&values, &values_allocated, &values_offset, strlen(buffer)+256, "0x%s,",
+ buffer);
+#endif
+ }
+ }
+ else /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */
+ {
+ zbx_hex2binary(buffer);
+ DBescape_string(buffer, value_esc,MAX_STRING_LEN);
+
+ zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, 256, "%s='%s',",
+ fieldname,
+ value_esc);
+ zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 256, "'%s',",
+ value_esc);
+ }
+ }
+
+ zbx_snprintf_alloc(&fields, &fields_allocated, &fields_offset, 128, "%s,", fieldname);
+ }
+ else
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Unknown record operation [%d]",
+ op);
+ res = FAIL;
+ goto out;
+ }
+ }
+ if(fields_offset != 0) fields[fields_offset - 1]='\0';
+ if(fields_update_offset != 0) fields_update[fields_update_offset - 1]='\0';
+ if(values_offset != 0) values[values_offset - 1]='\0';
+
+ if(op==NODE_CONFIGLOG_OP_UPDATE)
+ {
+ result = DBselect("select 0 from %s where %s="ZBX_FS_UI64,
+ tablename,
+ key,
+ recid);
+ row = DBfetch(result);
+ if(row)
+ {
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 16*1024, "update %s set %s where %s=" ZBX_FS_UI64,
+ tablename,
+ fields_update,
+ key,
+ recid);
+ }
+ else
+ {
+ zbx_snprintf_alloc(&tmp, &tmp_allocated, &tmp_offset, 16*1024, "insert into %s (%s) values(%s)",
+ tablename,
+ fields,
+ values);
+ }
+ DBfree_result(result);
+ }
+ DBexecute("%s",tmp);
+
+ if (FAIL == calculate_checksums(nodeid, tablename, recid) ||
+ FAIL == update_checksums(nodeid, sender_nodetype, SUCCEED, tablename, recid, fields) ) {
+ res = FAIL;
+ goto out;
+ }
+/* zabbix_log( LOG_LEVEL_CRIT, "RECORD [%s]", record);*/
+/* zabbix_log( LOG_LEVEL_CRIT, "SQL [%s] %s", tmp, res == FAIL ? "FAIL" : "SUCCEED");*/
+
+out:
+ if (NULL != buffer)
+ zbx_free(buffer);
+ if (NULL != tmp)
+ zbx_free(tmp);
+ if (NULL != fields_update)
+ zbx_free(fields_update);
+ if (NULL != fields)
+ zbx_free(fields);
+ if (NULL != values)
+ zbx_free(values);
+
+ return res;
+}
+/******************************************************************************
+ * *
+ * Function: node_sync *
+ * *
+ * Purpose: process configuration changes received from a node *
+ * *
+ * Parameters: *
+ * *
+ * Return value: SUCCEED - processed successfully *
+ * FAIL - an error occured *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: *
+ * *
+ ******************************************************************************/
+int node_sync(char *data, int *sender_nodeid, int *nodeid)
+{
+ const char *r;
+ char *newline, *tmp = NULL;
+ int tmp_allocated = 128;
+ int firstline=1;
+ int sender_nodetype=0;
+ int datalen;
+ int res = SUCCEED;
+
+ datalen=strlen(data);
+
+ zabbix_log( LOG_LEVEL_DEBUG, "In node_sync(len:%d)", datalen);
+
+ tmp = zbx_malloc(tmp, tmp_allocated);
+
+/*zabbix_log(LOG_LEVEL_CRIT, "<----- [%s]", data);*/
+
+ for (r = data; *r != '\0' && res == SUCCEED;) {
+ if (NULL != (newline = strchr(r, '\n')))
+ *newline = '\0';
+
+ if (firstline == 1) {
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER); /* Data */
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER);
+ *sender_nodeid=atoi(tmp);
+ sender_nodetype = *sender_nodeid == CONFIG_MASTER_NODEID ? ZBX_NODE_MASTER : ZBX_NODE_SLAVE;
+ zbx_get_next_field(&r, &tmp, &tmp_allocated, ZBX_DM_DELIMITER);
+ *nodeid=atoi(tmp);
+
+ if (0 != *sender_nodeid && 0 != *nodeid) {
+ zabbix_log( LOG_LEVEL_WARNING, "NODE %d: Received data from %s node %d for node %d datalen %d",
+ CONFIG_NODEID,
+ sender_nodetype == ZBX_NODE_SLAVE ? "slave" : "master",
+ *sender_nodeid,
+ *nodeid,
+ datalen);
+
+/* DBbegin();*/
+
+ DBexecute("delete from node_cksum where nodeid=%d and cksumtype=%d",
+ *nodeid,
+ NODE_CKSUM_TYPE_NEW);
+
+ firstline=0;
+ } else
+ res = FAIL;
+ } else
+ res = process_record(*nodeid, r, sender_nodetype);
+
+ if (newline != NULL) {
+ *newline = '\n';
+ r = newline + 1;
+ } else
+ break;
+ }
+ zbx_free(tmp);
+
+ return res;
+}
diff --git a/src/zabbix_proxy/trapper/nodesync.h b/src/zabbix_proxy/trapper/nodesync.h
new file mode 100644
index 00000000..94c3a594
--- /dev/null
+++ b/src/zabbix_proxy/trapper/nodesync.h
@@ -0,0 +1,26 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#ifndef ZABBIX_NODESYNC_H
+#define ZABBIX_NODESYNC_H
+
+int node_sync(char *data, int *sender_nodeid, int *nodeid);
+
+#endif
diff --git a/src/zabbix_proxy/trapper/trapper.c b/src/zabbix_proxy/trapper/trapper.c
new file mode 100644
index 00000000..d6ee142b
--- /dev/null
+++ b/src/zabbix_proxy/trapper/trapper.c
@@ -0,0 +1,245 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#include "common.h"
+
+#include "cfg.h"
+#include "comms.h"
+#include "pid.h"
+#include "db.h"
+#include "log.h"
+#include "zlog.h"
+
+#include "../functions.h"
+#include "../expression.h"
+
+#include "../nodewatcher/nodecomms.h"
+#include "../nodewatcher/nodesender.h"
+#include "nodesync.h"
+#include "nodehistory.h"
+#include "trapper.h"
+#include "active.h"
+#include "nodecommand.h"
+
+#include "daemon.h"
+
+static int process_trap(zbx_sock_t *sock,char *s, int max_len)
+{
+ char *line,*host;
+ char *server,*key,*value_string, *data;
+ char copy[MAX_STRING_LEN];
+ char host_dec[MAX_STRING_LEN],key_dec[MAX_STRING_LEN],value_dec[MAX_STRING_LEN];
+ char lastlogsize[MAX_STRING_LEN];
+ char timestamp[MAX_STRING_LEN];
+ char source[MAX_STRING_LEN];
+ char severity[MAX_STRING_LEN];
+ int sender_nodeid, nodeid;
+ char *answer;
+
+ int ret=SUCCEED, res;
+ size_t datalen;
+
+ zbx_rtrim(s, " \r\n\0");
+
+ datalen = strlen(s);
+ zabbix_log( LOG_LEVEL_DEBUG, "Trapper got [%s] len %zd",
+ s,
+ datalen);
+/* Request for list of active checks */
+ if (strncmp(s,"ZBX_GET_ACTIVE_CHECKS", 21) == 0) {
+ line=strtok(s,"\n");
+ host=strtok(NULL,"\n");
+ if(host == NULL)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "ZBX_GET_ACTIVE_CHECKS: host is null. Ignoring.");
+ }
+ else
+ {
+ ret = send_list_of_active_checks(sock, host);
+ }
+/* Request for last ids */
+ } else if (strncmp(s,"ZBX_GET_HISTORY_LAST_ID", 23) == 0) {
+ send_history_last_id(sock, s);
+ return ret;
+ } else if (strncmp(s,"ZBX_GET_TRENDS_LAST_ID", 22) == 0) {
+ send_trends_last_id(sock, s);
+ return ret;
+/* Process information sent by zabbix_sender */
+ } else {
+ /* Command? */
+ if(strncmp(s,"Command",7) == 0)
+ {
+ node_process_command(sock, s);
+ return ret;
+ }
+ /* Node data exchange? */
+ if(strncmp(s,"Data",4) == 0)
+ {
+ node_sync_lock(0);
+
+/* zabbix_log( LOG_LEVEL_WARNING, "Node data received [len:%d]", strlen(s)); */
+ res = node_sync(s, &sender_nodeid, &nodeid);
+ if (FAIL == res)
+ send_data_to_node(sender_nodeid, sock, "FAIL");
+ else {
+ res = calculate_checksums(nodeid, NULL, 0);
+ if (SUCCEED == res && NULL != (data = get_config_data(nodeid, ZBX_NODE_SLAVE))) {
+ res = send_data_to_node(sender_nodeid, sock, data);
+ zbx_free(data);
+ if (SUCCEED == res)
+ res = recv_data_from_node(sender_nodeid, sock, &answer);
+ if (SUCCEED == res && 0 == strcmp(answer, "OK"))
+ res = update_checksums(nodeid, ZBX_NODE_SLAVE, SUCCEED, NULL, 0, NULL);
+ }
+ }
+
+ node_sync_unlock(0);
+
+ return ret;
+ }
+ /* Slave node history ? */
+ if(strncmp(s,"History",7) == 0)
+ {
+/* zabbix_log( LOG_LEVEL_WARNING, "Slave node history received [len:%d]", strlen(s)); */
+ if (node_history(s, datalen) == SUCCEED) {
+ if (zbx_tcp_send_raw(sock,"OK") != SUCCEED) {
+ zabbix_log( LOG_LEVEL_WARNING, "Error sending confirmation to node");
+ zabbix_syslog("Trapper: error sending confirmation to node");
+ }
+ }
+ return ret;
+ }
+ /* New XML protocol? */
+ else if(s[0]=='<')
+ {
+ zabbix_log( LOG_LEVEL_DEBUG, "XML received [%s]", s);
+
+ comms_parse_response(s,host_dec,key_dec,value_dec,lastlogsize,timestamp,source,severity,sizeof(host_dec)-1);
+
+ server=host_dec;
+ value_string=value_dec;
+ key=key_dec;
+ }
+ else
+ {
+ strscpy(copy,s);
+
+ server=(char *)strtok(s,":");
+ if(NULL == server)
+ {
+ return FAIL;
+ }
+
+ key=(char *)strtok(NULL,":");
+ if(NULL == key)
+ {
+ return FAIL;
+ }
+
+ value_string=strchr(copy,':');
+ value_string=strchr(value_string+1,':');
+
+ if(NULL == value_string)
+ {
+ return FAIL;
+ }
+ /* It points to ':', so have to increment */
+ value_string++;
+ lastlogsize[0]=0;
+ timestamp[0]=0;
+ source[0]=0;
+ severity[0]=0;
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "Value [%s]", value_string);
+
+ DBbegin();
+ ret=process_data(sock,server,key,value_string,lastlogsize,timestamp,source,severity);
+ DBcommit();
+
+ if( zbx_tcp_send_raw(sock, SUCCEED == ret ? "OK" : "NOT OK") != SUCCEED)
+ {
+ zabbix_log( LOG_LEVEL_WARNING, "Error sending result back");
+ zabbix_syslog("Trapper: error sending result back");
+ }
+ zabbix_log( LOG_LEVEL_DEBUG, "After write()");
+ }
+ return ret;
+}
+
+void process_trapper_child(zbx_sock_t *sock)
+{
+ char *data;
+
+/* suseconds_t is not defined under HP-UX */
+/* struct timeval tv;
+ suseconds_t msec;
+ gettimeofday(&tv, NULL);
+ msec = tv.tv_usec;*/
+
+/* alarm(CONFIG_TIMEOUT);*/
+
+ if(zbx_tcp_recv(sock, &data) != SUCCEED)
+ {
+/* alarm(0);*/
+ return;
+ }
+
+ process_trap(sock, data, sizeof(data));
+/* alarm(0);*/
+
+/* gettimeofday(&tv, NULL);
+ zabbix_log( LOG_LEVEL_DEBUG, "Trap processed in " ZBX_FS_DBL " seconds",
+ (double)(tv.tv_usec-msec)/1000000 );*/
+}
+
+void child_trapper_main(int i, zbx_sock_t *s)
+{
+ zabbix_log( LOG_LEVEL_DEBUG, "In child_trapper_main()");
+
+ zabbix_log( LOG_LEVEL_WARNING, "server #%d started [Trapper]", i);
+
+ DBconnect(ZBX_DB_CONNECT_NORMAL);
+
+ for(;;)
+ {
+ zbx_setproctitle("waiting for connection");
+ zbx_tcp_accept(s);
+
+ zbx_setproctitle("processing data");
+ process_trapper_child(s);
+
+ zbx_tcp_unaccept(s);
+ }
+ DBclose();
+}
+
+/*
+pid_t child_trapper_make(int i,int listenfd, int addrlen)
+{
+ pid_t pid;
+
+ if((pid = zbx_fork()) >0)
+ {
+ return (pid);
+ }
+
+ child_trapper_main(i, listenfd, addrlen);
+
+ return 0;
+}*/
diff --git a/src/zabbix_proxy/trapper/trapper.h b/src/zabbix_proxy/trapper/trapper.h
new file mode 100644
index 00000000..3e3b543d
--- /dev/null
+++ b/src/zabbix_proxy/trapper/trapper.h
@@ -0,0 +1,31 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+#ifndef ZABBIX_TRAPPER_H
+#define ZABBIX_TRAPPER_H
+
+extern int server_num;
+
+extern int CONFIG_TIMEOUT;
+
+extern void signal_handler( int sig );
+
+void child_trapper_main(int i, zbx_sock_t *s);
+
+#endif
diff --git a/src/zabbix_proxy/zlog.c b/src/zabbix_proxy/zlog.c
new file mode 100644
index 00000000..a3071662
--- /dev/null
+++ b/src/zabbix_proxy/zlog.c
@@ -0,0 +1,92 @@
+/*
+** ZABBIX
+** Copyright (C) 2000-2005 SIA Zabbix
+**
+** 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.
+**/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <time.h>
+
+#include "common.h"
+#include "functions.h"
+#include "log.h"
+#include "zlog.h"
+
+/******************************************************************************
+ * *
+ * Function: zabbix_syslog *
+ * *
+ * Purpose: save internal warning or error message in item zabbix[log] *
+ * *
+ * Parameters: va_list arguments *
+ * *
+ * Return value: *
+ * *
+ * Author: Alexei Vladishev *
+ * *
+ * Comments: do nothing if no zabbix[log] items *
+ * *
+ ******************************************************************************/
+void __zbx_zabbix_syslog(const char *fmt, ...)
+{
+ va_list ap;
+ char value_str[MAX_STRING_LEN];
+
+ DB_ITEM item;
+ DB_RESULT result;
+ DB_ROW row;
+
+ AGENT_RESULT agent;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In zabbix_log()");
+
+ /* This is made to disable writing to database for watchdog */
+ if(CONFIG_ENABLE_LOG == 0) return;
+
+ result = DBselect("select %s where h.hostid=i.hostid and i.key_='%s' and i.value_type=%d and" ZBX_COND_NODEID,
+ ZBX_SQL_ITEM_SELECT,
+ SERVER_ZABBIXLOG_KEY,
+ ITEM_VALUE_TYPE_STR,
+ LOCAL_NODE("h.hostid"));
+
+ while((row=DBfetch(result)))
+ {
+ DBget_item_from_db(&item,row);
+
+ va_start(ap,fmt);
+ vsnprintf(value_str,sizeof(value_str),fmt,ap);
+ value_str[MAX_STRING_LEN-1]=0;
+ va_end(ap);
+
+ init_result(&agent);
+ SET_STR_RESULT(&agent, strdup(value_str));
+ process_new_value(&item,&agent);
+ free_result(&agent);
+
+ update_triggers(item.itemid);
+ }
+
+ DBfree_result(result);
+}