/* This file is part of Ping903
Copyright (C) 2020 Sergey Poznyakoff
Ping903 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
Ping903 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Ping903. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <limits.h>
#include <poll.h>
#include "ping903.h"
#include "json.h"
#include "defs.h"
/* Time in seconds between two subsequent probes. */
unsigned long probe_interval = 60;
/* Time between two subsequent echo requests within the same probe. */
unsigned long ping_interval = 1;
/* Number of echo requests per probe */
unsigned long ping_count = 10;
/* Number of unanswered echo requests after which the host is declared dead. */
unsigned long ping_tolerance = 3;
/* Initial value for the tmin member of struct hostping */
#define HOSTPING_TMIN_INIT 999999999.0
static double
nabs(double a)
{
return (a < 0) ? -a : a;
}
static double
nsqrt(double a, double prec)
{
double x0, x1;
if (a < 0)
return 0;
if (a < prec)
return 0;
x1 = a / 2;
do {
x0 = x1;
x1 = (x0 + a / x0) / 2;
} while (nabs(x1 - x0) > prec);
return x1;
}
static inline int
timeval_is_null(struct timeval const *tv)
{
return tv->tv_sec == 0 && tv->tv_usec == 0;
}
static inline double
timeval_to_double(struct timeval const *tv)
{
return (double)tv->tv_sec + (double)tv->tv_usec / 1000000;
}
enum { NANOSEC_IN_SEC = 1000000000 };
static inline void
timespec_add(struct timespec const *a, struct timespec const *b,
struct timespec *res)
{
res->tv_sec = a->tv_sec + b->tv_sec;
res->tv_nsec = a->tv_nsec + b->tv_nsec;
if (res->tv_nsec >= NANOSEC_IN_SEC) {
++res->tv_sec;
res->tv_nsec -= NANOSEC_IN_SEC;
}
}
static inline void
timespec_incr(struct timespec *a, struct timespec const *b)
{
struct timespec t = *a;
timespec_add(&t, b, a);
}
static void
hostping_free(HOSTPING *hp)
{
free(hp->name);
free(hp->addr);
pthread_mutex_destroy(&hp->mutex);
free(hp);
}
static HOSTPING *
hostping_create(char const *name, struct sockaddr *addr, socklen_t addrlen)
{
HOSTPING *hp;
size_t hostsize = sizeof(*hp) +
(ping_count - 1) * sizeof(hp->nreply[0]);
hp = malloc(hostsize);
if (hp) {
memset(hp, 0, hostsize);
hp->tmin = HOSTPING_TMIN_INIT;
hp->name = strdup(name);
if (!hp)
goto err;
hp->addr = malloc(addrlen);
if (!hp)
goto err;
memcpy(hp->addr, addr, addrlen);
hp->addrlen = addrlen;
pthread_mutex_init(&hp->mutex, NULL);
}
return hp;
err:
hostping_free(hp);
return NULL;
}
static inline void
hostping_lock(HOSTPING *host)
{
pthread_mutex_lock(&host->mutex);
}
static inline void
hostping_unlock(HOSTPING *host)
{
pthread_mutex_unlock(&host->mutex);
}
typedef struct hostlist {
HOSTPING *head, *tail;
size_t count;
} HOSTLIST;
static HOSTLIST *
hostlist_create(void)
{
HOSTLIST *hl = malloc(sizeof(*hl));
if (hl) {
hl->head = hl->tail = NULL;
hl->count = 0;
}
return hl;
}
static void
hostlist_free(HOSTLIST *list)
{
HOSTPING *hp = list->head;
while (hp) {
HOSTPING *next = hp->next;
hostping_free(hp);
hp = next;
}
free(list);
}
static void
hostlist_add(HOSTLIST *list, HOSTPING *hp)
{
hp->prev = list->tail;
|