/**
* Object oriented C module to send ICMP and ICMPv6 `echo's.
- * Copyright (C) 2006 Florian octo Forster <octo at verplant.org>
+ * Copyright (C) 2006-2009 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 <inttypes.h>
# include <errno.h>
# include <assert.h>
#else
# error "You don't have the standard C99 header files installed"
#endif /* STDC_HEADERS */
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#if HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
+
#if HAVE_NETDB_H
# include <netdb.h>
#endif
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;
+ int recv_ttl;
char *data;
void *context;
struct pingobj
{
- double timeout;
- int ttl;
- int addrfamily;
- char *data;
+ double timeout;
+ int ttl;
+ int addrfamily;
+ char *data;
+
+ struct sockaddr *srcaddr;
+ socklen_t srcaddrlen;
- char errmsg[PING_ERRMSG_LEN];
+ char errmsg[PING_ERRMSG_LEN];
- pinghost_t *head;
+ pinghost_t *head;
};
/*
* private (static) functions
*/
+/* Even though Posix requires "strerror_r" to return an "int",
+ * some systems (e.g. the GNU libc) return a "char *" _and_
+ * ignore the second argument ... -tokkee */
+static char *sstrerror (int errnum, char *buf, size_t buflen)
+{
+ buf[0] = 0;
+
+#if !HAVE_STRERROR_R
+ {
+ snprintf (buf, buflen, "Error %i (%#x)", errnum, errnum);
+ }
+/* #endif !HAVE_STRERROR_R */
+
+#elif STRERROR_R_CHAR_P
+ {
+ char *temp;
+ temp = strerror_r (errnum, buf, buflen);
+ if (buf[0] == 0)
+ {
+ if ((temp != NULL) && (temp != buf) && (temp[0] != 0))
+ strncpy (buf, temp, buflen);
+ else
+ strncpy (buf, "strerror_r did not return "
+ "an error message", buflen);
+ }
+ }
+/* #endif STRERROR_R_CHAR_P */
+
+#else
+ if (strerror_r (errnum, buf, buflen) != 0)
+ {
+ snprintf (buf, buflen, "Error %i (%#x); "
+ "Additionally, strerror_r failed.",
+ errnum, errnum);
+ }
+#endif /* STRERROR_R_CHAR_P */
+
+ buf[buflen - 1] = 0;
+
+ return (buf);
+} /* char *sstrerror */
+
static void ping_set_error (pingobj_t *obj, const char *function,
const char *message)
{
- snprintf (obj->errmsg, PING_ERRMSG_LEN, "%s: %s", function, message);
- obj->errmsg[PING_ERRMSG_LEN - 1] = '\0';
+ snprintf (obj->errmsg, sizeof (obj->errmsg),
+ "%s: %s", function, message);
+ obj->errmsg[sizeof (obj->errmsg) - 1] = 0;
+}
+
+static void ping_set_errno (pingobj_t *obj, int error_number)
+{
+ sstrerror (error_number, obj->errmsg, sizeof (obj->errmsg));
}
static int ping_timeval_add (struct timeval *tv1, struct timeval *tv2,
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)
{
ident, seq);
}
+ if (ptr != NULL)
+ ptr->recv_ttl = ip_hdr->ip_ttl;
+
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;
static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now)
{
- char buffer[4096];
- size_t buffer_len;
-
struct timeval diff;
-
pinghost_t *host = NULL;
+ int recv_ttl;
+
+ /*
+ * Set up the receive buffer..
+ */
+ struct msghdr msghdr;
+ struct cmsghdr *cmsg;
+ char payload_buffer[4096];
+ ssize_t payload_buffer_len;
+ char control_buffer[4096];
+ struct iovec payload_iovec;
+
+ memset (&payload_iovec, 0, sizeof (payload_iovec));
+ payload_iovec.iov_base = payload_buffer;
+ payload_iovec.iov_len = sizeof (payload_buffer);
+
+ memset (&msghdr, 0, sizeof (msghdr));
+ /* unspecified source address */
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+ /* output buffer vector, see readv(2) */
+ msghdr.msg_iov = &payload_iovec;
+ msghdr.msg_iovlen = 1;
+ /* output buffer for control messages */
+ msghdr.msg_control = control_buffer;
+ msghdr.msg_controllen = sizeof (control_buffer);
+ /* flags; this is an output only field.. */
+ msghdr.msg_flags = 0;
+#ifdef MSG_XPG4_2
+ msghdr.msg_flags |= MSG_XPG4_2;
+#endif
- struct sockaddr_storage sa;
- socklen_t sa_len;
-
- sa_len = sizeof (sa);
-
- buffer_len = recvfrom (fd, buffer, sizeof (buffer), 0,
- (struct sockaddr *) &sa, &sa_len);
- if (buffer_len == -1)
+ payload_buffer_len = recvmsg (fd, &msghdr, /* flags = */ 0);
+ if (payload_buffer_len < 0)
{
- dprintf ("recvfrom: %s\n", strerror (errno));
+#if WITH_DEBUG
+ char errbuf[PING_ERRMSG_LEN];
+ dprintf ("recvfrom: %s\n",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+#endif
return (-1);
}
+ dprintf ("Read %zi bytes from fd = %i\n", payload_buffer_len, fd);
+
+ /* Iterate over all auxiliary data in msghdr */
+ recv_ttl = -1;
+ ph->recv_ttl = -1;
+ for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR (&msghdr, cmsg))
+ {
+ if (ph->addrfamily == AF_INET) /* {{{ */
+ {
+ if (cmsg->cmsg_level != IPPROTO_IP)
+ continue;
- dprintf ("Read %u bytes from fd = %i\n", (unsigned int) buffer_len, fd);
+ if (cmsg->cmsg_type == IP_TTL)
+ {
+ memcpy (&recv_ttl, CMSG_DATA (cmsg),
+ sizeof (recv_ttl));
+ dprintf ("TTLv4 = %i;\n", recv_ttl);
+ }
+ else
+ {
+ dprintf ("Not handling option %i.\n",
+ cmsg->cmsg_type);
+ }
+ } /* }}} */
+ else if (ph->addrfamily == AF_INET6) /* {{{ */
+ {
+ if (cmsg->cmsg_level != IPPROTO_IPV6)
+ continue;
- if (sa.ss_family == AF_INET)
+ if (cmsg->cmsg_type == IPV6_HOPLIMIT)
+ {
+ memcpy (&recv_ttl, CMSG_DATA (cmsg),
+ sizeof (recv_ttl));
+ dprintf ("TTLv6 = %i;\n", recv_ttl);
+ }
+ else
+ {
+ dprintf ("Not handling option %i.\n",
+ cmsg->cmsg_type);
+ }
+ } /* }}} */
+ else
+ {
+ dprintf ("Don't know how to handle "
+ "unknown protocol %i.\n",
+ cmsg->cmsg_level);
+ }
+ } /* }}} for (cmsg) */
+
+ if (ph->addrfamily == AF_INET)
{
- if ((host = ping_receive_ipv4 (ph, buffer, buffer_len)) == NULL)
+ host = ping_receive_ipv4 (ph, payload_buffer, payload_buffer_len);
+ if (host == NULL)
return (-1);
}
- else if (sa.ss_family == AF_INET6)
+ else if (ph->addrfamily == AF_INET6)
{
- if ((host = ping_receive_ipv6 (ph, buffer, buffer_len)) == NULL)
+ host = ping_receive_ipv6 (ph, payload_buffer, payload_buffer_len);
+ if (host == NULL)
return (-1);
}
+ else
+ {
+ dprintf ("ping_receive_one: Unknown address family %i.\n",
+ ph->addrfamily);
+ return (-1);
+ }
dprintf ("rcvd: %12i.%06i\n",
(int) now->tv_sec,
(int) diff.tv_sec,
(int) diff.tv_usec);
+ if (recv_ttl >= 0)
+ host->recv_ttl = recv_ttl;
+
host->latency = ((double) diff.tv_usec) / 1000.0;
host->latency += ((double) diff.tv_sec) * 1000.0;
if (gettimeofday (&nowtime, NULL) == -1)
{
- ping_set_error (obj, "gettimeofday", strerror (errno));
+ ping_set_errno (obj, errno);
return (-1);
}
if (gettimeofday (&nowtime, NULL) == -1)
{
- ping_set_error (obj, "gettimeofday", strerror (errno));
+ ping_set_errno (obj, errno);
return (-1);
}
if (gettimeofday (&nowtime, NULL) == -1)
{
- ping_set_error (obj, "gettimeofday", strerror (errno));
+ ping_set_errno (obj, errno);
return (-1);
}
}
else if (status < 0)
{
- dprintf ("select: %s\n", strerror (errno));
+#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;
}
(struct sockaddr *) ph->addr, ph->addrlen);
if (ret < 0)
- ping_set_error (obj, "sendto", strerror (errno));
+ {
+#if defined(EHOSTUNREACH)
+ if (errno == EHOSTUNREACH)
+ return (0);
+#endif
+#if defined(ENETUNREACH)
+ if (errno == ENETUNREACH)
+ return (0);
+#endif
+ ping_set_errno (obj, errno);
+ }
return (ret);
}
* sending the packet, so I will do that too */
if (gettimeofday (ptr->timer, NULL) == -1)
{
- dprintf ("gettimeofday: %s\n", strerror (errno));
+#if WITH_DEBUG
+ char errbuf[PING_ERRMSG_LEN];
+ dprintf ("gettimeofday: %s\n",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+#endif
timerclear (ptr->timer);
ret--;
continue;
if (ph->addrfamily == AF_INET)
{
- ret = setsockopt (ph->fd, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl));
+ dprintf ("Setting TTLv4 to %i\n", ttl);
+ ret = setsockopt (ph->fd, IPPROTO_IP, IP_TTL,
+ &ttl, sizeof (ttl));
}
else if (ph->addrfamily == AF_INET6)
{
- ret = setsockopt (ph->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof (ttl));
+ dprintf ("Setting TTLv6 to %i\n", ttl);
+ ret = setsockopt (ph->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ &ttl, sizeof (ttl));
}
return (ret);
if (read (fd, &seed, sizeof (seed)) != -1)
{
did_seed = 1;
- dprintf ("Random seed: %i\n", seed);
+ dprintf ("Random seed: %#x\n", seed);
srandom (seed);
}
close (fd);
}
+#if WITH_DEBUG
else
{
- dprintf ("open (/dev/urandom): %s\n", strerror (errno));
+ char errbuf[PING_ERRMSG_LEN];
+ dprintf ("open (/dev/urandom): %s\n",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
}
+#endif
}
retval = (int) random ();
- dprintf ("Random number: %i\n", retval);
+ dprintf ("Random number: %#x\n", retval);
return (retval);
}
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 (obj->data != NULL)
free (obj->data);
+ if (obj->srcaddr != NULL)
+ free (obj->srcaddr);
+
free (obj);
return;
obj->ttl = PING_DEF_TTL;
ret = -1;
}
+ else
+ {
+ pinghost_t *ph;
+
+ for (ph = obj->head; ph != NULL; ph = ph->next)
+ ping_set_ttl (ph, obj->ttl);
+ }
break;
case PING_OPT_AF:
obj->addrfamily = PING_DEF_AF;
ret = -1;
}
+ if (obj->srcaddr != NULL)
+ {
+ free (obj->srcaddr);
+ obj->srcaddr = NULL;
+ }
break;
case PING_OPT_DATA:
obj->data = strdup ((const char *) value);
break;
+ case PING_OPT_SOURCE:
+ {
+ char *hostname = (char *) value;
+ struct addrinfo ai_hints;
+ struct addrinfo *ai_list;
+ int status;
+#if WITH_DEBUG
+ if (obj->addrfamily != AF_UNSPEC)
+ {
+ dprintf ("Resetting obj->addrfamily to AF_UNSPEC.\n");
+ }
+#endif
+ memset ((void *) &ai_hints, '\0', sizeof (ai_hints));
+ ai_hints.ai_family = obj->addrfamily = AF_UNSPEC;
+#if defined(AI_ADDRCONFIG)
+ ai_hints.ai_flags = AI_ADDRCONFIG;
+#endif
+ status = getaddrinfo (hostname, NULL, &ai_hints, &ai_list);
+ if (status != 0)
+ {
+#if defined(EAI_SYSTEM)
+ char errbuf[PING_ERRMSG_LEN];
+#endif
+ ping_set_error (obj, "getaddrinfo",
+#if defined(EAI_SYSTEM)
+ (status == EAI_SYSTEM)
+ ? sstrerror (errno, errbuf, sizeof (errbuf)) :
+#endif
+ gai_strerror (status));
+ ret = -1;
+ break;
+ }
+#if WITH_DEBUG
+ if (ai_list->ai_next != NULL)
+ {
+ dprintf ("hostname = `%s' is ambiguous.\n", hostname);
+ }
+#endif
+ if (obj->srcaddr == NULL)
+ {
+ obj->srcaddrlen = 0;
+ obj->srcaddr = malloc (sizeof (struct sockaddr_storage));
+ if (obj->srcaddr == NULL)
+ {
+ ping_set_errno (obj, errno);
+ ret = -1;
+ freeaddrinfo (ai_list);
+ break;
+ }
+ }
+ memset ((void *) obj->srcaddr, 0, sizeof (struct sockaddr_storage));
+ assert (ai_list->ai_addrlen <= sizeof (struct sockaddr_storage));
+ memcpy ((void *) obj->srcaddr, (const void *) ai_list->ai_addr,
+ ai_list->ai_addrlen);
+ obj->srcaddrlen = ai_list->ai_addrlen;
+ obj->addrfamily = ai_list->ai_family;
+
+ freeaddrinfo (ai_list);
+ } /* case PING_OPT_SOURCE */
+ break;
+
default:
ret = -2;
} /* switch (option) */
{
while (ph != NULL)
{
- if (strcasecmp (ph->hostname, host) == 0)
+ if (strcasecmp (ph->username, host) == 0)
break;
ph = ph->next;
{
pinghost_t *ph;
- struct sockaddr_storage sockaddr;
- socklen_t sockaddr_len;
-
struct addrinfo ai_hints;
struct addrinfo *ai_list, *ai_ptr;
int ai_return;
return (-1);
}
+ if ((ph->username = strdup (host)) == NULL)
+ {
+ dprintf ("Out of memory!\n");
+ ping_set_errno (obj, errno);
+ ping_free (ph);
+ return (-1);
+ }
+
if ((ph->hostname = strdup (host)) == NULL)
{
dprintf ("Out of memory!\n");
- ping_set_error (obj, "strdup", strerror (errno));
+ ping_set_errno (obj, errno);
ping_free (ph);
return (-1);
}
if ((ph->data = strdup (obj->data == NULL ? PING_DEF_DATA : obj->data)) == NULL)
{
dprintf ("Out of memory!\n");
- ping_set_error (obj, "strdup", strerror (errno));
+ ping_set_errno (obj, errno);
ping_free (ph);
return (-1);
}
if ((ai_return = getaddrinfo (host, NULL, &ai_hints, &ai_list)) != 0)
{
+#if defined(EAI_SYSTEM)
+ char errbuf[PING_ERRMSG_LEN];
+#endif
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)
+ ? sstrerror (errno, errbuf, sizeof (errbuf)) :
+#endif
+ gai_strerror (ai_return));
ping_free (ph);
return (-1);
}
{
ph->fd = -1;
- sockaddr_len = sizeof (sockaddr);
- memset (&sockaddr, '\0', sockaddr_len);
-
if (ai_ptr->ai_family == AF_INET)
{
- struct sockaddr_in *si;
-
- si = (struct sockaddr_in *) &sockaddr;
- si->sin_family = AF_INET;
- si->sin_port = htons (ph->ident);
- si->sin_addr.s_addr = htonl (INADDR_ANY);
-
ai_ptr->ai_socktype = SOCK_RAW;
ai_ptr->ai_protocol = IPPROTO_ICMP;
}
else if (ai_ptr->ai_family == AF_INET6)
{
- struct sockaddr_in6 *si;
-
- si = (struct sockaddr_in6 *) &sockaddr;
- si->sin6_family = AF_INET6;
- si->sin6_port = htons (ph->ident);
- si->sin6_addr = in6addr_any;
-
ai_ptr->ai_socktype = SOCK_RAW;
ai_ptr->ai_protocol = IPPROTO_ICMPV6;
}
ph->fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (ph->fd == -1)
{
- dprintf ("socket: %s\n", strerror (errno));
- ping_set_error (obj, "socket", strerror (errno));
+#if WITH_DEBUG
+ char errbuf[PING_ERRMSG_LEN];
+ dprintf ("socket: %s\n",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+#endif
+ ping_set_errno (obj, errno);
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, 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;
+ }
+ }
assert (sizeof (struct sockaddr_storage) >= ai_ptr->ai_addrlen);
memset (ph->addr, '\0', sizeof (struct sockaddr_storage));
}
#endif /* AI_CANONNAME */
+ if (ph->addrfamily == AF_INET)
+ {
+ int opt = 1;
+
+ setsockopt (ph->fd, IPPROTO_IP, IP_RECVTTL,
+ &opt, sizeof (opt));
+ }
+#if defined(IPPROTO_IPV6) && defined(IPV6_RECVHOPLIMIT)
+ else if (ph->addrfamily == AF_INET6)
+ {
+ int opt = 1;
+
+ setsockopt (ph->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+ &opt, sizeof (opt));
+ }
+#endif
+
break;
}
if (ph->fd < 0)
{
- free (ph->hostname);
- free (ph);
+ ping_free (ph);
return (-1);
}
ping_set_ttl (ph, obj->ttl);
return (0);
-}
+} /* int ping_host_add */
int ping_host_remove (pingobj_t *obj, const char *host)
{
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);
strncpy ((char *) buffer, iter->data, orig_buffer_len);
ret = 0;
break;
+
+ case PING_INFO_RECV_TTL:
+ ret = ENOMEM;
+ *buffer_len = sizeof (int);
+ if (orig_buffer_len < sizeof (int))
+ break;
+ *((int *) buffer) = iter->recv_ttl;
+ ret = 0;
+ break;
}
return (ret);
-}
+} /* ping_iterator_get_info */
void *ping_iterator_get_context (pingobj_iter_t *iter)
{