struct timeval *timer;
double latency;
uint32_t dropped;
+ int recv_ttl;
char *data;
void *context;
int addrfamily;
char *data;
- struct sockaddr_storage *srcaddr;
+ struct sockaddr *srcaddr;
socklen_t srcaddrlen;
char errmsg[PING_ERRMSG_LEN];
obj->errmsg[sizeof (obj->errmsg) - 1] = 0;
}
-static void ping_set_errno (pingobj_t *obj, const char *function,
- int error_number)
+static void ping_set_errno (pingobj_t *obj, int error_number)
{
sstrerror (error_number, obj->errmsg, sizeof (obj->errmsg));
}
static int ping_receive_one (int fd, pinghost_t *ph, struct timeval *now)
{
- char buffer[4096];
- ssize_t buffer_len;
-
struct timeval diff;
-
pinghost_t *host = NULL;
-
- 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 < 0)
+ int family;
+ 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;
+
+ payload_buffer_len = recvmsg (fd, &msghdr, /* flags = */ 0);
+ if (payload_buffer_len < 0)
{
#if WITH_DEBUG
char errbuf[PING_ERRMSG_LEN];
#endif
return (-1);
}
+ dprintf ("Read %zi bytes from fd = %i\n", payload_buffer_len, fd);
+
+ /* Iterate over all auxiliary data in msghdr */
+ family = -1;
+ recv_ttl = -1;
+ for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR (&msghdr, cmsg))
+ {
+ if (cmsg->cmsg_level == IPPROTO_IP) /* {{{ */
+ {
+ family = AF_INET;
+ 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 (cmsg->cmsg_level == IPPROTO_IPV6) /* {{{ */
+ {
+ family = AF_INET6;
+ 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) */
- dprintf ("Read %zi bytes from fd = %i\n", buffer_len, fd);
-
- if (sa.ss_family == AF_INET)
+ if (family == 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 (family == 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",
+ family);
+ return (-1);
+ }
dprintf ("rcvd: %12i.%06i\n",
(int) now->tv_sec,
host->latency = ((double) diff.tv_usec) / 1000.0;
host->latency += ((double) diff.tv_sec) * 1000.0;
+ host->recv_ttl = recv_ttl;
+
timerclear (host->timer);
return (0);
if (gettimeofday (&nowtime, NULL) == -1)
{
- ping_set_errno (obj, "gettimeofday", errno);
+ ping_set_errno (obj, errno);
return (-1);
}
if (gettimeofday (&nowtime, NULL) == -1)
{
- ping_set_errno (obj, "gettimeofday", errno);
+ ping_set_errno (obj, errno);
return (-1);
}
if (gettimeofday (&nowtime, NULL) == -1)
{
- ping_set_errno (obj, "gettimeofday", errno);
+ ping_set_errno (obj, errno);
return (-1);
}
if (errno == ENETUNREACH)
return (0);
#endif
- ping_set_errno (obj, "sendto", errno);
+ ping_set_errno (obj, errno);
}
return (ret);
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);
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:
if (obj->srcaddr == NULL)
{
obj->srcaddrlen = 0;
- obj->srcaddr = (struct sockaddr_storage *) malloc (sizeof (struct sockaddr_storage));
+ obj->srcaddr = malloc (sizeof (struct sockaddr_storage));
if (obj->srcaddr == NULL)
{
- ping_set_errno (obj, "malloc", errno);
+ ping_set_errno (obj, errno);
ret = -1;
freeaddrinfo (ai_list);
break;
}
}
- memset ((void *) obj->srcaddr, '\0', sizeof (struct sockaddr_storage));
+ 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);
{
pinghost_t *ph;
- struct sockaddr_storage sockaddr;
- socklen_t sockaddr_len;
-
struct addrinfo ai_hints;
struct addrinfo *ai_list, *ai_ptr;
int ai_return;
if ((ph->username = strdup (host)) == NULL)
{
dprintf ("Out of memory!\n");
- ping_set_errno (obj, "strdup", errno);
+ ping_set_errno (obj, errno);
ping_free (ph);
return (-1);
}
if ((ph->hostname = strdup (host)) == NULL)
{
dprintf ("Out of memory!\n");
- ping_set_errno (obj, "strdup", 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_errno (obj, "strdup", errno);
+ ping_set_errno (obj, errno);
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;
}
dprintf ("socket: %s\n",
sstrerror (errno, errbuf, sizeof (errbuf)));
#endif
- ping_set_errno (obj, "socket", errno);
+ ping_set_errno (obj, errno);
continue;
}
assert (obj->srcaddrlen > 0);
assert (obj->srcaddrlen <= sizeof (struct sockaddr_storage));
- if (bind (ph->fd, (struct sockaddr *) obj->srcaddr, obj->srcaddrlen) == -1)
+ 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, "bind", errno);
+ ping_set_errno (obj, errno);
close (ph->fd);
ph->fd = -1;
continue;
}
#endif /* AI_CANONNAME */
+ if (ph->addrfamily == AF_INET)
+ {
+ int opt = 1;
+
+ setsockopt (ph->fd, IPPROTO_IP, IP_RECVTTL,
+ &opt, sizeof (opt));
+ }
+ else if (ph->addrfamily == AF_INET6)
+ {
+ int opt = 1;
+
+ setsockopt (ph->fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
+ &opt, sizeof (opt));
+ }
+
break;
}
ping_set_ttl (ph, obj->ttl);
return (0);
-}
+} /* int ping_host_add */
int ping_host_remove (pingobj_t *obj, const char *host)
{
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);