"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/liboping.c" between
liboping-1.9.0.tar.gz and liboping-1.10.0.tar.gz

About: liboping is a C library to generate ICMP echo requests, better known as "ping packets". It can "ping" multiple hosts in parallel using IPv4 or IPv6 transparently. A commandline and a ncurses-based application are included.

liboping.c  (liboping-1.9.0):liboping.c  (liboping-1.10.0)
/** /**
* Object oriented C module to send ICMP and ICMPv6 `echo's. * Object oriented C module to send ICMP and ICMPv6 `echo's.
* Copyright (C) 2006-2016 Florian octo Forster <ff at octo.it> * Copyright (C) 2006-2017 Florian octo Forster <ff at octo.it>
* *
* This library is free software; you can redistribute it and/or modify it * This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the * under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your * Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This library is distributed in the hope that it will be useful, but WITHOUT * This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details. * for more details.
skipping to change at line 107 skipping to change at line 107
#include "oping.h" #include "oping.h"
#if WITH_DEBUG #if WITH_DEBUG
# define dprintf(...) printf ("%s[%4i]: %-20s: ", __FILE__, __LINE__, __FUNCTION __); printf (__VA_ARGS__) # define dprintf(...) printf ("%s[%4i]: %-20s: ", __FILE__, __LINE__, __FUNCTION __); printf (__VA_ARGS__)
#else #else
# define dprintf(...) /**/ # define dprintf(...) /**/
#endif #endif
#define PING_ERRMSG_LEN 256 #define PING_ERRMSG_LEN 256
#define PING_TABLE_LEN 5381
struct pinghost struct pinghost
{ {
/* username: name passed in by the user */ /* username: name passed in by the user */
char *username; char *username;
/* hostname: name returned by the reverse lookup */ /* hostname: name returned by the reverse lookup */
char *hostname; char *hostname;
struct sockaddr_storage *addr; struct sockaddr_storage *addr;
socklen_t addrlen; socklen_t addrlen;
int addrfamily; int addrfamily;
int fd;
int ident; int ident;
int sequence; int sequence;
struct timeval *timer; struct timeval *timer;
double latency; double latency;
uint32_t dropped; uint32_t dropped;
int recv_ttl; int recv_ttl;
uint8_t recv_qos; uint8_t recv_qos;
char *data; char *data;
void *context; void *context;
struct pinghost *next; struct pinghost *next;
struct pinghost *table_next;
}; };
struct pingobj struct pingobj
{ {
double timeout; double timeout;
int ttl; int ttl;
int addrfamily; int addrfamily;
uint8_t qos; uint8_t qos;
char *data; char *data;
int fd4;
int fd6;
struct sockaddr *srcaddr; struct sockaddr *srcaddr;
socklen_t srcaddrlen; socklen_t srcaddrlen;
char *device; char *device;
char set_mark; char set_mark;
int mark; int mark;
char errmsg[PING_ERRMSG_LEN]; char errmsg[PING_ERRMSG_LEN];
pinghost_t *head; pinghost_t *head;
pinghost_t *table[PING_TABLE_LEN];
}; };
/* /*
* private (static) functions * private (static) functions
*/ */
/* Even though Posix requires "strerror_r" to return an "int", /* Even though Posix requires "strerror_r" to return an "int",
* some systems (e.g. the GNU libc) return a "char *" _and_ * some systems (e.g. the GNU libc) return a "char *" _and_
* ignore the second argument ... -tokkee */ * ignore the second argument ... -tokkee */
static char *sstrerror (int errnum, char *buf, size_t buflen) static char *sstrerror (int errnum, char *buf, size_t buflen)
{ {
skipping to change at line 301 skipping to change at line 306
ip_hdr = (struct ip *) buffer; ip_hdr = (struct ip *) buffer;
ip_hdr_len = ip_hdr->ip_hl << 2; ip_hdr_len = ip_hdr->ip_hl << 2;
if (buffer_len < ip_hdr_len) if (buffer_len < ip_hdr_len)
return (NULL); return (NULL);
buffer += ip_hdr_len; buffer += ip_hdr_len;
buffer_len -= ip_hdr_len; buffer_len -= ip_hdr_len;
if (buffer_len < sizeof (struct icmp)) if (buffer_len < ICMP_MINLEN)
return (NULL); return (NULL);
icmp_hdr = (struct icmp *) buffer; icmp_hdr = (struct icmp *) buffer;
buffer += sizeof (struct icmp);
buffer_len -= sizeof (struct icmp);
if (icmp_hdr->icmp_type != ICMP_ECHOREPLY) if (icmp_hdr->icmp_type != ICMP_ECHOREPLY)
{ {
dprintf ("Unexpected ICMP type: %i\n", icmp_hdr->icmp_type); dprintf ("Unexpected ICMP type: %"PRIu8"\n", icmp_hdr->icmp_type) ;
return (NULL); return (NULL);
} }
recv_checksum = icmp_hdr->icmp_cksum; recv_checksum = icmp_hdr->icmp_cksum;
/* This writes to buffer. */
icmp_hdr->icmp_cksum = 0; icmp_hdr->icmp_cksum = 0;
calc_checksum = ping_icmp4_checksum ((char *) icmp_hdr, calc_checksum = ping_icmp4_checksum (buffer, buffer_len);
sizeof (struct icmp) + buffer_len);
if (recv_checksum != calc_checksum) if (recv_checksum != calc_checksum)
{ {
dprintf ("Checksum missmatch: Got 0x%04"PRIx16", " dprintf ("Checksum missmatch: Got 0x%04"PRIx16", "
"calculated 0x%04"PRIx16"\n", "calculated 0x%04"PRIx16"\n",
recv_checksum, calc_checksum); recv_checksum, calc_checksum);
return (NULL); return (NULL);
} }
ident = ntohs (icmp_hdr->icmp_id); ident = ntohs (icmp_hdr->icmp_id);
seq = ntohs (icmp_hdr->icmp_seq); seq = ntohs (icmp_hdr->icmp_seq);
/* We have to iterate over all hosts, since ICMPv4 packets may for (ptr = obj->table[ident % PING_TABLE_LEN];
* be received on any raw v4 socket. */ ptr != NULL; ptr = ptr->table_next)
for (ptr = obj->head; ptr != NULL; ptr = ptr->next)
{ {
dprintf ("hostname = %s, ident = 0x%04x, seq = %i\n", dprintf ("hostname = %s, ident = 0x%04x, seq = %i\n",
ptr->hostname, ptr->ident, ((ptr->sequence - 1) & 0xFFFF)); ptr->hostname, ptr->ident, ((ptr->sequence - 1) & 0xFFFF));
if (ptr->addrfamily != AF_INET) if (ptr->addrfamily != AF_INET)
continue; continue;
if (!timerisset (ptr->timer)) if (!timerisset (ptr->timer))
continue; continue;
skipping to change at line 395 skipping to change at line 396
static pinghost_t *ping_receive_ipv6 (pingobj_t *obj, char *buffer, static pinghost_t *ping_receive_ipv6 (pingobj_t *obj, char *buffer,
size_t buffer_len) size_t buffer_len)
{ {
struct icmp6_hdr *icmp_hdr; struct icmp6_hdr *icmp_hdr;
uint16_t ident; uint16_t ident;
uint16_t seq; uint16_t seq;
pinghost_t *ptr; pinghost_t *ptr;
if (buffer_len < sizeof (struct icmp6_hdr)) if (buffer_len < ICMP_MINLEN)
return (NULL); return (NULL);
icmp_hdr = (struct icmp6_hdr *) buffer; icmp_hdr = (struct icmp6_hdr *) buffer;
buffer += sizeof (struct icmp); buffer += ICMP_MINLEN;
buffer_len -= sizeof (struct icmp); buffer_len -= ICMP_MINLEN;
if (icmp_hdr->icmp6_type != ICMP6_ECHO_REPLY) if (icmp_hdr->icmp6_type != ICMP6_ECHO_REPLY)
{ {
dprintf ("Unexpected ICMP type: %02x\n", icmp_hdr->icmp6_type); dprintf ("Unexpected ICMP type: %02x\n", icmp_hdr->icmp6_type);
return (NULL); return (NULL);
} }
if (icmp_hdr->icmp6_code != 0) if (icmp_hdr->icmp6_code != 0)
{ {
dprintf ("Unexpected ICMP code: %02x\n", icmp_hdr->icmp6_code); dprintf ("Unexpected ICMP code: %02x\n", icmp_hdr->icmp6_code);
skipping to change at line 453 skipping to change at line 454
if (ptr == NULL) if (ptr == NULL)
{ {
dprintf ("No match found for ident = 0x%04"PRIx16", " dprintf ("No match found for ident = 0x%04"PRIx16", "
"seq = %"PRIu16"\n", "seq = %"PRIu16"\n",
ident, seq); ident, seq);
} }
return (ptr); return (ptr);
} }
static int ping_receive_one (pingobj_t *obj, const pinghost_t *ph, static int ping_receive_one (pingobj_t *obj, struct timeval *now, int addrfam)
struct timeval *now)
{ {
/* Note: 'ph' is not necessarily the host object for which we receive a int fd = addrfam == AF_INET6 ? obj->fd6 : obj->fd4;
* reply. The right object will be returned by ping_receive_ipv*(). For
* now, we can only rely on ph->fd and ph->addrfamily. */
struct timeval diff, pkt_now = *now; struct timeval diff, pkt_now = *now;
pinghost_t *host = NULL; pinghost_t *host = NULL;
int recv_ttl; int recv_ttl;
uint8_t recv_qos; uint8_t recv_qos;
/* /*
* Set up the receive buffer.. * Set up the receive buffer..
*/ */
struct msghdr msghdr; struct msghdr msghdr;
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
skipping to change at line 495 skipping to change at line 492
msghdr.msg_iovlen = 1; msghdr.msg_iovlen = 1;
/* output buffer for control messages */ /* output buffer for control messages */
msghdr.msg_control = control_buffer; msghdr.msg_control = control_buffer;
msghdr.msg_controllen = sizeof (control_buffer); msghdr.msg_controllen = sizeof (control_buffer);
/* flags; this is an output only field.. */ /* flags; this is an output only field.. */
msghdr.msg_flags = 0; msghdr.msg_flags = 0;
#ifdef MSG_XPG4_2 #ifdef MSG_XPG4_2
msghdr.msg_flags |= MSG_XPG4_2; msghdr.msg_flags |= MSG_XPG4_2;
#endif #endif
payload_buffer_len = recvmsg (ph->fd, &msghdr, /* flags = */ 0); payload_buffer_len = recvmsg (fd, &msghdr, /* flags = */ 0);
if (payload_buffer_len < 0) if (payload_buffer_len < 0)
{ {
#if WITH_DEBUG #if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN]; char errbuf[PING_ERRMSG_LEN];
dprintf ("recvfrom: %s\n", dprintf ("recvfrom: %s\n",
sstrerror (errno, errbuf, sizeof (errbuf))); sstrerror (errno, errbuf, sizeof (errbuf)));
#endif #endif
return (-1); return (-1);
} }
dprintf ("Read %zi bytes from fd = %i\n", payload_buffer_len, ph->fd); dprintf ("Read %zi bytes from fd = %i\n", payload_buffer_len, fd);
/* Iterate over all auxiliary data in msghdr */ /* Iterate over all auxiliary data in msghdr */
recv_ttl = -1; recv_ttl = -1;
recv_qos = 0; recv_qos = 0;
for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */ for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */
cmsg != NULL; cmsg != NULL;
cmsg = CMSG_NXTHDR (&msghdr, cmsg)) cmsg = CMSG_NXTHDR (&msghdr, cmsg))
{ {
if (cmsg->cmsg_level == SOL_SOCKET) if (cmsg->cmsg_level == SOL_SOCKET)
{ {
#ifdef SO_TIMESTAMP #ifdef SO_TIMESTAMP
if (cmsg->cmsg_type == SO_TIMESTAMP) if (cmsg->cmsg_type == SO_TIMESTAMP)
memcpy (&pkt_now, CMSG_DATA (cmsg), sizeof (pkt_n ow)); memcpy (&pkt_now, CMSG_DATA (cmsg), sizeof (pkt_n ow));
#endif /* SO_TIMESTAMP */ #endif /* SO_TIMESTAMP */
} }
else if (ph->addrfamily == AF_INET) /* {{{ */ else if (addrfam == AF_INET) /* {{{ */
{ {
if (cmsg->cmsg_level != IPPROTO_IP) if (cmsg->cmsg_level != IPPROTO_IP)
continue; continue;
if (cmsg->cmsg_type == IP_TOS) if (cmsg->cmsg_type == IP_TOS)
{ {
memcpy (&recv_qos, CMSG_DATA (cmsg), memcpy (&recv_qos, CMSG_DATA (cmsg),
sizeof (recv_qos)); sizeof (recv_qos));
dprintf ("TOSv4 = 0x%02"PRIx8";\n", recv_qos); dprintf ("TOSv4 = 0x%02"PRIx8";\n", recv_qos);
} else } else
skipping to change at line 544 skipping to change at line 541
memcpy (&recv_ttl, CMSG_DATA (cmsg), memcpy (&recv_ttl, CMSG_DATA (cmsg),
sizeof (recv_ttl)); sizeof (recv_ttl));
dprintf ("TTLv4 = %i;\n", recv_ttl); dprintf ("TTLv4 = %i;\n", recv_ttl);
} }
else else
{ {
dprintf ("Not handling option %i.\n", dprintf ("Not handling option %i.\n",
cmsg->cmsg_type); cmsg->cmsg_type);
} }
} /* }}} */ } /* }}} */
else if (ph->addrfamily == AF_INET6) /* {{{ */ else if (addrfam == AF_INET6) /* {{{ */
{ {
if (cmsg->cmsg_level != IPPROTO_IPV6) if (cmsg->cmsg_level != IPPROTO_IPV6)
continue; continue;
if (cmsg->cmsg_type == IPV6_TCLASS) if (cmsg->cmsg_type == IPV6_TCLASS)
{ {
memcpy (&recv_qos, CMSG_DATA (cmsg), memcpy (&recv_qos, CMSG_DATA (cmsg),
sizeof (recv_qos)); sizeof (recv_qos));
dprintf ("TOSv6 = 0x%02"PRIx8";\n", recv_qos); dprintf ("TOSv6 = 0x%02"PRIx8";\n", recv_qos);
} else } else
skipping to change at line 595 skipping to change at line 592
} }
} /* }}} */ } /* }}} */
else else
{ {
dprintf ("Don't know how to handle " dprintf ("Don't know how to handle "
"unknown protocol %i.\n", "unknown protocol %i.\n",
cmsg->cmsg_level); cmsg->cmsg_level);
} }
} /* }}} for (cmsg) */ } /* }}} for (cmsg) */
if (ph->addrfamily == AF_INET) if (addrfam == AF_INET)
{ {
host = ping_receive_ipv4 (obj, payload_buffer, payload_buffer_len ); host = ping_receive_ipv4 (obj, payload_buffer, payload_buffer_len );
if (host == NULL) if (host == NULL)
return (-1); return (-1);
} }
else if (ph->addrfamily == AF_INET6) else if (addrfam == AF_INET6)
{ {
host = ping_receive_ipv6 (obj, payload_buffer, payload_buffer_len ); host = ping_receive_ipv6 (obj, payload_buffer, payload_buffer_len );
if (host == NULL) if (host == NULL)
return (-1); return (-1);
} }
else else
{ {
dprintf ("ping_receive_one: Unknown address family %i.\n", dprintf ("ping_receive_one: Unknown address family %i.\n",
ph->addrfamily); addrfam);
return (-1); return (-1);
} }
dprintf ("rcvd: %12i.%06i\n", dprintf ("rcvd: %12i.%06i\n",
(int) pkt_now.tv_sec, (int) pkt_now.tv_sec,
(int) pkt_now.tv_usec); (int) pkt_now.tv_usec);
dprintf ("sent: %12i.%06i\n", dprintf ("sent: %12i.%06i\n",
(int) host->timer->tv_sec, (int) host->timer->tv_sec,
(int) host->timer->tv_usec); (int) host->timer->tv_usec);
skipping to change at line 643 skipping to change at line 640
host->recv_qos = recv_qos; host->recv_qos = recv_qos;
host->latency = ((double) diff.tv_usec) / 1000.0; host->latency = ((double) diff.tv_usec) / 1000.0;
host->latency += ((double) diff.tv_sec) * 1000.0; host->latency += ((double) diff.tv_sec) * 1000.0;
timerclear (host->timer); timerclear (host->timer);
return (0); return (0);
} }
/* Blocks until a packet was received from all hosts or the timeout is reached.
* When interrupted, (-EINTR) is returned. On error, -1 is returned. On
* success, returns zero. */
static int ping_receive_all (pingobj_t *obj)
{
fd_set read_fds;
fd_set err_fds;
int num_fds;
int max_fd;
pinghost_t *ph;
pinghost_t *ptr;
struct timeval endtime;
struct timeval nowtime;
struct timeval timeout;
int status;
int ret;
ph = obj->head;
ret = 0;
for (ptr = ph; ptr != NULL; ptr = ptr->next)
{
ptr->latency = -1.0;
ptr->recv_ttl = -1;
}
if (gettimeofday (&nowtime, NULL) == -1)
{
ping_set_errno (obj, errno);
return (-1);
}
/* Set up timeout */
timeout.tv_sec = (time_t) obj->timeout;
timeout.tv_usec = (suseconds_t) (1000000 * (obj->timeout - ((double) time
out.tv_sec)));
dprintf ("Set timeout to %i.%06i seconds\n",
(int) timeout.tv_sec,
(int) timeout.tv_usec);
ping_timeval_add (&nowtime, &timeout, &endtime);
while (1)
{
FD_ZERO (&read_fds);
FD_ZERO (&err_fds);
num_fds = 0;
max_fd = -1;
for (ptr = ph; ptr != NULL; ptr = ptr->next)
{
if (!timerisset (ptr->timer))
continue;
FD_SET (ptr->fd, &read_fds);
FD_SET (ptr->fd, &err_fds);
num_fds++;
if (max_fd < ptr->fd)
max_fd = ptr->fd;
}
if (num_fds == 0)
break;
if (gettimeofday (&nowtime, NULL) == -1)
{
ping_set_errno (obj, errno);
return (-1);
}
if (ping_timeval_sub (&endtime, &nowtime, &timeout) == -1)
break;
dprintf ("Waiting on %i sockets for %i.%06i seconds\n", num_fds,
(int) timeout.tv_sec,
(int) timeout.tv_usec);
status = select (max_fd + 1, &read_fds, NULL, &err_fds, &timeout)
;
if (gettimeofday (&nowtime, NULL) == -1)
{
ping_set_errno (obj, errno);
return (-1);
}
if ((status == -1) && (errno == EINTR))
{
dprintf ("select was interrupted by signal..\n");
ping_set_errno (obj, EINTR);
return (-EINTR);
}
else if (status < 0)
{
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("select: %s\n",
sstrerror (errno, errbuf, sizeof (errbuf)
));
#endif
break;
}
else if (status == 0)
{
dprintf ("select timed out\n");
for (ptr = ph; ptr != NULL; ptr = ptr->next)
if (ptr->latency < 0.0)
ptr->dropped++;
break;
}
for (ptr = ph; ptr != NULL; ptr = ptr->next)
{
if (FD_ISSET (ptr->fd, &read_fds))
{
if (ping_receive_one (obj, ptr, &nowtime) == 0)
ret++;
}
else if (FD_ISSET (ptr->fd, &err_fds))
{
/* clear the timer in this case so that we
* don't run into an endless loop. */
/* TODO: Set an error flag in this case. */
timerclear (ptr->timer);
}
}
} /* while (1) */
return (ret);
} /* int ping_receive_all */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Sending functions: * * Sending functions: *
* * * *
* ping_send_all * * ping_send_all *
* +-> ping_send_one_ipv4 * * +-> ping_send_one_ipv4 *
* `-> ping_send_one_ipv6 * * `-> ping_send_one_ipv6 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ssize_t ping_sendto (pingobj_t *obj, pinghost_t *ph, static ssize_t ping_sendto (pingobj_t *obj, pinghost_t *ph,
const void *buf, size_t buflen) const void *buf, size_t buflen, int fd)
{ {
ssize_t ret; ssize_t ret;
if (gettimeofday (ph->timer, NULL) == -1) if (gettimeofday (ph->timer, NULL) == -1)
{ {
timerclear (ph->timer); timerclear (ph->timer);
return (-1); return (-1);
} }
ret = sendto (ph->fd, buf, buflen, 0, ret = sendto (fd, buf, buflen, 0,
(struct sockaddr *) ph->addr, ph->addrlen); (struct sockaddr *) ph->addr, ph->addrlen);
if (ret < 0) if (ret < 0)
{ {
#if defined(EHOSTUNREACH) #if defined(EHOSTUNREACH)
if (errno == EHOSTUNREACH) if (errno == EHOSTUNREACH)
return (0); return (0);
#endif #endif
#if defined(ENETUNREACH) #if defined(ENETUNREACH)
if (errno == ENETUNREACH) if (errno == ENETUNREACH)
return (0); return (0);
#endif #endif
ping_set_errno (obj, errno); ping_set_errno (obj, errno);
} }
return (ret); return (ret);
} }
static int ping_send_one_ipv4 (pingobj_t *obj, pinghost_t *ph) static int ping_send_one_ipv4 (pingobj_t *obj, pinghost_t *ph, int fd)
{ {
struct icmp *icmp4; struct icmp *icmp4;
int status; int status;
char buf[4096]; char buf[4096] = {0};
int buflen; size_t buflen;
char *data; char *data;
int datalen; size_t datalen;
dprintf ("ph->hostname = %s\n", ph->hostname); dprintf ("ph->hostname = %s\n", ph->hostname);
memset (buf, '\0', sizeof (buf));
icmp4 = (struct icmp *) buf; icmp4 = (struct icmp *) buf;
data = (char *) (icmp4 + 1); *icmp4 = (struct icmp) {
.icmp_type = ICMP_ECHO,
.icmp_id = htons (ph->ident),
.icmp_seq = htons (ph->sequence),
};
datalen = strlen (ph->data);
buflen = ICMP_MINLEN + datalen;
if (sizeof (buf) < buflen)
return (EINVAL);
icmp4->icmp_type = ICMP_ECHO; data = buf + ICMP_MINLEN;
icmp4->icmp_code = 0; memcpy (data, ph->data, datalen);
icmp4->icmp_cksum = 0;
icmp4->icmp_id = htons (ph->ident);
icmp4->icmp_seq = htons (ph->sequence);
buflen = 4096 - sizeof (struct icmp);
strncpy (data, ph->data, buflen);
datalen = strlen (data);
buflen = datalen + sizeof (struct icmp);
icmp4->icmp_cksum = ping_icmp4_checksum (buf, buflen); icmp4->icmp_cksum = ping_icmp4_checksum (buf, buflen);
dprintf ("Sending ICMPv4 package with ID 0x%04x\n", ph->ident); dprintf ("Sending ICMPv4 package with ID 0x%04x\n", ph->ident);
status = ping_sendto (obj, ph, buf, buflen); status = ping_sendto (obj, ph, buf, buflen, fd);
if (status < 0) if (status < 0)
{ {
perror ("ping_sendto"); perror ("ping_sendto");
return (-1); return (-1);
} }
dprintf ("sendto: status = %i\n", status); dprintf ("sendto: status = %i\n", status);
return (0); return (0);
} }
static int ping_send_one_ipv6 (pingobj_t *obj, pinghost_t *ph) static int ping_send_one_ipv6 (pingobj_t *obj, pinghost_t *ph, int fd)
{ {
struct icmp6_hdr *icmp6; struct icmp6_hdr *icmp6;
int status; int status;
char buf[4096]; char buf[4096] = {0};
int buflen; int buflen;
char *data; char *data;
int datalen; int datalen;
dprintf ("ph->hostname = %s\n", ph->hostname); dprintf ("ph->hostname = %s\n", ph->hostname);
memset (buf, '\0', sizeof (buf));
icmp6 = (struct icmp6_hdr *) buf; icmp6 = (struct icmp6_hdr *) buf;
data = (char *) (icmp6 + 1); *icmp6 = (struct icmp6_hdr) {
.icmp6_type = ICMP6_ECHO_REQUEST,
.icmp6_id = htons (ph->ident),
.icmp6_seq = htons (ph->sequence),
};
datalen = strlen (ph->data);
buflen = sizeof (*icmp6) + datalen;
if (sizeof (buf) < buflen)
return (EINVAL);
icmp6->icmp6_type = ICMP6_ECHO_REQUEST; data = buf + ICMP_MINLEN;
icmp6->icmp6_code = 0; memcpy (data, ph->data, datalen);
/* The checksum will be calculated by the TCP/IP stack. */
/* FIXME */
icmp6->icmp6_cksum = 0;
icmp6->icmp6_id = htons (ph->ident);
icmp6->icmp6_seq = htons (ph->sequence);
buflen = 4096 - sizeof (struct icmp6_hdr);
strncpy (data, ph->data, buflen);
datalen = strlen (data);
buflen = datalen + sizeof (struct icmp6_hdr); /* The checksum will be calculated by the TCP/IP stack. */
dprintf ("Sending ICMPv6 package with ID 0x%04x\n", ph->ident); dprintf ("Sending ICMPv6 package with ID 0x%04x\n", ph->ident);
status = ping_sendto (obj, ph, buf, buflen); status = ping_sendto (obj, ph, buf, buflen, fd);
if (status < 0) if (status < 0)
{ {
perror ("ping_sendto"); perror ("ping_sendto");
return (-1); return (-1);
} }
dprintf ("sendto: status = %i\n", status); dprintf ("sendto: status = %i\n", status);
return (0); return (0);
} }
static int ping_send_all (pingobj_t *obj) static int ping_send_one (pingobj_t *obj, pinghost_t *ptr, int fd)
{ {
pinghost_t *ph; if (gettimeofday (ptr->timer, NULL) == -1)
pinghost_t *ptr;
int ret;
ret = 0;
ph = obj->head;
for (ptr = ph; ptr != NULL; ptr = ptr->next)
{ {
/* start timer.. The GNU `ping6' starts the timer before /* start timer.. The GNU `ping6' starts the timer before
* sending the packet, so I will do that too */ * sending the packet, so I will do that too */
if (gettimeofday (ptr->timer, NULL) == -1)
{
#if WITH_DEBUG #if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN]; char errbuf[PING_ERRMSG_LEN];
dprintf ("gettimeofday: %s\n", dprintf ("gettimeofday: %s\n",
sstrerror (errno, errbuf, sizeof (errbuf) sstrerror (errno, errbuf, sizeof (errbuf)));
));
#endif #endif
timerclear (ptr->timer); timerclear (ptr->timer);
ret--; return (-1);
continue; }
} else
else {
{ dprintf ("timer set for hostname = %s\n", ptr->hostname);
dprintf ("timer set for hostname = %s\n", ptr->hostname); }
}
if (ptr->addrfamily == AF_INET6) if (ptr->addrfamily == AF_INET6)
{ {
dprintf ("Sending ICMPv6 echo request to `%s'\n", ptr->ho dprintf ("Sending ICMPv6 echo request to `%s'\n", ptr->hostname);
stname); if (ping_send_one_ipv6 (obj, ptr, fd) != 0)
if (ping_send_one_ipv6 (obj, ptr) != 0)
{
timerclear (ptr->timer);
ret--;
continue;
}
}
else if (ptr->addrfamily == AF_INET)
{ {
dprintf ("Sending ICMPv4 echo request to `%s'\n", ptr->ho timerclear (ptr->timer);
stname); return (-1);
if (ping_send_one_ipv4 (obj, ptr) != 0)
{
timerclear (ptr->timer);
ret--;
continue;
}
} }
else /* this should not happen */ }
else if (ptr->addrfamily == AF_INET)
{
dprintf ("Sending ICMPv4 echo request to `%s'\n", ptr->hostname);
if (ping_send_one_ipv4 (obj, ptr, fd) != 0)
{ {
dprintf ("Unknown address family: %i\n", ptr->addrfamily) ;
timerclear (ptr->timer); timerclear (ptr->timer);
ret--; return (-1);
continue;
} }
}
ptr->sequence++; else /* this should not happen */
{
dprintf ("Unknown address family: %i\n", ptr->addrfamily);
timerclear (ptr->timer);
return (-1);
} }
return (ret); ptr->sequence++;
return (0);
} }
/* /*
* Set the TTL of a socket protocol independently. * Set the TTL of a socket protocol independently.
*/ */
static int ping_set_ttl (pinghost_t *ph, int ttl) static int ping_set_ttl (pingobj_t *obj, int ttl)
{ {
int ret = -2; int ret = 0;
char errbuf[PING_ERRMSG_LEN];
if (ph->addrfamily == AF_INET) if (obj->fd4 != -1)
{ {
dprintf ("Setting TTLv4 to %i\n", ttl); if (setsockopt (obj->fd4, IPPROTO_IP, IP_TTL,
ret = setsockopt (ph->fd, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl)))
&ttl, sizeof (ttl)); {
ret = errno;
ping_set_error (obj, "ping_set_ttl",
sstrerror (ret, errbuf, sizeof (errbuf)))
;
dprintf ("Setting TTLv4 failed: %s\n", errbuf);
}
} }
else if (ph->addrfamily == AF_INET6)
if (obj->fd6 != -1)
{ {
dprintf ("Setting TTLv6 to %i\n", ttl); dprintf ("Setting TTLv6 to %i\n", ttl);
ret = setsockopt (ph->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, if (setsockopt (obj->fd6, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
&ttl, sizeof (ttl)); &ttl, sizeof (ttl)))
{
ret = errno;
ping_set_error (obj, "ping_set_ttl",
sstrerror (ret, errbuf, sizeof (errbuf)))
;
dprintf ("Setting TTLv6 failed: %s\n", errbuf);
}
} }
return (ret); return (ret);
} }
/* /*
* Set the TOS of a socket protocol independently. * Set the TOS of a socket protocol independently.
* *
* Using SOL_SOCKET / SO_PRIORITY might be a protocol independent way to * Using SOL_SOCKET / SO_PRIORITY might be a protocol independent way to
* set this. See socket(7) for details. * set this. See socket(7) for details.
*/ */
static int ping_set_qos (pingobj_t *obj, pinghost_t *ph, uint8_t qos) static int ping_set_qos (pingobj_t *obj, uint8_t qos)
{ {
int ret = EINVAL; int ret = 0;
char errbuf[PING_ERRMSG_LEN]; char errbuf[PING_ERRMSG_LEN];
if (ph->addrfamily == AF_INET) if (obj->fd4 != -1)
{ {
dprintf ("Setting TP_TOS to %#04"PRIx8"\n", qos); dprintf ("Setting TP_TOS to %#04"PRIx8"\n", qos);
ret = setsockopt (ph->fd, IPPROTO_IP, IP_TOS, if (setsockopt (obj->fd4, IPPROTO_IP, IP_TOS,
&qos, sizeof (qos)); &qos, sizeof (qos)))
if (ret != 0)
{ {
ret = errno; ret = errno;
ping_set_error (obj, "ping_set_qos", ping_set_error (obj, "ping_set_qos",
sstrerror (ret, errbuf, sizeof (errbuf))) ; sstrerror (ret, errbuf, sizeof (errbuf))) ;
dprintf ("Setting TP_TOS failed: %s\n", errbuf); dprintf ("Setting TP_TOS failed: %s\n", errbuf);
} }
} }
else if (ph->addrfamily == AF_INET6)
if (obj->fd6 != -1)
{ {
/* IPV6_TCLASS requires an "int". */ /* IPV6_TCLASS requires an "int". */
int tmp = (int) qos; int tmp = (int) qos;
dprintf ("Setting IPV6_TCLASS to %#04"PRIx8" (%i)\n", qos, tmp); dprintf ("Setting IPV6_TCLASS to %#04"PRIx8" (%i)\n", qos, tmp);
ret = setsockopt (ph->fd, IPPROTO_IPV6, IPV6_TCLASS, if (setsockopt (obj->fd6, IPPROTO_IPV6, IPV6_TCLASS,
&tmp, sizeof (tmp)); &tmp, sizeof (tmp)))
if (ret != 0)
{ {
ret = errno; ret = errno;
ping_set_error (obj, "ping_set_qos", ping_set_error (obj, "ping_set_qos",
sstrerror (ret, errbuf, sizeof (errbuf))) ; sstrerror (ret, errbuf, sizeof (errbuf))) ;
dprintf ("Setting IPV6_TCLASS failed: %s\n", errbuf); dprintf ("Setting IPV6_TCLASS failed: %s\n", errbuf);
} }
} }
return (ret); return (ret);
} }
skipping to change at line 1092 skipping to change at line 951
ph = (pinghost_t *) malloc (ph_size); ph = (pinghost_t *) malloc (ph_size);
if (ph == NULL) if (ph == NULL)
return (NULL); return (NULL);
memset (ph, '\0', ph_size); memset (ph, '\0', ph_size);
ph->timer = (struct timeval *) (ph + 1); ph->timer = (struct timeval *) (ph + 1);
ph->addr = (struct sockaddr_storage *) (ph->timer + 1); ph->addr = (struct sockaddr_storage *) (ph->timer + 1);
ph->addrlen = sizeof (struct sockaddr_storage); ph->addrlen = sizeof (struct sockaddr_storage);
ph->fd = -1;
ph->latency = -1.0; ph->latency = -1.0;
ph->dropped = 0; ph->dropped = 0;
ph->ident = ping_get_ident () & 0xFFFF; ph->ident = ping_get_ident () & 0xFFFF;
return (ph); return (ph);
} }
static void ping_free (pinghost_t *ph) static void ping_free (pinghost_t *ph)
{ {
if (ph->fd >= 0) if (ph == NULL)
close (ph->fd); return;
if (ph->username != NULL) free (ph->username);
free (ph->username); free (ph->hostname);
free (ph->data);
if (ph->hostname != NULL) free (ph);
free (ph->hostname); }
if (ph->data != NULL) /* ping_open_socket opens, initializes and returns a new raw socket to use for
free (ph->data); * ICMPv4 or ICMPv6 packets. addrfam must be either AF_INET or AF_INET6. On
* error, -1 is returned and obj->errmsg is set appropriately. */
static int ping_open_socket(pingobj_t *obj, int addrfam)
{
int fd;
if (addrfam == AF_INET6)
{
fd = socket(addrfam, SOCK_RAW, IPPROTO_ICMPV6);
}
else if (addrfam == AF_INET)
{
fd = socket(addrfam, SOCK_RAW, IPPROTO_ICMP);
}
else /* this should not happen */
{
ping_set_error (obj, "ping_open_socket", "Unknown address family"
);
dprintf ("Unknown address family: %i\n", addrfam);
return -1;
}
free (ph); if (fd == -1)
{
ping_set_errno (obj, errno);
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("socket: %s\n",
sstrerror (errno, errbuf, sizeof (errbuf)));
#endif
return -1;
}
else if (fd >= FD_SETSIZE)
{
ping_set_errno (obj, EMFILE);
dprintf ("socket(2) returned file descriptor %d, which is above t
he file "
"descriptor limit for select(2) (FD_SETSIZE = %d)\n",
fd, FD_SETSIZE);
close (fd);
return -1;
}
if (obj->srcaddr != NULL)
{
assert (obj->srcaddrlen > 0);
assert (obj->srcaddrlen <= sizeof (struct sockaddr_storage));
if (bind (fd, obj->srcaddr, obj->srcaddrlen) == -1)
{
ping_set_errno (obj, errno);
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("bind: %s\n",
sstrerror (errno, errbuf, sizeof (errbuf)
));
#endif
close (fd);
return -1;
}
}
#ifdef SO_BINDTODEVICE
if (obj->device != NULL)
{
if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE,
obj->device, strlen (obj->device) + 1) != 0)
{
ping_set_errno (obj, errno);
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("setsockopt (SO_BINDTODEVICE): %s\n",
sstrerror (errno, errbuf, sizeof (errbuf)
));
#endif
close (fd);
return -1;
}
}
#endif /* SO_BINDTODEVICE */
#ifdef SO_MARK
if (obj->set_mark)
{
if (setsockopt(fd, SOL_SOCKET, SO_MARK,
&obj->mark, sizeof(obj->mark)) != 0)
{
ping_set_errno (obj, errno);
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("setsockopt (SO_MARK): %s\n",
sstrerror (errno, errbuf, sizeof (errbuf)));
#endif
close (fd);
return -1;
}
}
#endif
#ifdef SO_TIMESTAMP
if (1) /* {{{ */
{
int status = setsockopt (fd, SOL_SOCKET, SO_TIMESTAMP,
&(int){1}, sizeof(int));
if (status != 0)
{
ping_set_errno (obj, errno);
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("setsockopt (SO_TIMESTAMP): %s\n",
sstrerror (errno, errbuf, sizeof (errbuf)
));
#endif
close (fd);
return -1;
}
} /* }}} if (1) */
#endif /* SO_TIMESTAMP */
if (addrfam == AF_INET)
{
#ifdef IP_RECVTOS
/* Enable receiving the TOS field */
setsockopt (fd, IPPROTO_IP, IP_RECVTOS, &(int){1}, sizeof(int));
#endif /* IP_RECVTOS */
/* Enable receiving the TTL field */
setsockopt (fd, IPPROTO_IP, IP_RECVTTL, &(int){1}, sizeof(int));
}
#if defined(IPV6_RECVHOPLIMIT) || defined(IPV6_RECVTCLASS)
else if (addrfam == AF_INET6)
{
# if defined(IPV6_RECVHOPLIMIT)
/* For details see RFC 3542, section 6.3. */
setsockopt (fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
&(int){1}, sizeof(int));
# endif /* IPV6_RECVHOPLIMIT */
# if defined(IPV6_RECVTCLASS)
/* For details see RFC 3542, section 6.5. */
setsockopt (fd, IPPROTO_IPV6, IPV6_RECVTCLASS,
&(int){1}, sizeof(int));
# endif /* IPV6_RECVTCLASS */
}
#endif /* IPV6_RECVHOPLIMIT || IPV6_RECVTCLASS */
return fd;
} }
/* /*
* public methods * public methods
*/ */
const char *ping_get_error (pingobj_t *obj) const char *ping_get_error (pingobj_t *obj)
{ {
if (obj == NULL) if (obj == NULL)
return (NULL); return (NULL);
return (obj->errmsg); return (obj->errmsg);
} }
pingobj_t *ping_construct (void) pingobj_t *ping_construct (void)
{ {
pingobj_t *obj; pingobj_t *obj;
if ((obj = (pingobj_t *) malloc (sizeof (pingobj_t))) == NULL) if ((obj = malloc (sizeof (*obj))) == NULL)
return (NULL); return (NULL);
memset (obj, 0, sizeof (pingobj_t)); memset (obj, 0, sizeof (*obj));
obj->timeout = PING_DEF_TIMEOUT; obj->timeout = PING_DEF_TIMEOUT;
obj->ttl = PING_DEF_TTL; obj->ttl = PING_DEF_TTL;
obj->addrfamily = PING_DEF_AF; obj->addrfamily = PING_DEF_AF;
obj->data = strdup (PING_DEF_DATA); obj->data = strdup (PING_DEF_DATA);
obj->qos = 0; obj->qos = 0;
obj->fd4 = -1;
obj->fd6 = -1;
return (obj); return (obj);
} }
void ping_destroy (pingobj_t *obj) void ping_destroy (pingobj_t *obj)
{ {
pinghost_t *current; pinghost_t *current;
pinghost_t *next;
if (obj == NULL) if (obj == NULL)
return; return;
current = obj->head; current = obj->head;
next = NULL;
while (current != NULL) while (current != NULL)
{ {
next = current->next; pinghost_t *next = current->next;
ping_free (current); ping_free (current);
current = next; current = next;
} }
if (obj->data != NULL) free (obj->data);
free (obj->data); free (obj->srcaddr);
free (obj->device);
if (obj->srcaddr != NULL) if (obj->fd4 != -1)
free (obj->srcaddr); close(obj->fd4);
if (obj->device != NULL) if (obj->fd6 != -1)
free (obj->device); close(obj->fd6);
free (obj); free (obj);
return; return;
} }
int ping_setopt (pingobj_t *obj, int option, void *value) int ping_setopt (pingobj_t *obj, int option, void *value)
{ {
int ret = 0; int ret = 0;
if ((obj == NULL) || (value == NULL)) if ((obj == NULL) || (value == NULL))
return (-1); return (-1);
switch (option) switch (option)
{ {
case PING_OPT_QOS: case PING_OPT_QOS:
{ {
pinghost_t *ph;
obj->qos = *((uint8_t *) value); obj->qos = *((uint8_t *) value);
for (ph = obj->head; ph != NULL; ph = ph->next) ret = ping_set_qos (obj, obj->qos);
ping_set_qos (obj, ph, obj->qos);
break; break;
} }
case PING_OPT_TIMEOUT: case PING_OPT_TIMEOUT:
obj->timeout = *((double *) value); obj->timeout = *((double *) value);
if (obj->timeout < 0.0) if (obj->timeout < 0.0)
{ {
obj->timeout = PING_DEF_TIMEOUT; obj->timeout = PING_DEF_TIMEOUT;
ret = -1; ret = -1;
} }
break; break;
case PING_OPT_TTL: case PING_OPT_TTL:
obj->ttl = *((int *) value); ret = *((int *) value);
if ((obj->ttl < 1) || (obj->ttl > 255)) if ((ret < 1) || (ret > 255))
{ {
obj->ttl = PING_DEF_TTL; obj->ttl = PING_DEF_TTL;
ret = -1; ret = -1;
} }
else else
{ {
pinghost_t *ph; obj->ttl = ret;
ret = ping_set_ttl (obj, obj->ttl);
for (ph = obj->head; ph != NULL; ph = ph->next)
ping_set_ttl (ph, obj->ttl);
} }
break; break;
case PING_OPT_AF: case PING_OPT_AF:
obj->addrfamily = *((int *) value); obj->addrfamily = *((int *) value);
if ((obj->addrfamily != AF_UNSPEC) if ((obj->addrfamily != AF_UNSPEC)
&& (obj->addrfamily != AF_INET) && (obj->addrfamily != AF_INET)
&& (obj->addrfamily != AF_INET6)) && (obj->addrfamily != AF_INET6))
{ {
obj->addrfamily = PING_DEF_AF; obj->addrfamily = PING_DEF_AF;
skipping to change at line 1350 skipping to change at line 1341
default: default:
ret = -2; ret = -2;
} /* switch (option) */ } /* switch (option) */
return (ret); return (ret);
} /* int ping_setopt */ } /* int ping_setopt */
int ping_send (pingobj_t *obj) int ping_send (pingobj_t *obj)
{ {
if (obj == NULL) pinghost_t *ptr;
struct timeval endtime;
struct timeval nowtime;
struct timeval timeout;
_Bool need_ipv4_socket = 0;
_Bool need_ipv6_socket = 0;
for (ptr = obj->head; ptr != NULL; ptr = ptr->next)
{
ptr->latency = -1.0;
ptr->recv_ttl = -1;
if (ptr->addrfamily == AF_INET)
need_ipv4_socket = 1;
else if (ptr->addrfamily == AF_INET6)
need_ipv6_socket = 1;
}
if (!need_ipv4_socket && !need_ipv6_socket)
{
ping_set_error (obj, "ping_send", "No hosts to ping");
return (-1); return (-1);
}
if (need_ipv4_socket && obj->fd4 == -1)
{
obj->fd4 = ping_open_socket(obj, AF_INET);
if (obj->fd4 == -1)
return (-1);
ping_set_ttl (obj, obj->ttl);
ping_set_qos (obj, obj->qos);
}
if (need_ipv6_socket && obj->fd6 == -1)
{
obj->fd6 = ping_open_socket(obj, AF_INET6);
if (obj->fd6 == -1)
return (-1);
ping_set_ttl (obj, obj->ttl);
ping_set_qos (obj, obj->qos);
}
if (ping_send_all (obj) < 0) if (gettimeofday (&nowtime, NULL) == -1)
{
ping_set_errno (obj, errno);
return (-1); return (-1);
}
return (ping_receive_all (obj)); /* Set up timeout */
} timeout.tv_sec = (time_t) obj->timeout;
timeout.tv_usec = (suseconds_t) (1000000 * (obj->timeout - ((double) time
out.tv_sec)));
dprintf ("Set timeout to %i.%06i seconds\n",
(int) timeout.tv_sec,
(int) timeout.tv_usec);
ping_timeval_add (&nowtime, &timeout, &endtime);
/* host_to_ping points to the host to which to send the next ping. The
* pointer is advanced to the next host in the linked list after the
* ping has been sent. If host_to_ping is NULL, no more pings need to be
* send out. */
pinghost_t *host_to_ping = obj->head;
/* pings_in_flight is the number of hosts we sent a "ping" to but didn't
* receive a "pong" yet. */
int pings_in_flight = 0;
/* pongs_received is the number of echo replies received. Unless there
* is an error, this is used as the return value of ping_send(). */
int pongs_received = 0;
int error_count = 0;
while (pings_in_flight > 0 || host_to_ping != NULL)
{
fd_set read_fds;
fd_set write_fds;
int write_fd = -1;
int max_fd = -1;
FD_ZERO (&read_fds);
FD_ZERO (&write_fds);
if (obj->fd4 != -1)
{
FD_SET(obj->fd4, &read_fds);
if (host_to_ping != NULL && host_to_ping->addrfamily == A
F_INET)
write_fd = obj->fd4;
if (max_fd < obj->fd4)
max_fd = obj->fd4;
}
if (obj->fd6 != -1)
{
FD_SET(obj->fd6, &read_fds);
if (host_to_ping != NULL && host_to_ping->addrfamily == A
F_INET6)
write_fd = obj->fd6;
if (max_fd < obj->fd6)
max_fd = obj->fd6;
}
if (write_fd != -1)
FD_SET(write_fd, &write_fds);
assert (max_fd != -1);
assert (max_fd < FD_SETSIZE);
if (gettimeofday (&nowtime, NULL) == -1)
{
ping_set_errno (obj, errno);
return (-1);
}
if (ping_timeval_sub (&endtime, &nowtime, &timeout) == -1)
break;
dprintf ("Waiting on %i sockets for %u.%06u seconds\n",
((obj->fd4 != -1) ? 1 : 0) + ((obj->fd6 != -1) ?
1 : 0),
(unsigned) timeout.tv_sec,
(unsigned) timeout.tv_usec);
int status = select (max_fd + 1, &read_fds, &write_fds, NULL, &ti
meout);
if (gettimeofday (&nowtime, NULL) == -1)
{
ping_set_errno (obj, errno);
return (-1);
}
if (status == -1)
{
ping_set_errno (obj, errno);
dprintf ("select: %s\n", obj->errmsg);
return (-1);
}
else if (status == 0)
{
dprintf ("select timed out\n");
pinghost_t *ph;
for (ph = obj->head; ph != NULL; ph = ph->next)
if (ph->latency < 0.0)
ph->dropped++;
break;
}
/* first, check if we can receive a reply ... */
if (obj->fd6 != -1 && FD_ISSET (obj->fd6, &read_fds))
{
if (ping_receive_one (obj, &nowtime, AF_INET6) == 0)
{
pings_in_flight--;
pongs_received++;
}
continue;
}
if (obj->fd4 != -1 && FD_ISSET (obj->fd4, &read_fds))
{
if (ping_receive_one (obj, &nowtime, AF_INET) == 0)
{
pings_in_flight--;
pongs_received++;
}
continue;
}
/* ... and if no reply is available to read, continue sending
* out pings. */
/* this condition should always be true. We keep it for
* consistency with the read blocks above and just to be on the
* safe side. */
if (write_fd != -1 && FD_ISSET (write_fd, &write_fds))
{
if (ping_send_one (obj, host_to_ping, write_fd) == 0)
pings_in_flight++;
else
error_count++;
host_to_ping = host_to_ping->next;
continue;
}
} /* while (1) */
if (error_count)
return (-1 * error_count);
return (pongs_received);
} /* int ping_send */
static pinghost_t *ping_host_search (pinghost_t *ph, const char *host) static pinghost_t *ping_host_search (pinghost_t *ph, const char *host)
{ {
while (ph != NULL) while (ph != NULL)
{ {
if (strcasecmp (ph->username, host) == 0) if (strcasecmp (ph->username, host) == 0)
break; break;
ph = ph->next; ph = ph->next;
} }
skipping to change at line 1451 skipping to change at line 1626
gai_strerror (ai_return)); gai_strerror (ai_return));
ping_free (ph); ping_free (ph);
return (-1); return (-1);
} }
if (ai_list == NULL) if (ai_list == NULL)
ping_set_error (obj, "getaddrinfo", "No hosts returned"); ping_set_error (obj, "getaddrinfo", "No hosts returned");
for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
{ {
ph->fd = -1;
if (ai_ptr->ai_family == AF_INET) if (ai_ptr->ai_family == AF_INET)
{ {
ai_ptr->ai_socktype = SOCK_RAW; ai_ptr->ai_socktype = SOCK_RAW;
ai_ptr->ai_protocol = IPPROTO_ICMP; ai_ptr->ai_protocol = IPPROTO_ICMP;
} }
else if (ai_ptr->ai_family == AF_INET6) else if (ai_ptr->ai_family == AF_INET6)
{ {
ai_ptr->ai_socktype = SOCK_RAW; ai_ptr->ai_socktype = SOCK_RAW;
ai_ptr->ai_protocol = IPPROTO_ICMPV6; ai_ptr->ai_protocol = IPPROTO_ICMPV6;
} }
skipping to change at line 1475 skipping to change at line 1648
char errmsg[PING_ERRMSG_LEN]; char errmsg[PING_ERRMSG_LEN];
snprintf (errmsg, PING_ERRMSG_LEN, "Unknown `ai_family': %i", ai_ptr->ai_family); snprintf (errmsg, PING_ERRMSG_LEN, "Unknown `ai_family': %i", ai_ptr->ai_family);
errmsg[PING_ERRMSG_LEN - 1] = '\0'; errmsg[PING_ERRMSG_LEN - 1] = '\0';
dprintf ("%s", errmsg); dprintf ("%s", errmsg);
ping_set_error (obj, "getaddrinfo", errmsg); ping_set_error (obj, "getaddrinfo", errmsg);
continue; continue;
} }
/* TODO: Move this to a static function `ping_open_socket' and
* call it whenever the socket dies. */
ph->fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->
ai_protocol);
if (ph->fd == -1)
{
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("socket: %s\n",
sstrerror (errno, errbuf, sizeof (errbuf)
));
#endif
ping_set_errno (obj, errno);
continue;
}
if (obj->srcaddr != NULL)
{
assert (obj->srcaddrlen > 0);
assert (obj->srcaddrlen <= sizeof (struct sockaddr_storag
e));
if (bind (ph->fd, obj->srcaddr, obj->srcaddrlen) == -1)
{
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("bind: %s\n",
sstrerror (errno, errbuf, sizeof
(errbuf)));
#endif
ping_set_errno (obj, errno);
close (ph->fd);
ph->fd = -1;
continue;
}
}
#ifdef SO_BINDTODEVICE
if (obj->device != NULL)
{
if (setsockopt (ph->fd, SOL_SOCKET, SO_BINDTODEVICE,
obj->device, strlen (obj->device) + 1) !=
0)
{
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("setsockopt (SO_BINDTODEVICE): %s\n",
sstrerror (errno, errbuf, sizeof
(errbuf)));
#endif
ping_set_errno (obj, errno);
close (ph->fd);
ph->fd = -1;
continue;
}
}
#endif /* SO_BINDTODEVICE */
#ifdef SO_MARK
if(obj->set_mark)
{
if(setsockopt(ph->fd, SOL_SOCKET, SO_MARK, &(obj->mark),
sizeof(obj->mark)) != 0)
{
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("setsockopt (SO_MARK): %s\n",
sstrerror (errno, errbuf, sizeof
(errbuf)));
#endif
ping_set_errno (obj, errno);
close (ph->fd);
ph->fd = -1;
continue;
}
}
#endif
#ifdef SO_TIMESTAMP
if (1) /* {{{ */
{
int status;
int opt = 1;
status = setsockopt (ph->fd,
SOL_SOCKET, SO_TIMESTAMP,
&opt, sizeof (opt));
if (status != 0)
{
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
dprintf ("setsockopt (SO_TIMESTAMP): %s\n",
sstrerror (errno, errbuf, sizeof
(errbuf)));
#endif
ping_set_errno (obj, errno);
close (ph->fd);
ph->fd = -1;
continue;
}
} /* }}} if (1) */
#endif /* SO_TIMESTAMP */
assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen); assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen);
memset (ph->addr, '\0', sizeof (struct sockaddr_storage)); memset (ph->addr, '\0', sizeof (struct sockaddr_storage));
memcpy (ph->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen); memcpy (ph->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
ph->addrlen = ai_ptr->ai_addrlen; ph->addrlen = ai_ptr->ai_addrlen;
ph->addrfamily = ai_ptr->ai_family; ph->addrfamily = ai_ptr->ai_family;
#ifdef AI_CANONNAME #ifdef AI_CANONNAME
if ((ai_ptr->ai_canonname != NULL) if ((ai_ptr->ai_canonname != NULL)
&& (strcmp (ph->hostname, ai_ptr->ai_canonname) ! = 0)) && (strcmp (ph->hostname, ai_ptr->ai_canonname) ! = 0))
{ {
skipping to change at line 1593 skipping to change at line 1675
{ {
/* strdup failed, falling back to old hostname */ /* strdup failed, falling back to old hostname */
ph->hostname = old_hostname; ph->hostname = old_hostname;
} }
else if (old_hostname != NULL) else if (old_hostname != NULL)
{ {
free (old_hostname); free (old_hostname);
} }
} }
#endif /* AI_CANONNAME */ #endif /* AI_CANONNAME */
if (ph->addrfamily == AF_INET)
{
int opt;
#ifdef IP_RECVTOS
/* Enable receiving the TOS field */
opt = 1;
setsockopt (ph->fd, IPPROTO_IP, IP_RECVTOS,
&opt, sizeof (opt));
#endif /* IP_RECVTOS */
/* Enable receiving the TTL field */
opt = 1;
setsockopt (ph->fd, IPPROTO_IP, IP_RECVTTL,
&opt, sizeof (opt));
}
#if defined(IPV6_RECVHOPLIMIT) || defined(IPV6_RECVTCLASS)
else if (ph->addrfamily == AF_INET6)
{
int opt;
# if defined(IPV6_RECVHOPLIMIT)
/* For details see RFC 3542, section 6.3. */
opt = 1;
setsockopt (ph->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
&opt, sizeof (opt));
# endif /* IPV6_RECVHOPLIMIT */
# if defined(IPV6_RECVTCLASS)
/* For details see RFC 3542, section 6.5. */
opt = 1;
setsockopt (ph->fd, IPPROTO_IPV6, IPV6_RECVTCLASS,
&opt, sizeof (opt));
# endif /* IPV6_RECVTCLASS */
}
#endif /* IPV6_RECVHOPLIMIT || IPV6_RECVTCLASS */
break;
} /* for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) */ } /* for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) */
freeaddrinfo (ai_list); freeaddrinfo (ai_list);
if (ph->fd < 0)
{
ping_free (ph);
return (-1);
}
/* /*
* Adding in the front is much easier, but then the iterator will * Adding in the front is much easier, but then the iterator will
* return the host that was added last as first host. That's just not * return the host that was added last as first host. That's just not
* nice. -octo * nice. -octo
*/ */
if (obj->head == NULL) if (obj->head == NULL)
{ {
obj->head = ph; obj->head = ph;
} }
else else
skipping to change at line 1663 skipping to change at line 1700
pinghost_t *hptr; pinghost_t *hptr;
hptr = obj->head; hptr = obj->head;
while (hptr->next != NULL) while (hptr->next != NULL)
hptr = hptr->next; hptr = hptr->next;
assert ((hptr != NULL) && (hptr->next == NULL)); assert ((hptr != NULL) && (hptr->next == NULL));
hptr->next = ph; hptr->next = ph;
} }
ping_set_ttl (ph, obj->ttl); ph->table_next = obj->table[ph->ident % PING_TABLE_LEN];
ping_set_qos (obj, ph, obj->qos); obj->table[ph->ident % PING_TABLE_LEN] = ph;
return (0); return (0);
} /* int ping_host_add */ } /* int ping_host_add */
int ping_host_remove (pingobj_t *obj, const char *host) int ping_host_remove (pingobj_t *obj, const char *host)
{ {
pinghost_t *pre, *cur; pinghost_t *pre, *cur, *target;
if ((obj == NULL) || (host == NULL)) if ((obj == NULL) || (host == NULL))
return (-1); return (-1);
pre = NULL; pre = NULL;
cur = obj->head; cur = obj->head;
while (cur != NULL) while (cur != NULL)
{ {
if (strcasecmp (host, cur->username) == 0) if (strcasecmp (host, cur->username) == 0)
skipping to change at line 1699 skipping to change at line 1736
{ {
ping_set_error (obj, "ping_host_remove", "Host not found"); ping_set_error (obj, "ping_host_remove", "Host not found");
return (-1); return (-1);
} }
if (pre == NULL) if (pre == NULL)
obj->head = cur->next; obj->head = cur->next;
else else
pre->next = cur->next; pre->next = cur->next;
target = cur;
pre = NULL;
cur = obj->table[target->ident % PING_TABLE_LEN];
while (cur != NULL)
{
if (cur == target)
break;
pre = cur;
cur = cur->table_next;
}
if (cur == NULL)
{
ping_set_error(obj, "ping_host_remove", "Host not found (T)");
ping_free(target);
return (-1);
}
if (pre == NULL)
obj->table[target->ident % PING_TABLE_LEN] = cur->table_next;
else
pre->table_next = cur->table_next;
ping_free (cur); ping_free (cur);
return (0); return (0);
} }
pingobj_iter_t *ping_iterator_get (pingobj_t *obj) pingobj_iter_t *ping_iterator_get (pingobj_t *obj)
{ {
if (obj == NULL) if (obj == NULL)
return (NULL); return (NULL);
return ((pingobj_iter_t *) obj->head); return ((pingobj_iter_t *) obj->head);
} }
pingobj_iter_t *ping_iterator_next (pingobj_iter_t *iter) pingobj_iter_t *ping_iterator_next (pingobj_iter_t *iter)
{ {
if (iter == NULL) if (iter == NULL)
return (NULL); return (NULL);
return ((pingobj_iter_t *) iter->next); return ((pingobj_iter_t *) iter->next);
} }
int ping_iterator_count (pingobj_t *obj)
{
if (obj == NULL)
return 0;
int count = 0;
pingobj_iter_t *iter = obj->head;
while (iter) {
count++;
iter = iter->next;
}
return count;
}
int ping_iterator_get_info (pingobj_iter_t *iter, int info, int ping_iterator_get_info (pingobj_iter_t *iter, int info,
void *buffer, size_t *buffer_len) void *buffer, size_t *buffer_len)
{ {
int ret = EINVAL; int ret = EINVAL;
size_t orig_buffer_len = *buffer_len; size_t orig_buffer_len = *buffer_len;
if ((iter == NULL) || (buffer_len == NULL)) if ((iter == NULL) || (buffer_len == NULL))
return (-1); return (-1);
 End of changes. 96 change blocks. 
456 lines changed or deleted 530 lines changed or added

Home  |  About  |  All  |  Newest  |  Fossies Dox  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTPS