1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "daemon.h"
22 #include "log.h"
23 #include "zbxjson.h"
24 #include "zbxself.h"
25 
26 #include "heart.h"
27 #include "../servercomms.h"
28 #include "zbxcrypto.h"
29 #include "zbxcompress.h"
30 
31 extern unsigned char	process_type, program_type;
32 extern int		server_num, process_num;
33 
34 /******************************************************************************
35  *                                                                            *
36  * Function: send_heartbeat                                                   *
37  *                                                                            *
38  ******************************************************************************/
send_heartbeat(void)39 static int	send_heartbeat(void)
40 {
41 	zbx_socket_t	sock;
42 	struct zbx_json	j;
43 	int		ret = SUCCEED;
44 	char		*error = NULL, *buffer = NULL;
45 	size_t		buffer_size, reserved;
46 
47 	zabbix_log(LOG_LEVEL_DEBUG, "In send_heartbeat()");
48 
49 	zbx_json_init(&j, 128);
50 	zbx_json_addstring(&j, "request", ZBX_PROTO_VALUE_PROXY_HEARTBEAT, ZBX_JSON_TYPE_STRING);
51 	zbx_json_addstring(&j, "host", CONFIG_HOSTNAME, ZBX_JSON_TYPE_STRING);
52 	zbx_json_addstring(&j, ZBX_PROTO_TAG_VERSION, ZABBIX_VERSION, ZBX_JSON_TYPE_STRING);
53 
54 	if (SUCCEED != zbx_compress(j.buffer, j.buffer_size, &buffer, &buffer_size))
55 	{
56 		zabbix_log(LOG_LEVEL_ERR,"cannot compress data: %s", zbx_compress_strerror());
57 		goto clean;
58 	}
59 
60 	reserved = j.buffer_size;
61 
62 	if (FAIL == (ret = connect_to_server(&sock, CONFIG_HEARTBEAT_FREQUENCY, 0))) /* do not retry */
63 		goto clean;
64 
65 	if (SUCCEED != (ret = put_data_to_server(&sock, &buffer, buffer_size, reserved, &error)))
66 	{
67 		zabbix_log(LOG_LEVEL_WARNING, "cannot send heartbeat message to server at \"%s\": %s", sock.peer,
68 				error);
69 	}
70 
71 	disconnect_server(&sock);
72 	zbx_free(error);
73 clean:
74 	zbx_free(buffer);
75 	zbx_json_free(&j);
76 
77 	return ret;
78 }
79 
80 /******************************************************************************
81  *                                                                            *
82  * Function: main_heart_loop                                                  *
83  *                                                                            *
84  * Purpose: periodically send heartbeat message to the server                 *
85  *                                                                            *
86  ******************************************************************************/
ZBX_THREAD_ENTRY(heart_thread,args)87 ZBX_THREAD_ENTRY(heart_thread, args)
88 {
89 	int	start, sleeptime = 0, res;
90 	double	sec, total_sec = 0.0, old_total_sec = 0.0;
91 	time_t	last_stat_time;
92 
93 #define STAT_INTERVAL	5	/* if a process is busy and does not sleep then update status not faster than */
94 				/* once in STAT_INTERVAL seconds */
95 
96 	process_type = ((zbx_thread_args_t *)args)->process_type;
97 	server_num = ((zbx_thread_args_t *)args)->server_num;
98 	process_num = ((zbx_thread_args_t *)args)->process_num;
99 
100 	zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
101 			server_num, get_process_type_string(process_type), process_num);
102 
103 	update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
104 
105 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
106 	zbx_tls_init_child();
107 #endif
108 	last_stat_time = time(NULL);
109 
110 	zbx_setproctitle("%s [sending heartbeat message]", get_process_type_string(process_type));
111 
112 	while (ZBX_IS_RUNNING())
113 	{
114 		sec = zbx_time();
115 		zbx_update_env(sec);
116 
117 		if (0 != sleeptime)
118 		{
119 			zbx_setproctitle("%s [sending heartbeat message %s in " ZBX_FS_DBL " sec, "
120 					"sending heartbeat message]",
121 					get_process_type_string(process_type),
122 					SUCCEED == res ? "success" : "failed", old_total_sec);
123 		}
124 
125 		start = time(NULL);
126 		res = send_heartbeat();
127 		total_sec += zbx_time() - sec;
128 
129 		sleeptime = CONFIG_HEARTBEAT_FREQUENCY - (time(NULL) - start);
130 
131 		if (0 != sleeptime || STAT_INTERVAL <= time(NULL) - last_stat_time)
132 		{
133 			if (0 == sleeptime)
134 			{
135 				zbx_setproctitle("%s [sending heartbeat message %s in " ZBX_FS_DBL " sec, "
136 						"sending heartbeat message]",
137 						get_process_type_string(process_type),
138 						SUCCEED == res ? "success" : "failed", total_sec);
139 
140 			}
141 			else
142 			{
143 				zbx_setproctitle("%s [sending heartbeat message %s in " ZBX_FS_DBL " sec, "
144 						"idle %d sec]",
145 						get_process_type_string(process_type),
146 						SUCCEED == res ? "success" : "failed", total_sec, sleeptime);
147 
148 				old_total_sec = total_sec;
149 			}
150 			total_sec = 0.0;
151 			last_stat_time = time(NULL);
152 		}
153 
154 		zbx_sleep_loop(sleeptime);
155 	}
156 
157 	zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
158 
159 	while (1)
160 		zbx_sleep(SEC_PER_MIN);
161 #undef STAT_INTERVAL
162 }
163