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 "log.h"
22 #include "setproctitle.h"
23 
24 /* scheduler support */
25 
26 #define ZBX_SCHEDULER_FILTER_DAY	1
27 #define ZBX_SCHEDULER_FILTER_HOUR	2
28 #define ZBX_SCHEDULER_FILTER_MINUTE	3
29 #define ZBX_SCHEDULER_FILTER_SECOND	4
30 
31 typedef struct zbx_scheduler_filter
32 {
33 	int				start;
34 	int				end;
35 	int				step;
36 
37 	struct zbx_scheduler_filter	*next;
38 }
39 zbx_scheduler_filter_t;
40 
41 typedef struct zbx_scheduler_interval
42 {
43 	zbx_scheduler_filter_t		*mdays;
44 	zbx_scheduler_filter_t		*wdays;
45 	zbx_scheduler_filter_t		*hours;
46 	zbx_scheduler_filter_t		*minutes;
47 	zbx_scheduler_filter_t		*seconds;
48 
49 	int				filter_level;
50 
51 	struct zbx_scheduler_interval	*next;
52 }
53 zbx_scheduler_interval_t;
54 
55 static ZBX_THREAD_LOCAL volatile sig_atomic_t	zbx_timed_out;	/* 0 - no timeout occurred, 1 - SIGALRM took place */
56 
57 #ifdef _WINDOWS
58 
59 char	ZABBIX_SERVICE_NAME[ZBX_SERVICE_NAME_LEN] = APPLICATION_NAME;
60 char	ZABBIX_EVENT_SOURCE[ZBX_SERVICE_NAME_LEN] = APPLICATION_NAME;
61 
__zbx_stat(const char * path,zbx_stat_t * buf)62 int	__zbx_stat(const char *path, zbx_stat_t *buf)
63 {
64 	int	ret, fd;
65 	wchar_t	*wpath;
66 
67 	wpath = zbx_utf8_to_unicode(path);
68 
69 	if (-1 == (ret = _wstat64(wpath, buf)))
70 		goto out;
71 
72 	if (0 != S_ISDIR(buf->st_mode) || 0 != buf->st_size)
73 		goto out;
74 
75 	/* In the case of symlinks _wstat64 returns zero file size.   */
76 	/* Try to work around it by opening the file and using fstat. */
77 
78 	ret = -1;
79 
80 	if (-1 != (fd = _wopen(wpath, O_RDONLY)))
81 	{
82 		ret = _fstat64(fd, buf);
83 		_close(fd);
84 	}
85 out:
86 	zbx_free(wpath);
87 
88 	return ret;
89 }
90 
91 #endif
92 
93 /******************************************************************************
94  *                                                                            *
95  * Function: get_program_name                                                 *
96  *                                                                            *
97  * Purpose: return program name without path                                  *
98  *                                                                            *
99  * Parameters: path                                                           *
100  *                                                                            *
101  * Return value: program name without path                                    *
102  *                                                                            *
103  * Author: Eugene Grigorjev                                                   *
104  *                                                                            *
105  ******************************************************************************/
get_program_name(const char * path)106 const char	*get_program_name(const char *path)
107 {
108 	const char	*filename = NULL;
109 
110 	for (filename = path; path && *path; path++)
111 	{
112 		if ('\\' == *path || '/' == *path)
113 			filename = path + 1;
114 	}
115 
116 	return filename;
117 }
118 
119 /******************************************************************************
120  *                                                                            *
121  * Function: zbx_timespec                                                     *
122  *                                                                            *
123  * Purpose: Gets the current time.                                            *
124  *                                                                            *
125  * Author: Alexander Vladishev                                                *
126  *                                                                            *
127  * Comments: Time in seconds since midnight (00:00:00),                       *
128  *           January 1, 1970, coordinated universal time (UTC).               *
129  *                                                                            *
130  ******************************************************************************/
zbx_timespec(zbx_timespec_t * ts)131 void	zbx_timespec(zbx_timespec_t *ts)
132 {
133 	static zbx_timespec_t	*last_ts = NULL;
134 	static int		corr = 0;
135 #ifdef _WINDOWS
136 	LARGE_INTEGER	tickPerSecond, tick;
137 	static int	boottime = 0;
138 	BOOL		rc = FALSE;
139 #else
140 	struct timeval	tv;
141 	int		rc = -1;
142 #	ifdef HAVE_TIME_CLOCK_GETTIME
143 	struct timespec	tp;
144 #	endif
145 #endif
146 
147 	if (NULL == last_ts)
148 		last_ts = zbx_calloc(last_ts, 1, sizeof(zbx_timespec_t));
149 
150 #ifdef _WINDOWS
151 	if (TRUE == (rc = QueryPerformanceFrequency(&tickPerSecond)))
152 	{
153 		if (TRUE == (rc = QueryPerformanceCounter(&tick)))
154 		{
155 			ts->ns = (int)(1000000000 * (tick.QuadPart % tickPerSecond.QuadPart) / tickPerSecond.QuadPart);
156 
157 			tick.QuadPart = tick.QuadPart / tickPerSecond.QuadPart;
158 
159 			if (0 == boottime)
160 				boottime = (int)(time(NULL) - tick.QuadPart);
161 
162 			ts->sec = (int)(tick.QuadPart + boottime);
163 		}
164 	}
165 
166 	if (TRUE != rc)
167 	{
168 		struct _timeb   tb;
169 
170 		_ftime(&tb);
171 
172 		ts->sec = (int)tb.time;
173 		ts->ns = tb.millitm * 1000000;
174 	}
175 #else	/* not _WINDOWS */
176 #ifdef HAVE_TIME_CLOCK_GETTIME
177 	if (0 == (rc = clock_gettime(CLOCK_REALTIME, &tp)))
178 	{
179 		ts->sec = (int)tp.tv_sec;
180 		ts->ns = (int)tp.tv_nsec;
181 	}
182 #endif	/* HAVE_TIME_CLOCK_GETTIME */
183 
184 	if (0 != rc && 0 == (rc = gettimeofday(&tv, NULL)))
185 	{
186 		ts->sec = (int)tv.tv_sec;
187 		ts->ns = (int)tv.tv_usec * 1000;
188 	}
189 
190 	if (0 != rc)
191 	{
192 		ts->sec = (int)time(NULL);
193 		ts->ns = 0;
194 	}
195 #endif	/* not _WINDOWS */
196 
197 	if (last_ts->ns == ts->ns && last_ts->sec == ts->sec)
198 	{
199 		ts->ns += ++corr;
200 
201 		while (ts->ns >= 1000000000)
202 		{
203 			ts->sec++;
204 			ts->ns -= 1000000000;
205 		}
206 	}
207 	else
208 	{
209 		last_ts->sec = ts->sec;
210 		last_ts->ns = ts->ns;
211 		corr = 0;
212 	}
213 }
214 
215 /******************************************************************************
216  *                                                                            *
217  * Function: zbx_time                                                         *
218  *                                                                            *
219  * Purpose: Gets the current time.                                            *
220  *                                                                            *
221  * Return value: Time in seconds                                              *
222  *                                                                            *
223  * Author: Eugene Grigorjev                                                   *
224  *                                                                            *
225  * Comments: Time in seconds since midnight (00:00:00),                       *
226  *           January 1, 1970, coordinated universal time (UTC).               *
227  *                                                                            *
228  ******************************************************************************/
zbx_time(void)229 double	zbx_time(void)
230 {
231 	zbx_timespec_t	ts;
232 
233 	zbx_timespec(&ts);
234 
235 	return (double)ts.sec + 1.0e-9 * (double)ts.ns;
236 }
237 
238 /******************************************************************************
239  *                                                                            *
240  * Function: zbx_current_time                                                 *
241  *                                                                            *
242  * Purpose: Gets the current time including UTC offset                        *
243  *                                                                            *
244  * Return value: Time in seconds                                              *
245  *                                                                            *
246  * Author: Eugene Grigorjev                                                   *
247  *                                                                            *
248  ******************************************************************************/
zbx_current_time(void)249 double	zbx_current_time(void)
250 {
251 	return zbx_time() + ZBX_JAN_1970_IN_SEC;
252 }
253 
254 /******************************************************************************
255  *                                                                            *
256  * Function: is_leap_year                                                     *
257  *                                                                            *
258  * Return value:  SUCCEED - year is a leap year                               *
259  *                FAIL    - year is not a leap year                           *
260  *                                                                            *
261  ******************************************************************************/
is_leap_year(int year)262 static int	is_leap_year(int year)
263 {
264 	return 0 == year % 4 && (0 != year % 100 || 0 == year % 400) ? SUCCEED : FAIL;
265 }
266 
267 /******************************************************************************
268  *                                                                            *
269  * Function: zbx_get_time                                                     *
270  *                                                                            *
271  * Purpose:                                                                   *
272  *     get current time and store it in memory locations provided by caller   *
273  *                                                                            *
274  * Parameters:                                                                *
275  *     tm           - [OUT] broken-down representation of the current time    *
276  *     milliseconds - [OUT] milliseconds since the previous second            *
277  *     tz           - [OUT] local time offset from UTC (optional)             *
278  *                                                                            *
279  * Comments:                                                                  *
280  *     On Windows localtime() and gmtime() return pointers to static,         *
281  *     thread-local storage locations. On Unix localtime() and gmtime() are   *
282  *     not thread-safe and re-entrant as they return pointers to static       *
283  *     storage locations which can be overwritten by localtime(), gmtime()    *
284  *     or other time functions in other threads or signal handlers. To avoid  *
285  *     this we use localtime_r() and gmtime_r().                              *
286  *                                                                            *
287  ******************************************************************************/
zbx_get_time(struct tm * tm,long * milliseconds,zbx_timezone_t * tz)288 void	zbx_get_time(struct tm *tm, long *milliseconds, zbx_timezone_t *tz)
289 {
290 #ifdef _WINDOWS
291 	struct _timeb	current_time;
292 
293 	_ftime(&current_time);
294 	*tm = *localtime(&current_time.time);	/* localtime() cannot return NULL if called with valid parameter */
295 	*milliseconds = current_time.millitm;
296 #else
297 	struct timeval	current_time;
298 
299 	gettimeofday(&current_time, NULL);
300 	localtime_r(&current_time.tv_sec, tm);
301 	*milliseconds = current_time.tv_usec / 1000;
302 #endif
303 	if (NULL != tz)
304 	{
305 #ifdef HAVE_TM_TM_GMTOFF
306 #	define ZBX_UTC_OFF	tm->tm_gmtoff
307 #else
308 #	define ZBX_UTC_OFF	offset
309 		long		offset;
310 		struct tm	tm_utc;
311 #ifdef _WINDOWS
312 		tm_utc = *gmtime(&current_time.time);	/* gmtime() cannot return NULL if called with valid parameter */
313 #else
314 		gmtime_r(&current_time.tv_sec, &tm_utc);
315 #endif
316 		offset = (tm->tm_yday - tm_utc.tm_yday) * SEC_PER_DAY + (tm->tm_hour - tm_utc.tm_hour) * SEC_PER_HOUR +
317 				(tm->tm_min - tm_utc.tm_min) * SEC_PER_MIN;	/* assuming seconds are equal */
318 
319 		while (tm->tm_year > tm_utc.tm_year)
320 			offset += (SUCCEED == is_leap_year(tm_utc.tm_year++) ? SEC_PER_YEAR + SEC_PER_DAY : SEC_PER_YEAR);
321 
322 		while (tm->tm_year < tm_utc.tm_year)
323 			offset -= (SUCCEED == is_leap_year(--tm_utc.tm_year) ? SEC_PER_YEAR + SEC_PER_DAY : SEC_PER_YEAR);
324 #endif
325 		tz->tz_sign = (0 <= ZBX_UTC_OFF ? '+' : '-');
326 		tz->tz_hour = labs(ZBX_UTC_OFF) / SEC_PER_HOUR;
327 		tz->tz_min = (labs(ZBX_UTC_OFF) - tz->tz_hour * SEC_PER_HOUR) / SEC_PER_MIN;
328 		/* assuming no remaining seconds like in historic Asia/Riyadh87, Asia/Riyadh88 and Asia/Riyadh89 */
329 #undef ZBX_UTC_OFF
330 	}
331 }
332 
333 /******************************************************************************
334  *                                                                            *
335  * Function: zbx_utc_time                                                     *
336  *                                                                            *
337  * Purpose: get UTC time from time from broken down time elements             *
338  *                                                                            *
339  * Parameters:                                                                *
340  *     year  - [IN] year (1970-...)                                           *
341  *     month - [IN] month (1-12)                                              *
342  *     mday  - [IN] day of month (1-..., depending on month and year)         *
343  *     hour  - [IN] hours (0-23)                                              *
344  *     min   - [IN] minutes (0-59)                                            *
345  *     sec   - [IN] seconds (0-61, leap seconds are not strictly validated)   *
346  *     t     - [OUT] Epoch timestamp                                          *
347  *                                                                            *
348  * Return value:  SUCCEED - date is valid and resulting timestamp is positive *
349  *                FAIL - otherwise                                            *
350  *                                                                            *
351  ******************************************************************************/
zbx_utc_time(int year,int mon,int mday,int hour,int min,int sec,int * t)352 int	zbx_utc_time(int year, int mon, int mday, int hour, int min, int sec, int *t)
353 {
354 /* number of leap years before but not including year */
355 #define ZBX_LEAP_YEARS(year)	(((year) - 1) / 4 - ((year) - 1) / 100 + ((year) - 1) / 400)
356 
357 	/* days since the beginning of non-leap year till the beginning of the month */
358 	static const int	month_day[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
359 	static const int	epoch_year = 1970;
360 
361 	if (epoch_year <= year && 1 <= mon && mon <= 12 && 1 <= mday && mday <= zbx_day_in_month(year, mon) &&
362 			0 <= hour && hour <= 23 && 0 <= min && min <= 59 && 0 <= sec && sec <= 61 &&
363 			0 <= (*t = (year - epoch_year) * SEC_PER_YEAR +
364 			(ZBX_LEAP_YEARS(2 < mon ? year + 1 : year) - ZBX_LEAP_YEARS(epoch_year)) * SEC_PER_DAY +
365 			(month_day[mon - 1] + mday - 1) * SEC_PER_DAY + hour * SEC_PER_HOUR + min * SEC_PER_MIN + sec))
366 	{
367 		return SUCCEED;
368 	}
369 
370 	return FAIL;
371 #undef ZBX_LEAP_YEARS
372 }
373 
374 /******************************************************************************
375  *                                                                            *
376  * Function: zbx_day_in_month                                                 *
377  *                                                                            *
378  * Purpose: returns number of days in a month                                 *
379  *                                                                            *
380  * Parameters:                                                                *
381  *     year  - [IN] year                                                      *
382  *     mon   - [IN] month (1-12)                                              *
383  *                                                                            *
384  * Return value: 28-31 depending on number of days in the month, defaults to  *
385  *               30 if the month is outside of allowed range                  *
386  *                                                                            *
387  * Author: Alexander Vladishev                                                *
388  *                                                                            *
389  ******************************************************************************/
zbx_day_in_month(int year,int mon)390 int	zbx_day_in_month(int year, int mon)
391 {
392 	/* number of days in the month of a non-leap year */
393 	static const unsigned char	month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
394 
395 	if (1 <= mon && mon <= 12)	/* add one day in February of a leap year */
396 		return month[mon - 1] + (2 == mon && SUCCEED == is_leap_year(year) ? 1 : 0);
397 
398 	return 30;
399 }
400 
401 /******************************************************************************
402  *                                                                            *
403  * Function: zbx_calloc2                                                      *
404  *                                                                            *
405  * Purpose: allocates nmemb * size bytes of memory and fills it with zeros    *
406  *                                                                            *
407  * Return value: returns a pointer to the newly allocated memory              *
408  *                                                                            *
409  * Author: Eugene Grigorjev, Rudolfs Kreicbergs                               *
410  *                                                                            *
411  ******************************************************************************/
zbx_calloc2(const char * filename,int line,void * old,size_t nmemb,size_t size)412 void    *zbx_calloc2(const char *filename, int line, void *old, size_t nmemb, size_t size)
413 {
414 	int	max_attempts;
415 	void	*ptr = NULL;
416 
417 	/* old pointer must be NULL */
418 	if (NULL != old)
419 	{
420 		zabbix_log(LOG_LEVEL_CRIT, "[file:%s,line:%d] zbx_calloc: allocating already allocated memory. "
421 				"Please report this to Zabbix developers.",
422 				filename, line);
423 	}
424 
425 	for (
426 		max_attempts = 10, nmemb = MAX(nmemb, 1), size = MAX(size, 1);
427 		0 < max_attempts && NULL == ptr;
428 		ptr = calloc(nmemb, size), max_attempts--
429 	);
430 
431 	if (NULL != ptr)
432 		return ptr;
433 
434 	zabbix_log(LOG_LEVEL_CRIT, "[file:%s,line:%d] zbx_calloc: out of memory. Requested " ZBX_FS_SIZE_T " bytes.",
435 			filename, line, (zbx_fs_size_t)size);
436 
437 	exit(EXIT_FAILURE);
438 }
439 
440 /******************************************************************************
441  *                                                                            *
442  * Function: zbx_malloc2                                                      *
443  *                                                                            *
444  * Purpose: allocates size bytes of memory                                    *
445  *                                                                            *
446  * Return value: returns a pointer to the newly allocated memory              *
447  *                                                                            *
448  * Author: Eugene Grigorjev                                                   *
449  *                                                                            *
450  ******************************************************************************/
zbx_malloc2(const char * filename,int line,void * old,size_t size)451 void    *zbx_malloc2(const char *filename, int line, void *old, size_t size)
452 {
453 	int	max_attempts;
454 	void	*ptr = NULL;
455 
456 	/* old pointer must be NULL */
457 	if (NULL != old)
458 	{
459 		zabbix_log(LOG_LEVEL_CRIT, "[file:%s,line:%d] zbx_malloc: allocating already allocated memory. "
460 				"Please report this to Zabbix developers.",
461 				filename, line);
462 	}
463 
464 	for (
465 		max_attempts = 10, size = MAX(size, 1);
466 		0 < max_attempts && NULL == ptr;
467 		ptr = malloc(size), max_attempts--
468 	);
469 
470 	if (NULL != ptr)
471 		return ptr;
472 
473 	zabbix_log(LOG_LEVEL_CRIT, "[file:%s,line:%d] zbx_malloc: out of memory. Requested " ZBX_FS_SIZE_T " bytes.",
474 			filename, line, (zbx_fs_size_t)size);
475 
476 	exit(EXIT_FAILURE);
477 }
478 
479 /******************************************************************************
480  *                                                                            *
481  * Function: zbx_realloc2                                                     *
482  *                                                                            *
483  * Purpose: changes the size of the memory block pointed to by old            *
484  *          to size bytes                                                     *
485  *                                                                            *
486  * Return value: returns a pointer to the newly allocated memory              *
487  *                                                                            *
488  * Author: Eugene Grigorjev                                                   *
489  *                                                                            *
490  ******************************************************************************/
zbx_realloc2(const char * filename,int line,void * old,size_t size)491 void    *zbx_realloc2(const char *filename, int line, void *old, size_t size)
492 {
493 	int	max_attempts;
494 	void	*ptr = NULL;
495 
496 	for (
497 		max_attempts = 10, size = MAX(size, 1);
498 		0 < max_attempts && NULL == ptr;
499 		ptr = realloc(old, size), max_attempts--
500 	);
501 
502 	if (NULL != ptr)
503 		return ptr;
504 
505 	zabbix_log(LOG_LEVEL_CRIT, "[file:%s,line:%d] zbx_realloc: out of memory. Requested " ZBX_FS_SIZE_T " bytes.",
506 			filename, line, (zbx_fs_size_t)size);
507 
508 	exit(EXIT_FAILURE);
509 }
510 
zbx_strdup2(const char * filename,int line,char * old,const char * str)511 char    *zbx_strdup2(const char *filename, int line, char *old, const char *str)
512 {
513 	int	retry;
514 	char	*ptr = NULL;
515 
516 	zbx_free(old);
517 
518 	for (retry = 10; 0 < retry && NULL == ptr; ptr = strdup(str), retry--)
519 		;
520 
521 	if (NULL != ptr)
522 		return ptr;
523 
524 	zabbix_log(LOG_LEVEL_CRIT, "[file:%s,line:%d] zbx_strdup: out of memory. Requested " ZBX_FS_SIZE_T " bytes.",
525 			filename, line, (zbx_fs_size_t)(strlen(str) + 1));
526 
527 	exit(EXIT_FAILURE);
528 }
529 
530 /****************************************************************************************
531  *                                                                                      *
532  * Function: zbx_guaranteed_memset                                                      *
533  *                                                                                      *
534  * Purpose: For overwriting sensitive data in memory.                                   *
535  *          Similar to memset() but should not be optimized out by a compiler.          *
536  *                                                                                      *
537  * Derived from:                                                                        *
538  *   http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html *
539  * See also:                                                                            *
540  *   http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1381.pdf on secure_memset()       *
541  *                                                                                      *
542  ****************************************************************************************/
zbx_guaranteed_memset(void * v,int c,size_t n)543 void	*zbx_guaranteed_memset(void *v, int c, size_t n)
544 {
545 	volatile signed char	*p = (volatile signed char *)v;
546 
547 	while (0 != n--)
548 		*p++ = (signed char)c;
549 
550 	return v;
551 }
552 
553 /******************************************************************************
554  *                                                                            *
555  * Function: __zbx_zbx_setproctitle                                           *
556  *                                                                            *
557  * Purpose: set process title                                                 *
558  *                                                                            *
559  * Author: Eugene Grigorjev                                                   *
560  *                                                                            *
561  ******************************************************************************/
__zbx_zbx_setproctitle(const char * fmt,...)562 void	__zbx_zbx_setproctitle(const char *fmt, ...)
563 {
564 #if defined(HAVE_FUNCTION_SETPROCTITLE) || defined(PS_OVERWRITE_ARGV) || defined(PS_PSTAT_ARGV)
565 	const char	*__function_name = "__zbx_zbx_setproctitle";
566 	char		title[MAX_STRING_LEN];
567 	va_list		args;
568 
569 	va_start(args, fmt);
570 	zbx_vsnprintf(title, sizeof(title), fmt, args);
571 	va_end(args);
572 
573 	zabbix_log(LOG_LEVEL_DEBUG, "%s() title:'%s'", __function_name, title);
574 #endif
575 
576 #if defined(HAVE_FUNCTION_SETPROCTITLE)
577 	setproctitle(title);
578 #elif defined(PS_OVERWRITE_ARGV) || defined(PS_PSTAT_ARGV)
579 	setproctitle_set_status(title);
580 #endif
581 }
582 
583 /******************************************************************************
584  *                                                                            *
585  * Function: check_time_period                                                *
586  *                                                                            *
587  * Purpose: check if current time is within given period                      *
588  *                                                                            *
589  * Parameters: period - time period in format [d1-d2,hh:mm-hh:mm]*            *
590  *             now    - timestamp for comparison                              *
591  *                      if NULL - use current timestamp.                      *
592  *                                                                            *
593  * Return value: FAIL - out of period, SUCCEED - within the period            *
594  *                                                                            *
595  * Author: Alexei Vladishev                                                   *
596  *                                                                            *
597  * Comments:   !!! Don't forget to sync code with PHP !!!                     *
598  *                                                                            *
599  ******************************************************************************/
check_time_period(const char * period,time_t now)600 int	check_time_period(const char *period, time_t now)
601 {
602 	const char	*__function_name = "check_time_period";
603 	const char	*s, *delim;
604 	int		d1, d2, h1, h2, m1, m2, flag, day, sec, sec1, sec2, ret = FAIL;
605 	struct tm	*tm;
606 
607 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() period:'%s'", __function_name, period);
608 
609 	if ((time_t)0 == now)
610 		now = time(NULL);
611 
612 	tm = localtime(&now);
613 	day = 0 == tm->tm_wday ? 7 : tm->tm_wday;
614 	sec = SEC_PER_HOUR * tm->tm_hour + SEC_PER_MIN * tm->tm_min + tm->tm_sec;
615 
616 	zabbix_log(LOG_LEVEL_DEBUG, "%d,%d:%d", day, (int)tm->tm_hour, (int)tm->tm_min);
617 
618 	for (s = period; '\0' != *s;)
619 	{
620 		delim = strchr(s, ';');
621 
622 		zabbix_log(LOG_LEVEL_DEBUG, "period [%s]", s);
623 
624 		flag = (6 == sscanf(s, "%d-%d,%d:%d-%d:%d", &d1, &d2, &h1, &m1, &h2, &m2));
625 
626 		if (0 == flag)
627 		{
628 			flag = (5 == sscanf(s, "%d,%d:%d-%d:%d", &d1, &h1, &m1, &h2, &m2));
629 			d2 = d1;
630 		}
631 
632 		if (0 != flag)
633 		{
634 			zabbix_log(LOG_LEVEL_DEBUG, "%d-%d,%d:%d-%d:%d", d1, d2, h1, m1, h2, m2);
635 
636 			sec1 = SEC_PER_HOUR * h1 + SEC_PER_MIN * m1;
637 			sec2 = SEC_PER_HOUR * h2 + SEC_PER_MIN * m2;	/* do not include upper bound */
638 
639 			if (d1 <= day && day <= d2 && sec1 <= sec && sec < sec2)
640 			{
641 				ret = SUCCEED;
642 				break;
643 			}
644 		}
645 		else
646 			zabbix_log(LOG_LEVEL_ERR, "wrong time period format [%s]", period);
647 
648 		if (NULL != delim)
649 			s = delim + 1;
650 		else
651 			break;
652 	}
653 
654 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
655 
656 	return ret;
657 }
658 
659 /******************************************************************************
660  *                                                                            *
661  * Function: get_current_delay                                                *
662  *                                                                            *
663  * Purpose: return delay value that is currently applicable                   *
664  *                                                                            *
665  * Parameters: delay - [IN] default delay value, can be overridden            *
666  *             flex_intervals - [IN] descriptions of flexible intervals       *
667  *                                   in the form [dd/d1-d2,hh:mm-hh:mm;]      *
668  *             now - [IN] current time                                        *
669  *                                                                            *
670  * Return value: delay value - either default or minimum delay value          *
671  *                             out of all applicable intervals                *
672  *                                                                            *
673  * Author: Alexei Vladishev, Alexander Vladishev, Aleksandrs Saveljevs        *
674  *                                                                            *
675  ******************************************************************************/
get_current_delay(int delay,const char * flex_intervals,time_t now)676 static int	get_current_delay(int delay, const char *flex_intervals, time_t now)
677 {
678 	const char	*s, *delim;
679 	char		flex_period[30];
680 	int		flex_delay, current_delay = -1;
681 
682 	if (NULL == flex_intervals || '\0' == *flex_intervals)
683 		return delay;
684 
685 	for (s = flex_intervals; '\0' != *s; s = delim + 1)
686 	{
687 		delim = strchr(s, ';');
688 
689 		zabbix_log(LOG_LEVEL_DEBUG, "delay period [%s]", s);
690 
691 		if (2 == sscanf(s, "%d/%29[^;]s", &flex_delay, flex_period))
692 		{
693 			zabbix_log(LOG_LEVEL_DEBUG, "%d sec at %s", flex_delay, flex_period);
694 
695 			if ((-1 == current_delay || flex_delay < current_delay) &&
696 					SUCCEED == check_time_period(flex_period, now))
697 			{
698 				current_delay = flex_delay;
699 			}
700 		}
701 		else
702 			zabbix_log(LOG_LEVEL_ERR, "wrong delay period format: \"%s\"", s);
703 
704 		if (NULL == delim)
705 			break;
706 	}
707 
708 	if (-1 == current_delay)
709 		return delay;
710 
711 	return current_delay;
712 }
713 
714 /******************************************************************************
715  *                                                                            *
716  * Function: get_next_delay_interval                                          *
717  *                                                                            *
718  * Purpose: return time when next delay settings take effect                  *
719  *                                                                            *
720  * Parameters: flex_intervals - [IN] descriptions of flexible intervals       *
721  *                                   in the form [dd/d1-d2,hh:mm-hh:mm;]      *
722  *             now = [IN] current time                                        *
723  *             next_interval = [OUT] start of next delay interval             *
724  *                                                                            *
725  * Return value: SUCCEED - there is a next interval                           *
726  *               FAIL - otherwise (in this case, next_interval is unaffected) *
727  *                                                                            *
728  * Author: Alexei Vladishev, Alexander Vladishev, Aleksandrs Saveljevs        *
729  *                                                                            *
730  ******************************************************************************/
get_next_delay_interval(const char * flex_intervals,time_t now,time_t * next_interval)731 static int	get_next_delay_interval(const char *flex_intervals, time_t now, time_t *next_interval)
732 {
733 	const char	*s, *delim;
734 	struct tm	*tm;
735 	int		day, sec, sec1, sec2, delay, d1, d2, h1, h2, m1, m2, flag;
736 	time_t		next = 0;
737 
738 	if (NULL == flex_intervals || '\0' == *flex_intervals)
739 		return FAIL;
740 
741 	tm = localtime(&now);
742 	day = 0 == tm->tm_wday ? 7 : tm->tm_wday;
743 	sec = SEC_PER_HOUR * tm->tm_hour + SEC_PER_MIN * tm->tm_min + tm->tm_sec;
744 
745 	for (s = flex_intervals; '\0' != *s;)
746 	{
747 		delim = strchr(s, ';');
748 
749 		zabbix_log(LOG_LEVEL_DEBUG, "delay period [%s]", s);
750 
751 		flag = (7 == sscanf(s, "%d/%d-%d,%d:%d-%d:%d", &delay, &d1, &d2, &h1, &m1, &h2, &m2));
752 
753 		if (0 == flag)
754 		{
755 			flag = (6 == sscanf(s, "%d/%d,%d:%d-%d:%d", &delay, &d1, &h1, &m1, &h2, &m2));
756 			d2 = d1;
757 		}
758 
759 		if (0 != flag)
760 		{
761 			zabbix_log(LOG_LEVEL_DEBUG, "%d/%d-%d,%d:%d-%d:%d", delay, d1, d2, h1, m1, h2, m2);
762 
763 			sec1 = SEC_PER_HOUR * h1 + SEC_PER_MIN * m1;
764 			sec2 = SEC_PER_HOUR * h2 + SEC_PER_MIN * m2;	/* do not include upper bound */
765 
766 			if (d1 <= day && day <= d2 && sec1 <= sec && sec < sec2)	/* current period */
767 			{
768 				if (0 == next || next > now - sec + sec2)
769 					next = now - sec + sec2;	/* the next second after the */
770 									/* current interval's upper bound */
771 			}
772 			else if (d1 <= day && day <= d2 && sec < sec1)			/* will be active today */
773 			{
774 				if (0 == next || next > now - sec + sec1)
775 					next = now - sec + sec1;
776 			}
777 			else
778 			{
779 				int	next_day;
780 
781 				next_day = (7 >= day + 1 ? day + 1 : 1);
782 
783 				if (d1 <= next_day && next_day <= d2)			/* will be active tomorrow */
784 				{
785 					if (0 == next || next > now - sec + SEC_PER_DAY + sec1)
786 						next = now - sec + SEC_PER_DAY + sec1;
787 				}
788 				else							/* later in the future */
789 				{
790 					int	day_diff = -1;
791 
792 					if (day < d1)
793 						day_diff = d1 - day;
794 					if (day >= d2)
795 						day_diff = (d1 + 7) - day;
796 					if (d1 <= day && day < d2)
797 					{
798 						/* should never happen */
799 						zabbix_log(LOG_LEVEL_ERR, "could not deduce day difference"
800 								" [%s, day=%d, time=%02d:%02d:%02d]",
801 								s, day, tm->tm_hour, tm->tm_min, tm->tm_sec);
802 						day_diff = -1;
803 					}
804 
805 					if (-1 != day_diff &&
806 							(0 == next || next > now - sec + SEC_PER_DAY * day_diff + sec1))
807 						next = now - sec + SEC_PER_DAY * day_diff + sec1;
808 				}
809 			}
810 		}
811 		else
812 			zabbix_log(LOG_LEVEL_ERR, "wrong delay period format: \"%s\"", s);
813 
814 		if (NULL != delim)
815 			s = delim + 1;
816 		else
817 			break;
818 	}
819 
820 	if (0 != next && NULL != next_interval)
821 		*next_interval = next;
822 
823 	return 0 != next ? SUCCEED : FAIL;
824 }
825 
826 /******************************************************************************
827  *                                                                            *
828  * Function: calculate_dayofweek                                              *
829  *                                                                            *
830  * Purpose: calculates day of week                                            *
831  *                                                                            *
832  * Parameters: year - [IN] the year (>1752)                                   *
833  *             mon  - [IN] the month (1-12)                                   *
834  *             mday - [IN] the month day (1-31)                               *
835  *                                                                            *
836  * Return value: The day of week: 1 - Monday, 2 - Tuesday, ...                *
837  *                                                                            *
838  ******************************************************************************/
calculate_dayofweek(int year,int mon,int mday)839 static int	calculate_dayofweek(int year, int mon, int mday)
840 {
841 	static int	mon_table[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
842 
843 	if (mon < 3)
844 		year--;
845 
846 	return (year + year / 4 - year / 100 + year / 400 + mon_table[mon - 1] + mday - 1) % 7 + 1;
847 }
848 
849 /******************************************************************************
850  *                                                                            *
851  * Function: scheduler_filter_free                                            *
852  *                                                                            *
853  * Purpose: frees scheduler interval filter                                   *
854  *                                                                            *
855  * Parameters: filter - [IN] scheduler interval filter                        *
856  *                                                                            *
857  ******************************************************************************/
scheduler_filter_free(zbx_scheduler_filter_t * filter)858 static void	scheduler_filter_free(zbx_scheduler_filter_t *filter)
859 {
860 	zbx_scheduler_filter_t	*filter_next;
861 
862 	for (; NULL != filter; filter = filter_next)
863 	{
864 		filter_next = filter->next;
865 		zbx_free(filter);
866 	}
867 }
868 
869 /******************************************************************************
870  *                                                                            *
871  * Function: scheduler_interval_free                                          *
872  *                                                                            *
873  * Purpose: frees scheduler interval                                          *
874  *                                                                            *
875  * Parameters: filter - [IN] scheduler interval                               *
876  *                                                                            *
877  ******************************************************************************/
scheduler_interval_free(zbx_scheduler_interval_t * interval)878 static void	scheduler_interval_free(zbx_scheduler_interval_t *interval)
879 {
880 	zbx_scheduler_interval_t	*interval_next;
881 
882 	for (; NULL != interval; interval = interval_next)
883 	{
884 		interval_next = interval->next;
885 
886 		scheduler_filter_free(interval->mdays);
887 		scheduler_filter_free(interval->wdays);
888 		scheduler_filter_free(interval->hours);
889 		scheduler_filter_free(interval->minutes);
890 		scheduler_filter_free(interval->seconds);
891 
892 		zbx_free(interval);
893 	}
894 }
895 
896 /******************************************************************************
897  *                                                                            *
898  * Function: scheduler_parse_filter_r                                         *
899  *                                                                            *
900  * Purpose: parses text string into scheduler filter                          *
901  *                                                                            *
902  * Parameters: filter  - [IN/OUT] the first filter                            *
903  *             text    - [IN] the text to parse                               *
904  *             len     - [IN/OUT] the number of characters left to parse      *
905  *             min     - [IN] the minimal time unit value                     *
906  *             max     - [IN] the maximal time unit value                     *
907  *             var_len - [IN] the maximum number of characters for a filter   *
908  *                       variable (<from>, <to>, <step>)                      *
909  *                                                                            *
910  * Return value: SUCCEED - the fitler was successfully parsed                 *
911  *               FAIL    - otherwise                                          *
912  *                                                                            *
913  * Comments: This function recursively calls itself for each filter fragment. *
914  *                                                                            *
915  ******************************************************************************/
scheduler_parse_filter_r(zbx_scheduler_filter_t ** filter,const char * text,int * len,int min,int max,int var_len)916 static int	scheduler_parse_filter_r(zbx_scheduler_filter_t **filter, const char *text, int *len, int min, int max,
917 		int var_len)
918 {
919 	int			start = 0, end = 0, step = 1;
920 	const char		*pstart, *pend;
921 	zbx_scheduler_filter_t	*filter_new;
922 
923 	pstart = pend = text;
924 	while (0 != isdigit(*pend) && 0 < *len)
925 	{
926 		pend++;
927 		(*len)--;
928 	}
929 
930 	if (pend != pstart)
931 	{
932 		if (pend - pstart > var_len)
933 			return FAIL;
934 
935 		if (SUCCEED != is_uint_n_range(pstart, pend - pstart, &start, sizeof(start), min, max))
936 			return FAIL;
937 
938 		if ('-' == *pend)
939 		{
940 			pstart = pend + 1;
941 
942 			do
943 			{
944 				pend++;
945 				(*len)--;
946 			}
947 			while (0 != isdigit(*pend) && 0 < *len);
948 
949 			/* empty or too long value, fail */
950 			if (pend == pstart || pend - pstart > var_len)
951 				return FAIL;
952 
953 			if (SUCCEED != is_uint_n_range(pstart, pend - pstart, &end, sizeof(end), min, max))
954 				return FAIL;
955 
956 			if (end < start)
957 				return FAIL;
958 		}
959 		else
960 		{
961 			/* step is valid only for defined range */
962 			if ('/' == *pend)
963 				return FAIL;
964 
965 			end = start;
966 		}
967 	}
968 	else
969 	{
970 		start = min;
971 		end = max;
972 	}
973 
974 	if ('/' == *pend)
975 	{
976 		pstart = pend + 1;
977 
978 		do
979 		{
980 			pend++;
981 			(*len)--;
982 		}
983 		while (0 != isdigit(*pend) && 0 < *len);
984 
985 		/* empty or too long step, fail */
986 		if (pend == pstart || pend - pstart > var_len)
987 			return FAIL;
988 
989 		if (SUCCEED != is_uint_n_range(pstart, pend - pstart, &step, sizeof(step), 1, end - start))
990 			return FAIL;
991 	}
992 	else
993 	{
994 		if (pend == text)
995 			return FAIL;
996 	}
997 
998 	if (',' == *pend)
999 	{
1000 		/* no next filter after ',' */
1001 		if (0 == --(*len))
1002 			return FAIL;
1003 
1004 		pend++;
1005 
1006 		if (SUCCEED != scheduler_parse_filter_r(filter, pend, len, min, max, var_len))
1007 			return FAIL;
1008 	}
1009 
1010 	filter_new = zbx_malloc(NULL, sizeof(zbx_scheduler_filter_t));
1011 	filter_new->start = start;
1012 	filter_new->end = end;
1013 	filter_new->step = step;
1014 	filter_new->next = *filter;
1015 	*filter = filter_new;
1016 
1017 	return SUCCEED;
1018 }
1019 
1020 /******************************************************************************
1021  *                                                                            *
1022  * Function: scheduler_parse_filter                                           *
1023  *                                                                            *
1024  * Purpose: parses text string into scheduler filter                          *
1025  *                                                                            *
1026  * Parameters: filter  - [IN/OUT] the first filter                            *
1027  *             text    - [IN] the text to parse                               *
1028  *             len     - [IN/OUT] the number of characters left to parse      *
1029  *             min     - [IN] the minimal time unit value                     *
1030  *             max     - [IN] the maximal time unit value                     *
1031  *             var_len - [IN] the maximum number of characters for a filter   *
1032  *                       variable (<from>, <to>, <step>)                      *
1033  *                                                                            *
1034  * Return value: SUCCEED - the fitler was successfully parsed                 *
1035  *               FAIL    - otherwise                                          *
1036  *                                                                            *
1037  * Comments: This function will fail if a filter already exists. This         *
1038  *           user from defining multiple filters of the same time unit in a   *
1039  *           single interval. For example: h0h12 is invalid filter and its    *
1040  *           parsing must fail.                                               *
1041  *                                                                            *
1042  ******************************************************************************/
scheduler_parse_filter(zbx_scheduler_filter_t ** filter,const char * text,int * len,int min,int max,int var_len)1043 static int	scheduler_parse_filter(zbx_scheduler_filter_t **filter, const char *text, int *len, int min, int max,
1044 		int var_len)
1045 {
1046 	if (NULL != *filter)
1047 		return FAIL;
1048 
1049 	return scheduler_parse_filter_r(filter, text, len, min, max, var_len);
1050 }
1051 
1052 /******************************************************************************
1053  *                                                                            *
1054  * Function: scheduler_interval_parse                                         *
1055  *                                                                            *
1056  * Purpose: parses scheduler interval                                         *
1057  *                                                                            *
1058  * Parameters: interval - [IN/OUT] the first interval                         *
1059  *             text     - [IN] the text to parse                              *
1060  *             len      - [IN] the text length                                *
1061  *                                                                            *
1062  * Return value: SUCCEED - the interval was successfully parsed               *
1063  *               FAIL    - otherwise                                          *
1064  *                                                                            *
1065  ******************************************************************************/
scheduler_interval_parse(zbx_scheduler_interval_t * interval,const char * text,int len)1066 static int	scheduler_interval_parse(zbx_scheduler_interval_t *interval, const char *text, int len)
1067 {
1068 	int	ret = SUCCEED;
1069 
1070 	if (0 == len)
1071 		return FAIL;
1072 
1073 	while (SUCCEED == ret && 0 != len)
1074 	{
1075 		int	old_len = len--;
1076 
1077 		switch (*text)
1078 		{
1079 			case '\0':
1080 				return FAIL;
1081 			case 'h':
1082 				if (ZBX_SCHEDULER_FILTER_HOUR < interval->filter_level)
1083 					return FAIL;
1084 
1085 				ret = scheduler_parse_filter(&interval->hours, text + 1, &len, 0, 23, 2);
1086 				interval->filter_level = ZBX_SCHEDULER_FILTER_HOUR;
1087 
1088 				break;
1089 			case 's':
1090 				if (ZBX_SCHEDULER_FILTER_SECOND < interval->filter_level)
1091 					return FAIL;
1092 
1093 				ret = scheduler_parse_filter(&interval->seconds, text + 1, &len, 0, 59, 2);
1094 				interval->filter_level = ZBX_SCHEDULER_FILTER_SECOND;
1095 
1096 				break;
1097 			case 'w':
1098 				if ('d' != text[1])
1099 					return FAIL;
1100 
1101 				if (ZBX_SCHEDULER_FILTER_DAY < interval->filter_level)
1102 					return FAIL;
1103 
1104 				len--;
1105 				ret = scheduler_parse_filter(&interval->wdays, text + 2, &len, 1, 7, 1);
1106 				interval->filter_level = ZBX_SCHEDULER_FILTER_DAY;
1107 
1108 				break;
1109 			case 'm':
1110 				if ('d' == text[1])
1111 				{
1112 					if (ZBX_SCHEDULER_FILTER_DAY < interval->filter_level ||
1113 							NULL != interval->wdays)
1114 					{
1115 						return FAIL;
1116 					}
1117 
1118 					len--;
1119 					ret = scheduler_parse_filter(&interval->mdays, text + 2, &len, 1, 31, 2);
1120 					interval->filter_level = ZBX_SCHEDULER_FILTER_DAY;
1121 				}
1122 				else
1123 				{
1124 					if (ZBX_SCHEDULER_FILTER_MINUTE < interval->filter_level)
1125 						return FAIL;
1126 
1127 					ret = scheduler_parse_filter(&interval->minutes, text + 1, &len, 0, 59, 2);
1128 					interval->filter_level = ZBX_SCHEDULER_FILTER_MINUTE;
1129 				}
1130 
1131 				break;
1132 			default:
1133 				return FAIL;
1134 		}
1135 
1136 		text += old_len - len;
1137 	}
1138 
1139 	return ret;
1140 }
1141 
1142 /******************************************************************************
1143  *                                                                            *
1144  * Function: preprocess_flexible_interval                                     *
1145  *                                                                            *
1146  * Purpose: parses out the flexible interval in a text format and scheduler   *
1147  *          interval in zbx_scheduler_interval_t structure                    *
1148  *                                                                            *
1149  * Parameters: text       - [IN] the text to parse                            *
1150  *             interval   - [OUT] the parsed scheduler interval. Must be a    *
1151  *                          pointer to a NULL pointer on the first call. It   *
1152  *                          will be left untouched if the text does not       *
1153  *                          contain scheduler intervals                       *
1154  *             out        - [IN/OUT] flexible interval in text format         *
1155  *             out_alloc  - [IN/OUT] the number of bytes allocated for out    *
1156  *             out_offset - [IN/OUT] the flexible interval length in out      *
1157  *                          buffer                                            *
1158  *                                                                            *
1159  * Return value: SUCCEED - the text was successfully parsed                   *
1160  *               FAIL    - otherwise                                          *
1161  *                                                                            *
1162  * Comments: This function recursively calls itself for each interval.        *
1163  *                                                                            *
1164  ******************************************************************************/
preprocess_flexible_interval(const char * text,zbx_scheduler_interval_t ** interval,char ** out,size_t * out_alloc,size_t * out_offset,char ** errmsg)1165 static int	preprocess_flexible_interval(const char *text, zbx_scheduler_interval_t **interval,
1166 		char **out, size_t *out_alloc, size_t *out_offset, char **errmsg)
1167 {
1168 	const char			*ptr;
1169 	zbx_scheduler_interval_t	*new_interval;
1170 
1171 	ptr = strchr(text, ';');
1172 
1173 	if (NULL == ptr)
1174 		ptr = text + strlen(text);
1175 
1176 	if (0 != isdigit(*text))
1177 	{
1178 		if (0 != *out_offset)
1179 			zbx_chrcpy_alloc(out, out_alloc, out_offset, ';');
1180 
1181 		zbx_strncpy_alloc(out, out_alloc, out_offset, text, ptr - text);
1182 	}
1183 
1184 	if ('\0' != *ptr)
1185 	{
1186 		if (SUCCEED != preprocess_flexible_interval(ptr + 1, interval, out, out_alloc, out_offset, errmsg))
1187 			return FAIL;
1188 	}
1189 
1190 	/* flexible interval has already been copied, return success */
1191 	if (0 != isdigit(*text))
1192 		return SUCCEED;
1193 
1194 	new_interval = zbx_malloc(NULL, sizeof(zbx_scheduler_interval_t));
1195 	memset(new_interval, 0, sizeof(zbx_scheduler_interval_t));
1196 
1197 	if (SUCCEED != scheduler_interval_parse(new_interval, text, ptr - text))
1198 	{
1199 		size_t	errmsg_alloc = 0, errmsg_offset = 0;
1200 
1201 		zbx_free(*errmsg);
1202 		zbx_strcpy_alloc(errmsg, &errmsg_alloc, &errmsg_offset, "invalid scheduling interval: \"");
1203 		zbx_strncpy_alloc(errmsg, &errmsg_alloc, &errmsg_offset, text, ptr - text + 1);
1204 		zbx_strcpy_alloc(errmsg, &errmsg_alloc, &errmsg_offset, "\"");
1205 
1206 		scheduler_interval_free(new_interval);
1207 		return FAIL;
1208 	}
1209 
1210 	new_interval->next = *interval;
1211 	*interval = new_interval;
1212 
1213 	return SUCCEED;
1214 }
1215 
1216 /******************************************************************************
1217  *                                                                            *
1218  * Function: scheduler_get_nearest_filter_value                               *
1219  *                                                                            *
1220  * Purpose: gets the next nearest value that satisfies the filter chain       *
1221  *                                                                            *
1222  * Parameters: filter - [IN] the filter chain                                 *
1223  *             value  - [IN] the current value                                *
1224  *                      [OUT] the next nearest value (>= than input value)    *
1225  *                                                                            *
1226  * Return value: SUCCEED - the next nearest value was successfully found      *
1227  *               FAIL    - otherwise                                          *
1228  *                                                                            *
1229  ******************************************************************************/
scheduler_get_nearest_filter_value(const zbx_scheduler_filter_t * filter,int * value)1230 static int	scheduler_get_nearest_filter_value(const zbx_scheduler_filter_t *filter, int *value)
1231 {
1232 	const zbx_scheduler_filter_t	*filter_next = NULL;
1233 
1234 	for (; NULL != filter; filter = filter->next)
1235 	{
1236 		/* find matching filter */
1237 		if (filter->start <= *value && *value <= filter->end)
1238 		{
1239 			int	next = *value, offset;
1240 
1241 			/* apply step */
1242 			offset = (next - filter->start) % filter->step;
1243 			if (0 != offset)
1244 				next += filter->step - offset;
1245 
1246 			/* succeed if the calculated value is still in filter range */
1247 			if (next <= filter->end)
1248 			{
1249 				*value = next;
1250 				return SUCCEED;
1251 			}
1252 		}
1253 
1254 		/* find the next nearest filter */
1255 		if (filter->start > *value && (NULL == filter_next || filter_next->start > filter->start))
1256 			filter_next = filter;
1257 	}
1258 
1259 	/* The value is not in a range of any filters, but we have next nearest filter. */
1260 	if (NULL != filter_next)
1261 	{
1262 		*value = filter_next->start;
1263 		return SUCCEED;
1264 	}
1265 
1266 	return FAIL;
1267 }
1268 
1269 /******************************************************************************
1270  *                                                                            *
1271  * Function: scheduler_get_wday_nextcheck                                     *
1272  *                                                                            *
1273  * Purpose: calculates the next day that satisfies the week day filter        *
1274  *                                                                            *
1275  * Parameters: interval - [IN] the scheduler interval                         *
1276  *             tm       - [IN/OUT] the input/output date & time               *
1277  *                                                                            *
1278  * Return value: SUCCEED - the next day was found                             *
1279  *               FAIL    - the next day satisfying week day filter was not    *
1280  *                         found in the current month                         *
1281  *                                                                            *
1282  ******************************************************************************/
scheduler_get_wday_nextcheck(const zbx_scheduler_interval_t * interval,struct tm * tm)1283 static int	scheduler_get_wday_nextcheck(const zbx_scheduler_interval_t *interval, struct tm *tm)
1284 {
1285 	int	value_now, value_next;
1286 
1287 	if (NULL == interval->wdays)
1288 		return SUCCEED;
1289 
1290 	value_now = value_next = calculate_dayofweek(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
1291 
1292 	/* get the nearest week day from the current week day*/
1293 	if (SUCCEED != scheduler_get_nearest_filter_value(interval->wdays, &value_next))
1294 	{
1295 		/* in the case of failure move month day to the next week, reset week day and try again */
1296 		tm->tm_mday += 7 - value_now + 1;
1297 		value_now = value_next = 1;
1298 
1299 		if (SUCCEED != scheduler_get_nearest_filter_value(interval->wdays, &value_next))
1300 		{
1301 			/* a valid week day filter must always match some day of a new week */
1302 			THIS_SHOULD_NEVER_HAPPEN;
1303 			return FAIL;
1304 		}
1305 	}
1306 
1307 	/* adjust the month day by the week day offset */
1308 	tm->tm_mday += value_next - value_now;
1309 
1310 	/* check if the resulting month day is valid */
1311 	return (tm->tm_mday <= zbx_day_in_month(tm->tm_year + 1970, tm->tm_mon + 1) ? SUCCEED : FAIL);
1312 }
1313 
1314 /******************************************************************************
1315  *                                                                            *
1316  * Function: scheduler_validate_wday_filter                                   *
1317  *                                                                            *
1318  * Purpose: checks if the specified date satisfies week day filter            *
1319  *                                                                            *
1320  * Parameters: interval - [IN] the scheduler interval                         *
1321  *             tm       - [IN] the date & time to validate                    *
1322  *                                                                            *
1323  * Return value: SUCCEED - the input date satisfies week day filter           *
1324  *               FAIL    - otherwise                                          *
1325  *                                                                            *
1326  ******************************************************************************/
scheduler_validate_wday_filter(const zbx_scheduler_interval_t * interval,struct tm * tm)1327 static int	scheduler_validate_wday_filter(const zbx_scheduler_interval_t *interval, struct tm *tm)
1328 {
1329 	const zbx_scheduler_filter_t	*filter;
1330 	int				value;
1331 
1332 	if (NULL == interval->wdays)
1333 		return SUCCEED;
1334 
1335 	value = calculate_dayofweek(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
1336 
1337 	/* check if the value match week day filter */
1338 	for (filter = interval->wdays; NULL != filter; filter = filter->next)
1339 	{
1340 		if (filter->start <= value && value <= filter->end)
1341 		{
1342 			int	next = value, offset;
1343 
1344 			/* apply step */
1345 			offset = (next - filter->start) % filter->step;
1346 			if (0 != offset)
1347 				next += filter->step - offset;
1348 
1349 			/* succeed if the calculated value is still in filter range */
1350 			if (next <= filter->end)
1351 				return SUCCEED;
1352 		}
1353 	}
1354 
1355 	return FAIL;
1356 }
1357 
1358 /******************************************************************************
1359  *                                                                            *
1360  * Function: scheduler_get_day_nextcheck                                      *
1361  *                                                                            *
1362  * Purpose: calculates the next day that satisfies month and week day filters *
1363  *                                                                            *
1364  * Parameters: interval - [IN] the scheduler interval                         *
1365  *             tm       - [IN/OUT] the input/output date & time               *
1366  *                                                                            *
1367  * Return value: SUCCEED - the next day was found                             *
1368  *               FAIL    - the next day satisfying day filters was not        *
1369  *                         found in the current month                         *
1370  *                                                                            *
1371  ******************************************************************************/
scheduler_get_day_nextcheck(const zbx_scheduler_interval_t * interval,struct tm * tm)1372 static int	scheduler_get_day_nextcheck(const zbx_scheduler_interval_t *interval, struct tm *tm)
1373 {
1374 	int	tmp;
1375 
1376 	/* first check if the provided tm structure has valid date format */
1377 	if (FAIL == zbx_utc_time(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
1378 			&tmp))
1379 	{
1380 		return FAIL;
1381 	}
1382 
1383 	if (NULL == interval->mdays)
1384 		return scheduler_get_wday_nextcheck(interval, tm);
1385 
1386 	/* iterate through month days until week day filter matches or we have ran out of month days */
1387 	while (SUCCEED == scheduler_get_nearest_filter_value(interval->mdays, &tm->tm_mday))
1388 	{
1389 		/* check if the date is still valid - we haven't ran out of month days */
1390 		if (tm->tm_mday > zbx_day_in_month(tm->tm_year + 1970, tm->tm_mon + 1))
1391 			break;
1392 
1393 		if (SUCCEED == scheduler_validate_wday_filter(interval, tm))
1394 			return SUCCEED;
1395 
1396 		tm->tm_mday++;
1397 
1398 		/* check if the date is still valid - we haven't ran out of month days */
1399 		if (tm->tm_mday > zbx_day_in_month(tm->tm_year + 1970, tm->tm_mon + 1))
1400 			break;
1401 	}
1402 
1403 	return FAIL;
1404 }
1405 
1406 /******************************************************************************
1407  *                                                                            *
1408  * Function: scheduler_get_filter_nextcheck                                   *
1409  *                                                                            *
1410  * Purpose: calculates the time/day that satisfies the specified filter       *
1411  *                                                                            *
1412  * Parameters: interval - [IN] the scheduler interval                         *
1413  *             level    - [IN] the filter level, see ZBX_SCHEDULER_FILTER_*   *
1414  *                        defines                                             *
1415  *             tm       - [IN/OUT] the input/output date & time               *
1416  *                                                                            *
1417  * Return value: SUCCEED - the next time/day was found                        *
1418  *               FAIL    - the next time/day was not found on the current     *
1419  *                         filter level                                       *
1420  *                                                                            *
1421  ******************************************************************************/
scheduler_get_filter_nextcheck(const zbx_scheduler_interval_t * interval,int level,struct tm * tm)1422 static int	scheduler_get_filter_nextcheck(const zbx_scheduler_interval_t *interval, int level, struct tm *tm)
1423 {
1424 	const zbx_scheduler_filter_t	*filter;
1425 	int				max, *value;
1426 
1427 	/* initialize data depending on filter level */
1428 	switch (level)
1429 	{
1430 		case ZBX_SCHEDULER_FILTER_DAY:
1431 			return scheduler_get_day_nextcheck(interval, tm);
1432 		case ZBX_SCHEDULER_FILTER_HOUR:
1433 			max = 23;
1434 			filter = interval->hours;
1435 			value = &tm->tm_hour;
1436 			break;
1437 		case ZBX_SCHEDULER_FILTER_MINUTE:
1438 			max = 59;
1439 			filter = interval->minutes;
1440 			value = &tm->tm_min;
1441 			break;
1442 		case ZBX_SCHEDULER_FILTER_SECOND:
1443 			max = 59;
1444 			filter = interval->seconds;
1445 			value = &tm->tm_sec;
1446 			break;
1447 		default:
1448 			THIS_SHOULD_NEVER_HAPPEN;
1449 			return FAIL;
1450 	}
1451 
1452 	if (max < *value)
1453 		return FAIL;
1454 
1455 	/* handle unspecified (default) filter */
1456 	if (NULL == filter)
1457 	{
1458 		/* Empty filter matches all valid values if the filter level is less than        */
1459 		/* interval filter level. For example if interval filter level is minutes - m30, */
1460 		/* then hour filter matches all hours.                                           */
1461 		if (interval->filter_level > level)
1462 			return SUCCEED;
1463 
1464 		/* If the filter level is greater than interval filter level, then filter       */
1465 		/* matches only 0 value. For example if interval filter level is minutes - m30, */
1466 		/* then seconds filter matches the 0th second.                                  */
1467 		return 0 == *value ? SUCCEED : FAIL;
1468 	}
1469 
1470 	return scheduler_get_nearest_filter_value(filter, value);
1471 }
1472 
1473 /******************************************************************************
1474  *                                                                            *
1475  * Function: scheduler_apply_day_filter                                       *
1476  *                                                                            *
1477  * Purpose: applies day filter to the specified time/day calculating the next *
1478  *          scheduled check                                                   *
1479  *                                                                            *
1480  * Parameters: interval - [IN] the scheduler interval                         *
1481  *             tm       - [IN/OUT] the input/output date & time               *
1482  *                                                                            *
1483  ******************************************************************************/
scheduler_apply_day_filter(zbx_scheduler_interval_t * interval,struct tm * tm)1484 static void	scheduler_apply_day_filter(zbx_scheduler_interval_t *interval, struct tm *tm)
1485 {
1486 	int	day = tm->tm_mday, mon = tm->tm_mon, year = tm->tm_year;
1487 
1488 	while (SUCCEED != scheduler_get_filter_nextcheck(interval, ZBX_SCHEDULER_FILTER_DAY, tm))
1489 	{
1490 		if (11 < ++tm->tm_mon)
1491 		{
1492 			tm->tm_mon = 0;
1493 			tm->tm_year++;
1494 		}
1495 
1496 		tm->tm_mday = 1;
1497 	}
1498 
1499 	/* reset hours, minutes and seconds if the day has been changed */
1500 	if (tm->tm_mday != day || tm->tm_mon != mon || tm->tm_year != year)
1501 	{
1502 		tm->tm_hour = 0;
1503 		tm->tm_min = 0;
1504 		tm->tm_sec = 0;
1505 	}
1506 }
1507 
1508 /******************************************************************************
1509  *                                                                            *
1510  * Function: scheduler_apply_hour_filter                                      *
1511  *                                                                            *
1512  * Purpose: applies hour filter to the specified time/day calculating the     *
1513  *          next scheduled check                                              *
1514  *                                                                            *
1515  * Parameters: interval - [IN] the scheduler interval                         *
1516  *             tm       - [IN/OUT] the input/output date & time               *
1517  *                                                                            *
1518  ******************************************************************************/
scheduler_apply_hour_filter(zbx_scheduler_interval_t * interval,struct tm * tm)1519 static void	scheduler_apply_hour_filter(zbx_scheduler_interval_t *interval, struct tm *tm)
1520 {
1521 	int	hour = tm->tm_hour;
1522 
1523 	while (SUCCEED != scheduler_get_filter_nextcheck(interval, ZBX_SCHEDULER_FILTER_HOUR, tm))
1524 	{
1525 		tm->tm_mday++;
1526 		tm->tm_hour = 0;
1527 
1528 		/* day has been changed, we have to reapply day filter */
1529 		scheduler_apply_day_filter(interval, tm);
1530 	}
1531 
1532 	/* reset minutes and seconds if hours has been changed */
1533 	if (tm->tm_hour != hour)
1534 	{
1535 		tm->tm_min = 0;
1536 		tm->tm_sec = 0;
1537 	}
1538 }
1539 
1540 /******************************************************************************
1541  *                                                                            *
1542  * Function: scheduler_apply_minute_filter                                    *
1543  *                                                                            *
1544  * Purpose: applies minute filter to the specified time/day calculating the   *
1545  *          next scheduled check                                              *
1546  *                                                                            *
1547  * Parameters: interval - [IN] the scheduler interval                         *
1548  *             tm       - [IN/OUT] the input/output date & time               *
1549  *                                                                            *
1550  ******************************************************************************/
scheduler_apply_minute_filter(zbx_scheduler_interval_t * interval,struct tm * tm)1551 static void	scheduler_apply_minute_filter(zbx_scheduler_interval_t *interval, struct tm *tm)
1552 {
1553 	int	min = tm->tm_min;
1554 
1555 	while (SUCCEED != scheduler_get_filter_nextcheck(interval, ZBX_SCHEDULER_FILTER_MINUTE, tm))
1556 	{
1557 		tm->tm_hour++;
1558 		tm->tm_min = 0;
1559 
1560 		/* hours have been changed, we have to reapply hour filter */
1561 		scheduler_apply_hour_filter(interval, tm);
1562 	}
1563 
1564 	/* reset seconds if minutes has been changed */
1565 	if (tm->tm_min != min)
1566 		tm->tm_sec = 0;
1567 }
1568 
1569 /******************************************************************************
1570  *                                                                            *
1571  * Function: scheduler_apply_second_filter                                    *
1572  *                                                                            *
1573  * Purpose: applies second filter to the specified time/day calculating the   *
1574  *          next scheduled check                                              *
1575  *                                                                            *
1576  * Parameters: interval - [IN] the scheduler interval                         *
1577  *             tm       - [IN/OUT] the input/output date & time               *
1578  *                                                                            *
1579  ******************************************************************************/
scheduler_apply_second_filter(zbx_scheduler_interval_t * interval,struct tm * tm)1580 static void	scheduler_apply_second_filter(zbx_scheduler_interval_t *interval, struct tm *tm)
1581 {
1582 	while (SUCCEED != scheduler_get_filter_nextcheck(interval, ZBX_SCHEDULER_FILTER_SECOND, tm))
1583 	{
1584 		tm->tm_min++;
1585 		tm->tm_sec = 0;
1586 
1587 		/* minutes have been changed, we have to reapply minute filter */
1588 		scheduler_apply_minute_filter(interval, tm);
1589 	}
1590 }
1591 
1592 /******************************************************************************
1593  *                                                                            *
1594  * Function: scheduler_find_dst_change                                        *
1595  *                                                                            *
1596  * Purpose: finds daylight saving change time inside specified time period    *
1597  *                                                                            *
1598  * Parameters: time_start - [IN] the time period start                        *
1599  *             time_end   - [IN] the the time period end                      *
1600  *                                                                            *
1601  * Return Value: Time when the daylight saving changes should occur.          *
1602  *                                                                            *
1603  * Comments: The calculated time is cached and reused if it first the         *
1604  *           specified period.                                                *
1605  *                                                                            *
1606  ******************************************************************************/
scheduler_find_dst_change(time_t time_start,time_t time_end)1607 static time_t	scheduler_find_dst_change(time_t time_start, time_t time_end)
1608 {
1609 	static time_t	time_dst = 0;
1610 	struct tm	*tm;
1611 	time_t		time_mid;
1612 	int		start, end, mid, dst_start;
1613 
1614 	if (time_dst < time_start || time_dst > time_end)
1615 	{
1616 		/* assume that daylight saving will change only on 0 seconds */
1617 		start = time_start / 60;
1618 		end = time_end / 60;
1619 
1620 		tm = localtime(&time_start);
1621 		dst_start = tm->tm_isdst;
1622 
1623 		while (end > start + 1)
1624 		{
1625 			mid = (start + end) / 2;
1626 			time_mid = mid * 60;
1627 
1628 			tm = localtime(&time_mid);
1629 
1630 			if (tm->tm_isdst == dst_start)
1631 				start = mid;
1632 			else
1633 				end = mid;
1634 		}
1635 
1636 		time_dst = end * 60;
1637 	}
1638 
1639 	return time_dst;
1640 }
1641 
1642 /******************************************************************************
1643  *                                                                            *
1644  * Function: scheduler_tm_inc                                                 *
1645  *                                                                            *
1646  * Purpose: increment struct tm value by one second                           *
1647  *                                                                            *
1648  * Parameters: tm - [IN/OUT] the tm structure to increment                    *
1649  *                                                                            *
1650  ******************************************************************************/
scheduler_tm_inc(struct tm * tm)1651 static void	scheduler_tm_inc(struct tm *tm)
1652 {
1653 	if (60 > ++tm->tm_sec)
1654 		return;
1655 
1656 	tm->tm_sec = 0;
1657 	if (60 > ++tm->tm_min)
1658 		return;
1659 
1660 	tm->tm_min = 0;
1661 	if (24 > ++tm->tm_hour)
1662 		return;
1663 
1664 	tm->tm_hour = 0;
1665 	if (zbx_day_in_month(tm->tm_year + 1900, tm->tm_mon + 1) >= ++tm->tm_mday)
1666 		return;
1667 
1668 	tm->tm_mday = 1;
1669 	if (12 > ++tm->tm_mon)
1670 		return;
1671 
1672 	tm->tm_mon = 0;
1673 	tm->tm_year++;
1674 	return;
1675 }
1676 
1677 /******************************************************************************
1678  *                                                                            *
1679  * Function: scheduler_get_nextcheck                                          *
1680  *                                                                            *
1681  * Purpose: finds the next timestamp satisfying one of intervals.             *
1682  *                                                                            *
1683  * Parameters: interval - [IN] the scheduler interval                         *
1684  *             now      - [IN] the current timestamp                          *
1685  *                                                                            *
1686  * Return Value: Timestamp when the next check must be scheduled.             *
1687  *                                                                            *
1688  ******************************************************************************/
scheduler_get_nextcheck(zbx_scheduler_interval_t * interval,time_t now)1689 static time_t	scheduler_get_nextcheck(zbx_scheduler_interval_t *interval, time_t now)
1690 {
1691 	struct tm	tm_start, tm, tm_dst;
1692 	time_t		nextcheck = 0, current_nextcheck;
1693 
1694 	tm_start = *(localtime(&now));
1695 
1696 	for (; NULL != interval; interval = interval->next)
1697 	{
1698 		tm = tm_start;
1699 
1700 		do
1701 		{
1702 			scheduler_tm_inc(&tm);
1703 			scheduler_apply_day_filter(interval, &tm);
1704 			scheduler_apply_hour_filter(interval, &tm);
1705 			scheduler_apply_minute_filter(interval, &tm);
1706 			scheduler_apply_second_filter(interval, &tm);
1707 
1708 			tm.tm_isdst = tm_start.tm_isdst;
1709 		}
1710 		while (-1 == (current_nextcheck = mktime(&tm)));
1711 
1712 		tm_dst = *(localtime(&current_nextcheck));
1713 		if (tm_dst.tm_isdst != tm_start.tm_isdst)
1714 		{
1715 			int	dst = tm_dst.tm_isdst;
1716 			time_t	time_dst;
1717 
1718 			time_dst = scheduler_find_dst_change(now, current_nextcheck);
1719 			tm_dst = *localtime(&time_dst);
1720 
1721 			scheduler_apply_day_filter(interval, &tm_dst);
1722 			scheduler_apply_hour_filter(interval, &tm_dst);
1723 			scheduler_apply_minute_filter(interval, &tm_dst);
1724 			scheduler_apply_second_filter(interval, &tm_dst);
1725 
1726 			tm_dst.tm_isdst = dst;
1727 			current_nextcheck = mktime(&tm_dst);
1728 		}
1729 
1730 		if (0 == nextcheck || current_nextcheck < nextcheck)
1731 			nextcheck = current_nextcheck;
1732 	}
1733 
1734 	return nextcheck;
1735 }
1736 
1737 /******************************************************************************
1738  *                                                                            *
1739  * Function: calculate_item_nextcheck                                         *
1740  *                                                                            *
1741  * Purpose: calculate nextcheck timestamp for item                            *
1742  *                                                                            *
1743  * Parameters: seed             - [IN] the seed value applied to delay to     *
1744  *                                     spread item checks over the delay      *
1745  *                                     period                                 *
1746  *             item_type        - [IN] the item type                          *
1747  *             delay            - [IN] default delay value, can be overridden *
1748  *             custom_intervals - [IN] descriptions of flexible intervals     *
1749  *                                     in the form [dd/d1-d2,hh:mm-hh:mm;]    *
1750  *             now              - [IN] current timestamp                      *
1751  *                                                                            *
1752  * Return value: nextcheck value                                              *
1753  *                                                                            *
1754  * Author: Alexei Vladishev, Aleksandrs Saveljevs                             *
1755  *                                                                            *
1756  * Comments: if item check is forbidden with delay=0 (default and flexible),  *
1757  *           a timestamp very far in the future is returned                   *
1758  *                                                                            *
1759  *           Old algorithm: now+delay                                         *
1760  *           New one: preserve period, if delay==5, nextcheck = 0,5,10,15,... *
1761  *           !!! Don't forget to sync code with PHP !!!                       *
1762  *                                                                            *
1763  ******************************************************************************/
calculate_item_nextcheck(zbx_uint64_t seed,int item_type,int delay,const char * custom_intervals,time_t now)1764 int	calculate_item_nextcheck(zbx_uint64_t seed, int item_type, int delay, const char *custom_intervals, time_t now)
1765 {
1766 	int	nextcheck = 0;
1767 
1768 	/* special processing of active items to see better view in queue */
1769 	if (ITEM_TYPE_ZABBIX_ACTIVE == item_type)
1770 	{
1771 		if (0 != delay)
1772 			nextcheck = (int)now + delay;
1773 		else
1774 			nextcheck = ZBX_JAN_2038;
1775 	}
1776 	else
1777 	{
1778 		int	current_delay = 0, try = 0;
1779 		time_t	next_interval, t, tmax, scheduled_check = 0;
1780 		char	*flex = NULL;
1781 		size_t	flex_alloc = 0, flex_offset = 0;
1782 
1783 		/* first try to parse out and calculate scheduled intervals */
1784 		if (NULL != custom_intervals)
1785 		{
1786 			zbx_scheduler_interval_t	*interval = NULL;
1787 			char				*errmsg = NULL;
1788 
1789 			if (SUCCEED == preprocess_flexible_interval(custom_intervals, &interval, &flex, &flex_alloc,
1790 					&flex_offset, &errmsg))
1791 			{
1792 				custom_intervals = flex;
1793 				scheduled_check = scheduler_get_nextcheck(interval, now);
1794 				scheduler_interval_free(interval);
1795 			}
1796 			else
1797 			{
1798 				zabbix_log(LOG_LEVEL_ERR, "%s", errmsg);
1799 				zbx_free(errmsg);
1800 			}
1801 		}
1802 
1803 		/* Try to find the nearest 'nextcheck' value with condition */
1804 		/* 'now' < 'nextcheck' < 'now' + SEC_PER_YEAR. If it is not */
1805 		/* possible to check the item within a year, fail. */
1806 
1807 		t = now;
1808 		tmax = now + SEC_PER_YEAR;
1809 
1810 		while (t < tmax)
1811 		{
1812 			/* calculate 'nextcheck' value for the current interval */
1813 			current_delay = get_current_delay(delay, custom_intervals, t);
1814 
1815 			if (0 != current_delay)
1816 			{
1817 				nextcheck = current_delay * (int)(t / (time_t)current_delay) +
1818 						(int)(seed % (zbx_uint64_t)current_delay);
1819 
1820 				if (0 == try)
1821 				{
1822 					while (nextcheck <= t)
1823 						nextcheck += current_delay;
1824 				}
1825 				else
1826 				{
1827 					while (nextcheck < t)
1828 						nextcheck += current_delay;
1829 				}
1830 			}
1831 			else
1832 				nextcheck = ZBX_JAN_2038;
1833 
1834 			/* 'nextcheck' < end of the current interval ? */
1835 			/* the end of the current interval is the beginning of the next interval - 1 */
1836 			if (FAIL != get_next_delay_interval(custom_intervals, t, &next_interval) &&
1837 					nextcheck >= next_interval)
1838 			{
1839 				/* 'nextcheck' is beyond the current interval */
1840 				t = next_interval;
1841 				try++;
1842 			}
1843 			else
1844 				break;	/* nextcheck is within the current interval */
1845 		}
1846 
1847 		zbx_free(flex);
1848 
1849 		if (0 != scheduled_check && scheduled_check < nextcheck)
1850 			nextcheck = scheduled_check;
1851 	}
1852 
1853 	return nextcheck;
1854 }
1855 
1856 /******************************************************************************
1857  *                                                                            *
1858  * Function: calculate_proxy_nextcheck                                        *
1859  *                                                                            *
1860  * Purpose: calculate nextcheck timestamp for passive proxy                   *
1861  *                                                                            *
1862  * Parameters: hostid - [IN] host identificator from database                 *
1863  *             delay  - [IN] default delay value, can be overridden           *
1864  *             now    - [IN] current timestamp                                *
1865  *                                                                            *
1866  * Return value: nextcheck value                                              *
1867  *                                                                            *
1868  * Author: Alexander Vladishev                                                *
1869  *                                                                            *
1870  ******************************************************************************/
calculate_proxy_nextcheck(zbx_uint64_t hostid,unsigned int delay,time_t now)1871 time_t	calculate_proxy_nextcheck(zbx_uint64_t hostid, unsigned int delay, time_t now)
1872 {
1873 	time_t	nextcheck;
1874 
1875 	nextcheck = delay * (now / delay) + (unsigned int)(hostid % delay);
1876 
1877 	while (nextcheck <= now)
1878 		nextcheck += delay;
1879 
1880 	return nextcheck;
1881 }
1882 
1883 /******************************************************************************
1884  *                                                                            *
1885  * Function: is_ip4                                                           *
1886  *                                                                            *
1887  * Purpose: is string IPv4 address                                            *
1888  *                                                                            *
1889  * Parameters: ip - string                                                    *
1890  *                                                                            *
1891  * Return value: SUCCEED - is IPv4 address                                    *
1892  *               FAIL - otherwise                                             *
1893  *                                                                            *
1894  * Author: Alexei Vladishev, Alexander Vladishev                              *
1895  *                                                                            *
1896  ******************************************************************************/
is_ip4(const char * ip)1897 int	is_ip4(const char *ip)
1898 {
1899 	const char	*__function_name = "is_ip4";
1900 	const char	*p = ip;
1901 	int		nums = 0, dots = 0, res = FAIL;
1902 
1903 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() ip:'%s'", __function_name, ip);
1904 
1905 	while ('\0' != *p)
1906 	{
1907 		if (0 != isdigit(*p))
1908 		{
1909 			nums++;
1910 		}
1911 		else if ('.' == *p)
1912 		{
1913 			if (0 == nums || 3 < nums)
1914 				break;
1915 			nums = 0;
1916 			dots++;
1917 		}
1918 		else
1919 		{
1920 			nums = 0;
1921 			break;
1922 		}
1923 
1924 		p++;
1925 	}
1926 	if (dots == 3 && 1 <= nums && nums <= 3)
1927 		res = SUCCEED;
1928 
1929 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res));
1930 
1931 	return res;
1932 }
1933 
1934 /******************************************************************************
1935  *                                                                            *
1936  * Function: is_ip6                                                           *
1937  *                                                                            *
1938  * Purpose: is string IPv6 address                                            *
1939  *                                                                            *
1940  * Parameters: ip - string                                                    *
1941  *                                                                            *
1942  * Return value: SUCCEED - is IPv6 address                                    *
1943  *               FAIL - otherwise                                             *
1944  *                                                                            *
1945  * Author: Alexander Vladishev                                                *
1946  *                                                                            *
1947  ******************************************************************************/
is_ip6(const char * ip)1948 int	is_ip6(const char *ip)
1949 {
1950 	const char	*__function_name = "is_ip6";
1951 	const char	*p = ip, *last_colon;
1952 	int		xdigits = 0, only_xdigits = 0, colons = 0, dbl_colons = 0, res;
1953 
1954 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() ip:'%s'", __function_name, ip);
1955 
1956 	while ('\0' != *p)
1957 	{
1958 		if (0 != isxdigit(*p))
1959 		{
1960 			xdigits++;
1961 			only_xdigits = 1;
1962 		}
1963 		else if (':' == *p)
1964 		{
1965 			if (0 == xdigits && 0 < colons)
1966 			{
1967 				/* consecutive sections of zeros are replaced with a double colon */
1968 				only_xdigits = 1;
1969 				dbl_colons++;
1970 			}
1971 
1972 			if (4 < xdigits || 1 < dbl_colons)
1973 				break;
1974 
1975 			xdigits = 0;
1976 			colons++;
1977 		}
1978 		else
1979 		{
1980 			only_xdigits = 0;
1981 			break;
1982 		}
1983 
1984 		p++;
1985 	}
1986 
1987 	if (2 > colons || 7 < colons || 1 < dbl_colons || 4 < xdigits)
1988 		res = FAIL;
1989 	else if (1 == only_xdigits)
1990 		res = SUCCEED;
1991 	else if (7 > colons && (last_colon = strrchr(ip, ':')) < p)
1992 		res = is_ip4(last_colon + 1);	/* past last column is ipv4 mapped address */
1993 	else
1994 		res = FAIL;
1995 
1996 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res));
1997 
1998 	return res;
1999 }
2000 
2001 /******************************************************************************
2002  *                                                                            *
2003  * Function: is_supported_ip                                                  *
2004  *                                                                            *
2005  * Purpose: is string IP address of supported version                         *
2006  *                                                                            *
2007  * Parameters: ip - string                                                    *
2008  *                                                                            *
2009  * Return value: SUCCEED - is IP address                                      *
2010  *               FAIL - otherwise                                             *
2011  *                                                                            *
2012  * Author: Alexander Vladishev                                                *
2013  *                                                                            *
2014  ******************************************************************************/
is_supported_ip(const char * ip)2015 int	is_supported_ip(const char *ip)
2016 {
2017 	if (SUCCEED == is_ip4(ip))
2018 		return SUCCEED;
2019 #ifdef HAVE_IPV6
2020 	if (SUCCEED == is_ip6(ip))
2021 		return SUCCEED;
2022 #endif
2023 	return FAIL;
2024 }
2025 
2026 /******************************************************************************
2027  *                                                                            *
2028  * Function: is_ip                                                            *
2029  *                                                                            *
2030  * Purpose: is string IP address                                              *
2031  *                                                                            *
2032  * Parameters: ip - string                                                    *
2033  *                                                                            *
2034  * Return value: SUCCEED - is IP address                                      *
2035  *               FAIL - otherwise                                             *
2036  *                                                                            *
2037  * Author: Alexander Vladishev                                                *
2038  *                                                                            *
2039  ******************************************************************************/
is_ip(const char * ip)2040 int	is_ip(const char *ip)
2041 {
2042 	return SUCCEED == is_ip4(ip) ? SUCCEED : is_ip6(ip);
2043 }
2044 
2045 /******************************************************************************
2046  *                                                                            *
2047  * Function: zbx_validate_hostname                                            *
2048  *                                                                            *
2049  * Purpose: check if string is a valid internet hostname                      *
2050  *                                                                            *
2051  * Parameters: hostname - [IN] hostname string to be checked                  *
2052  *                                                                            *
2053  * Return value: SUCCEED - could be a valid hostname,                         *
2054  *               FAIL - definitely not a valid hostname                       *
2055  * Comments:                                                                  *
2056  *     Validation is not strict. Restrictions not checked:                    *
2057  *         - individual label (component) length 1-63,                        *
2058  *         - hyphens ('-') allowed only as interior characters in labels,     *
2059  *         - underscores ('_') allowed in domain name, but not in hostname.   *
2060  *                                                                            *
2061  ******************************************************************************/
zbx_validate_hostname(const char * hostname)2062 int	zbx_validate_hostname(const char *hostname)
2063 {
2064 	int		component;	/* periods ('.') are only allowed when they serve to delimit components */
2065 	int		len = MAX_ZBX_DNSNAME_LEN;
2066 	const char	*p;
2067 
2068 	/* the first character must be an alphanumeric character */
2069 	if (0 == isalnum(*hostname))
2070 		return FAIL;
2071 
2072 	/* check only up to the first 'len' characters, the 1st character is already successfully checked */
2073 	for (p = hostname + 1, component = 1; '\0' != *p; p++)
2074 	{
2075 		if (0 == --len)				/* hostname too long */
2076 			return FAIL;
2077 
2078 		/* check for allowed characters */
2079 		if (0 != isalnum(*p) || '-' == *p || '_' == *p)
2080 			component = 1;
2081 		else if ('.' == *p && 1 == component)
2082 			component = 0;
2083 		else
2084 			return FAIL;
2085 	}
2086 
2087 	return SUCCEED;
2088 }
2089 
2090 /******************************************************************************
2091  *                                                                            *
2092  * Function: ip_in_list                                                       *
2093  *                                                                            *
2094  * Purpose: check if ip matches range of ip addresses                         *
2095  *                                                                            *
2096  * Parameters: list - [IN] comma-separated list of ip ranges                  *
2097  *                    192.168.0.1-64,192.168.0.128,10.10.0.0/24,12fc::21      *
2098  *             ip   - [IN] ip address                                         *
2099  *                                                                            *
2100  * Return value: FAIL - out of range, SUCCEED - within the range              *
2101  *                                                                            *
2102  ******************************************************************************/
ip_in_list(const char * list,const char * ip)2103 int	ip_in_list(const char *list, const char *ip)
2104 {
2105 	const char	*__function_name = "ip_in_list";
2106 
2107 	int		ipaddress[8];
2108 	zbx_iprange_t	iprange;
2109 	char		*address = NULL;
2110 	size_t		address_alloc = 0, address_offset;
2111 	const char	*ptr;
2112 	int		ret = FAIL;
2113 
2114 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() list:'%s' ip:'%s'", __function_name, list, ip);
2115 
2116 	if (SUCCEED != iprange_parse(&iprange, ip))
2117 		goto out;
2118 #ifndef HAVE_IPV6
2119 	if (ZBX_IPRANGE_V6 == iprange.type)
2120 		goto out;
2121 #endif
2122 	iprange_first(&iprange, ipaddress);
2123 
2124 	for (ptr = list; '\0' != *ptr; list = ptr + 1)
2125 	{
2126 		if (NULL == (ptr = strchr(list, ',')))
2127 			ptr = list + strlen(list);
2128 
2129 		address_offset = 0;
2130 		zbx_strncpy_alloc(&address, &address_alloc, &address_offset, list, ptr - list);
2131 
2132 		if (SUCCEED != iprange_parse(&iprange, address))
2133 			continue;
2134 #ifndef HAVE_IPV6
2135 		if (ZBX_IPRANGE_V6 == iprange.type)
2136 			continue;
2137 #endif
2138 		if (SUCCEED == iprange_validate(&iprange, ipaddress))
2139 		{
2140 			ret = SUCCEED;
2141 			break;
2142 		}
2143 	}
2144 
2145 	zbx_free(address);
2146 out:
2147 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
2148 
2149 	return ret;
2150 }
2151 
2152 /******************************************************************************
2153  *                                                                            *
2154  * Function: int_in_list                                                      *
2155  *                                                                            *
2156  * Purpose: check if integer matches a list of integers                       *
2157  *                                                                            *
2158  * Parameters: list  - integers [i1-i2,i3,i4,i5-i6] (10-25,45,67-699)         *
2159  *             value - integer to check                                       *
2160  *                                                                            *
2161  * Return value: FAIL - out of period, SUCCEED - within the period            *
2162  *                                                                            *
2163  * Author: Alexei Vladishev                                                   *
2164  *                                                                            *
2165  ******************************************************************************/
int_in_list(char * list,int value)2166 int	int_in_list(char *list, int value)
2167 {
2168 	const char	*__function_name = "int_in_list";
2169 	char		*start = NULL, *end = NULL, c = '\0';
2170 	int		i1, i2, ret = FAIL;
2171 
2172 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() list:'%s' value:%d", __function_name, list, value);
2173 
2174 	for (start = list; '\0' != *start;)
2175 	{
2176 		if (NULL != (end = strchr(start, ',')))
2177 		{
2178 			c = *end;
2179 			*end = '\0';
2180 		}
2181 
2182 		if (2 == sscanf(start, "%d-%d", &i1, &i2))
2183 		{
2184 			if (i1 <= value && value <= i2)
2185 			{
2186 				ret = SUCCEED;
2187 				break;
2188 			}
2189 		}
2190 		else
2191 		{
2192 			if (value == atoi(start))
2193 			{
2194 				ret = SUCCEED;
2195 				break;
2196 			}
2197 		}
2198 
2199 		if (NULL != end)
2200 		{
2201 			*end = c;
2202 			start = end + 1;
2203 		}
2204 		else
2205 			break;
2206 	}
2207 
2208 	if (NULL != end)
2209 		*end = c;
2210 
2211 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
2212 
2213 	return ret;
2214 }
2215 
zbx_double_compare(double a,double b)2216 int	zbx_double_compare(double a, double b)
2217 {
2218 	return fabs(a - b) <= ZBX_DOUBLE_EPSILON ? SUCCEED : FAIL;
2219 }
2220 
2221 /******************************************************************************
2222  *                                                                            *
2223  * Function: is_double_suffix                                                 *
2224  *                                                                            *
2225  * Purpose: check if the string is double                                     *
2226  *                                                                            *
2227  * Parameters: str   - string to check                                        *
2228  *             flags - extra options including:                               *
2229  *                       ZBX_FLAG_DOUBLE_SUFFIX - allow suffixes              *
2230  *                                                                            *
2231  * Return value:  SUCCEED - the string is double                              *
2232  *                FAIL - otherwise                                            *
2233  *                                                                            *
2234  * Author: Alexei Vladishev                                                   *
2235  *                                                                            *
2236  * Comments: the function automatically processes suffixes K, M, G, T and     *
2237  *           s, m, h, d, w                                                    *
2238  *                                                                            *
2239  ******************************************************************************/
is_double_suffix(const char * str,unsigned char flags)2240 int	is_double_suffix(const char *str, unsigned char flags)
2241 {
2242 	size_t	i;
2243 	char	dot = 0;
2244 
2245 	for (i = 0; '\0' != str[i]; i++)
2246 	{
2247 		/* negative number? */
2248 		if ('-' == str[i] && 0 == i)
2249 			continue;
2250 
2251 		if (0 != isdigit(str[i]))
2252 			continue;
2253 
2254 		if ('.' == str[i] && 0 == dot)
2255 		{
2256 			dot = 1;
2257 			continue;
2258 		}
2259 
2260 		/* last character is suffix */
2261 		if (0 != (flags & ZBX_FLAG_DOUBLE_SUFFIX) && NULL != strchr("KMGTsmhdw", str[i]) && '\0' == str[i + 1])
2262 			continue;
2263 
2264 		return FAIL;
2265 	}
2266 
2267 	return SUCCEED;
2268 }
2269 
2270 /******************************************************************************
2271  *                                                                            *
2272  * Function: is_double                                                        *
2273  *                                                                            *
2274  * Purpose: check if the string is double                                     *
2275  *                                                                            *
2276  * Parameters: str - string to check                                          *
2277  *                                                                            *
2278  * Return value:  SUCCEED - the string is double                              *
2279  *                FAIL - otherwise                                            *
2280  *                                                                            *
2281  * Author: Alexei Vladishev, Aleksandrs Saveljevs                             *
2282  *                                                                            *
2283  ******************************************************************************/
is_double(const char * str)2284 int	is_double(const char *str)
2285 {
2286 	int	i = 0, digits = 0;
2287 
2288 	while (' ' == str[i])				/* trim left spaces */
2289 		i++;
2290 
2291 	if ('-' == str[i] || '+' == str[i])		/* check leading sign */
2292 		i++;
2293 
2294 	while (0 != isdigit(str[i]))			/* check digits before dot */
2295 	{
2296 		i++;
2297 		digits = 1;
2298 	}
2299 
2300 	if ('.' == str[i])				/* check decimal dot */
2301 		i++;
2302 
2303 	while (0 != isdigit(str[i]))			/* check digits after dot */
2304 	{
2305 		i++;
2306 		digits = 1;
2307 	}
2308 
2309 	if (0 == digits)				/* 1., .1, and 1.1 are good, just . is not */
2310 		return FAIL;
2311 
2312 	if ('e' == str[i] || 'E' == str[i])		/* check exponential part */
2313 	{
2314 		i++;
2315 
2316 		if ('-' == str[i] || '+' == str[i])	/* check exponent sign */
2317 			i++;
2318 
2319 		if (0 == isdigit(str[i]))		/* check exponent */
2320 			return FAIL;
2321 
2322 		while (0 != isdigit(str[i]))
2323 			i++;
2324 	}
2325 
2326 	while (' ' == str[i])				/* trim right spaces */
2327 		i++;
2328 
2329 	return '\0' == str[i] ? SUCCEED : FAIL;
2330 }
2331 
2332 /******************************************************************************
2333  *                                                                            *
2334  * Function: is_time_suffix                                                   *
2335  *                                                                            *
2336  * Purpose: check if the string is a non-negative integer with or without     *
2337  *          supported time suffix                                             *
2338  *                                                                            *
2339  * Parameters: str   - [IN] string to check                                   *
2340  *             value - [OUT] a pointer to converted value (optional)          *
2341  *                                                                            *
2342  * Return value: SUCCEED - the string is valid and within reasonable limits   *
2343  *               FAIL    - otherwise                                          *
2344  *                                                                            *
2345  * Author: Aleksandrs Saveljevs, Vladimir Levijev                             *
2346  *                                                                            *
2347  * Comments: the function automatically processes suffixes s, m, h, d, w      *
2348  *                                                                            *
2349  ******************************************************************************/
is_time_suffix(const char * str,int * value)2350 int	is_time_suffix(const char *str, int *value)
2351 {
2352 	const int	max = 0x7fffffff;	/* minimum acceptable value for INT_MAX is 2 147 483 647 */
2353 	int		value_tmp = 0, c, factor = 1;
2354 
2355 	if ('\0' == *str || 0 == isdigit(*str))
2356 		return FAIL;
2357 
2358 	while ('\0' != *str && 0 != isdigit(*str))
2359 	{
2360 		c = (int)(unsigned char)(*str - '0');
2361 
2362 		if ((max - c) / 10 < value_tmp)
2363 			return FAIL;	/* overflow */
2364 
2365 		value_tmp = value_tmp * 10 + c;
2366 
2367 		str++;
2368 	}
2369 
2370 	if ('\0' != *str)
2371 	{
2372 		switch (*str)
2373 		{
2374 			case 's':
2375 				break;
2376 			case 'm':
2377 				factor = SEC_PER_MIN;
2378 				break;
2379 			case 'h':
2380 				factor = SEC_PER_HOUR;
2381 				break;
2382 			case 'd':
2383 				factor = SEC_PER_DAY;
2384 				break;
2385 			case 'w':
2386 				factor = SEC_PER_WEEK;
2387 				break;
2388 			default:
2389 				return FAIL;
2390 		}
2391 
2392 		str++;
2393 	}
2394 
2395 	if ('\0' != *str)
2396 		return FAIL;
2397 
2398 	if (max / factor < value_tmp)
2399 		return FAIL;	/* overflow */
2400 
2401 	if (NULL != value)
2402 		*value = value_tmp * factor;
2403 
2404 	return SUCCEED;
2405 }
2406 
2407 #if defined(_WINDOWS)
_wis_uint(const wchar_t * wide_string)2408 int	_wis_uint(const wchar_t *wide_string)
2409 {
2410 	const wchar_t	*wide_char = wide_string;
2411 
2412 	if (L'\0' == *wide_char)
2413 		return FAIL;
2414 
2415 	while (L'\0' != *wide_char)
2416 	{
2417 		if (0 != iswdigit(*wide_char))
2418 		{
2419 			wide_char++;
2420 			continue;
2421 		}
2422 		return FAIL;
2423 	}
2424 
2425 	return SUCCEED;
2426 }
2427 #endif
2428 
2429 /******************************************************************************
2430  *                                                                            *
2431  * Function: is_int_prefix                                                    *
2432  *                                                                            *
2433  * Purpose: check if the beginning of string is a signed integer              *
2434  *                                                                            *
2435  * Parameters: str - string to check                                          *
2436  *                                                                            *
2437  * Return value:  SUCCEED - the beginning of string is a signed integer       *
2438  *                FAIL - otherwise                                            *
2439  *                                                                            *
2440  * Author: Aleksandrs Saveljevs                                               *
2441  *                                                                            *
2442  ******************************************************************************/
is_int_prefix(const char * str)2443 int	is_int_prefix(const char *str)
2444 {
2445 	size_t	i = 0;
2446 
2447 	while (' ' == str[i])	/* trim left spaces */
2448 		i++;
2449 
2450 	if ('-' == str[i] || '+' == str[i])
2451 		i++;
2452 
2453 	if (0 == isdigit(str[i]))
2454 		return FAIL;
2455 
2456 	return SUCCEED;
2457 }
2458 
2459 /******************************************************************************
2460  *                                                                            *
2461  * Function: is_uint_n_range                                                  *
2462  *                                                                            *
2463  * Purpose: check if the string is unsigned integer within the specified      *
2464  *          range and optionally store it into value parameter                *
2465  *                                                                            *
2466  * Parameters: str   - [IN] string to check                                   *
2467  *             n     - [IN] string length or ZBX_MAX_UINT64_LEN               *
2468  *             value - [OUT] a pointer to output buffer where the converted   *
2469  *                     value is to be written (optional, can be NULL)         *
2470  *             size  - [IN] size of the output buffer (optional)              *
2471  *             min   - [IN] the minimum acceptable value                      *
2472  *             max   - [IN] the maximum acceptable value                      *
2473  *                                                                            *
2474  * Return value:  SUCCEED - the string is unsigned integer                    *
2475  *                FAIL - the string is not a number or its value is outside   *
2476  *                       the specified range                                  *
2477  *                                                                            *
2478  * Author: Alexander Vladishev, Andris Zeila                                  *
2479  *                                                                            *
2480  ******************************************************************************/
is_uint_n_range(const char * str,size_t n,void * value,size_t size,zbx_uint64_t min,zbx_uint64_t max)2481 int	is_uint_n_range(const char *str, size_t n, void *value, size_t size, zbx_uint64_t min, zbx_uint64_t max)
2482 {
2483 	zbx_uint64_t		value_uint64 = 0, c;
2484 	const zbx_uint64_t	max_uint64 = ~(zbx_uint64_t)__UINT64_C(0);
2485 
2486 	if ('\0' == *str || 0 == n || sizeof(zbx_uint64_t) < size || (0 == size && NULL != value))
2487 		return FAIL;
2488 
2489 	while ('\0' != *str && 0 < n--)
2490 	{
2491 		if (0 == isdigit(*str))
2492 			return FAIL;	/* not a digit */
2493 
2494 		c = (zbx_uint64_t)(unsigned char)(*str - '0');
2495 
2496 		if ((max_uint64 - c) / 10 < value_uint64)
2497 			return FAIL;	/* maximum value exceeded */
2498 
2499 		value_uint64 = value_uint64 * 10 + c;
2500 
2501 		str++;
2502 	}
2503 
2504 	if (min > value_uint64 || value_uint64 > max)
2505 		return FAIL;
2506 
2507 	if (NULL != value)
2508 	{
2509 		/* On little endian architecture the output value will be stored starting from the first bytes */
2510 		/* of 'value' buffer while on big endian architecture it will be stored starting from the last */
2511 		/* bytes. We handle it by storing the offset in the most significant byte of short value and   */
2512 		/* then use the first byte as source offset.                                                   */
2513 		unsigned short	value_offset = (unsigned short)((sizeof(zbx_uint64_t) - size) << 8);
2514 
2515 		memcpy(value, (unsigned char *)&value_uint64 + *((unsigned char *)&value_offset), size);
2516 	}
2517 
2518 	return SUCCEED;
2519 }
2520 
2521 /******************************************************************************
2522  *                                                                            *
2523  * Function: is_hex_n_range                                                   *
2524  *                                                                            *
2525  * Purpose: check if the string is unsigned hexadecimal integer within the    *
2526  *          specified range and optionally store it into value parameter      *
2527  *                                                                            *
2528  * Parameters: str   - [IN] string to check                                   *
2529  *             n     - [IN] string length                                     *
2530  *             value - [OUT] a pointer to output buffer where the converted   *
2531  *                     value is to be written (optional, can be NULL)         *
2532  *             size  - [IN] size of the output buffer (optional)              *
2533  *             min   - [IN] the minimum acceptable value                      *
2534  *             max   - [IN] the maximum acceptable value                      *
2535  *                                                                            *
2536  * Return value:  SUCCEED - the string is unsigned integer                    *
2537  *                FAIL - the string is not a hexadecimal number or its value  *
2538  *                       is outside the specified range                       *
2539  *                                                                            *
2540  ******************************************************************************/
is_hex_n_range(const char * str,size_t n,void * value,size_t size,zbx_uint64_t min,zbx_uint64_t max)2541 int	is_hex_n_range(const char *str, size_t n, void *value, size_t size, zbx_uint64_t min, zbx_uint64_t max)
2542 {
2543 	zbx_uint64_t		value_uint64 = 0, c;
2544 	const zbx_uint64_t	max_uint64 = ~(zbx_uint64_t)__UINT64_C(0);
2545 	int			len = 0;
2546 
2547 	if ('\0' == *str || 0 == n || sizeof(zbx_uint64_t) < size || (0 == size && NULL != value))
2548 		return FAIL;
2549 
2550 	while ('\0' != *str && 0 < n--)
2551 	{
2552 		if ('0' <= *str && *str <= '9')
2553 			c = *str - '0';
2554 		else if ('a' <= *str && *str <= 'f')
2555 			c = 10 + (*str - 'a');
2556 		else if ('A' <= *str && *str <= 'F')
2557 			c = 10 + (*str - 'A');
2558 		else
2559 			return FAIL;	/* not a hexadecimal digit */
2560 
2561 		if (16 < ++len && (max_uint64 >> 4) < value_uint64)
2562 			return FAIL;	/* maximum value exceeded */
2563 
2564 		value_uint64 = (value_uint64 << 4) + c;
2565 
2566 		str++;
2567 	}
2568 	if (min > value_uint64 || value_uint64 > max)
2569 		return FAIL;
2570 
2571 	if (NULL != value)
2572 	{
2573 		/* On little endian architecture the output value will be stored starting from the first bytes */
2574 		/* of 'value' buffer while on big endian architecture it will be stored starting from the last */
2575 		/* bytes. We handle it by storing the offset in the most significant byte of short value and   */
2576 		/* then use the first byte as source offset.                                                   */
2577 		unsigned short	value_offset = (unsigned short)((sizeof(zbx_uint64_t) - size) << 8);
2578 
2579 		memcpy(value, (unsigned char *)&value_uint64 + *((unsigned char *)&value_offset), size);
2580 	}
2581 
2582 	return SUCCEED;
2583 }
2584 
2585 /******************************************************************************
2586  *                                                                            *
2587  * Function: is_boolean                                                       *
2588  *                                                                            *
2589  * Purpose: check if the string is boolean                                    *
2590  *                                                                            *
2591  * Parameters: str - string to check                                          *
2592  *                                                                            *
2593  * Return value:  SUCCEED - the string is boolean                             *
2594  *                FAIL - otherwise                                            *
2595  *                                                                            *
2596  * Author: Aleksandrs Saveljevs                                               *
2597  *                                                                            *
2598  * Comments:                                                                  *
2599  *                                                                            *
2600  ******************************************************************************/
is_boolean(const char * str,zbx_uint64_t * value)2601 int	is_boolean(const char *str, zbx_uint64_t *value)
2602 {
2603 	int	res;
2604 
2605 	if (SUCCEED == (res = is_double(str)))
2606 		*value = (0 != atof(str));
2607 	else
2608 	{
2609 		char	tmp[16];
2610 
2611 		strscpy(tmp, str);
2612 		zbx_strlower(tmp);
2613 
2614 		if (SUCCEED == (res = str_in_list("true,t,yes,y,on,up,running,enabled,available", tmp, ',')))
2615 			*value = 1;
2616 		else if (SUCCEED == (res = str_in_list("false,f,no,n,off,down,unused,disabled,unavailable", tmp, ',')))
2617 			*value = 0;
2618 	}
2619 
2620 	return res;
2621 }
2622 
2623 /******************************************************************************
2624  *                                                                            *
2625  * Function: is_uoct                                                          *
2626  *                                                                            *
2627  * Purpose: check if the string is unsigned octal                             *
2628  *                                                                            *
2629  * Parameters: str - string to check                                          *
2630  *                                                                            *
2631  * Return value:  SUCCEED - the string is unsigned octal                      *
2632  *                FAIL - otherwise                                            *
2633  *                                                                            *
2634  * Author: Alexander Vladishev                                                *
2635  *                                                                            *
2636  ******************************************************************************/
is_uoct(const char * str)2637 int	is_uoct(const char *str)
2638 {
2639 	int	res = FAIL;
2640 
2641 	while (' ' == *str)	/* trim left spaces */
2642 		str++;
2643 
2644 	for (; '\0' != *str; str++)
2645 	{
2646 		if (*str < '0' || *str > '7')
2647 			break;
2648 
2649 		res = SUCCEED;
2650 	}
2651 
2652 	while (' ' == *str)	/* check right spaces */
2653 		str++;
2654 
2655 	if ('\0' != *str)
2656 		return FAIL;
2657 
2658 	return res;
2659 }
2660 
2661 /******************************************************************************
2662  *                                                                            *
2663  * Function: is_uhex                                                          *
2664  *                                                                            *
2665  * Purpose: check if the string is unsigned hexadecimal                       *
2666  *                                                                            *
2667  * Parameters: str - string to check                                          *
2668  *                                                                            *
2669  * Return value:  SUCCEED - the string is unsigned hexadecimal                *
2670  *                FAIL - otherwise                                            *
2671  *                                                                            *
2672  * Author: Alexander Vladishev                                                *
2673  *                                                                            *
2674  ******************************************************************************/
is_uhex(const char * str)2675 int	is_uhex(const char *str)
2676 {
2677 	int	res = FAIL;
2678 
2679 	while (' ' == *str)	/* trim left spaces */
2680 		str++;
2681 
2682 	for (; '\0' != *str; str++)
2683 	{
2684 		if (0 == isxdigit(*str))
2685 			break;
2686 
2687 		res = SUCCEED;
2688 	}
2689 
2690 	while (' ' == *str)	/* check right spaces */
2691 		str++;
2692 
2693 	if ('\0' != *str)
2694 		return FAIL;
2695 
2696 	return res;
2697 }
2698 
2699 /******************************************************************************
2700  *                                                                            *
2701  * Function: is_hex_string                                                    *
2702  *                                                                            *
2703  * Purpose: check if the string is a hexadecimal representation of data in    *
2704  *          the form "F4 CE 46 01 0C 44 8B F4\nA0 2C 29 74 5D 3F 13 49\n"     *
2705  *                                                                            *
2706  * Parameters: str - string to check                                          *
2707  *                                                                            *
2708  * Return value:  SUCCEED - the string is formatted like the example above    *
2709  *                FAIL - otherwise                                            *
2710  *                                                                            *
2711  * Author: Aleksandrs Saveljevs                                               *
2712  *                                                                            *
2713  ******************************************************************************/
is_hex_string(const char * str)2714 int	is_hex_string(const char *str)
2715 {
2716 	if ('\0' == *str)
2717 		return FAIL;
2718 
2719 	while ('\0' != *str)
2720 	{
2721 		if (0 == isxdigit(*str))
2722 			return FAIL;
2723 
2724 		if (0 == isxdigit(*(str + 1)))
2725 			return FAIL;
2726 
2727 		if ('\0' == *(str + 2))
2728 			break;
2729 
2730 		if (' ' != *(str + 2) && '\n' != *(str + 2))
2731 			return FAIL;
2732 
2733 		str += 3;
2734 	}
2735 
2736 	return SUCCEED;
2737 }
2738 
2739 /******************************************************************************
2740  *                                                                            *
2741  * Function: get_nearestindex                                                 *
2742  *                                                                            *
2743  * Purpose: get nearest index position of sorted elements in array            *
2744  *                                                                            *
2745  * Parameters: p   - pointer to array of elements                             *
2746  *             sz  - element size                                             *
2747  *             num - number of elements                                       *
2748  *             id  - index to look for                                        *
2749  *                                                                            *
2750  * Return value: index at which it would be possible to insert the element so *
2751  *               that the array is still sorted                               *
2752  *                                                                            *
2753  ******************************************************************************/
get_nearestindex(const void * p,size_t sz,int num,zbx_uint64_t id)2754 int	get_nearestindex(const void *p, size_t sz, int num, zbx_uint64_t id)
2755 {
2756 	int		first_index, last_index, index;
2757 	zbx_uint64_t	element_id;
2758 
2759 	if (0 == num)
2760 		return 0;
2761 
2762 	first_index = 0;
2763 	last_index = num - 1;
2764 
2765 	while (1)
2766 	{
2767 		index = first_index + (last_index - first_index) / 2;
2768 
2769 		if (id == (element_id = *(const zbx_uint64_t *)((const char *)p + index * sz)))
2770 			return index;
2771 
2772 		if (last_index == first_index)
2773 		{
2774 			if (element_id < id)
2775 				index++;
2776 			return index;
2777 		}
2778 
2779 		if (element_id < id)
2780 			first_index = index + 1;
2781 		else
2782 			last_index = index;
2783 	}
2784 }
2785 
2786 /******************************************************************************
2787  *                                                                            *
2788  * Function: uint64_array_add                                                 *
2789  *                                                                            *
2790  * Purpose: add uint64 value to dynamic array                                 *
2791  *                                                                            *
2792  * Author: Alexander Vladishev                                                *
2793  *                                                                            *
2794  ******************************************************************************/
uint64_array_add(zbx_uint64_t ** values,int * alloc,int * num,zbx_uint64_t value,int alloc_step)2795 int	uint64_array_add(zbx_uint64_t **values, int *alloc, int *num, zbx_uint64_t value, int alloc_step)
2796 {
2797 	int	index;
2798 
2799 	index = get_nearestindex(*values, sizeof(zbx_uint64_t), *num, value);
2800 	if (index < (*num) && (*values)[index] == value)
2801 		return index;
2802 
2803 	if (*alloc == *num)
2804 	{
2805 		if (0 == alloc_step)
2806 		{
2807 			zbx_error("Unable to reallocate buffer");
2808 			assert(0);
2809 		}
2810 
2811 		*alloc += alloc_step;
2812 		*values = zbx_realloc(*values, *alloc * sizeof(zbx_uint64_t));
2813 	}
2814 
2815 	memmove(&(*values)[index + 1], &(*values)[index], sizeof(zbx_uint64_t) * (*num - index));
2816 
2817 	(*values)[index] = value;
2818 	(*num)++;
2819 
2820 	return index;
2821 }
2822 
2823 /******************************************************************************
2824  *                                                                            *
2825  * Function: uint64_array_exists                                              *
2826  *                                                                            *
2827  * Author: Alexander Vladishev                                                *
2828  *                                                                            *
2829  ******************************************************************************/
uint64_array_exists(const zbx_uint64_t * values,int num,zbx_uint64_t value)2830 int	uint64_array_exists(const zbx_uint64_t *values, int num, zbx_uint64_t value)
2831 {
2832 	int	index;
2833 
2834 	index = get_nearestindex(values, sizeof(zbx_uint64_t), num, value);
2835 	if (index < num && values[index] == value)
2836 		return SUCCEED;
2837 
2838 	return FAIL;
2839 }
2840 
2841 /******************************************************************************
2842  *                                                                            *
2843  * Function: uint64_array_remove                                              *
2844  *                                                                            *
2845  * Purpose: remove uint64 values from array                                   *
2846  *                                                                            *
2847  * Author: Alexander Vladishev                                                *
2848  *                                                                            *
2849  ******************************************************************************/
uint64_array_remove(zbx_uint64_t * values,int * num,const zbx_uint64_t * rm_values,int rm_num)2850 void	uint64_array_remove(zbx_uint64_t *values, int *num, const zbx_uint64_t *rm_values, int rm_num)
2851 {
2852 	int	rindex, index;
2853 
2854 	for (rindex = 0; rindex < rm_num; rindex++)
2855 	{
2856 		index = get_nearestindex(values, sizeof(zbx_uint64_t), *num, rm_values[rindex]);
2857 		if (index == *num || values[index] != rm_values[rindex])
2858 			continue;
2859 
2860 		memmove(&values[index], &values[index + 1], sizeof(zbx_uint64_t) * ((*num) - index - 1));
2861 		(*num)--;
2862 	}
2863 }
2864 
suffix2factor(char c)2865 zbx_uint64_t	suffix2factor(char c)
2866 {
2867 	switch (c)
2868 	{
2869 		case 'K':
2870 			return ZBX_KIBIBYTE;
2871 		case 'M':
2872 			return ZBX_MEBIBYTE;
2873 		case 'G':
2874 			return ZBX_GIBIBYTE;
2875 		case 'T':
2876 			return ZBX_TEBIBYTE;
2877 		case 's':
2878 			return 1;
2879 		case 'm':
2880 			return SEC_PER_MIN;
2881 		case 'h':
2882 			return SEC_PER_HOUR;
2883 		case 'd':
2884 			return SEC_PER_DAY;
2885 		case 'w':
2886 			return SEC_PER_WEEK;
2887 		default:
2888 			return 1;
2889 	}
2890 }
2891 
2892 /******************************************************************************
2893  *                                                                            *
2894  * Function: str2uint64                                                       *
2895  *                                                                            *
2896  * Purpose: convert string to 64bit unsigned integer                          *
2897  *                                                                            *
2898  * Parameters: str   - string to convert                                      *
2899  *             value - a pointer to converted value                           *
2900  *                                                                            *
2901  * Return value:  SUCCEED - the string is unsigned integer                    *
2902  *                FAIL - otherwise                                            *
2903  *                                                                            *
2904  * Author: Alexander Vladishev                                                *
2905  *                                                                            *
2906  * Comments: the function automatically processes suffixes K, M, G, T         *
2907  *                                                                            *
2908  ******************************************************************************/
str2uint64(const char * str,const char * suffixes,zbx_uint64_t * value)2909 int	str2uint64(const char *str, const char *suffixes, zbx_uint64_t *value)
2910 {
2911 	size_t		sz;
2912 	const char	*p;
2913 	int		ret;
2914 	zbx_uint64_t	factor = 1;
2915 
2916 	sz = strlen(str);
2917 	p = str + sz - 1;
2918 
2919 	if (NULL != strchr(suffixes, *p))
2920 	{
2921 		factor = suffix2factor(*p);
2922 
2923 		sz--;
2924 	}
2925 
2926 	if (SUCCEED == (ret = is_uint64_n(str, sz, value)))
2927 		*value *= factor;
2928 
2929 	return ret;
2930 }
2931 
2932 /******************************************************************************
2933  *                                                                            *
2934  * Function: str2double                                                       *
2935  *                                                                            *
2936  * Purpose: convert string to double                                          *
2937  *                                                                            *
2938  * Parameters: str - string to convert                                        *
2939  *                                                                            *
2940  * Return value: converted double value                                       *
2941  *                                                                            *
2942  * Author: Alexei Vladishev                                                   *
2943  *                                                                            *
2944  * Comments: the function automatically processes suffixes K, M, G, T and     *
2945  *           s, m, h, d, w                                                    *
2946  *                                                                            *
2947  ******************************************************************************/
str2double(const char * str)2948 double	str2double(const char *str)
2949 {
2950 	size_t	sz;
2951 
2952 	sz = strlen(str) - 1;
2953 
2954 	return atof(str) * suffix2factor(str[sz]);
2955 }
2956 
2957 /******************************************************************************
2958  *                                                                            *
2959  * Function: is_hostname_char                                                 *
2960  *                                                                            *
2961  * Return value:  SUCCEED - the char is allowed in the host name              *
2962  *                FAIL - otherwise                                            *
2963  *                                                                            *
2964  * Author: Alexander Vladishev                                                *
2965  *                                                                            *
2966  * Comments: in host name allowed characters: '0-9a-zA-Z. _-'                 *
2967  *           !!! Don't forget to sync the code with PHP !!!                   *
2968  *                                                                            *
2969  ******************************************************************************/
is_hostname_char(unsigned char c)2970 int	is_hostname_char(unsigned char c)
2971 {
2972 	if (0 != isalnum(c))
2973 		return SUCCEED;
2974 
2975 	if (c == '.' || c == ' ' || c == '_' || c == '-')
2976 		return SUCCEED;
2977 
2978 	return FAIL;
2979 }
2980 
2981 /******************************************************************************
2982  *                                                                            *
2983  * Function: is_key_char                                                      *
2984  *                                                                            *
2985  * Return value:  SUCCEED - the char is allowed in the item key               *
2986  *                FAIL - otherwise                                            *
2987  *                                                                            *
2988  * Author: Alexander Vladishev                                                *
2989  *                                                                            *
2990  * Comments: in key allowed characters: '0-9a-zA-Z._-'                        *
2991  *           !!! Don't forget to sync the code with PHP !!!                   *
2992  *                                                                            *
2993  ******************************************************************************/
is_key_char(unsigned char c)2994 int	is_key_char(unsigned char c)
2995 {
2996 	if (0 != isalnum(c))
2997 		return SUCCEED;
2998 
2999 	if (c == '.' || c == '_' || c == '-')
3000 		return SUCCEED;
3001 
3002 	return FAIL;
3003 }
3004 
3005 /******************************************************************************
3006  *                                                                            *
3007  * Function: is_function_char                                                 *
3008  *                                                                            *
3009  * Return value:  SUCCEED - the char is allowed in the trigger function       *
3010  *                FAIL - otherwise                                            *
3011  *                                                                            *
3012  * Author: Alexander Vladishev                                                *
3013  *                                                                            *
3014  * Comments: in trigger function allowed characters: 'a-z'                    *
3015  *           !!! Don't forget to sync the code with PHP !!!                   *
3016  *                                                                            *
3017  ******************************************************************************/
is_function_char(unsigned char c)3018 int	is_function_char(unsigned char c)
3019 {
3020 	if (0 != islower(c))
3021 		return SUCCEED;
3022 
3023 	return FAIL;
3024 }
3025 
3026 /******************************************************************************
3027  *                                                                            *
3028  * Function: is_macro_char                                                    *
3029  *                                                                            *
3030  * Return value:  SUCCEED - the char is allowed in the macro name             *
3031  *                FAIL - otherwise                                            *
3032  *                                                                            *
3033  * Author: Alexander Vladishev                                                *
3034  *                                                                            *
3035  * Comments: allowed characters in macro names: '0-9A-Z._'                    *
3036  *           !!! Don't forget to sync the code with PHP !!!                   *
3037  *                                                                            *
3038  ******************************************************************************/
is_macro_char(unsigned char c)3039 int	is_macro_char(unsigned char c)
3040 {
3041 	if (0 != isupper(c))
3042 		return SUCCEED;
3043 
3044 	if ('.' == c || '_' == c)
3045 		return SUCCEED;
3046 
3047 	if (0 != isdigit(c))
3048 		return SUCCEED;
3049 
3050 	return FAIL;
3051 }
3052 
3053 /******************************************************************************
3054  *                                                                            *
3055  * Function: is_discovery_macro                                               *
3056  *                                                                            *
3057  * Purpose: checks if the name is a valid discovery macro                     *
3058  *                                                                            *
3059  * Return value:  SUCCEED - the name is a valid discovery macro               *
3060  *                FAIL - otherwise                                            *
3061  *                                                                            *
3062  ******************************************************************************/
is_discovery_macro(const char * name)3063 int	is_discovery_macro(const char *name)
3064 {
3065 	if ('{' != *name++ || '#' != *name++)
3066 		return FAIL;
3067 
3068 	do
3069 	{
3070 		if (SUCCEED != is_macro_char(*name++))
3071 			return FAIL;
3072 
3073 	} while ('}' != *name);
3074 
3075 	if ('\0' != name[1])
3076 		return FAIL;
3077 
3078 	return SUCCEED;
3079 }
3080 
3081 /******************************************************************************
3082  *                                                                            *
3083  * Function: is_time_function                                                 *
3084  *                                                                            *
3085  * Return value:  SUCCEED - given function is time-based                      *
3086  *                FAIL - otherwise                                            *
3087  *                                                                            *
3088  * Author: Aleksandrs Saveljevs                                               *
3089  *                                                                            *
3090  ******************************************************************************/
is_time_function(const char * func)3091 int	is_time_function(const char *func)
3092 {
3093 	return str_in_list("nodata,date,dayofmonth,dayofweek,time,now", func, ',');
3094 }
3095 
3096 /******************************************************************************
3097  *                                                                            *
3098  * Function: is_snmp_type                                                     *
3099  *                                                                            *
3100  * Return value:  SUCCEED  - the given type is one of regular SNMP types      *
3101  *                FAIL - otherwise                                            *
3102  *                                                                            *
3103  * Author: Aleksandrs Saveljevs                                               *
3104  *                                                                            *
3105  ******************************************************************************/
is_snmp_type(unsigned char type)3106 int	is_snmp_type(unsigned char type)
3107 {
3108 	return ITEM_TYPE_SNMPv1 == type || ITEM_TYPE_SNMPv2c == type || ITEM_TYPE_SNMPv3 == type ? SUCCEED : FAIL;
3109 }
3110 
3111 /******************************************************************************
3112  *                                                                            *
3113  * Function: make_hostname                                                    *
3114  *                                                                            *
3115  * Purpose: replace all not-allowed hostname characters in the string         *
3116  *                                                                            *
3117  * Parameters: host - the target C-style string                               *
3118  *                                                                            *
3119  * Author: Dmitry Borovikov                                                   *
3120  *                                                                            *
3121  * Comments: the string must be null-terminated, otherwise not secure!        *
3122  *                                                                            *
3123  ******************************************************************************/
make_hostname(char * host)3124 void	make_hostname(char *host)
3125 {
3126 	char	*c;
3127 
3128 	assert(host);
3129 
3130 	for (c = host; '\0' != *c; ++c)
3131 	{
3132 		if (FAIL == is_hostname_char(*c))
3133 			*c = '_';
3134 	}
3135 }
3136 
3137 /******************************************************************************
3138  *                                                                            *
3139  * Function: get_interface_type_by_item_type                                  *
3140  *                                                                            *
3141  * Purpose:                                                                   *
3142  *                                                                            *
3143  * Parameters:                                                                *
3144  *                                                                            *
3145  * Return value: Interface type                                               *
3146  *                                                                            *
3147  * Author: Alexander Vladishev                                                *
3148  *                                                                            *
3149  * Comments: !!! Don't forget to sync the code with PHP !!!                   *
3150  *                                                                            *
3151  ******************************************************************************/
get_interface_type_by_item_type(unsigned char type)3152 unsigned char	get_interface_type_by_item_type(unsigned char type)
3153 {
3154 	switch (type)
3155 	{
3156 		case ITEM_TYPE_ZABBIX:
3157 			return INTERFACE_TYPE_AGENT;
3158 		case ITEM_TYPE_SNMPv1:
3159 		case ITEM_TYPE_SNMPv2c:
3160 		case ITEM_TYPE_SNMPv3:
3161 		case ITEM_TYPE_SNMPTRAP:
3162 			return INTERFACE_TYPE_SNMP;
3163 		case ITEM_TYPE_IPMI:
3164 			return INTERFACE_TYPE_IPMI;
3165 		case ITEM_TYPE_JMX:
3166 			return INTERFACE_TYPE_JMX;
3167 		case ITEM_TYPE_SIMPLE:
3168 		case ITEM_TYPE_EXTERNAL:
3169 		case ITEM_TYPE_SSH:
3170 		case ITEM_TYPE_TELNET:
3171 			return INTERFACE_TYPE_ANY;
3172 		default:
3173 			return INTERFACE_TYPE_UNKNOWN;
3174 	}
3175 }
3176 
3177 /******************************************************************************
3178  *                                                                            *
3179  * Function: calculate_sleeptime                                              *
3180  *                                                                            *
3181  * Purpose: calculate sleep time for Zabbix processes                         *
3182  *                                                                            *
3183  * Parameters: nextcheck     - [IN] next check or -1 (FAIL) if nothing to do  *
3184  *             max_sleeptime - [IN] maximum sleep time, in seconds            *
3185  *                                                                            *
3186  * Return value: sleep time, in seconds                                       *
3187  *                                                                            *
3188  * Author: Alexander Vladishev                                                *
3189  *                                                                            *
3190  ******************************************************************************/
calculate_sleeptime(int nextcheck,int max_sleeptime)3191 int	calculate_sleeptime(int nextcheck, int max_sleeptime)
3192 {
3193 	int	sleeptime;
3194 
3195 	if (FAIL == nextcheck)
3196 		return max_sleeptime;
3197 
3198 	sleeptime = nextcheck - (int)time(NULL);
3199 
3200 	if (sleeptime < 0)
3201 		return 0;
3202 
3203 	if (sleeptime > max_sleeptime)
3204 		return max_sleeptime;
3205 
3206 	return sleeptime;
3207 }
3208 
3209 /******************************************************************************
3210  *                                                                            *
3211  * Function: parse_serveractive_element                                       *
3212  *                                                                            *
3213  * Purpose: parse a ServerActive element like "IP<:port>" or "[IPv6]<:port>"  *
3214  *                                                                            *
3215  ******************************************************************************/
parse_serveractive_element(char * str,char ** host,unsigned short * port,unsigned short port_default)3216 int	parse_serveractive_element(char *str, char **host, unsigned short *port, unsigned short port_default)
3217 {
3218 #ifdef HAVE_IPV6
3219 	char	*r1 = NULL;
3220 #endif
3221 	char	*r2 = NULL;
3222 	int	res = FAIL;
3223 
3224 	*port = port_default;
3225 
3226 #ifdef HAVE_IPV6
3227 	if ('[' == *str)
3228 	{
3229 		str++;
3230 
3231 		if (NULL == (r1 = strchr(str, ']')))
3232 			goto fail;
3233 
3234 		if (':' != r1[1] && '\0' != r1[1])
3235 			goto fail;
3236 
3237 		if (':' == r1[1] && SUCCEED != is_ushort(r1 + 2, port))
3238 			goto fail;
3239 
3240 		*r1 = '\0';
3241 
3242 		if (SUCCEED != is_ip6(str))
3243 			goto fail;
3244 
3245 		*host = zbx_strdup(*host, str);
3246 	}
3247 	else if (SUCCEED == is_ip6(str))
3248 	{
3249 		*host = zbx_strdup(*host, str);
3250 	}
3251 	else
3252 	{
3253 #endif
3254 		if (NULL != (r2 = strchr(str, ':')))
3255 		{
3256 			if (SUCCEED != is_ushort(r2 + 1, port))
3257 				goto fail;
3258 
3259 			*r2 = '\0';
3260 		}
3261 
3262 		*host = zbx_strdup(NULL, str);
3263 #ifdef HAVE_IPV6
3264 	}
3265 #endif
3266 
3267 	res = SUCCEED;
3268 fail:
3269 #ifdef HAVE_IPV6
3270 	if (NULL != r1)
3271 		*r1 = ']';
3272 #endif
3273 	if (NULL != r2)
3274 		*r2 = ':';
3275 
3276 	return res;
3277 }
3278 
zbx_alarm_flag_set(void)3279 void	zbx_alarm_flag_set(void)
3280 {
3281 	zbx_timed_out = 1;
3282 }
3283 
zbx_alarm_flag_clear(void)3284 void	zbx_alarm_flag_clear(void)
3285 {
3286 	zbx_timed_out = 0;
3287 }
3288 
3289 #if !defined(_WINDOWS)
zbx_alarm_on(unsigned int seconds)3290 unsigned int	zbx_alarm_on(unsigned int seconds)
3291 {
3292 	zbx_alarm_flag_clear();
3293 
3294 	return alarm(seconds);
3295 }
3296 
zbx_alarm_off(void)3297 unsigned int	zbx_alarm_off(void)
3298 {
3299 	unsigned int	ret;
3300 
3301 	ret = alarm(0);
3302 	zbx_alarm_flag_clear();
3303 	return ret;
3304 }
3305 #endif
3306 
zbx_alarm_timed_out(void)3307 int	zbx_alarm_timed_out(void)
3308 {
3309 	return (0 == zbx_timed_out ? FAIL : SUCCEED);
3310 }
3311