Blame util.c

Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Copyright (c) 2010-2011, Red Hat, Inc.
Packit Service 34e2f8
 *
Packit Service 34e2f8
 * Permission to use, copy, modify, and/or distribute this software for any
Packit Service 34e2f8
 * purpose with or without fee is hereby granted, provided that the above
Packit Service 34e2f8
 * copyright notice and this permission notice appear in all copies.
Packit Service 34e2f8
 *
Packit Service 34e2f8
 * THE SOFTWARE IS PROVIDED "AS IS" AND RED HAT, INC. DISCLAIMS ALL WARRANTIES
Packit Service 34e2f8
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
Packit Service 34e2f8
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RED HAT, INC. BE LIABLE
Packit Service 34e2f8
 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Packit Service 34e2f8
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
Packit Service 34e2f8
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
Packit Service 34e2f8
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Packit Service 34e2f8
 */
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Author: Jan Friesse <jfriesse@redhat.com>
Packit Service 34e2f8
 */
Packit Service 34e2f8
Packit Service 34e2f8
#include <sys/types.h>
Packit Service 34e2f8
Packit Service 34e2f8
#include <sys/time.h>
Packit Service 34e2f8
Packit Service 34e2f8
#include <netinet/in.h>
Packit Service 34e2f8
#include <arpa/inet.h>
Packit Service 34e2f8
Packit Service 34e2f8
#include <err.h>
Packit Service 34e2f8
#include <limits.h>
Packit Service 34e2f8
#include <stdlib.h>
Packit Service 34e2f8
#include <string.h>
Packit Service 34e2f8
#include <time.h>
Packit Service 34e2f8
#include <unistd.h>
Packit Service 34e2f8
Packit Service 34e2f8
#ifdef __CYGWIN__
Packit Service 34e2f8
#include <windows.h>
Packit Service 34e2f8
#endif
Packit Service 34e2f8
Packit Service 34e2f8
#include "logging.h"
Packit Service 34e2f8
#include "util.h"
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Function prototypes
Packit Service 34e2f8
 */
Packit Service 34e2f8
#ifdef __CYGWIN__
Packit Service 34e2f8
static int	util_cygwin_gettimeofday(struct timeval *tv, struct timezone *tz);
Packit Service 34e2f8
#endif
Packit Service 34e2f8
Packit Service 34e2f8
static void	util_gen_id(char *id, size_t len, const struct ai_item *ai_item,
Packit Service 34e2f8
    const struct sockaddr_storage *sas);
Packit Service 34e2f8
Packit Service 34e2f8
static void	util_gen_id_add_sas(char *id, size_t len, size_t *pos,
Packit Service 34e2f8
    const struct sockaddr_storage *sas);
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Functions implementation
Packit Service 34e2f8
 */
Packit Service 34e2f8
Packit Service 34e2f8
#ifdef __CYGWIN__
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * cygwin version of gettimeofday but with microseconds precision. Uses windows Performance
Packit Service 34e2f8
 * Counters to achieve precision if possible, otherwise cygwin gettimeofday implementation
Packit Service 34e2f8
 * is used.
Packit Service 34e2f8
 * Return 0 on success, otherwise -1.
Packit Service 34e2f8
 */
Packit Service 34e2f8
int
Packit Service 34e2f8
util_cygwin_gettimeofday(struct timeval *tv, struct timezone *tz)
Packit Service 34e2f8
{
Packit Service 34e2f8
	/* Frequency of performance counter */
Packit Service 34e2f8
	static LARGE_INTEGER freq;
Packit Service 34e2f8
	/* Offset of starting pc */
Packit Service 34e2f8
	static LARGE_INTEGER perf_count_offset;
Packit Service 34e2f8
	/* Actual pc */
Packit Service 34e2f8
	static LARGE_INTEGER perf_count;
Packit Service 34e2f8
	/* Microsenconds base time */
Packit Service 34e2f8
	static uint64_t us_base = 0;
Packit Service 34e2f8
	/* Function was not called yet */
Packit Service 34e2f8
	static int initialized = 0;
Packit Service 34e2f8
	/* If not used pf, fallback to gettimeofday implementation */
Packit Service 34e2f8
	static BOOL use_pf = 0;
Packit Service 34e2f8
	/* Tmp timeval */
Packit Service 34e2f8
	struct timeval tv2;
Packit Service 34e2f8
	/* Diff between offset pc and actual pc */
Packit Service 34e2f8
	int64_t perf_diff;
Packit Service 34e2f8
	/* Actual time in microseconds */
Packit Service 34e2f8
	uint64_t us;
Packit Service 34e2f8
	/* Time in microseconds returned by gettimeofday */
Packit Service 34e2f8
	uint64_t us_ref;
Packit Service 34e2f8
Packit Service 34e2f8
	if (!initialized) {
Packit Service 34e2f8
		initialized = 1;
Packit Service 34e2f8
		use_pf = QueryPerformanceFrequency(&freq);
Packit Service 34e2f8
		if (use_pf) {
Packit Service 34e2f8
			QueryPerformanceCounter(&perf_count_offset);
Packit Service 34e2f8
			gettimeofday(&tv2, tz);
Packit Service 34e2f8
			us_base = tv2.tv_sec * (uint64_t)1000000 + tv2.tv_usec;
Packit Service 34e2f8
		}
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	if (use_pf) {
Packit Service 34e2f8
		QueryPerformanceCounter(&perf_count);
Packit Service 34e2f8
	} else {
Packit Service 34e2f8
		return (gettimeofday(tv, tz));
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	perf_diff = perf_count.QuadPart - perf_count_offset.QuadPart;
Packit Service 34e2f8
	us = ((double)perf_diff / (double)freq.QuadPart) * 1000000.0 + us_base;
Packit Service 34e2f8
Packit Service 34e2f8
	gettimeofday(&tv2, tz);
Packit Service 34e2f8
	us_ref = tv2.tv_sec * (uint64_t)1000000 + tv2.tv_usec;
Packit Service 34e2f8
Packit Service 34e2f8
	if (util_u64_absdiff(us, us_ref) > (uint64_t)1000000) {
Packit Service 34e2f8
		us_base = us = us_ref;
Packit Service 34e2f8
		perf_count_offset.QuadPart = perf_count.QuadPart;
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	tv->tv_sec = us / (uint64_t)1000000;
Packit Service 34e2f8
	tv->tv_usec = us % (uint64_t)1000000;
Packit Service 34e2f8
Packit Service 34e2f8
	return (0);
Packit Service 34e2f8
}
Packit Service 34e2f8
#endif /* __CYGWIN__ */
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Returns absolute value of n
Packit Service 34e2f8
 */
Packit Service 34e2f8
double
Packit Service 34e2f8
util_fabs(double n)
Packit Service 34e2f8
{
Packit Service 34e2f8
Packit Service 34e2f8
	return (n < 0 ? -n : n);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * generate random ID from current pid, random data from random(3) and optionally addresses ai_item
Packit Service 34e2f8
 * and sas. ID is stored in id with maximum length len.
Packit Service 34e2f8
 */
Packit Service 34e2f8
static void
Packit Service 34e2f8
util_gen_id(char *id, size_t len, const struct ai_item *ai_item,
Packit Service 34e2f8
    const struct sockaddr_storage *sas)
Packit Service 34e2f8
{
Packit Service 34e2f8
	pid_t pid;
Packit Service 34e2f8
	size_t pos;
Packit Service 34e2f8
Packit Service 34e2f8
	/*
Packit Service 34e2f8
	 * First fill item with some random data
Packit Service 34e2f8
	 */
Packit Service 34e2f8
	for (pos = 0; pos < len; pos++) {
Packit Service 34e2f8
#if defined(__FreeBSD__) || defined(__OPENBSD__)
Packit Service 34e2f8
		id[pos] = (unsigned char)arc4random_uniform(UCHAR_MAX);
Packit Service 34e2f8
#else
Packit Service 34e2f8
		id[pos] = (unsigned char)random();
Packit Service 34e2f8
#endif
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	pos = 0;
Packit Service 34e2f8
Packit Service 34e2f8
	if (pos + sizeof(pid) < len) {
Packit Service 34e2f8
		/*
Packit Service 34e2f8
		 * Add PID
Packit Service 34e2f8
		 */
Packit Service 34e2f8
		pid = getpid();
Packit Service 34e2f8
		memcpy(id, &pid, sizeof(pid));
Packit Service 34e2f8
Packit Service 34e2f8
		pos += sizeof(pid);
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	/*
Packit Service 34e2f8
	 * Add sas from ai_item
Packit Service 34e2f8
	 */
Packit Service 34e2f8
	if (ai_item != NULL) {
Packit Service 34e2f8
		util_gen_id_add_sas(id, len, &pos, &ai_item->sas);
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	if (sas != NULL) {
Packit Service 34e2f8
		util_gen_id_add_sas(id, len, &pos, sas);
Packit Service 34e2f8
	}
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Add IP address from sas to id with length len to position pos. Also adjust pos to position after
Packit Service 34e2f8
 * added item.
Packit Service 34e2f8
 */
Packit Service 34e2f8
static void
Packit Service 34e2f8
util_gen_id_add_sas(char *id, size_t len, size_t *pos, const struct sockaddr_storage *sas)
Packit Service 34e2f8
{
Packit Service 34e2f8
	void *addr_pointer;
Packit Service 34e2f8
	size_t addr_len;
Packit Service 34e2f8
Packit Service 34e2f8
	switch (sas->ss_family) {
Packit Service 34e2f8
	case AF_INET:
Packit Service 34e2f8
		addr_pointer = &(((struct sockaddr_in *)sas)->sin_addr.s_addr);
Packit Service 34e2f8
		addr_len = sizeof(struct in_addr);
Packit Service 34e2f8
		break;
Packit Service 34e2f8
	case AF_INET6:
Packit Service 34e2f8
		addr_pointer = &(((struct sockaddr_in6 *)sas)->sin6_addr.s6_addr);
Packit Service 34e2f8
		addr_len = sizeof(struct in6_addr);
Packit Service 34e2f8
		break;
Packit Service 34e2f8
	default:
Packit Service 34e2f8
		DEBUG_PRINTF("Unknown ss family %d", sas->ss_family);
Packit Service 34e2f8
		errx(1, "Unknown ss family %d", sas->ss_family);
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	if (*pos + addr_len < len) {
Packit Service 34e2f8
		memcpy(id + *pos, addr_pointer, addr_len);
Packit Service 34e2f8
		*pos += addr_len;
Packit Service 34e2f8
	}
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Generate client id. Client id has length CLIENTID_LEN and takes only local address.
Packit Service 34e2f8
 */
Packit Service 34e2f8
void
Packit Service 34e2f8
util_gen_cid(char *client_id, const struct ai_item *local_addr)
Packit Service 34e2f8
{
Packit Service 34e2f8
	util_gen_id(client_id, CLIENTID_LEN, local_addr, NULL);
Packit Service 34e2f8
Packit Service 34e2f8
	DEBUG2_HEXDUMP("generated CID: ", client_id, CLIENTID_LEN);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Generate session id. Session id has length SESSIONID_LEN and takes local and remote addresses.
Packit Service 34e2f8
 */
Packit Service 34e2f8
void
Packit Service 34e2f8
util_gen_sid(char *session_id)
Packit Service 34e2f8
{
Packit Service 34e2f8
	util_gen_id(session_id, SESSIONID_LEN, NULL, NULL);
Packit Service 34e2f8
Packit Service 34e2f8
	DEBUG2_HEXDUMP("generated SESID: ", session_id, SESSIONID_LEN);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return current time stamp saved in timeval structure.
Packit Service 34e2f8
 */
Packit Service 34e2f8
struct timeval
Packit Service 34e2f8
util_get_time(void)
Packit Service 34e2f8
{
Packit Service 34e2f8
	struct timeval tv;
Packit Service 34e2f8
Packit Service 34e2f8
#ifdef __CYGWIN__
Packit Service 34e2f8
	util_cygwin_gettimeofday(&tv, NULL);
Packit Service 34e2f8
#else
Packit Service 34e2f8
	gettimeofday(&tv, NULL);
Packit Service 34e2f8
#endif
Packit Service 34e2f8
Packit Service 34e2f8
	return (tv);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Initialize random number generator.
Packit Service 34e2f8
 */
Packit Service 34e2f8
void
Packit Service 34e2f8
util_random_init(const struct sockaddr_storage *local_addr)
Packit Service 34e2f8
{
Packit Service 34e2f8
	unsigned int seed;
Packit Service 34e2f8
	unsigned int i;
Packit Service 34e2f8
Packit Service 34e2f8
	seed = time(NULL) + getpid();
Packit Service 34e2f8
Packit Service 34e2f8
	for (i = 0; i < af_sas_len(local_addr); i++) {
Packit Service 34e2f8
		seed += ((uint8_t *)local_addr)[i];
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	srandom(seed);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Returns abs(t1 - t2) in miliseconds.
Packit Service 34e2f8
 */
Packit Service 34e2f8
uint64_t
Packit Service 34e2f8
util_time_absdiff(struct timeval t1, struct timeval t2)
Packit Service 34e2f8
{
Packit Service 34e2f8
	uint64_t u64t1, u64t2, tmp;
Packit Service 34e2f8
Packit Service 34e2f8
	u64t1 = t1.tv_usec / 1000 + t1.tv_sec * 1000;
Packit Service 34e2f8
	u64t2 = t2.tv_usec / 1000 + t2.tv_sec * 1000;
Packit Service 34e2f8
Packit Service 34e2f8
	if (u64t2 > u64t1) {
Packit Service 34e2f8
		tmp = u64t1;
Packit Service 34e2f8
		u64t1 = u64t2;
Packit Service 34e2f8
		u64t2 = tmp;
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	return (u64t1 - u64t2);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return abs value of (t2 - t1) in ms double precission.
Packit Service 34e2f8
 */
Packit Service 34e2f8
double
Packit Service 34e2f8
util_time_double_absdiff(struct timeval t1, struct timeval t2)
Packit Service 34e2f8
{
Packit Service 34e2f8
	return (util_time_double_absdiff_us(t1, t2) / 1000.0);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return abs value of (t2 - t1) in ns (nano seconds) double precission.
Packit Service 34e2f8
 */
Packit Service 34e2f8
double
Packit Service 34e2f8
util_time_double_absdiff_ns(struct timeval t1, struct timeval t2)
Packit Service 34e2f8
{
Packit Service 34e2f8
	return (util_time_double_absdiff_us(t1, t2) * 1000.0);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return abs value of (t2 - t1) in us (micro seconds) double precission.
Packit Service 34e2f8
 */
Packit Service 34e2f8
double
Packit Service 34e2f8
util_time_double_absdiff_us(struct timeval t1, struct timeval t2)
Packit Service 34e2f8
{
Packit Service 34e2f8
	double dt1, dt2, tmp;
Packit Service 34e2f8
Packit Service 34e2f8
	dt1 = t1.tv_usec + t1.tv_sec * UTIL_NSINMS;
Packit Service 34e2f8
	dt2 = t2.tv_usec + t2.tv_sec * UTIL_NSINMS;
Packit Service 34e2f8
Packit Service 34e2f8
	if (dt2 > dt1) {
Packit Service 34e2f8
		tmp = dt1;
Packit Service 34e2f8
		dt1 = dt2;
Packit Service 34e2f8
		dt2 = tmp;
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	return (dt1 - dt2);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return standard deviation based on m2 value and number of items n. Value is rounded to 0.001.
Packit Service 34e2f8
 */
Packit Service 34e2f8
double
Packit Service 34e2f8
util_ov_std_dev(double m2, uint64_t n)
Packit Service 34e2f8
{
Packit Service 34e2f8
	return (util_u64sqrt((uint64_t)util_ov_variance(m2, n)));
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * On-line algorithm for compute variance.
Packit Service 34e2f8
 * Based on Donald E. Knuth (1998). The Art of Computer Programming, volume 2: p. 232.
Packit Service 34e2f8
 * function updats mean and m2. x is new value and n is absolute number of all items.
Packit Service 34e2f8
 */
Packit Service 34e2f8
void
Packit Service 34e2f8
util_ov_update(double *mean, double *m2, double x, uint64_t n)
Packit Service 34e2f8
{
Packit Service 34e2f8
	double delta;
Packit Service 34e2f8
Packit Service 34e2f8
	delta = x - *mean;
Packit Service 34e2f8
	*mean = *mean + delta / n;
Packit Service 34e2f8
	*m2 = *m2 + delta * (x - *mean);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return variance based on m2 value and number of items n.
Packit Service 34e2f8
 */
Packit Service 34e2f8
double
Packit Service 34e2f8
util_ov_variance(double m2, uint64_t n)
Packit Service 34e2f8
{
Packit Service 34e2f8
	return ((n > 1) ? (m2 / (n - 1)) : 0.0);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return number of miliseconds from timeval structure
Packit Service 34e2f8
 */
Packit Service 34e2f8
uint64_t
Packit Service 34e2f8
util_tv_to_ms(struct timeval t1)
Packit Service 34e2f8
{
Packit Service 34e2f8
	uint64_t u64;
Packit Service 34e2f8
Packit Service 34e2f8
	u64 = t1.tv_usec / 1000 + t1.tv_sec * 1000;
Packit Service 34e2f8
Packit Service 34e2f8
	return (u64);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return absolute difference between two unsigned 64-bit integers
Packit Service 34e2f8
 */
Packit Service 34e2f8
uint64_t
Packit Service 34e2f8
util_u64_absdiff(uint64_t u1, uint64_t u2)
Packit Service 34e2f8
{
Packit Service 34e2f8
	uint64_t tmpu;
Packit Service 34e2f8
Packit Service 34e2f8
	if (u1 > u2) {
Packit Service 34e2f8
		tmpu = u1;
Packit Service 34e2f8
		u1 = u2;
Packit Service 34e2f8
		u2 = tmpu;
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	return (u2 - u1);
Packit Service 34e2f8
}
Packit Service 34e2f8
Packit Service 34e2f8
/*
Packit Service 34e2f8
 * Return sqrt of 64bit unsigned int n
Packit Service 34e2f8
 */
Packit Service 34e2f8
uint32_t
Packit Service 34e2f8
util_u64sqrt(uint64_t n)
Packit Service 34e2f8
{
Packit Service 34e2f8
	double x, x2;
Packit Service 34e2f8
Packit Service 34e2f8
	if (n == 0) {
Packit Service 34e2f8
		return (0);
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	x = n;
Packit Service 34e2f8
Packit Service 34e2f8
	while (util_fabs((x2 = (x + n / x) / 2) - x) >= 0.5) {
Packit Service 34e2f8
		x = x2;
Packit Service 34e2f8
	}
Packit Service 34e2f8
Packit Service 34e2f8
	return ((uint32_t)x2);
Packit Service 34e2f8
}