Ejemplo n.º 1
0
/******************************************************************************
 *                                                                            *
 * Function: process_httptest                                                 *
 *                                                                            *
 * Purpose: process single scenario of http test                              *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value:                                                              *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
static void	process_httptest(DB_HTTPTEST *httptest)
{
	const char	*__function_name = "process_httptest";

	DB_RESULT	result;
	DB_ROW		row;
	DB_HTTPSTEP	httpstep;

	char		*err_str = NULL, *err_str_esc = NULL;
	int		now, lastfailedstep;

	ZBX_HTTPSTAT	stat;
	double		speed_download = 0;
	int		speed_download_num = 0;

#ifdef HAVE_LIBCURL
	int		err, opt;
	char		auth[HTTPTEST_HTTP_USER_LEN_MAX + HTTPTEST_HTTP_PASSWORD_LEN_MAX];

	CURL            *easyhandle = NULL;
#endif

	zabbix_log(LOG_LEVEL_DEBUG, "In %s() httptestid:" ZBX_FS_UI64 " name:'%s'",
			__function_name, httptest->httptestid, httptest->name);

	lastfailedstep = 0;
	httptest->time = 0;

	now = time(NULL);

	DBexecute("update httptest"
			" set lastcheck=%d"
			" where httptestid=" ZBX_FS_UI64,
			now, httptest->httptestid);

	result = DBselect(
			"select httpstepid,no,name,url,timeout,"
				"posts,required,status_codes"
			" from httpstep"
			" where httptestid=" ZBX_FS_UI64
			" order by no",
			httptest->httptestid);

#ifdef HAVE_LIBCURL

	if (NULL == (easyhandle = curl_easy_init()))
	{
		zabbix_log(LOG_LEVEL_ERR, "Web scenario [%s] error: could not init cURL library", httptest->name);
		err_str = zbx_strdup(err_str, "could not init cURL library");
		goto clean;
	}

	if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_COOKIEFILE, "")) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_USERAGENT, httptest->agent)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_FOLLOWLOCATION, 1)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_WRITEFUNCTION, WRITEFUNCTION2)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_HEADERFUNCTION, HEADERFUNCTION2)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_SSL_VERIFYPEER, 0)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_SSL_VERIFYHOST, 0)) ||
			/* The pointed data are not copied by the library. As a consequence, the data */
			/* must be preserved by the calling application until the transfer finishes. */
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POSTFIELDS, httpstep.posts)))
	{
		zabbix_log(LOG_LEVEL_ERR, "Web scenario [%s] error: could not set cURL option [%d]: %s",
				httptest->name, opt, curl_easy_strerror(err));
		err_str = zbx_strdup(err_str, curl_easy_strerror(err));
		goto clean;
	}

	while (NULL == err_str && NULL != (row = DBfetch(result)))
	{
		/* NOTE: do not use break or return for this block!
		 *       process_step_data calling required!
		 */
		ZBX_STR2UINT64(httpstep.httpstepid, row[0]);
		httpstep.httptestid = httptest->httptestid;
		httpstep.no = atoi(row[1]);
		httpstep.name = row[2];
		strscpy(httpstep.url, row[3]);
		httpstep.timeout = atoi(row[4]);
		strscpy(httpstep.posts, row[5]);
		strscpy(httpstep.required, row[6]);
		strscpy(httpstep.status_codes, row[7]);

		DBexecute("update httptest"
				" set curstep=%d,"
					"curstate=%d"
				" where httptestid=" ZBX_FS_UI64,
				httpstep.no,
				HTTPTEST_STATE_BUSY,
				httptest->httptestid);

		memset(&stat, 0, sizeof(stat));

		/* Substitute macros */
		http_substitute_macros(httptest, httpstep.url, sizeof(httpstep.url));
		http_substitute_macros(httptest, httpstep.posts, sizeof(httpstep.posts));

		zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: use step [%s]", httpstep.name);

		if ('\0' != *httpstep.posts)
		{
			zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: use post [%s]", httpstep.posts);
			curl_easy_setopt(easyhandle, CURLOPT_POST, 1);
		}
		else
			curl_easy_setopt(easyhandle, CURLOPT_POST, 0);

		if (HTTPTEST_AUTH_NONE != httptest->authentication)
		{
			long	curlauth = 0;

			zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: Setting HTTPAUTH [%d]", httptest->authentication);
			zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: Setting USERPWD for authentication");

			switch (httptest->authentication)
			{
				case HTTPTEST_AUTH_BASIC:
					curlauth = CURLAUTH_BASIC;
					break;
				case HTTPTEST_AUTH_NTLM:
					curlauth = CURLAUTH_NTLM;
					break;
				default:
					THIS_SHOULD_NEVER_HAPPEN;
					break;
			}

			zbx_snprintf(auth, sizeof(auth), "%s:%s", httptest->http_user, httptest->http_password);

			if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_HTTPAUTH, curlauth)) ||
					CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_USERPWD, auth)))
			{
				zabbix_log(LOG_LEVEL_ERR, "Web scenario step [%s:%s] error: could not set cURL option [%d]: %s",
						httptest->name, httpstep.name, opt, curl_easy_strerror(err));
				err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			}
		}

		if (NULL == err_str)
		{
			zabbix_log(LOG_LEVEL_DEBUG, "WEBMonitor: go to URL [%s]", httpstep.url);

			if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_URL, httpstep.url)) ||
					CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_TIMEOUT, httpstep.timeout)) ||
					CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_CONNECTTIMEOUT, httpstep.timeout)))
			{
				zabbix_log(LOG_LEVEL_ERR, "Web scenario step [%s:%s] error: could not set cURL option [%d]: %s",
						httptest->name, httpstep.name, opt, curl_easy_strerror(err));
				err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			}
		}

		if (NULL == err_str)
		{
			memset(&page, 0, sizeof(page));

			if (CURLE_OK != (err = curl_easy_perform(easyhandle)))
			{
				zabbix_log(LOG_LEVEL_ERR, "Web scenario step [%s:%s] error: error doing curl_easy_perform: %s",
						httptest->name, httpstep.name, curl_easy_strerror(err));
				err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			}
			else
			{
				if ('\0' != httpstep.required[0] && NULL == zbx_regexp_match(page.data, httpstep.required, NULL))
				{
					zabbix_log(LOG_LEVEL_DEBUG, "Page did not match [%s]", httpstep.required);
					err_str = zbx_strdup(err_str, "Page did not match");
				}

				if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_RESPONSE_CODE, &stat.rspcode)))
				{
					zabbix_log(LOG_LEVEL_ERR, "Web scenario step [%s:%s] error: error getting CURLINFO_RESPONSE_CODE: %s",
							httptest->name, httpstep.name, curl_easy_strerror(err));
					err_str = (NULL == err_str ? zbx_strdup(err_str, curl_easy_strerror(err)) : err_str);
				}
				else if ('\0' != httpstep.status_codes[0] && FAIL == int_in_list(httpstep.status_codes, stat.rspcode))
				{
					zabbix_log(LOG_LEVEL_DEBUG, "Status code did not match [%s]", httpstep.status_codes);
					err_str = (NULL == err_str ? zbx_strdup(err_str, "Status code did not match") : err_str);
				}

				if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_TOTAL_TIME, &stat.total_time)))
				{
					zabbix_log(LOG_LEVEL_ERR, "Web scenario step [%s:%s] error: error getting CURLINFO_TOTAL_TIME: %s",
							httptest->name, httpstep.name, curl_easy_strerror(err));
					err_str = (NULL == err_str ? zbx_strdup(err_str, curl_easy_strerror(err)) : err_str);
				}

				if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_SPEED_DOWNLOAD, &stat.speed_download)))
				{
					zabbix_log(LOG_LEVEL_ERR, "Web scenario step [%s:%s] error: error getting CURLINFO_SPEED_DOWNLOAD: %s",
							httptest->name, httpstep.name, curl_easy_strerror(err));
					err_str = (NULL == err_str ? zbx_strdup(err_str, curl_easy_strerror(err)) : err_str);
				}
				else
				{
					speed_download += stat.speed_download;
					speed_download_num++;
				}
			}

			zbx_free(page.data);
		}

		if (NULL != err_str)
			lastfailedstep = httpstep.no;

		httptest->time += stat.total_time;
		process_step_data(httpstep.httpstepid, &stat);
	}
clean:
	curl_easy_cleanup(easyhandle);
#else
	err_str = zbx_strdup(err_str, "cURL library is required for Web monitoring support");

#endif	/* HAVE_LIBCURL */

	if (0 == lastfailedstep && NULL != err_str)
	{
		/* we are here either because cURL initialization failed before */
		/* the first step or we have been compiled without cURL library */

		lastfailedstep = 1;

		if (NULL != (row = DBfetch(result)))
		{
			ZBX_STR2UINT64(httpstep.httpstepid, row[0]);

			memset(&stat, 0, sizeof(stat));

			process_step_data(httpstep.httpstepid, &stat);
		}
		else
			THIS_SHOULD_NEVER_HAPPEN;
	}

	DBfree_result(result);

	err_str_esc = DBdyn_escape_string_len(err_str, HTTPTEST_ERROR_LEN);

	DBexecute("update httptest"
			" set curstep=0,"
				"curstate=%d,"
				"lastcheck=%d,"
				"nextcheck=%d+delay,"
				"lastfailedstep=%d,"
				"time=" ZBX_FS_DBL ","
				"error='%s'"
			" where httptestid=" ZBX_FS_UI64,
			HTTPTEST_STATE_IDLE,
			now, now,
			lastfailedstep,
			httptest->time,
			err_str_esc,
			httptest->httptestid);

	zbx_free(err_str_esc);
	zbx_free(err_str);

	stat.test_total_time = httptest->time;
	stat.test_last_step = lastfailedstep;
	stat.speed_download = speed_download_num ? speed_download / speed_download_num : 0;

	process_test_data(httptest->httptestid, &stat);

	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() total_time:" ZBX_FS_DBL, __function_name, httptest->time);
}
Ejemplo n.º 2
0
/******************************************************************************
 *                                                                            *
 * Function: process_httptest                                                 *
 *                                                                            *
 * Purpose: process single scenario of http test                              *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value:                                                              *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
static void	process_httptest(DB_HTTPTEST *httptest)
{
	const char	*__function_name = "process_httptest";

	DB_RESULT	result;
	DB_ROW		row;
	DB_HTTPSTEP	httpstep;
	char		*err_str = NULL;
	int		lastfailedstep;
	zbx_timespec_t	ts;
	ZBX_HTTPSTAT	stat;
	double		speed_download = 0;
	int		speed_download_num = 0;
#ifdef HAVE_LIBCURL
	int		err, opt;
	char		auth[HTTPTEST_HTTP_USER_LEN_MAX + HTTPTEST_HTTP_PASSWORD_LEN_MAX];
	CURL            *easyhandle = NULL;
#endif

	zabbix_log(LOG_LEVEL_DEBUG, "In %s() httptestid:" ZBX_FS_UI64 " name:'%s'",
			__function_name, httptest->httptestid, httptest->name);

	lastfailedstep = 0;

	result = DBselect(
			"select httpstepid,no,name,url,timeout,posts,cookies,required,status_codes"
			" from httpstep"
			" where httptestid=" ZBX_FS_UI64
			" order by no",
			httptest->httptestid);

#ifdef HAVE_LIBCURL
	if (NULL == (easyhandle = curl_easy_init()))
	{
		err_str = zbx_strdup(err_str, "could not init cURL library");
		zabbix_log(LOG_LEVEL_ERR, "web scenario \"%s\" error: %s", httptest->name, err_str);
		goto clean;
	}

	if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_COOKIEFILE, "")) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_USERAGENT, httptest->agent)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_FOLLOWLOCATION, 1L)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_WRITEFUNCTION, WRITEFUNCTION2)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_HEADERFUNCTION, HEADERFUNCTION2)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_SSL_VERIFYPEER, 0L)) ||
			CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_SSL_VERIFYHOST, 0L)))
	{
		err_str = zbx_strdup(err_str, curl_easy_strerror(err));
		zabbix_log(LOG_LEVEL_ERR, "web scenario \"%s\" error: could not set cURL option [%d]: %s",
				httptest->name, opt, err_str);
		goto clean;
	}

	while (NULL != (row = DBfetch(result)))
	{
		/* NOTE: do not break or return from this block! */
		/*       process_step_data() call is required! */

		ZBX_STR2UINT64(httpstep.httpstepid, row[0]);
		httpstep.httptestid = httptest->httptestid;
		httpstep.no = atoi(row[1]);
		httpstep.name = row[2];
		httpstep.url = zbx_strdup(NULL, row[3]);
		httpstep.timeout = atoi(row[4]);
		httpstep.posts = zbx_strdup(NULL, row[5]);
		httpstep.cookies = zbx_strdup(NULL, row[6]);
		httpstep.required = row[7];
		httpstep.status_codes = row[8];

		memset(&stat, 0, sizeof(stat));

		http_substitute_macros(httptest->macros, &httpstep.url);
		http_substitute_macros(httptest->macros, &httpstep.posts);
		http_substitute_macros(httptest->macros, &httpstep.cookies);

		zabbix_log(LOG_LEVEL_DEBUG, "%s() use step \"%s\"", __function_name, httpstep.name);

		if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POSTFIELDS, httpstep.posts)))
		{
			err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			zabbix_log(LOG_LEVEL_ERR, "web scenario \"%s:%s\" error:"
					" could not set cURL option [%d]: %s",
					httptest->name, httpstep.name, opt, err_str);
			goto httpstep_error;
		}
		
		if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_COOKIE, httpstep.cookies)))
		{
			err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			zabbix_log(LOG_LEVEL_ERR, "web scenario \"%s:%s\" error:"
					" could not set cURL option [%d]: %s",
					httptest->name, httpstep.name, opt, err_str);
			goto httpstep_error;
		}

		if ('\0' != *httpstep.posts)
			zabbix_log(LOG_LEVEL_DEBUG, "%s() use post \"%s\"", __function_name, httpstep.posts);
		if ('\0' != *httpstep.cookies)
			zabbix_log(LOG_LEVEL_DEBUG, "%s() use cookies \"%s\"", __function_name, httpstep.cookies);

		if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POST,
				'\0' != *httpstep.posts ? 1L : 0L)))
		{
			err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			zabbix_log(LOG_LEVEL_ERR, "web scenario \"%s:%s\" error:"
					" could not set cURL option [%d]: %s",
					httptest->name, httpstep.name, opt, err_str);
			goto httpstep_error;
		}

		if (HTTPTEST_AUTH_NONE != httptest->authentication)
		{
			long	curlauth = 0;

			zabbix_log(LOG_LEVEL_DEBUG, "%s() setting HTTPAUTH [%d]",
					__function_name, httptest->authentication);
			zabbix_log(LOG_LEVEL_DEBUG, "%s() setting USERPWD for authentication", __function_name);

			switch (httptest->authentication)
			{
				case HTTPTEST_AUTH_BASIC:
					curlauth = CURLAUTH_BASIC;
					break;
				case HTTPTEST_AUTH_NTLM:
					curlauth = CURLAUTH_NTLM;
					break;
				default:
					THIS_SHOULD_NEVER_HAPPEN;
					break;
			}

			zbx_snprintf(auth, sizeof(auth), "%s:%s", httptest->http_user, httptest->http_password);

			if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_HTTPAUTH, curlauth)) ||
					CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_USERPWD, auth)))
			{
				err_str = zbx_strdup(err_str, curl_easy_strerror(err));
				zabbix_log(LOG_LEVEL_ERR, "web scenario step \"%s:%s\" error:"
						" could not set cURL option [%d]: %s",
						httptest->name, httpstep.name, opt, err_str);
				goto httpstep_error;
			}
		}

		zabbix_log(LOG_LEVEL_DEBUG, "%s() go to URL \"%s\"", __function_name, httpstep.url);

		if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_URL, httpstep.url)) ||
				CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_TIMEOUT, (long)httpstep.timeout)))
		{
			err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			zabbix_log(LOG_LEVEL_ERR, "web scenario step \"%s:%s\" error:"
					" could not set cURL option [%d]: %s",
					httptest->name, httpstep.name, opt, err_str);
			goto httpstep_error;
		}

		memset(&page, 0, sizeof(page));

		if (CURLE_OK != (err = curl_easy_perform(easyhandle)))
		{
			err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			zabbix_log(LOG_LEVEL_ERR, "web scenario step \"%s:%s\" error:"
					" error doing curl_easy_perform: %s",
					httptest->name, httpstep.name, err_str);
		}
		else
		{
			if ('\0' != *httpstep.required &&
					NULL == zbx_regexp_match(page.data, httpstep.required, NULL))
			{
				zabbix_log(LOG_LEVEL_DEBUG, "%s() required pattern \"%s\" not found on %s",
						__function_name, httpstep.required, httpstep.url);
				err_str = zbx_strdup(err_str, "Required pattern not found");
			}

			if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_RESPONSE_CODE, &stat.rspcode)))
			{
				zabbix_log(LOG_LEVEL_ERR, "web scenario step \"%s:%s\" error:"
						" error getting CURLINFO_RESPONSE_CODE: %s",
						httptest->name, httpstep.name, curl_easy_strerror(err));
				if (NULL == err_str)
					err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			}
			else if ('\0' != *httpstep.status_codes &&
					FAIL == int_in_list(httpstep.status_codes, stat.rspcode))
			{
				zabbix_log(LOG_LEVEL_DEBUG, "%s() status code did not match [%s]",
						__function_name, httpstep.status_codes);
				if (NULL == err_str)
					err_str = zbx_strdup(err_str, "Status code did not match");
			}

			if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_TOTAL_TIME, &stat.total_time)))
			{
				zabbix_log(LOG_LEVEL_ERR, "web scenario step \"%s:%s\" error:"
						" error getting CURLINFO_TOTAL_TIME: %s",
						httptest->name, httpstep.name, curl_easy_strerror(err));
				if (NULL == err_str)
					err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			}

			if (CURLE_OK != (err = curl_easy_getinfo(easyhandle, CURLINFO_SPEED_DOWNLOAD, &stat.speed_download)))
			{
				zabbix_log(LOG_LEVEL_ERR, "web scenario step \"%s:%s\" error:"
						" error getting CURLINFO_SPEED_DOWNLOAD: %s",
						httptest->name, httpstep.name, curl_easy_strerror(err));
				if (NULL == err_str)
					err_str = zbx_strdup(err_str, curl_easy_strerror(err));
			}
			else
			{
				speed_download += stat.speed_download;
				speed_download_num++;
			}
		}

		zbx_free(page.data);
httpstep_error:
		zbx_free(httpstep.posts);
		zbx_free(httpstep.cookies);
		zbx_free(httpstep.url);

		zbx_timespec(&ts);
		process_step_data(httpstep.httpstepid, &stat, &ts);

		if (NULL != err_str)
		{
			lastfailedstep = httpstep.no;
			break;
		}
	}
clean:
	curl_easy_cleanup(easyhandle);
#else
	err_str = zbx_strdup(err_str, "cURL library is required for Web monitoring support");
#endif	/* HAVE_LIBCURL */

	zbx_timespec(&ts);

	if (0 == lastfailedstep && NULL != err_str)
	{
		/* we are here either because cURL initialization failed */
		/* or we have been compiled without cURL library */

		lastfailedstep = 1;

		if (NULL != (row = DBfetch(result)))
		{
			ZBX_STR2UINT64(httpstep.httpstepid, row[0]);

			memset(&stat, 0, sizeof(stat));

			process_step_data(httpstep.httpstepid, &stat, &ts);
		}
		else
			THIS_SHOULD_NEVER_HAPPEN;
	}
	DBfree_result(result);

	DBexecute("update httptest set nextcheck=%d+delay where httptestid=" ZBX_FS_UI64,
			ts.sec, httptest->httptestid);

	if (0 != speed_download_num)
		speed_download /= speed_download_num;

	process_test_data(httptest->httptestid, lastfailedstep, speed_download, err_str, &ts);

	zbx_free(err_str);

	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
}