# define dprintf(...) /**/
#endif
+#define PING_ERRMSG_LEN 256
+
#define PING_DATA "Florian Forster <octo@verplant.org> http://verplant.org/"
+struct pinghost
+{
+ char *hostname;
+ struct sockaddr_storage *addr;
+ socklen_t addrlen;
+ int addrfamily;
+ int fd;
+ int ident;
+ int sequence;
+ struct timeval *timer;
+ double latency;
+
+ struct pinghost *next;
+};
+
+struct pingobj
+{
+ double timeout;
+ int ttl;
+ int addrfamily;
+
+ char errmsg[PING_ERRMSG_LEN];
+
+ pinghost_t *head;
+};
+
/*
* private (static) functions
*/
+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';
+}
+
static int ping_timeval_add (struct timeval *tv1, struct timeval *tv2,
struct timeval *res)
{
ptr->latency = -1.0;
if (gettimeofday (&nowtime, NULL) == -1)
+ {
+ ping_set_error (obj, "gettimeofday", strerror (errno));
return (-1);
+ }
/* Set up timeout */
timeout.tv_sec = (time_t) obj->timeout;
break;
if (gettimeofday (&nowtime, NULL) == -1)
+ {
+ ping_set_error (obj, "gettimeofday", strerror (errno));
return (-1);
+ }
if (ping_timeval_sub (&endtime, &nowtime, &timeout) == -1)
break;
status = select (max_readfds + 1, &readfds, NULL, NULL, &timeout);
if (gettimeofday (&nowtime, NULL) == -1)
+ {
+ ping_set_error (obj, "gettimeofday", strerror (errno));
return (-1);
+ }
if ((status == -1) && (errno == EINTR))
{
* +-> ping_send_one_ipv4 *
* `-> ping_send_one_ipv6 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-ssize_t ping_sendto (pinghost_t *ph, const void *buf, size_t buflen)
+static ssize_t ping_sendto (pinghost_t *ph, const void *buf, size_t buflen)
{
ssize_t ret;
/*
* public methods
*/
+const char *ping_get_error (pingobj_t *obj)
+{
+ return (obj->errmsg);
+}
+
pingobj_t *ping_construct (void)
{
pingobj_t *obj;
if ((ph->hostname = strdup (host)) == NULL)
{
dprintf ("Out of memory!\n");
+ ping_set_error (obj, "strdup", strerror (errno));
ping_free (ph);
return (-1);
}
if ((ai_return = getaddrinfo (host, NULL, &ai_hints, &ai_list)) != 0)
{
dprintf ("getaddrinfo failed\n");
+ ping_set_error (obj, "getaddrinfo",
+ (ai_return == EAI_SYSTEM)
+ ? strerror (errno)
+ : gai_strerror (ai_return));
ping_free (ph);
return (-1);
}
+ if (ai_list == NULL)
+ ping_set_error (obj, "getaddrinfo", "No hosts returned");
+
for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
{
ph->fd = -1;
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)
si->sin6_port = htons (ph->ident);
si->sin6_addr = in6addr_any;
+ ai_ptr->ai_socktype = SOCK_RAW;
ai_ptr->ai_protocol = IPPROTO_ICMPV6;
}
else
{
- dprintf ("Unknown `ai_family': %i\n", ai_ptr->ai_family);
+ char errmsg[PING_ERRMSG_LEN];
+
+ snprintf (errmsg, PING_ERRMSG_LEN, "Unknown `ai_family': %i", ai_ptr->ai_family);
+ errmsg[PING_ERRMSG_LEN - 1] = '\0';
+
+ dprintf (errmsg);
+ ping_set_error (obj, "getaddrinfo", errmsg);
continue;
}
if (ph->fd == -1)
{
dprintf ("socket: %s\n", strerror (errno));
+ ping_set_error (obj, "socket", strerror (errno));
continue;
}
if (bind (ph->fd, (struct sockaddr *) &sockaddr, sockaddr_len) == -1)
{
dprintf ("bind: %s\n", strerror (errno));
+ ping_set_error (obj, "bind", strerror (errno));
close (ph->fd);
ph->fd = -1;
continue;
}
if (cur == NULL)
+ {
+ ping_set_error (obj, "ping_host_remove", "Host not found");
return (-1);
+ }
if (pre == NULL)
obj->head = cur->next;