diff --git a/src/liboping.c b/src/liboping.c
index 9fad0c2dc09dbabf353a1fa9f28772c72ce28d6f..6ffb482c919b430aec964c909d8dfb53103370ff 100644 (file)
--- a/src/liboping.c
+++ b/src/liboping.c
/**
* Object oriented C module to send ICMP and ICMPv6 `echo's.
- * Copyright (C) 2006 Florian octo Forster <octo at verplant.org>
+ * Copyright (C) 2006-2008 Florian octo Forster <octo at verplant.org>
*
* This program 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 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; only version 2 of the License is
+ * applicable.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
+# include <stdint.h>
+# include <inttypes.h>
# include <errno.h>
# include <assert.h>
#else
struct pinghost
{
+ /* username: name passed in by the user */
+ char *username;
+ /* hostname: name returned by the reverse lookup */
char *hostname;
struct sockaddr_storage *addr;
socklen_t addrlen;
int sequence;
struct timeval *timer;
double latency;
+ uint32_t dropped;
char *data;
void *context;
static int ping_timeval_sub (struct timeval *tv1, struct timeval *tv2,
struct timeval *res)
{
-
if ((tv1->tv_sec < tv2->tv_sec)
|| ((tv1->tv_sec == tv2->tv_sec)
&& (tv1->tv_usec < tv2->tv_usec)))
res->tv_sec = tv1->tv_sec - tv2->tv_sec;
res->tv_usec = tv1->tv_usec - tv2->tv_usec;
- assert ((res->tv_sec > 0) || ((res->tv_sec == 0) && (res->tv_usec > 0)));
+ assert ((res->tv_sec > 0) || ((res->tv_sec == 0) && (res->tv_usec >= 0)));
while (res->tv_usec < 0)
{
@@ -288,6 +293,22 @@ static pinghost_t *ping_receive_ipv4 (pinghost_t *ph, char *buffer, size_t buffe
return (ptr);
}
+#ifndef ICMP6_ECHO_REQUEST
+# ifdef ICMP6_ECHO /* AIX netinet/ip6_icmp.h */
+# define ICMP6_ECHO_REQUEST ICMP6_ECHO
+# else
+# define ICMP6_ECHO_REQUEST 128
+# endif
+#endif
+
+#ifndef ICMP6_ECHO_REPLY
+# ifdef ICMP6_ECHOREPLY /* AIX netinet/ip6_icmp.h */
+# define ICMP6_ECHO_REPLY ICMP6_ECHOREPLY
+# else
+# define ICMP6_ECHO_REPLY 129
+# endif
+#endif
+
static pinghost_t *ping_receive_ipv6 (pinghost_t *ph, char *buffer, size_t buffer_len)
{
struct icmp6_hdr *icmp_hdr;
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;
}
(struct sockaddr *) ph->addr, ph->addrlen);
if (ret < 0)
+ {
+#if defined(EHOSTUNREACH)
+ if (errno == EHOSTUNREACH)
+ return (0);
+#endif
+#if defined(ENETUNREACH)
+ if (errno == ENETUNREACH)
+ return (0);
+#endif
ping_set_error (obj, "sendto", strerror (errno));
+ }
return (ret);
}
ph->addr = (struct sockaddr_storage *) (ph->timer + 1);
ph->addrlen = sizeof (struct sockaddr_storage);
+ ph->fd = -1;
ph->latency = -1.0;
+ ph->dropped = 0;
ph->ident = ping_get_ident () & 0xFFFF;
return (ph);
static void ping_free (pinghost_t *ph)
{
+ if (ph->fd >= 0)
+ close (ph->fd);
+
+ if (ph->username != NULL)
+ free (ph->username);
+
if (ph->hostname != NULL)
free (ph->hostname);
if (status != 0)
{
ping_set_error (obj, "getaddrinfo",
- status == EAI_SYSTEM
- ? strerror (errno)
- : gai_strerror (status));
+#if defined(EAI_SYSTEM)
+ (status == EAI_SYSTEM)
+ ? strerror (errno) :
+#endif
+ gai_strerror (status));
ret = -1;
break;
}
{
while (ph != NULL)
{
- if (strcasecmp (ph->hostname, host) == 0)
+ if (strcasecmp (ph->username, host) == 0)
break;
ph = ph->next;
return (-1);
}
+ if ((ph->username = strdup (host)) == NULL)
+ {
+ dprintf ("Out of memory!\n");
+ ping_set_error (obj, "strdup", strerror (errno));
+ ping_free (ph);
+ return (-1);
+ }
+
if ((ph->hostname = strdup (host)) == NULL)
{
dprintf ("Out of memory!\n");
{
dprintf ("getaddrinfo failed\n");
ping_set_error (obj, "getaddrinfo",
- (ai_return == EAI_SYSTEM)
- ? strerror (errno)
- : gai_strerror (ai_return));
+#if defined(EAI_SYSTEM)
+ (ai_return == EAI_SYSTEM)
+ ? strerror (errno) :
+#endif
+ gai_strerror (ai_return));
ping_free (ph);
return (-1);
}
continue;
}
-/*
- * The majority vote of operating systems has decided that you don't need to
- * bind here. This code should be reactivated to bind to a specific address,
- * though. See the `-I' option of `ping(1)' (GNU). -octo
- */
-#if 0
- if (bind (ph->fd, (struct sockaddr *) &sockaddr, sockaddr_len) == -1)
+ if (obj->srcaddr != NULL)
{
- dprintf ("bind: %s\n", strerror (errno));
- ping_set_error (obj, "bind", strerror (errno));
- close (ph->fd);
- ph->fd = -1;
- continue;
+ assert (obj->srcaddrlen > 0);
+ assert (obj->srcaddrlen <= sizeof (struct sockaddr_storage));
+
+ if (bind (ph->fd, (struct sockaddr *) obj->srcaddr, obj->srcaddrlen) == -1)
+ {
+ dprintf ("bind: %s\n", strerror (errno));
+ ping_set_error (obj, "bind", strerror (errno));
+ close (ph->fd);
+ ph->fd = -1;
+ continue;
+ }
}
-#endif
assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen);
memset (ph->addr, '\0', sizeof (struct sockaddr_storage));
if (ph->fd < 0)
{
- free (ph->hostname);
- free (ph);
+ ping_free (ph);
return (-1);
}
while (cur != NULL)
{
- if (strcasecmp (host, cur->hostname))
+ if (strcasecmp (host, cur->username) == 0)
break;
pre = cur;
else
pre->next = cur->next;
- if (cur->fd >= 0)
- close (cur->fd);
-
ping_free (cur);
return (0);
switch (info)
{
- case PING_INFO_HOSTNAME:
+ case PING_INFO_USERNAME:
ret = ENOMEM;
- *buffer_len = strlen (iter->hostname);
+ *buffer_len = strlen (iter->username) + 1;
if (orig_buffer_len <= *buffer_len)
break;
/* Since (orig_buffer_len > *buffer_len) `strncpy'
* will copy `*buffer_len' and pad the rest of
* `buffer' with null-bytes */
+ strncpy (buffer, iter->username, orig_buffer_len);
+ ret = 0;
+ break;
+
+ case PING_INFO_HOSTNAME:
+ ret = ENOMEM;
+ *buffer_len = strlen (iter->hostname) + 1;
+ if (orig_buffer_len < *buffer_len)
+ break;
+ /* Since (orig_buffer_len > *buffer_len) `strncpy'
+ * will copy `*buffer_len' and pad the rest of
+ * `buffer' with null-bytes */
strncpy (buffer, iter->hostname, orig_buffer_len);
ret = 0;
break;
#endif
)
ret = ENOMEM;
+#if defined(EAI_SYSTEM)
else if (ret == EAI_SYSTEM)
- /* XXX: Not thread-safe! */
ret = errno;
+#endif
else
ret = EINVAL;
}
ret = 0;
break;
+ case PING_INFO_DROPPED:
+ ret = ENOMEM;
+ *buffer_len = sizeof (uint32_t);
+ if (orig_buffer_len < sizeof (uint32_t))
+ break;
+ *((uint32_t *) buffer) = iter->dropped;
+ ret = 0;
+ break;
+
case PING_INFO_SEQUENCE:
ret = ENOMEM;
*buffer_len = sizeof (unsigned int);
}
return (ret);
-}
+} /* ping_iterator_get_info */
void *ping_iterator_get_context (pingobj_iter_t *iter)
{