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
22 #include "threads.h"
23 #include "comms.h"
24 #include "cfg.h"
25 #include "log.h"
26 #include "zbxgetopt.h"
27 #include "zbxjson.h"
28 #include "mutexs.h"
29 #include "zbxcrypto.h"
30 #if defined(_WINDOWS)
31 # include "../libs/zbxcrypto/tls.h"
32 #else
33 # include "zbxnix.h"
34 #endif
35
36 const char *progname = NULL;
37 const char title_message[] = "zabbix_sender";
38 const char syslog_app_name[] = "zabbix_sender";
39
40 const char *usage_message[] = {
41 "[-v]", "-z server", "[-p port]", "[-I IP-address]", "-s host", "-k key", "-o value", NULL,
42 "[-v]", "-z server", "[-p port]", "[-I IP-address]", "[-s host]", "[-T]", "[-N]", "[-r]", "-i input-file",
43 NULL,
44 "[-v]", "-c config-file", "[-z server]", "[-p port]", "[-I IP-address]", "[-s host]", "-k key", "-o value",
45 NULL,
46 "[-v]", "-c config-file", "[-z server]", "[-p port]", "[-I IP-address]", "[-s host]", "[-T]", "[-N]", "[-r]",
47 "-i input-file", NULL,
48 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
49 "[-v]", "-z server", "[-p port]", "[-I IP-address]", "-s host", "--tls-connect cert", "--tls-ca-file CA-file",
50 "[--tls-crl-file CRL-file]", "[--tls-server-cert-issuer cert-issuer]",
51 "[--tls-server-cert-subject cert-subject]", "--tls-cert-file cert-file", "--tls-key-file key-file",
52 #if defined(HAVE_OPENSSL)
53 "[--tls-cipher13 cipher-string]",
54 #endif
55 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
56 "[--tls-cipher cipher-string]",
57 #endif
58 "-k key", "-o value", NULL,
59 "[-v]", "-z server", "[-p port]", "[-I IP-address]", "[-s host]", "--tls-connect cert", "--tls-ca-file CA-file",
60 "[--tls-crl-file CRL-file]", "[--tls-server-cert-issuer cert-issuer]",
61 "[--tls-server-cert-subject cert-subject]", "--tls-cert-file cert-file", "--tls-key-file key-file",
62 #if defined(HAVE_OPENSSL)
63 "[--tls-cipher13] cipher-string",
64 #endif
65 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
66 "[--tls-cipher cipher-string]",
67 #endif
68 "[-T]", "[-N]", "[-r]", "-i input-file", NULL,
69 "[-v]", "-c config-file [-z server]", "[-p port]", "[-I IP-address]", "[-s host]", "--tls-connect cert",
70 "--tls-ca-file CA-file", "[--tls-crl-file CRL-file]", "[--tls-server-cert-issuer cert-issuer]",
71 "[--tls-server-cert-subject cert-subject]", "--tls-cert-file cert-file", "--tls-key-file key-file",
72 #if defined(HAVE_OPENSSL)
73 "[--tls-cipher13 cipher-string]",
74 #endif
75 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
76 "[--tls-cipher cipher-string]",
77 #endif
78 "-k key", "-o value", NULL,
79 "[-v]", "-c config-file", "[-z server]", "[-p port]", "[-I IP-address]", "[-s host]", "--tls-connect cert",
80 "--tls-ca-file CA-file", "[--tls-crl-file CRL-file]", "[--tls-server-cert-issuer cert-issuer]",
81 "[--tls-server-cert-subject cert-subject]", "--tls-cert-file cert-file", "--tls-key-file key-file",
82 #if defined(HAVE_OPENSSL)
83 "[--tls-cipher13 cipher-string]",
84 #endif
85 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
86 "[--tls-cipher cipher-string]",
87 #endif
88 "[-T]", "[-N]", "[-r]", "-i input-file", NULL,
89 "[-v]", "-z server", "[-p port]", "[-I IP-address]", "-s host", "--tls-connect psk",
90 "--tls-psk-identity PSK-identity", "--tls-psk-file PSK-file",
91 #if defined(HAVE_OPENSSL)
92 "[--tls-cipher13 cipher-string]",
93 #endif
94 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
95 "[--tls-cipher cipher-string]",
96 #endif
97 "-k key", "-o value", NULL,
98 "[-v]", "-z server", "[-p port]", "[-I IP-address]", "[-s host]", "--tls-connect psk",
99 "--tls-psk-identity PSK-identity", "--tls-psk-file PSK-file",
100 #if defined(HAVE_OPENSSL)
101 "[--tls-cipher13 cipher-string]",
102 #endif
103 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
104 "[--tls-cipher cipher-string]",
105 #endif
106 "[-T]", "[-N]", "[-r]", "-i input-file", NULL,
107 "[-v]", "-c config-file", "[-z server]", "[-p port]", "[-I IP-address]", "[-s host]", "--tls-connect psk",
108 "--tls-psk-identity PSK-identity", "--tls-psk-file PSK-file",
109 #if defined(HAVE_OPENSSL)
110 "[--tls-cipher13 cipher-string]",
111 #endif
112 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
113 "[--tls-cipher cipher-string]",
114 #endif
115 "-k key", "-o value", NULL,
116 "[-v]", "-c config-file", "[-z server]", "[-p port]", "[-I IP-address]", "[-s host]", "--tls-connect psk",
117 "--tls-psk-identity PSK-identity", "--tls-psk-file PSK-file",
118 #if defined(HAVE_OPENSSL)
119 "[--tls-cipher13 cipher-string]",
120 #endif
121 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
122 "[--tls-cipher cipher-string]",
123 #endif
124 "[-T]", "[-N]", "[-r]", "-i input-file", NULL,
125 #endif
126 "-h", NULL,
127 "-V", NULL,
128 NULL /* end of text */
129 };
130
131 unsigned char program_type = ZBX_PROGRAM_TYPE_SENDER;
132
133 const char *help_message[] = {
134 "Utility for sending monitoring data to Zabbix server or proxy.",
135 "",
136 "General options:",
137 " -c --config config-file Path to Zabbix agentd configuration file",
138 "",
139 " -z --zabbix-server server Hostname or IP address of Zabbix server or proxy",
140 " to send data to. When used together with --config,",
141 " overrides the first entry of \"ServerActive\"",
142 " parameter specified in agentd configuration file",
143 "",
144 " -p --port port Specify port number of trapper process of Zabbix",
145 " server or proxy. When used together with --config,",
146 " overrides the port of the first entry of",
147 " \"ServerActive\" parameter specified in agentd",
148 " configuration file (default: " ZBX_DEFAULT_SERVER_PORT_STR ")",
149 "",
150 " -I --source-address IP-address Specify source IP address. When used",
151 " together with --config, overrides \"SourceIP\"",
152 " parameter specified in agentd configuration file",
153 "",
154 " -s --host host Specify host name the item belongs to (as",
155 " registered in Zabbix frontend). Host IP address",
156 " and DNS name will not work. When used together",
157 " with --config, overrides \"Hostname\" parameter",
158 " specified in agentd configuration file",
159 "",
160 " -k --key key Specify item key",
161 " -o --value value Specify item value",
162 "",
163 " -i --input-file input-file Load values from input file. Specify - for",
164 " standard input. Each line of file contains",
165 " whitespace delimited: <host> <key> <value>.",
166 " Specify - in <host> to use hostname from",
167 " configuration file or --host argument",
168 "",
169 " -T --with-timestamps Each line of file contains whitespace delimited:",
170 " <host> <key> <timestamp> <value>. This can be used",
171 " with --input-file option. Timestamp should be",
172 " specified in Unix timestamp format",
173 "",
174 " -N --with-ns Each line of file contains whitespace delimited:",
175 " <host> <key> <timestamp> <ns> <value>. This can be used",
176 " with --with-timestamps option",
177 "",
178 " -r --real-time Send metrics one by one as soon as they are",
179 " received. This can be used when reading from",
180 " standard input",
181 "",
182 " -v --verbose Verbose mode, -vv for more details",
183 "",
184 " -h --help Display this help message",
185 " -V --version Display version number",
186 "",
187 "TLS connection options:",
188 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
189 " --tls-connect value How to connect to server or proxy. Values:",
190 " unencrypted - connect without encryption",
191 " (default)",
192 " psk - connect using TLS and a pre-shared",
193 " key",
194 " cert - connect using TLS and a",
195 " certificate",
196 "",
197 " --tls-ca-file CA-file Full pathname of a file containing the top-level",
198 " CA(s) certificates for peer certificate",
199 " verification",
200 "",
201 " --tls-crl-file CRL-file Full pathname of a file containing revoked",
202 " certificates",
203 "",
204 " --tls-server-cert-issuer cert-issuer Allowed server certificate issuer",
205 "",
206 " --tls-server-cert-subject cert-subject Allowed server certificate subject",
207 "",
208 " --tls-cert-file cert-file Full pathname of a file containing the certificate",
209 " or certificate chain",
210 "",
211 " --tls-key-file key-file Full pathname of a file containing the private key",
212 "",
213 " --tls-psk-identity PSK-identity Unique, case sensitive string used to",
214 " identify the pre-shared key",
215 "",
216 " --tls-psk-file PSK-file Full pathname of a file containing the pre-shared",
217 " key",
218 #if defined(HAVE_OPENSSL)
219 "",
220 " --tls-cipher13 Cipher string for OpenSSL 1.1.1 or newer for",
221 " TLS 1.3. Override the default ciphersuite",
222 " selection criteria. This option is not available",
223 " if OpenSSL version is less than 1.1.1",
224 #endif
225 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
226 "",
227 " --tls-cipher GnuTLS priority string (for TLS 1.2 and up) or",
228 " OpenSSL cipher string (only for TLS 1.2).",
229 " Override the default ciphersuite selection",
230 " criteria",
231 #endif
232 #else
233 " Not available. This Zabbix sender was compiled without TLS support",
234 #endif
235 "",
236 "Example(s):",
237 " zabbix_sender -z 127.0.0.1 -s \"Linux DB3\" -k db.connections -o 43",
238 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
239 "",
240 " zabbix_sender -z 127.0.0.1 -s \"Linux DB3\" -k db.connections -o 43 \\",
241 " --tls-connect cert --tls-ca-file /home/zabbix/zabbix_ca_file \\",
242 " --tls-server-cert-issuer \\",
243 " \"CN=Signing CA,OU=IT operations,O=Example Corp,DC=example,DC=com\" \\",
244 " --tls-server-cert-subject \\",
245 " \"CN=Zabbix proxy,OU=IT operations,O=Example Corp,DC=example,DC=com\" \\",
246 " --tls-cert-file /home/zabbix/zabbix_agentd.crt \\",
247 " --tls-key-file /home/zabbix/zabbix_agentd.key",
248 "",
249 " zabbix_sender -z 127.0.0.1 -s \"Linux DB3\" -k db.connections -o 43 \\",
250 " --tls-connect psk --tls-psk-identity \"PSK ID Zabbix agentd\" \\",
251 " --tls-psk-file /home/zabbix/zabbix_agentd.psk",
252 #endif
253 NULL /* end of text */
254 };
255
256 /* TLS parameters */
257 unsigned int configured_tls_connect_mode = ZBX_TCP_SEC_UNENCRYPTED;
258 unsigned int configured_tls_accept_modes = ZBX_TCP_SEC_UNENCRYPTED; /* not used in zabbix_sender, just for */
259 /* linking with tls.c */
260 char *CONFIG_TLS_CONNECT = NULL;
261 char *CONFIG_TLS_ACCEPT = NULL; /* not used in zabbix_sender, just for linking with tls.c */
262 char *CONFIG_TLS_CA_FILE = NULL;
263 char *CONFIG_TLS_CRL_FILE = NULL;
264 char *CONFIG_TLS_SERVER_CERT_ISSUER = NULL;
265 char *CONFIG_TLS_SERVER_CERT_SUBJECT = NULL;
266 char *CONFIG_TLS_CERT_FILE = NULL;
267 char *CONFIG_TLS_KEY_FILE = NULL;
268 char *CONFIG_TLS_PSK_IDENTITY = NULL;
269 char *CONFIG_TLS_PSK_FILE = NULL;
270
271 char *CONFIG_TLS_CIPHER_CERT13 = NULL; /* parameter 'TLSCipherCert13' from agent config file */
272 char *CONFIG_TLS_CIPHER_CERT = NULL; /* parameter 'TLSCipherCert' from agent config file */
273 char *CONFIG_TLS_CIPHER_PSK13 = NULL; /* parameter 'TLSCipherPSK13' from agent config file */
274 char *CONFIG_TLS_CIPHER_PSK = NULL; /* parameter 'TLSCipherPSK' from agent config file */
275 char *CONFIG_TLS_CIPHER_ALL13 = NULL; /* not used in zabbix_sender, just for linking with tls.c */
276 char *CONFIG_TLS_CIPHER_ALL = NULL; /* not used in zabbix_sender, just for linking with tls.c */
277 char *CONFIG_TLS_CIPHER_CMD13 = NULL; /* parameter '--tls-cipher13' from sender command line */
278 char *CONFIG_TLS_CIPHER_CMD = NULL; /* parameter '--tls-cipher' from sender command line */
279
280 int CONFIG_PASSIVE_FORKS = 0; /* not used in zabbix_sender, just for linking with tls.c */
281 int CONFIG_ACTIVE_FORKS = 0; /* not used in zabbix_sender, just for linking with tls.c */
282
283 int CONFIG_TCP_MAX_BACKLOG_SIZE = SOMAXCONN;
284
285 /* COMMAND LINE OPTIONS */
286
287 /* long options */
288 static struct zbx_option longopts[] =
289 {
290 {"config", 1, NULL, 'c'},
291 {"zabbix-server", 1, NULL, 'z'},
292 {"port", 1, NULL, 'p'},
293 {"host", 1, NULL, 's'},
294 {"source-address", 1, NULL, 'I'},
295 {"key", 1, NULL, 'k'},
296 {"value", 1, NULL, 'o'},
297 {"input-file", 1, NULL, 'i'},
298 {"with-timestamps", 0, NULL, 'T'},
299 {"with-ns", 0, NULL, 'N'},
300 {"real-time", 0, NULL, 'r'},
301 {"verbose", 0, NULL, 'v'},
302 {"help", 0, NULL, 'h'},
303 {"version", 0, NULL, 'V'},
304 {"tls-connect", 1, NULL, '1'},
305 {"tls-ca-file", 1, NULL, '2'},
306 {"tls-crl-file", 1, NULL, '3'},
307 {"tls-server-cert-issuer", 1, NULL, '4'},
308 {"tls-server-cert-subject", 1, NULL, '5'},
309 {"tls-cert-file", 1, NULL, '6'},
310 {"tls-key-file", 1, NULL, '7'},
311 {"tls-psk-identity", 1, NULL, '8'},
312 {"tls-psk-file", 1, NULL, '9'},
313 {"tls-cipher13", 1, NULL, 'A'},
314 {"tls-cipher", 1, NULL, 'B'},
315 {NULL}
316 };
317
318 /* short options */
319 static char shortopts[] = "c:I:z:p:s:k:o:TNi:rvhV";
320
321 /* end of COMMAND LINE OPTIONS */
322
323 static int CONFIG_LOG_LEVEL = LOG_LEVEL_CRIT;
324
325 static char *INPUT_FILE = NULL;
326 static int WITH_TIMESTAMPS = 0;
327 static int WITH_NS = 0;
328 static int REAL_TIME = 0;
329
330 static char *CONFIG_SOURCE_IP = NULL;
331 static char *ZABBIX_SERVER = NULL;
332 static char *ZABBIX_SERVER_PORT = NULL;
333 static char *ZABBIX_HOSTNAME = NULL;
334 static char *ZABBIX_KEY = NULL;
335 static char *ZABBIX_KEY_VALUE = NULL;
336
337 typedef struct
338 {
339 char *host;
340 unsigned short port;
341 ZBX_THREAD_HANDLE *thread;
342 }
343 zbx_send_destinations_t;
344
345 static zbx_send_destinations_t *destinations = NULL; /* list of servers to send data to */
346 static int destinations_count = 0;
347
348 volatile sig_atomic_t sig_exiting = 0;
349
350 #if !defined(_WINDOWS)
sender_signal_handler(int sig)351 static void sender_signal_handler(int sig)
352 {
353 #define CASE_LOG_WARNING(signal) \
354 case signal: \
355 zabbix_log(LOG_LEVEL_WARNING, "interrupted by signal " #signal " while executing operation"); \
356 break
357
358 switch (sig)
359 {
360 CASE_LOG_WARNING(SIGALRM);
361 CASE_LOG_WARNING(SIGINT);
362 CASE_LOG_WARNING(SIGQUIT);
363 CASE_LOG_WARNING(SIGTERM);
364 CASE_LOG_WARNING(SIGHUP);
365 CASE_LOG_WARNING(SIGPIPE);
366 default:
367 zabbix_log(LOG_LEVEL_WARNING, "signal %d while executing operation", sig);
368 }
369 #undef CASE_LOG_WARNING
370
371 /* Calling _exit() to terminate the process immediately is important. See ZBX-5732 for details. */
372 /* Return FAIL instead of EXIT_FAILURE to keep return signals consistent for send_value() */
373 _exit(FAIL);
374 }
375
main_signal_handler(int sig)376 static void main_signal_handler(int sig)
377 {
378 if (0 == sig_exiting)
379 {
380 int i;
381
382 sig_exiting = 1;
383
384 for (i = 0; i < destinations_count; i++)
385 {
386 pid_t child = *(destinations[i].thread);
387
388 if (ZBX_THREAD_HANDLE_NULL != child)
389 kill(child, sig);
390 }
391 }
392 }
393 #endif
394
395 typedef struct
396 {
397 char *server;
398 unsigned short port;
399 struct zbx_json json;
400 #if defined(_WINDOWS) && (defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL))
401 ZBX_THREAD_SENDVAL_TLS_ARGS tls_vars;
402 #endif
403 int sync_timestamp;
404 }
405 ZBX_THREAD_SENDVAL_ARGS;
406
407 #define SUCCEED_PARTIAL 2
408
409 /******************************************************************************
410 * *
411 * Function: sender_threads_wait *
412 * *
413 * Purpose: waits until the "threads" are in the signalled state and manages *
414 * exit status updates *
415 * *
416 * Parameters: *
417 * threads - [IN] thread handles *
418 * threads_num - [IN] thread count *
419 * old_status - [IN] previous status *
420 * *
421 * Return value: SUCCEED - success with all values at all destinations *
422 * FAIL - an error occurred *
423 * SUCCEED_PARTIAL - data sending was completed successfully *
424 * to at least one destination or processing of at least one *
425 * value at least at one destination failed *
426 * *
427 * Comments: SUCCEED_PARTIAL status should be sticky in the sense that *
428 * SUCCEED statuses that come after should not overwrite it *
429 * *
430 ******************************************************************************/
sender_threads_wait(ZBX_THREAD_HANDLE * threads,int threads_num,const int old_status)431 static int sender_threads_wait(ZBX_THREAD_HANDLE *threads, int threads_num, const int old_status)
432 {
433 int i, sp_count = 0, fail_count = 0;
434 #if defined(_WINDOWS)
435 /* wait for threads to finish */
436 WaitForMultipleObjectsEx(threads_num, threads, TRUE, INFINITE, FALSE);
437 #endif
438 for (i = 0; i < threads_num; i++)
439 {
440 int new_status;
441
442 if (SUCCEED_PARTIAL == (new_status = zbx_thread_wait(threads[i])))
443 sp_count++;
444
445 if (SUCCEED != new_status && SUCCEED_PARTIAL != new_status)
446 {
447 int j;
448
449 for (fail_count++, j = 0; j < destinations_count; j++)
450 {
451 if (destinations[j].thread == &threads[i])
452 {
453 zbx_free(destinations[j].host);
454 destinations[j] = destinations[--destinations_count];
455 break;
456 }
457 }
458 }
459
460 threads[i] = ZBX_THREAD_HANDLE_NULL;
461 }
462
463 if (threads_num == fail_count)
464 return FAIL;
465 else if (SUCCEED_PARTIAL == old_status || 0 != sp_count || 0 != fail_count)
466 return SUCCEED_PARTIAL;
467 else
468 return SUCCEED;
469 }
470
471 /******************************************************************************
472 * *
473 * Function: get_string *
474 * *
475 * Purpose: get current string from the quoted or unquoted string list, *
476 * delimited by blanks *
477 * *
478 * Parameters: *
479 * p - [IN] parameter list, delimited by blanks (' ' or '\t') *
480 * buf - [OUT] output buffer *
481 * bufsize - [IN] output buffer size *
482 * *
483 * Return value: pointer to the next string *
484 * *
485 ******************************************************************************/
get_string(const char * p,char * buf,size_t bufsize)486 static const char *get_string(const char *p, char *buf, size_t bufsize)
487 {
488 /* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
489 int state;
490 size_t buf_i = 0;
491
492 bufsize--; /* '\0' */
493
494 for (state = 0; '\0' != *p; p++)
495 {
496 switch (state)
497 {
498 /* init state */
499 case 0:
500 if (' ' == *p || '\t' == *p)
501 {
502 /* skipping the leading spaces */;
503 }
504 else if ('"' == *p)
505 {
506 state = 1;
507 }
508 else
509 {
510 state = 2;
511 p--;
512 }
513 break;
514 /* quoted */
515 case 1:
516 if ('"' == *p)
517 {
518 if (' ' != p[1] && '\t' != p[1] && '\0' != p[1])
519 return NULL; /* incorrect syntax */
520
521 while (' ' == p[1] || '\t' == p[1])
522 p++;
523
524 buf[buf_i] = '\0';
525 return ++p;
526 }
527 else if ('\\' == *p && ('"' == p[1] || '\\' == p[1]))
528 {
529 p++;
530 if (buf_i < bufsize)
531 buf[buf_i++] = *p;
532 }
533 else if ('\\' == *p && 'n' == p[1])
534 {
535 p++;
536 if (buf_i < bufsize)
537 buf[buf_i++] = '\n';
538 }
539 else if (buf_i < bufsize)
540 {
541 buf[buf_i++] = *p;
542 }
543 break;
544 /* unquoted */
545 case 2:
546 if (' ' == *p || '\t' == *p)
547 {
548 while (' ' == *p || '\t' == *p)
549 p++;
550
551 buf[buf_i] = '\0';
552 return p;
553 }
554 else if (buf_i < bufsize)
555 {
556 buf[buf_i++] = *p;
557 }
558 break;
559 }
560 }
561
562 /* missing terminating '"' character */
563 if (1 == state)
564 return NULL;
565
566 buf[buf_i] = '\0';
567
568 return p;
569 }
570
571 /******************************************************************************
572 * *
573 * Function: check_response *
574 * *
575 * Purpose: Check whether JSON response is SUCCEED *
576 * *
577 * Parameters: JSON response from Zabbix trapper *
578 * *
579 * Return value: SUCCEED - processed successfully *
580 * FAIL - an error occurred *
581 * SUCCEED_PARTIAL - the sending operation was completed *
582 * successfully, but processing of at least one value failed *
583 * *
584 * Author: Alexei Vladishev *
585 * *
586 * Comments: active agent has almost the same function! *
587 * *
588 ******************************************************************************/
check_response(char * response,const char * server,unsigned short port)589 static int check_response(char *response, const char *server, unsigned short port)
590 {
591 struct zbx_json_parse jp;
592 char value[MAX_STRING_LEN];
593 char info[MAX_STRING_LEN];
594 int ret;
595
596 ret = zbx_json_open(response, &jp);
597
598 if (SUCCEED == ret)
599 ret = zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_RESPONSE, value, sizeof(value), NULL);
600
601 if (SUCCEED == ret && 0 != strcmp(value, ZBX_PROTO_VALUE_SUCCESS))
602 ret = FAIL;
603
604 if (SUCCEED == ret && SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_INFO, info, sizeof(info), NULL))
605 {
606 int failed;
607
608 printf("Response from \"%s:%hu\": \"%s\"\n", server, port, info);
609 fflush(stdout);
610
611 if (1 == sscanf(info, "processed: %*d; failed: %d", &failed) && 0 < failed)
612 ret = SUCCEED_PARTIAL;
613 }
614
615 return ret;
616 }
617
ZBX_THREAD_ENTRY(send_value,args)618 static ZBX_THREAD_ENTRY(send_value, args)
619 {
620 ZBX_THREAD_SENDVAL_ARGS *sendval_args = (ZBX_THREAD_SENDVAL_ARGS *)((zbx_thread_args_t *)args)->args;
621 int tcp_ret, ret = FAIL;
622 char *tls_arg1, *tls_arg2;
623 zbx_socket_t sock;
624
625 #if !defined(_WINDOWS)
626 signal(SIGINT, sender_signal_handler);
627 signal(SIGQUIT, sender_signal_handler);
628 signal(SIGTERM, sender_signal_handler);
629 signal(SIGHUP, sender_signal_handler);
630 signal(SIGALRM, sender_signal_handler);
631 signal(SIGPIPE, sender_signal_handler);
632 #endif
633
634 #if defined(_WINDOWS) && (defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL))
635 if (ZBX_TCP_SEC_UNENCRYPTED != configured_tls_connect_mode)
636 {
637 /* take TLS data passed from 'main' thread */
638 zbx_tls_take_vars(&sendval_args->tls_vars);
639 }
640 #endif
641 switch (configured_tls_connect_mode)
642 {
643 case ZBX_TCP_SEC_UNENCRYPTED:
644 tls_arg1 = NULL;
645 tls_arg2 = NULL;
646 break;
647 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
648 case ZBX_TCP_SEC_TLS_CERT:
649 tls_arg1 = CONFIG_TLS_SERVER_CERT_ISSUER;
650 tls_arg2 = CONFIG_TLS_SERVER_CERT_SUBJECT;
651 break;
652 case ZBX_TCP_SEC_TLS_PSK:
653 tls_arg1 = CONFIG_TLS_PSK_IDENTITY;
654 tls_arg2 = NULL; /* zbx_tls_connect() will find PSK */
655 break;
656 #endif
657 default:
658 THIS_SHOULD_NEVER_HAPPEN;
659 goto out;
660 }
661
662 if (SUCCEED == (tcp_ret = zbx_tcp_connect(&sock, CONFIG_SOURCE_IP, sendval_args->server, sendval_args->port,
663 GET_SENDER_TIMEOUT, configured_tls_connect_mode, tls_arg1, tls_arg2)))
664 {
665 if (1 == sendval_args->sync_timestamp)
666 {
667 zbx_timespec_t ts;
668
669 zbx_timespec(&ts);
670
671 zbx_json_adduint64(&sendval_args->json, ZBX_PROTO_TAG_CLOCK, ts.sec);
672 zbx_json_adduint64(&sendval_args->json, ZBX_PROTO_TAG_NS, ts.ns);
673 }
674
675 if (SUCCEED == (tcp_ret = zbx_tcp_send(&sock, sendval_args->json.buffer)))
676 {
677 if (SUCCEED == (tcp_ret = zbx_tcp_recv(&sock)))
678 {
679 zabbix_log(LOG_LEVEL_DEBUG, "answer [%s]", sock.buffer);
680
681 if (FAIL == (ret = check_response(sock.buffer, sendval_args->server,
682 sendval_args->port)))
683 {
684 zabbix_log(LOG_LEVEL_WARNING, "incorrect answer from \"%s:%hu\": [%s]",
685 sendval_args->server, sendval_args->port, sock.buffer);
686 }
687 }
688 }
689
690 zbx_tcp_close(&sock);
691 }
692
693 if (FAIL == tcp_ret)
694 zabbix_log(LOG_LEVEL_DEBUG, "send value error: %s", zbx_socket_strerror());
695 out:
696 zbx_thread_exit(ret);
697 }
698
699 /******************************************************************************
700 * *
701 * Function: perform_data_sending *
702 * *
703 * Purpose: Send data to all destinations each in a separate thread and wait *
704 * till threads have completed their task *
705 * *
706 * Parameters: *
707 * sendval_args - [IN] arguments for thread function *
708 * old_status - [IN] previous status *
709 * *
710 * Return value: SUCCEED - success with all values at all destinations *
711 * FAIL - an error occurred *
712 * SUCCEED_PARTIAL - data sending was completed successfully *
713 * to at least one destination or processing of at least one *
714 * value at least at one destination failed *
715 * *
716 ******************************************************************************/
perform_data_sending(ZBX_THREAD_SENDVAL_ARGS * sendval_args,int old_status)717 static int perform_data_sending(ZBX_THREAD_SENDVAL_ARGS *sendval_args, int old_status)
718 {
719 int i, ret;
720 ZBX_THREAD_HANDLE *threads = NULL;
721
722 threads = (ZBX_THREAD_HANDLE *)zbx_calloc(threads, destinations_count, sizeof(ZBX_THREAD_HANDLE));
723
724 for (i = 0; i < destinations_count; i++)
725 {
726 zbx_thread_args_t *thread_args;
727
728 thread_args = (zbx_thread_args_t *)zbx_malloc(NULL, sizeof(zbx_thread_args_t));
729
730 thread_args->args = &sendval_args[i];
731
732 sendval_args[i].server = destinations[i].host;
733 sendval_args[i].port = destinations[i].port;
734
735 if (0 != i)
736 {
737 sendval_args[i].json = sendval_args[0].json;
738 #if defined(_WINDOWS) && (defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL))
739 sendval_args[i].tls_vars = sendval_args[0].tls_vars;
740 #endif
741 sendval_args[i].sync_timestamp = sendval_args[0].sync_timestamp;
742 }
743
744 destinations[i].thread = &threads[i];
745
746 zbx_thread_start(send_value, thread_args, &threads[i]);
747 #ifndef _WINDOWS
748 zbx_free(thread_args);
749 #endif
750 }
751
752 ret = sender_threads_wait(threads, destinations_count, old_status);
753
754 zbx_free(threads);
755
756 return ret;
757 }
758
759 /******************************************************************************
760 * *
761 * Function: sender_add_serveractive_host_cb *
762 * *
763 * Purpose: add server or proxy to the list of destinations *
764 * *
765 * Parameters: *
766 * host - [IN] IP or hostname *
767 * port - [IN] port number *
768 * *
769 * Return value: SUCCEED - destination added successfully *
770 * FAIL - destination has been already added *
771 * *
772 ******************************************************************************/
sender_add_serveractive_host_cb(const char * host,unsigned short port)773 static int sender_add_serveractive_host_cb(const char *host, unsigned short port)
774 {
775 int i;
776
777 for (i = 0; i < destinations_count; i++)
778 {
779 if (0 == strcmp(destinations[i].host, host) && destinations[i].port == port)
780 return FAIL;
781 }
782
783 destinations_count++;
784 #if defined(_WINDOWS)
785 if (MAXIMUM_WAIT_OBJECTS < destinations_count)
786 {
787 zbx_error("error parsing the \"ServerActive\" parameter: maximum destination limit of %d has been"
788 " exceeded", MAXIMUM_WAIT_OBJECTS);
789 exit(EXIT_FAILURE);
790 }
791 #endif
792 destinations = (zbx_send_destinations_t *)zbx_realloc(destinations,
793 sizeof(zbx_send_destinations_t) * destinations_count);
794
795 destinations[destinations_count - 1].host = zbx_strdup(NULL, host);
796 destinations[destinations_count - 1].port = port;
797
798 return SUCCEED;
799 }
800
zbx_fill_from_config_file(char ** dst,char * src)801 static void zbx_fill_from_config_file(char **dst, char *src)
802 {
803 /* helper function, only for TYPE_STRING configuration parameters */
804
805 if (NULL != src)
806 {
807 if (NULL == *dst)
808 *dst = zbx_strdup(*dst, src);
809
810 zbx_free(src);
811 }
812 }
813
zbx_load_config(const char * config_file)814 static void zbx_load_config(const char *config_file)
815 {
816 char *cfg_source_ip = NULL, *cfg_active_hosts = NULL, *cfg_hostname = NULL, *cfg_tls_connect = NULL,
817 *cfg_tls_ca_file = NULL, *cfg_tls_crl_file = NULL, *cfg_tls_server_cert_issuer = NULL,
818 *cfg_tls_server_cert_subject = NULL, *cfg_tls_cert_file = NULL, *cfg_tls_key_file = NULL,
819 *cfg_tls_psk_file = NULL, *cfg_tls_psk_identity = NULL,
820 *cfg_tls_cipher_cert13 = NULL, *cfg_tls_cipher_cert = NULL,
821 *cfg_tls_cipher_psk13 = NULL, *cfg_tls_cipher_psk = NULL;
822
823 struct cfg_line cfg[] =
824 {
825 /* PARAMETER, VAR, TYPE,
826 MANDATORY, MIN, MAX */
827 {"SourceIP", &cfg_source_ip, TYPE_STRING,
828 PARM_OPT, 0, 0},
829 {"ServerActive", &cfg_active_hosts, TYPE_STRING_LIST,
830 PARM_OPT, 0, 0},
831 {"Hostname", &cfg_hostname, TYPE_STRING,
832 PARM_OPT, 0, 0},
833 {"TLSConnect", &cfg_tls_connect, TYPE_STRING,
834 PARM_OPT, 0, 0},
835 {"TLSCAFile", &cfg_tls_ca_file, TYPE_STRING,
836 PARM_OPT, 0, 0},
837 {"TLSCRLFile", &cfg_tls_crl_file, TYPE_STRING,
838 PARM_OPT, 0, 0},
839 {"TLSServerCertIssuer", &cfg_tls_server_cert_issuer, TYPE_STRING,
840 PARM_OPT, 0, 0},
841 {"TLSServerCertSubject", &cfg_tls_server_cert_subject, TYPE_STRING,
842 PARM_OPT, 0, 0},
843 {"TLSCertFile", &cfg_tls_cert_file, TYPE_STRING,
844 PARM_OPT, 0, 0},
845 {"TLSKeyFile", &cfg_tls_key_file, TYPE_STRING,
846 PARM_OPT, 0, 0},
847 {"TLSPSKIdentity", &cfg_tls_psk_identity, TYPE_STRING,
848 PARM_OPT, 0, 0},
849 {"TLSPSKFile", &cfg_tls_psk_file, TYPE_STRING,
850 PARM_OPT, 0, 0},
851 {"TLSCipherCert13", &cfg_tls_cipher_cert13, TYPE_STRING,
852 PARM_OPT, 0, 0},
853 {"TLSCipherCert", &cfg_tls_cipher_cert, TYPE_STRING,
854 PARM_OPT, 0, 0},
855 {"TLSCipherPSK13", &cfg_tls_cipher_psk13, TYPE_STRING,
856 PARM_OPT, 0, 0},
857 {"TLSCipherPSK", &cfg_tls_cipher_psk, TYPE_STRING,
858 PARM_OPT, 0, 0},
859 {"ListenBacklog", &CONFIG_TCP_MAX_BACKLOG_SIZE, TYPE_INT,
860 PARM_OPT, 0, INT_MAX},
861 {NULL}
862 };
863
864 /* do not complain about unknown parameters in agent configuration file */
865 parse_cfg_file(config_file, cfg, ZBX_CFG_FILE_REQUIRED, ZBX_CFG_NOT_STRICT);
866
867 zbx_fill_from_config_file(&CONFIG_SOURCE_IP, cfg_source_ip);
868
869 if (NULL == ZABBIX_SERVER)
870 {
871 if (NULL != cfg_active_hosts && '\0' != *cfg_active_hosts)
872 zbx_set_data_destination_hosts(cfg_active_hosts, sender_add_serveractive_host_cb);
873 }
874 zbx_free(cfg_active_hosts);
875
876 zbx_fill_from_config_file(&ZABBIX_HOSTNAME, cfg_hostname);
877
878 zbx_fill_from_config_file(&CONFIG_TLS_CONNECT, cfg_tls_connect);
879 zbx_fill_from_config_file(&CONFIG_TLS_CA_FILE, cfg_tls_ca_file);
880 zbx_fill_from_config_file(&CONFIG_TLS_CRL_FILE, cfg_tls_crl_file);
881 zbx_fill_from_config_file(&CONFIG_TLS_SERVER_CERT_ISSUER, cfg_tls_server_cert_issuer);
882 zbx_fill_from_config_file(&CONFIG_TLS_SERVER_CERT_SUBJECT, cfg_tls_server_cert_subject);
883 zbx_fill_from_config_file(&CONFIG_TLS_CERT_FILE, cfg_tls_cert_file);
884 zbx_fill_from_config_file(&CONFIG_TLS_KEY_FILE, cfg_tls_key_file);
885 zbx_fill_from_config_file(&CONFIG_TLS_PSK_IDENTITY, cfg_tls_psk_identity);
886 zbx_fill_from_config_file(&CONFIG_TLS_PSK_FILE, cfg_tls_psk_file);
887
888 zbx_fill_from_config_file(&CONFIG_TLS_CIPHER_CERT13, cfg_tls_cipher_cert13);
889 zbx_fill_from_config_file(&CONFIG_TLS_CIPHER_CERT, cfg_tls_cipher_cert);
890 zbx_fill_from_config_file(&CONFIG_TLS_CIPHER_PSK13, cfg_tls_cipher_psk13);
891 zbx_fill_from_config_file(&CONFIG_TLS_CIPHER_PSK, cfg_tls_cipher_psk);
892 }
893
parse_commandline(int argc,char ** argv)894 static void parse_commandline(int argc, char **argv)
895 {
896 /* Minimum and maximum port numbers Zabbix sender can connect to. */
897 /* Do not forget to modify port number validation below if MAX_ZABBIX_PORT is ever changed. */
898 #define MIN_ZABBIX_PORT 1u
899 #define MAX_ZABBIX_PORT 65535u
900
901 int i, fatal = 0;
902 char ch;
903 unsigned int opt_mask = 0;
904 unsigned short opt_count[256] = {0};
905
906 /* parse the command-line */
907 while ((char)EOF != (ch = (char)zbx_getopt_long(argc, argv, shortopts, longopts, NULL)))
908 {
909 opt_count[(unsigned char)ch]++;
910
911 switch (ch)
912 {
913 case 'c':
914 if (NULL == CONFIG_FILE)
915 CONFIG_FILE = zbx_strdup(CONFIG_FILE, zbx_optarg);
916 break;
917 case 'h':
918 help();
919 exit(EXIT_SUCCESS);
920 break;
921 case 'V':
922 version();
923 exit(EXIT_SUCCESS);
924 break;
925 case 'I':
926 if (NULL == CONFIG_SOURCE_IP)
927 CONFIG_SOURCE_IP = zbx_strdup(CONFIG_SOURCE_IP, zbx_optarg);
928 break;
929 case 'z':
930 if (NULL == ZABBIX_SERVER)
931 ZABBIX_SERVER = zbx_strdup(ZABBIX_SERVER, zbx_optarg);
932 break;
933 case 'p':
934 if (NULL == ZABBIX_SERVER_PORT)
935 ZABBIX_SERVER_PORT = zbx_strdup(ZABBIX_SERVER_PORT, zbx_optarg);
936 break;
937 case 's':
938 if (NULL == ZABBIX_HOSTNAME)
939 ZABBIX_HOSTNAME = zbx_strdup(ZABBIX_HOSTNAME, zbx_optarg);
940 break;
941 case 'k':
942 if (NULL == ZABBIX_KEY)
943 ZABBIX_KEY = zbx_strdup(ZABBIX_KEY, zbx_optarg);
944 break;
945 case 'o':
946 if (NULL == ZABBIX_KEY_VALUE)
947 ZABBIX_KEY_VALUE = zbx_strdup(ZABBIX_KEY_VALUE, zbx_optarg);
948 break;
949 case 'i':
950 if (NULL == INPUT_FILE)
951 INPUT_FILE = zbx_strdup(INPUT_FILE, zbx_optarg);
952 break;
953 case 'T':
954 WITH_TIMESTAMPS = 1;
955 break;
956 case 'N':
957 WITH_NS = 1;
958 break;
959 case 'r':
960 REAL_TIME = 1;
961 break;
962 case 'v':
963 if (LOG_LEVEL_WARNING > CONFIG_LOG_LEVEL)
964 CONFIG_LOG_LEVEL = LOG_LEVEL_WARNING;
965 else if (LOG_LEVEL_DEBUG > CONFIG_LOG_LEVEL)
966 CONFIG_LOG_LEVEL = LOG_LEVEL_DEBUG;
967 break;
968 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
969 case '1':
970 CONFIG_TLS_CONNECT = zbx_strdup(CONFIG_TLS_CONNECT, zbx_optarg);
971 break;
972 case '2':
973 CONFIG_TLS_CA_FILE = zbx_strdup(CONFIG_TLS_CA_FILE, zbx_optarg);
974 break;
975 case '3':
976 CONFIG_TLS_CRL_FILE = zbx_strdup(CONFIG_TLS_CRL_FILE, zbx_optarg);
977 break;
978 case '4':
979 CONFIG_TLS_SERVER_CERT_ISSUER = zbx_strdup(CONFIG_TLS_SERVER_CERT_ISSUER, zbx_optarg);
980 break;
981 case '5':
982 CONFIG_TLS_SERVER_CERT_SUBJECT = zbx_strdup(CONFIG_TLS_SERVER_CERT_SUBJECT, zbx_optarg);
983 break;
984 case '6':
985 CONFIG_TLS_CERT_FILE = zbx_strdup(CONFIG_TLS_CERT_FILE, zbx_optarg);
986 break;
987 case '7':
988 CONFIG_TLS_KEY_FILE = zbx_strdup(CONFIG_TLS_KEY_FILE, zbx_optarg);
989 break;
990 case '8':
991 CONFIG_TLS_PSK_IDENTITY = zbx_strdup(CONFIG_TLS_PSK_IDENTITY, zbx_optarg);
992 break;
993 case '9':
994 CONFIG_TLS_PSK_FILE = zbx_strdup(CONFIG_TLS_PSK_FILE, zbx_optarg);
995 break;
996 case 'A':
997 #if defined(HAVE_OPENSSL)
998 CONFIG_TLS_CIPHER_CMD13 = zbx_strdup(CONFIG_TLS_CIPHER_CMD13, zbx_optarg);
999 #elif defined(HAVE_GNUTLS)
1000 zbx_error("parameter \"--tls-cipher13\" can be used with OpenSSL 1.1.1 or newer."
1001 " Zabbix sender was compiled with GnuTLS");
1002 exit(EXIT_FAILURE);
1003 #endif
1004 break;
1005 case 'B':
1006 CONFIG_TLS_CIPHER_CMD = zbx_strdup(CONFIG_TLS_CIPHER_CMD, zbx_optarg);
1007 break;
1008 #else
1009 case '1':
1010 case '2':
1011 case '3':
1012 case '4':
1013 case '5':
1014 case '6':
1015 case '7':
1016 case '8':
1017 case '9':
1018 case 'A':
1019 case 'B':
1020 zbx_error("TLS parameters cannot be used: Zabbix sender was compiled without TLS"
1021 " support");
1022 exit(EXIT_FAILURE);
1023 break;
1024 #endif
1025 default:
1026 usage();
1027 exit(EXIT_FAILURE);
1028 break;
1029 }
1030 }
1031
1032 if (NULL != ZABBIX_SERVER)
1033 {
1034 unsigned short port;
1035
1036 if (NULL != ZABBIX_SERVER_PORT)
1037 {
1038 if (SUCCEED != is_ushort(ZABBIX_SERVER_PORT, &port) || MIN_ZABBIX_PORT > port)
1039 {
1040 zbx_error("option \"-p\" used with invalid port number \"%s\", valid port numbers are"
1041 " %d-%d", ZABBIX_SERVER_PORT, (int)MIN_ZABBIX_PORT,
1042 (int)MAX_ZABBIX_PORT);
1043 exit(EXIT_FAILURE);
1044 }
1045 }
1046 else
1047 port = (unsigned short)ZBX_DEFAULT_SERVER_PORT;
1048
1049 sender_add_serveractive_host_cb(ZABBIX_SERVER, port);
1050 }
1051
1052 /* every option may be specified only once */
1053
1054 for (i = 0; NULL != longopts[i].name; i++)
1055 {
1056 ch = longopts[i].val;
1057
1058 if ('v' == ch && 2 < opt_count[(unsigned char)ch]) /* '-v' or '-vv' can be specified */
1059 {
1060 zbx_error("option \"-v\" or \"--verbose\" specified more than 2 times");
1061
1062 fatal = 1;
1063 continue;
1064 }
1065
1066 if ('v' != ch && 1 < opt_count[(unsigned char)ch])
1067 {
1068 if (NULL == strchr(shortopts, ch))
1069 zbx_error("option \"--%s\" specified multiple times", longopts[i].name);
1070 else
1071 zbx_error("option \"-%c\" or \"--%s\" specified multiple times", ch, longopts[i].name);
1072
1073 fatal = 1;
1074 }
1075 }
1076
1077 if (1 == fatal)
1078 exit(EXIT_FAILURE);
1079
1080 /* check for mutually exclusive options */
1081
1082 /* Allowed option combinations. */
1083 /* Option 'v' is always optional. */
1084 /* c z s k o i N T r p I opt_mask comment */
1085 /* --------------------------------- -------- ------- */
1086 /* - z - - - i - - - - - 0x220 !c i */
1087 /* - z - - - i - - - - I 0x221 */
1088 /* - z - - - i - - - p - 0x222 */
1089 /* - z - - - i - - - p I 0x223 */
1090 /* - z - - - i - - r - - 0x224 */
1091 /* - z - - - i - - r - I 0x225 */
1092 /* - z - - - i - - r p - 0x226 */
1093 /* - z - - - i - - r p I 0x227 */
1094 /* - z - - - i - T - - - 0x228 */
1095 /* - z - - - i - T - - I 0x229 */
1096 /* - z - - - i - T - p - 0x22a */
1097 /* - z - - - i - T - p I 0x22b */
1098 /* - z - - - i - T r - - 0x22c */
1099 /* - z - - - i - T r - I 0x22d */
1100 /* - z - - - i - T r p - 0x22e */
1101 /* - z - - - i - T r p I 0x22f */
1102 /* - z - - - i N T - - - 0x238 */
1103 /* - z - - - i N T - - I 0x239 */
1104 /* - z - - - i N T - p - 0x23a */
1105 /* - z - - - i N T - p I 0x23b */
1106 /* - z - - - i N T r - - 0x23c */
1107 /* - z - - - i N T r - I 0x23d */
1108 /* - z - - - i N T r p - 0x23e */
1109 /* - z - - - i N T r p I 0x23f */
1110 /* - z s - - i - - - - - 0x320 */
1111 /* - z s - - i - - - - I 0x321 */
1112 /* - z s - - i - - - p - 0x322 */
1113 /* - z s - - i - - - p I 0x323 */
1114 /* - z s - - i - - r - - 0x324 */
1115 /* - z s - - i - - r - I 0x325 */
1116 /* - z s - - i - - r p - 0x326 */
1117 /* - z s - - i - - r p I 0x327 */
1118 /* - z s - - i - T - - - 0x328 */
1119 /* - z s - - i - T - - I 0x329 */
1120 /* - z s - - i - T - p - 0x32a */
1121 /* - z s - - i - T - p I 0x32b */
1122 /* - z s - - i - T r - - 0x32c */
1123 /* - z s - - i - T r - I 0x32d */
1124 /* - z s - - i - T r p - 0x32e */
1125 /* - z s - - i - T r p I 0x32f */
1126 /* - z s - - i N T - - - 0x338 */
1127 /* - z s - - i N T - - I 0x339 */
1128 /* - z s - - i N T - p - 0x33a */
1129 /* - z s - - i N T - p I 0x33b */
1130 /* - z s - - i N T r - - 0x33c */
1131 /* - z s - - i N T r - I 0x33d */
1132 /* - z s - - i N T r p - 0x33e */
1133 /* - z s - - i N T r p I 0x33f */
1134 /* */
1135 /* - z s k o - - - - - - 0x3c0 !c !i */
1136 /* - z s k o - - - - - I 0x3c1 */
1137 /* - z s k o - - - - p - 0x3c2 */
1138 /* - z s k o - - - - p I 0x3c3 */
1139 /* */
1140 /* c - - - - i - - - - - 0x420 c i */
1141 /* c - - - - i - - - - I 0x421 */
1142 /* c - - - - i - - - p - 0x422 */
1143 /* c - - - - i - - - p I 0x423 */
1144 /* c - - - - i - - r - - 0x424 */
1145 /* c - - - - i - - r - I 0x425 */
1146 /* c - - - - i - - r p - 0x426 */
1147 /* c - - - - i - - r p I 0x427 */
1148 /* c - - - - i - T - - - 0x428 */
1149 /* c - - - - i - T - - I 0x429 */
1150 /* c - - - - i - T - p - 0x42a */
1151 /* c - - - - i - T - p I 0x42b */
1152 /* c - - - - i - T r - - 0x42c */
1153 /* c - - - - i - T r - I 0x42d */
1154 /* c - - - - i - T r p - 0x42e */
1155 /* c - - - - i - T r p I 0x42f */
1156 /* c - - - - i N T - - - 0x438 */
1157 /* c - - - - i N T - - I 0x439 */
1158 /* c - - - - i N T - p - 0x43a */
1159 /* c - - - - i N T - p I 0x43b */
1160 /* c - - - - i N T r - - 0x43c */
1161 /* c - - - - i N T r - I 0x43d */
1162 /* c - - - - i N T r p - 0x43e */
1163 /* c - - - - i N T r p I 0x43f */
1164 /* */
1165 /* c - - k o - - - - - - 0x4c0 c !i */
1166 /* c - - k o - - - - - I 0x4c1 */
1167 /* c - - k o - - - - p - 0x4c2 */
1168 /* c - - k o - - - - p I 0x4c3 */
1169 /* c - s k o - - - - - - 0x5c0 */
1170 /* c - s k o - - - - - I 0x5c1 */
1171 /* c - s k o - - - - p - 0x5c2 */
1172 /* c - s k o - - - - p I 0x5c3 */
1173 /* */
1174 /* c - s - - i - - - - - 0x520 c i (continues) */
1175 /* c - s - - i - - - - I 0x521 */
1176 /* c - s - - i - - - p - 0x522 */
1177 /* c - s - - i - - - p I 0x523 */
1178 /* c - s - - i - - r - - 0x524 */
1179 /* c - s - - i - - r - I 0x525 */
1180 /* c - s - - i - - r p - 0x526 */
1181 /* c - s - - i - - r p I 0x527 */
1182 /* c - s - - i - T - - - 0x528 */
1183 /* c - s - - i - T - - I 0x529 */
1184 /* c - s - - i - T - p - 0x52a */
1185 /* c - s - - i - T - p I 0x52b */
1186 /* c - s - - i - T r - - 0x52c */
1187 /* c - s - - i - T r - I 0x52d */
1188 /* c - s - - i - T r p - 0x52e */
1189 /* c - s - - i - T r p I 0x52f */
1190 /* c - s - - i N T - - - 0x538 */
1191 /* c - s - - i N T - - I 0x539 */
1192 /* c - s - - i N T - p - 0x53a */
1193 /* c - s - - i N T - p I 0x53b */
1194 /* c - s - - i N T r - - 0x53c */
1195 /* c - s - - i N T r - I 0x53d */
1196 /* c - s - - i N T r p - 0x53e */
1197 /* c - s - - i N T r p I 0x53f */
1198 /* c z - - - i - - - - - 0x620 */
1199 /* c z - - - i - - - - I 0x621 */
1200 /* c z - - - i - - - p - 0x622 */
1201 /* c z - - - i - - - p I 0x623 */
1202 /* c z - - - i - - r - - 0x624 */
1203 /* c z - - - i - - r - I 0x625 */
1204 /* c z - - - i - - r p - 0x626 */
1205 /* c z - - - i - - r p I 0x627 */
1206 /* c z - - - i - T - - - 0x628 */
1207 /* c z - - - i - T - - I 0x629 */
1208 /* c z - - - i - T - p - 0x62a */
1209 /* c z - - - i - T - p I 0x62b */
1210 /* c z - - - i - T r - - 0x62c */
1211 /* c z - - - i - T r - I 0x62d */
1212 /* c z - - - i - T r p - 0x62e */
1213 /* c z - - - i - T r p I 0x62f */
1214 /* c z - - - i N T - - - 0x638 */
1215 /* c z - - - i N T - - I 0x639 */
1216 /* c z - - - i N T - p - 0x63a */
1217 /* c z - - - i N T - p I 0x63b */
1218 /* c z - - - i N T r - - 0x63c */
1219 /* c z - - - i N T r - I 0x63d */
1220 /* c z - - - i N T r p - 0x63e */
1221 /* c z - - - i N T r p I 0x63f */
1222 /* c z s - - i - - - - - 0x720 */
1223 /* c z s - - i - - - - I 0x721 */
1224 /* c z s - - i - - - p - 0x722 */
1225 /* c z s - - i - - - p I 0x723 */
1226 /* c z s - - i - - r - - 0x724 */
1227 /* c z s - - i - - r - I 0x725 */
1228 /* c z s - - i - - r p - 0x726 */
1229 /* c z s - - i - - r p I 0x727 */
1230 /* c z s - - i - T - - - 0x728 */
1231 /* c z s - - i - T - - I 0x729 */
1232 /* c z s - - i - T - p - 0x72a */
1233 /* c z s - - i - T - p I 0x72b */
1234 /* c z s - - i - T r - - 0x72c */
1235 /* c z s - - i - T r - I 0x72d */
1236 /* c z s - - i - T r p - 0x72e */
1237 /* c z s - - i - T r p I 0x72f */
1238 /* c z s - - i N T - - - 0x738 */
1239 /* c z s - - i N T - - I 0x739 */
1240 /* c z s - - i N T - p - 0x73a */
1241 /* c z s - - i N T - p I 0x73b */
1242 /* c z s - - i N T r - - 0x73c */
1243 /* c z s - - i N T r - I 0x73d */
1244 /* c z s - - i N T r p - 0x73e */
1245 /* c z s - - i N T r p I 0x73f */
1246 /* */
1247 /* c z - k o - - - - - - 0x6c0 c !i (continues) */
1248 /* c z - k o - - - - - I 0x6c1 */
1249 /* c z - k o - - - - p - 0x6c2 */
1250 /* c z - k o - - - - p I 0x6c3 */
1251 /* c z s k o - - - - - - 0x7c0 */
1252 /* c z s k o - - - - - I 0x7c1 */
1253 /* c z s k o - - - - p - 0x7c2 */
1254 /* c z s k o - - - - p I 0x7c3 */
1255
1256 if (0 == opt_count['c'] + opt_count['z'])
1257 {
1258 zbx_error("either '-c' or '-z' option must be specified");
1259 usage();
1260 printf("Try '%s --help' for more information.\n", progname);
1261 exit(EXIT_FAILURE);
1262 }
1263
1264 if (0 < opt_count['c'])
1265 opt_mask |= 0x400;
1266 if (0 < opt_count['z'])
1267 opt_mask |= 0x200;
1268 if (0 < opt_count['s'])
1269 opt_mask |= 0x100;
1270 if (0 < opt_count['k'])
1271 opt_mask |= 0x80;
1272 if (0 < opt_count['o'])
1273 opt_mask |= 0x40;
1274 if (0 < opt_count['i'])
1275 opt_mask |= 0x20;
1276 if (0 < opt_count['N'])
1277 opt_mask |= 0x10;
1278 if (0 < opt_count['T'])
1279 opt_mask |= 0x08;
1280 if (0 < opt_count['r'])
1281 opt_mask |= 0x04;
1282 if (0 < opt_count['p'])
1283 opt_mask |= 0x02;
1284 if (0 < opt_count['I'])
1285 opt_mask |= 0x01;
1286
1287 if (
1288 (0 == opt_count['c'] && 1 == opt_count['i'] && /* !c i */
1289 !((0x220 <= opt_mask && opt_mask <= 0x22f) ||
1290 (0x238 <= opt_mask && opt_mask <= 0x23f) ||
1291 (0x320 <= opt_mask && opt_mask <= 0x32f) ||
1292 (0x338 <= opt_mask && opt_mask <= 0x33f))) ||
1293 (0 == opt_count['c'] && 0 == opt_count['i'] && /* !c !i */
1294 !(0x3c0 <= opt_mask && opt_mask <= 0x3c3)) ||
1295 (1 == opt_count['c'] && 1 == opt_count['i'] && /* c i */
1296 !((0x420 <= opt_mask && opt_mask <= 0x42f) ||
1297 (0x438 <= opt_mask && opt_mask <= 0x43f) ||
1298 (0x620 <= opt_mask && opt_mask <= 0x62f) ||
1299 (0x638 <= opt_mask && opt_mask <= 0x63f) ||
1300 (0x520 <= opt_mask && opt_mask <= 0x52f) ||
1301 (0x538 <= opt_mask && opt_mask <= 0x53f) ||
1302 (0x720 <= opt_mask && opt_mask <= 0x72f) ||
1303 (0x738 <= opt_mask && opt_mask <= 0x73f))) ||
1304 (1 == opt_count['c'] && 0 == opt_count['i'] && /* c !i */
1305 !((0x4c0 <= opt_mask && opt_mask <= 0x4c3) ||
1306 (0x5c0 <= opt_mask && opt_mask <= 0x5c3) ||
1307 (0x6c0 <= opt_mask && opt_mask <= 0x6c3) ||
1308 (0x7c0 <= opt_mask && opt_mask <= 0x7c3))))
1309 {
1310 zbx_error("too few or mutually exclusive options used");
1311 usage();
1312 exit(EXIT_FAILURE);
1313 }
1314
1315 /* Parameters which are not option values are invalid. The check relies on zbx_getopt_internal() which */
1316 /* always permutes command line arguments regardless of POSIXLY_CORRECT environment variable. */
1317 if (argc > zbx_optind)
1318 {
1319 for (i = zbx_optind; i < argc; i++)
1320 zbx_error("invalid parameter \"%s\"", argv[i]);
1321
1322 exit(EXIT_FAILURE);
1323 }
1324 }
1325
1326 /******************************************************************************
1327 * *
1328 * Function: zbx_fgets_alloc *
1329 * *
1330 * Purpose: reads a line from file *
1331 * *
1332 * Parameters: buffer - [IN/OUT] the output buffer *
1333 * buffer_alloc - [IN/OUT] the buffer size *
1334 * fp - [IN] the file to read *
1335 * *
1336 * Return value: Pointer to the line or NULL. *
1337 * *
1338 * Comments: This is a fgets() function wrapper with dynamically reallocated *
1339 * buffer. *
1340 * *
1341 ******************************************************************************/
zbx_fgets_alloc(char ** buffer,size_t * buffer_alloc,FILE * fp)1342 static char *zbx_fgets_alloc(char **buffer, size_t *buffer_alloc, FILE *fp)
1343 {
1344 char tmp[MAX_BUFFER_LEN];
1345 size_t buffer_offset = 0, len;
1346
1347 do
1348 {
1349 if (NULL == fgets(tmp, sizeof(tmp), fp))
1350 return (0 != buffer_offset ? *buffer : NULL);
1351
1352 len = strlen(tmp);
1353
1354 if (*buffer_alloc - buffer_offset < len + 1)
1355 {
1356 *buffer_alloc = (buffer_offset + len + 1) * 3 / 2;
1357 *buffer = (char *)zbx_realloc(*buffer, *buffer_alloc);
1358 }
1359
1360 memcpy(*buffer + buffer_offset, tmp, len);
1361 buffer_offset += len;
1362 (*buffer)[buffer_offset] = '\0';
1363 }
1364 while (MAX_BUFFER_LEN - 1 == len && '\n' != tmp[len - 1]);
1365
1366 return *buffer;
1367 }
1368
1369 /* sending a huge amount of values in a single connection is likely to */
1370 /* take long and hit timeout, so we limit values to 250 per connection */
1371 #define VALUES_MAX 250
1372
main(int argc,char ** argv)1373 int main(int argc, char **argv)
1374 {
1375 char *error = NULL;
1376 int total_count = 0, succeed_count = 0, ret = FAIL, timestamp, ns;
1377 ZBX_THREAD_SENDVAL_ARGS *sendval_args = NULL;
1378
1379 progname = get_program_name(argv[0]);
1380
1381 parse_commandline(argc, argv);
1382
1383 if (NULL != CONFIG_FILE)
1384 zbx_load_config(CONFIG_FILE);
1385
1386 #ifndef _WINDOWS
1387 if (SUCCEED != zbx_locks_create(&error))
1388 {
1389 zbx_error("cannot create locks: %s", error);
1390 zbx_free(error);
1391 exit(EXIT_FAILURE);
1392 }
1393 #endif
1394 if (SUCCEED != zabbix_open_log(LOG_TYPE_UNDEFINED, CONFIG_LOG_LEVEL, NULL, &error))
1395 {
1396 zbx_error("cannot open log: %s", error);
1397 zbx_free(error);
1398 exit(EXIT_FAILURE);
1399 }
1400 #if defined(_WINDOWS)
1401 if (SUCCEED != zbx_socket_start(&error))
1402 {
1403 zbx_error(error);
1404 zbx_free(error);
1405 exit(EXIT_FAILURE);
1406 }
1407 #endif
1408 #if !defined(_WINDOWS) && (defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL))
1409 if (SUCCEED != zbx_coredump_disable())
1410 {
1411 zabbix_log(LOG_LEVEL_CRIT, "cannot disable core dump, exiting...");
1412 goto exit;
1413 }
1414 #endif
1415 if (0 == destinations_count)
1416 {
1417 zabbix_log(LOG_LEVEL_CRIT, "'ServerActive' parameter required");
1418 goto exit;
1419 }
1420 #if !defined(_WINDOWS)
1421 signal(SIGINT, main_signal_handler);
1422 signal(SIGQUIT, main_signal_handler);
1423 signal(SIGTERM, main_signal_handler);
1424 signal(SIGHUP, main_signal_handler);
1425 signal(SIGALRM, main_signal_handler);
1426 signal(SIGPIPE, main_signal_handler);
1427 #endif
1428 if (NULL != CONFIG_TLS_CONNECT || NULL != CONFIG_TLS_CA_FILE || NULL != CONFIG_TLS_CRL_FILE ||
1429 NULL != CONFIG_TLS_SERVER_CERT_ISSUER || NULL != CONFIG_TLS_SERVER_CERT_SUBJECT ||
1430 NULL != CONFIG_TLS_CERT_FILE || NULL != CONFIG_TLS_KEY_FILE ||
1431 NULL != CONFIG_TLS_PSK_IDENTITY || NULL != CONFIG_TLS_PSK_FILE ||
1432 NULL != CONFIG_TLS_CIPHER_CERT13 || NULL != CONFIG_TLS_CIPHER_CERT ||
1433 NULL != CONFIG_TLS_CIPHER_PSK13 || NULL != CONFIG_TLS_CIPHER_PSK ||
1434 NULL != CONFIG_TLS_CIPHER_CMD13 || NULL != CONFIG_TLS_CIPHER_CMD)
1435 {
1436 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1437 zbx_tls_validate_config();
1438
1439 if (ZBX_TCP_SEC_UNENCRYPTED != configured_tls_connect_mode)
1440 {
1441 #if defined(_WINDOWS)
1442 zbx_tls_init_parent();
1443 #endif
1444 zbx_tls_init_child();
1445 }
1446 #else
1447 zabbix_log(LOG_LEVEL_CRIT, "TLS parameters cannot be used: Zabbix sender was compiled without TLS"
1448 " support");
1449 goto exit;
1450 #endif
1451 }
1452
1453 sendval_args = (ZBX_THREAD_SENDVAL_ARGS *)zbx_calloc(sendval_args, destinations_count,
1454 sizeof(ZBX_THREAD_SENDVAL_ARGS));
1455
1456 #if defined(_WINDOWS) && (defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL))
1457 if (ZBX_TCP_SEC_UNENCRYPTED != configured_tls_connect_mode)
1458 {
1459 /* prepare to pass necessary TLS data to 'send_value' thread (to be started soon) */
1460 zbx_tls_pass_vars(&sendval_args->tls_vars);
1461 }
1462 #endif
1463 zbx_json_init(&sendval_args->json, ZBX_JSON_STAT_BUF_LEN);
1464 zbx_json_addstring(&sendval_args->json, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_SENDER_DATA, ZBX_JSON_TYPE_STRING);
1465 zbx_json_addarray(&sendval_args->json, ZBX_PROTO_TAG_DATA);
1466
1467 if (INPUT_FILE)
1468 {
1469 FILE *in;
1470 char *in_line = NULL, *key = NULL, *key_value = NULL;
1471 int buffer_count = 0;
1472 size_t key_alloc = 0, in_line_alloc = MAX_BUFFER_LEN;
1473 double last_send = 0;
1474
1475 if (0 == strcmp(INPUT_FILE, "-"))
1476 {
1477 in = stdin;
1478 if (1 == REAL_TIME)
1479 {
1480 /* set line buffering on stdin */
1481 setvbuf(stdin, (char *)NULL, _IOLBF, 1024);
1482 }
1483 }
1484 else if (NULL == (in = fopen(INPUT_FILE, "r")))
1485 {
1486 zabbix_log(LOG_LEVEL_CRIT, "cannot open [%s]: %s", INPUT_FILE, zbx_strerror(errno));
1487 goto free;
1488 }
1489
1490 sendval_args->sync_timestamp = WITH_TIMESTAMPS;
1491 in_line = (char *)zbx_malloc(NULL, in_line_alloc);
1492
1493 ret = SUCCEED;
1494
1495 while (0 == sig_exiting && (SUCCEED == ret || SUCCEED_PARTIAL == ret) &&
1496 NULL != zbx_fgets_alloc(&in_line, &in_line_alloc, in))
1497 {
1498 char hostname[MAX_STRING_LEN], clock[32];
1499 int read_more = 0;
1500 size_t key_value_alloc = 0;
1501 const char *p;
1502
1503 /* line format: <hostname> <key> [<timestamp>] [<ns>] <value> */
1504
1505 total_count++; /* also used as inputline */
1506
1507 zbx_rtrim(in_line, "\r\n");
1508
1509 p = in_line;
1510
1511 if ('\0' == *p || NULL == (p = get_string(p, hostname, sizeof(hostname))) || '\0' == *hostname)
1512 {
1513 zabbix_log(LOG_LEVEL_CRIT, "[line %d] 'Hostname' required", total_count);
1514 ret = FAIL;
1515 break;
1516 }
1517
1518 if (0 == strcmp(hostname, "-"))
1519 {
1520 if (NULL == ZABBIX_HOSTNAME)
1521 {
1522 zabbix_log(LOG_LEVEL_CRIT, "[line %d] '-' encountered as 'Hostname',"
1523 " but no default hostname was specified", total_count);
1524 ret = FAIL;
1525 break;
1526 }
1527 else
1528 zbx_strlcpy(hostname, ZABBIX_HOSTNAME, sizeof(hostname));
1529 }
1530
1531 if (key_alloc != in_line_alloc)
1532 {
1533 key_alloc = in_line_alloc;
1534 key = (char *)zbx_realloc(key, key_alloc);
1535 }
1536
1537 if ('\0' == *p || NULL == (p = get_string(p, key, key_alloc)) || '\0' == *key)
1538 {
1539 zabbix_log(LOG_LEVEL_CRIT, "[line %d] 'Key' required", total_count);
1540 ret = FAIL;
1541 break;
1542 }
1543
1544 if (1 == WITH_TIMESTAMPS)
1545 {
1546 if ('\0' == *p || NULL == (p = get_string(p, clock, sizeof(clock))) || '\0' == *clock)
1547 {
1548 zabbix_log(LOG_LEVEL_CRIT, "[line %d] 'Timestamp' required", total_count);
1549 ret = FAIL;
1550 break;
1551 }
1552
1553 if (FAIL == is_uint31(clock, ×tamp))
1554 {
1555 zabbix_log(LOG_LEVEL_WARNING, "[line %d] invalid 'Timestamp' value detected",
1556 total_count);
1557 ret = FAIL;
1558 break;
1559 }
1560
1561 if (1 == WITH_NS)
1562 {
1563 if ('\0' == *p || NULL == (p = get_string(p, clock, sizeof(clock))) ||
1564 '\0' == *clock)
1565 {
1566 zabbix_log(LOG_LEVEL_CRIT, "[line %d] 'Nanoseconds' required",
1567 total_count);
1568 ret = FAIL;
1569 break;
1570 }
1571
1572 if (FAIL == is_uint_n_range(clock, sizeof(clock), &ns, sizeof(ns),
1573 0LL, 999999999LL))
1574 {
1575 zabbix_log(LOG_LEVEL_WARNING,
1576 "[line %d] invalid 'Nanoseconds' value detected",
1577 total_count);
1578 ret = FAIL;
1579 break;
1580 }
1581 }
1582 }
1583
1584 if (key_value_alloc != in_line_alloc)
1585 {
1586 key_value_alloc = in_line_alloc;
1587 key_value = (char *)zbx_realloc(key_value, key_value_alloc);
1588 }
1589
1590 if ('\0' != *p && '"' != *p)
1591 {
1592 zbx_strlcpy(key_value, p, key_value_alloc);
1593 }
1594 else if ('\0' == *p || NULL == (p = get_string(p, key_value, key_value_alloc)))
1595 {
1596 zabbix_log(LOG_LEVEL_CRIT, "[line %d] 'Key value' required", total_count);
1597 ret = FAIL;
1598 break;
1599 }
1600 else if ('\0' != *p)
1601 {
1602 zabbix_log(LOG_LEVEL_CRIT, "[line %d] too many parameters", total_count);
1603 ret = FAIL;
1604 break;
1605 }
1606
1607 zbx_json_addobject(&sendval_args->json, NULL);
1608 zbx_json_addstring(&sendval_args->json, ZBX_PROTO_TAG_HOST, hostname, ZBX_JSON_TYPE_STRING);
1609 zbx_json_addstring(&sendval_args->json, ZBX_PROTO_TAG_KEY, key, ZBX_JSON_TYPE_STRING);
1610 zbx_json_addstring(&sendval_args->json, ZBX_PROTO_TAG_VALUE, key_value, ZBX_JSON_TYPE_STRING);
1611
1612 if (1 == WITH_TIMESTAMPS)
1613 {
1614 zbx_json_adduint64(&sendval_args->json, ZBX_PROTO_TAG_CLOCK, timestamp);
1615
1616 if (1 == WITH_NS)
1617 zbx_json_adduint64(&sendval_args->json, ZBX_PROTO_TAG_NS, ns);
1618 }
1619
1620 zbx_json_close(&sendval_args->json);
1621
1622 succeed_count++;
1623 buffer_count++;
1624
1625 if (stdin == in && 1 == REAL_TIME)
1626 {
1627 /* if there is nothing on standard input after 1/5 seconds, we send what we have */
1628 /* otherwise, we keep reading, but we should send data at least once per second */
1629
1630 struct timeval tv;
1631 fd_set read_set;
1632
1633 tv.tv_sec = 0;
1634 tv.tv_usec = 200000;
1635
1636 FD_ZERO(&read_set);
1637 FD_SET(0, &read_set); /* stdin is file descriptor 0 */
1638
1639 if (-1 == (read_more = select(1, &read_set, NULL, NULL, &tv)))
1640 {
1641 zabbix_log(LOG_LEVEL_WARNING, "select() failed: %s", zbx_strerror(errno));
1642 }
1643 else if (1 <= read_more)
1644 {
1645 if (0 == last_send)
1646 last_send = zbx_time();
1647 else if (zbx_time() - last_send >= 1)
1648 read_more = 0;
1649 }
1650 }
1651
1652 if (VALUES_MAX == buffer_count || (stdin == in && 1 == REAL_TIME && 0 >= read_more))
1653 {
1654 zbx_json_close(&sendval_args->json);
1655
1656 last_send = zbx_time();
1657
1658 ret = perform_data_sending(sendval_args, ret);
1659
1660 buffer_count = 0;
1661 zbx_json_clean(&sendval_args->json);
1662 zbx_json_addstring(&sendval_args->json, ZBX_PROTO_TAG_REQUEST,
1663 ZBX_PROTO_VALUE_SENDER_DATA, ZBX_JSON_TYPE_STRING);
1664 zbx_json_addarray(&sendval_args->json, ZBX_PROTO_TAG_DATA);
1665 }
1666 }
1667
1668 if (FAIL != ret && 0 != buffer_count)
1669 {
1670 zbx_json_close(&sendval_args->json);
1671 ret = perform_data_sending(sendval_args, ret);
1672 }
1673
1674 if (in != stdin)
1675 fclose(in);
1676
1677 zbx_free(key);
1678 zbx_free(key_value);
1679 zbx_free(in_line);
1680 }
1681 else
1682 {
1683 sendval_args->sync_timestamp = 0;
1684 total_count++;
1685
1686 do /* try block simulation */
1687 {
1688 if (NULL == ZABBIX_HOSTNAME)
1689 {
1690 zabbix_log(LOG_LEVEL_WARNING, "'Hostname' parameter required");
1691 break;
1692 }
1693 if (NULL == ZABBIX_KEY)
1694 {
1695 zabbix_log(LOG_LEVEL_WARNING, "Key required");
1696 break;
1697 }
1698 if (NULL == ZABBIX_KEY_VALUE)
1699 {
1700 zabbix_log(LOG_LEVEL_WARNING, "Key value required");
1701 break;
1702 }
1703
1704 ret = SUCCEED;
1705
1706 zbx_json_addobject(&sendval_args->json, NULL);
1707 zbx_json_addstring(&sendval_args->json, ZBX_PROTO_TAG_HOST, ZABBIX_HOSTNAME, ZBX_JSON_TYPE_STRING);
1708 zbx_json_addstring(&sendval_args->json, ZBX_PROTO_TAG_KEY, ZABBIX_KEY, ZBX_JSON_TYPE_STRING);
1709 zbx_json_addstring(&sendval_args->json, ZBX_PROTO_TAG_VALUE, ZABBIX_KEY_VALUE, ZBX_JSON_TYPE_STRING);
1710 zbx_json_close(&sendval_args->json);
1711
1712 succeed_count++;
1713
1714 ret = perform_data_sending(sendval_args, ret);
1715 }
1716 while (0); /* try block simulation */
1717 }
1718 free:
1719 zbx_json_free(&sendval_args->json);
1720 zbx_free(sendval_args);
1721 exit:
1722 if (FAIL != ret)
1723 {
1724 printf("sent: %d; skipped: %d; total: %d\n", succeed_count, total_count - succeed_count, total_count);
1725 }
1726 else
1727 {
1728 printf("Sending failed.%s\n", CONFIG_LOG_LEVEL != LOG_LEVEL_DEBUG ?
1729 " Use option -vv for more detailed output." : "");
1730 }
1731
1732 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
1733 if (ZBX_TCP_SEC_UNENCRYPTED != configured_tls_connect_mode)
1734 {
1735 zbx_tls_free();
1736 #if defined(_WINDOWS)
1737 zbx_tls_library_deinit();
1738 #endif
1739 }
1740 #endif
1741 zabbix_close_log();
1742 #if defined(_WINDOWS)
1743 while (0 == WSACleanup())
1744 ;
1745 #endif
1746 #if !defined(_WINDOWS) && defined(HAVE_PTHREAD_PROCESS_SHARED)
1747 zbx_locks_disable();
1748 #endif
1749 if (FAIL == ret)
1750 ret = EXIT_FAILURE;
1751
1752 return ret;
1753 }
1754