|
|
@@ -23,6 +23,7 @@
|
|
|
#include "util.h"
|
|
|
#include <arpa/inet.h>
|
|
|
#include <errno.h>
|
|
|
+#include <fcntl.h>
|
|
|
#include <linux/filter.h>
|
|
|
#include <netdb.h>
|
|
|
#include <netinet/icmp6.h>
|
|
|
@@ -44,61 +45,63 @@
|
|
|
#define ICMP_INPACKET_SIZE 1024
|
|
|
|
|
|
struct fast_ping_packet_msg {
|
|
|
- struct timeval tv;
|
|
|
- unsigned int sid;
|
|
|
- unsigned int seq;
|
|
|
+ struct timeval tv;
|
|
|
+ unsigned int sid;
|
|
|
+ unsigned int seq;
|
|
|
};
|
|
|
|
|
|
struct fast_ping_packet {
|
|
|
- union {
|
|
|
- struct icmp icmp;
|
|
|
- struct icmp6_hdr icmp6;
|
|
|
- };
|
|
|
- struct fast_ping_packet_msg msg;
|
|
|
+ union {
|
|
|
+ struct icmp icmp;
|
|
|
+ struct icmp6_hdr icmp6;
|
|
|
+ };
|
|
|
+ struct fast_ping_packet_msg msg;
|
|
|
};
|
|
|
|
|
|
struct ping_host_struct {
|
|
|
- atomic_t ref;
|
|
|
- struct hlist_node host_node;
|
|
|
- struct hlist_node addr_node;
|
|
|
- FAST_PING_TYPE type;
|
|
|
-
|
|
|
- void *userptr;
|
|
|
- fast_ping_result ping_callback;
|
|
|
- char host[PING_MAX_HOSTLEN];
|
|
|
-
|
|
|
- int fd;
|
|
|
- unsigned int seq;
|
|
|
- struct timeval last;
|
|
|
- int interval;
|
|
|
- int timeout;
|
|
|
- int count;
|
|
|
- int send;
|
|
|
- unsigned int sid;
|
|
|
- union {
|
|
|
- struct sockaddr addr;
|
|
|
- struct sockaddr_in6 in6;
|
|
|
- struct sockaddr_in in;
|
|
|
- };
|
|
|
- socklen_t addr_len;
|
|
|
- struct fast_ping_packet packet;
|
|
|
+ atomic_t ref;
|
|
|
+ struct hlist_node host_node;
|
|
|
+ struct hlist_node addr_node;
|
|
|
+ FAST_PING_TYPE type;
|
|
|
+
|
|
|
+ void *userptr;
|
|
|
+ fast_ping_result ping_callback;
|
|
|
+ char host[PING_MAX_HOSTLEN];
|
|
|
+
|
|
|
+ int fd;
|
|
|
+ unsigned int seq;
|
|
|
+ struct timeval last;
|
|
|
+ int interval;
|
|
|
+ int timeout;
|
|
|
+ int count;
|
|
|
+ int send;
|
|
|
+ unsigned int sid;
|
|
|
+ unsigned short port;
|
|
|
+ unsigned short ss_family;
|
|
|
+ union {
|
|
|
+ struct sockaddr addr;
|
|
|
+ struct sockaddr_in6 in6;
|
|
|
+ struct sockaddr_in in;
|
|
|
+ };
|
|
|
+ socklen_t addr_len;
|
|
|
+ struct fast_ping_packet packet;
|
|
|
};
|
|
|
|
|
|
struct fast_ping_struct {
|
|
|
- int run;
|
|
|
- pthread_t tid;
|
|
|
- pthread_mutex_t lock;
|
|
|
- unsigned short ident;
|
|
|
-
|
|
|
- int epoll_fd;
|
|
|
- int fd_icmp;
|
|
|
- struct ping_host_struct icmp_host;
|
|
|
- int fd_icmp6;
|
|
|
- struct ping_host_struct icmp6_host;
|
|
|
-
|
|
|
- pthread_mutex_t map_lock;
|
|
|
- DECLARE_HASHTABLE(hostmap, 6);
|
|
|
- DECLARE_HASHTABLE(addrmap, 6);
|
|
|
+ int run;
|
|
|
+ pthread_t tid;
|
|
|
+ pthread_mutex_t lock;
|
|
|
+ unsigned short ident;
|
|
|
+
|
|
|
+ int epoll_fd;
|
|
|
+ int fd_icmp;
|
|
|
+ struct ping_host_struct icmp_host;
|
|
|
+ int fd_icmp6;
|
|
|
+ struct ping_host_struct icmp6_host;
|
|
|
+
|
|
|
+ pthread_mutex_t map_lock;
|
|
|
+ DECLARE_HASHTABLE(hostmap, 6);
|
|
|
+ DECLARE_HASHTABLE(addrmap, 6);
|
|
|
};
|
|
|
|
|
|
static struct fast_ping_struct ping;
|
|
|
@@ -106,806 +109,913 @@ static atomic_t ping_sid = ATOMIC_INIT(0);
|
|
|
|
|
|
uint16_t _fast_ping_checksum(uint16_t *header, size_t len)
|
|
|
{
|
|
|
- uint32_t sum = 0;
|
|
|
- int i;
|
|
|
+ uint32_t sum = 0;
|
|
|
+ int i;
|
|
|
|
|
|
- for (i = 0; i < len / sizeof(uint16_t); i++) {
|
|
|
- sum += ntohs(header[i]);
|
|
|
- }
|
|
|
+ for (i = 0; i < len / sizeof(uint16_t); i++) {
|
|
|
+ sum += ntohs(header[i]);
|
|
|
+ }
|
|
|
|
|
|
- return htons(~((sum >> 16) + (sum & 0xffff)));
|
|
|
+ return htons(~((sum >> 16) + (sum & 0xffff)));
|
|
|
}
|
|
|
|
|
|
void _fast_ping_install_filter_v6(int sock)
|
|
|
{
|
|
|
- struct icmp6_filter icmp6_filter;
|
|
|
- ICMP6_FILTER_SETBLOCKALL(&icmp6_filter);
|
|
|
- ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &icmp6_filter);
|
|
|
- setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_filter, sizeof(struct icmp6_filter));
|
|
|
-
|
|
|
- static int once;
|
|
|
- static struct sock_filter insns[] = {
|
|
|
- BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4), /* Load icmp echo ident */
|
|
|
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
|
|
|
- BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
|
|
|
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0), /* Load icmp type */
|
|
|
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */
|
|
|
- BPF_STMT(BPF_RET | BPF_K, ~0U), /* No. It passes. This must not happen. */
|
|
|
- BPF_STMT(BPF_RET | BPF_K, 0), /* Echo with wrong ident. Reject. */
|
|
|
- };
|
|
|
- static struct sock_fprog filter = {sizeof insns / sizeof(insns[0]), insns};
|
|
|
-
|
|
|
- if (once) {
|
|
|
- return;
|
|
|
- }
|
|
|
- once = 1;
|
|
|
-
|
|
|
- /* Patch bpflet for current identifier. */
|
|
|
- insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
|
|
|
-
|
|
|
- if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
|
|
|
- perror("WARNING: failed to install socket filter\n");
|
|
|
- }
|
|
|
+ struct icmp6_filter icmp6_filter;
|
|
|
+ ICMP6_FILTER_SETBLOCKALL(&icmp6_filter);
|
|
|
+ ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &icmp6_filter);
|
|
|
+ setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_filter, sizeof(struct icmp6_filter));
|
|
|
+
|
|
|
+ static int once;
|
|
|
+ static struct sock_filter insns[] = {
|
|
|
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4), /* Load icmp echo ident */
|
|
|
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
|
|
|
+ BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
|
|
|
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0), /* Load icmp type */
|
|
|
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */
|
|
|
+ BPF_STMT(BPF_RET | BPF_K, ~0U), /* No. It passes. This must not happen. */
|
|
|
+ BPF_STMT(BPF_RET | BPF_K, 0), /* Echo with wrong ident. Reject. */
|
|
|
+ };
|
|
|
+ static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns };
|
|
|
+
|
|
|
+ if (once) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ once = 1;
|
|
|
+
|
|
|
+ /* Patch bpflet for current identifier. */
|
|
|
+ insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
|
|
|
+
|
|
|
+ if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
|
|
|
+ perror("WARNING: failed to install socket filter\n");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void _fast_ping_install_filter_v4(int sock)
|
|
|
{
|
|
|
- static int once;
|
|
|
- static struct sock_filter insns[] = {
|
|
|
- BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
|
|
|
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
|
|
|
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
|
|
|
- BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
|
|
|
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
|
|
|
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
|
|
|
- BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFF), /* No. It passes. */
|
|
|
- BPF_STMT(BPF_RET | BPF_K, 0) /* Echo with wrong ident. Reject. */
|
|
|
- };
|
|
|
-
|
|
|
- static struct sock_fprog filter = {sizeof insns / sizeof(insns[0]), insns};
|
|
|
-
|
|
|
- if (once) {
|
|
|
- return;
|
|
|
- }
|
|
|
- once = 1;
|
|
|
-
|
|
|
- /* Patch bpflet for current identifier. */
|
|
|
- insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
|
|
|
-
|
|
|
- if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
|
|
|
- perror("WARNING: failed to install socket filter\n");
|
|
|
- }
|
|
|
+ static int once;
|
|
|
+ static struct sock_filter insns[] = {
|
|
|
+ BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
|
|
|
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
|
|
|
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
|
|
|
+ BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
|
|
|
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
|
|
|
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
|
|
|
+ BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFF), /* No. It passes. */
|
|
|
+ BPF_STMT(BPF_RET | BPF_K, 0) /* Echo with wrong ident. Reject. */
|
|
|
+ };
|
|
|
+
|
|
|
+ static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns };
|
|
|
+
|
|
|
+ if (once) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ once = 1;
|
|
|
+
|
|
|
+ /* Patch bpflet for current identifier. */
|
|
|
+ insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
|
|
|
+
|
|
|
+ if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
|
|
|
+ perror("WARNING: failed to install socket filter\n");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static struct addrinfo *_fast_ping_getaddr(const char *host, int type, int protocol)
|
|
|
+static struct addrinfo *_fast_ping_getaddr(const char *host, const char *port, int type, int protocol)
|
|
|
{
|
|
|
- struct addrinfo hints;
|
|
|
- struct addrinfo *result = NULL;
|
|
|
-
|
|
|
- memset(&hints, 0, sizeof(hints));
|
|
|
- hints.ai_family = AF_UNSPEC;
|
|
|
- hints.ai_socktype = type;
|
|
|
- hints.ai_protocol = protocol;
|
|
|
- if (getaddrinfo(host, NULL, &hints, &result) != 0) {
|
|
|
- tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
+ struct addrinfo hints;
|
|
|
+ struct addrinfo *result = NULL;
|
|
|
+
|
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
|
+ hints.ai_family = AF_UNSPEC;
|
|
|
+ hints.ai_socktype = type;
|
|
|
+ hints.ai_protocol = protocol;
|
|
|
+ if (getaddrinfo(host, port, &hints, &result) != 0) {
|
|
|
+ tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
errout:
|
|
|
- if (result) {
|
|
|
- freeaddrinfo(result);
|
|
|
- }
|
|
|
- return NULL;
|
|
|
+ if (result) {
|
|
|
+ freeaddrinfo(result);
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
static int _fast_ping_getdomain(const char *host)
|
|
|
{
|
|
|
- struct addrinfo hints;
|
|
|
- struct addrinfo *result = NULL;
|
|
|
- int domain = -1;
|
|
|
-
|
|
|
- memset(&hints, 0, sizeof(hints));
|
|
|
- hints.ai_family = AF_UNSPEC;
|
|
|
- hints.ai_socktype = SOCK_STREAM;
|
|
|
- hints.ai_protocol = 0;
|
|
|
- if (getaddrinfo(host, NULL, &hints, &result) != 0) {
|
|
|
- tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
|
|
|
- goto errout;
|
|
|
- }
|
|
|
+ struct addrinfo hints;
|
|
|
+ struct addrinfo *result = NULL;
|
|
|
+ int domain = -1;
|
|
|
|
|
|
- domain = result->ai_family;
|
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
|
+ hints.ai_family = AF_UNSPEC;
|
|
|
+ hints.ai_socktype = SOCK_STREAM;
|
|
|
+ hints.ai_protocol = 0;
|
|
|
+ if (getaddrinfo(host, NULL, &hints, &result) != 0) {
|
|
|
+ tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
|
|
|
- freeaddrinfo(result);
|
|
|
+ domain = result->ai_family;
|
|
|
|
|
|
- return domain;
|
|
|
+ freeaddrinfo(result);
|
|
|
+
|
|
|
+ return domain;
|
|
|
errout:
|
|
|
- if (result) {
|
|
|
- freeaddrinfo(result);
|
|
|
- }
|
|
|
- return -1;
|
|
|
+ if (result) {
|
|
|
+ freeaddrinfo(result);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
static void _fast_ping_host_get(struct ping_host_struct *ping_host)
|
|
|
{
|
|
|
- atomic_inc(&ping_host->ref);
|
|
|
+ atomic_inc(&ping_host->ref);
|
|
|
}
|
|
|
|
|
|
-static void _fast_ping_host_put(struct ping_host_struct *ping_host)
|
|
|
+static void _fast_ping_host_put_locked(struct ping_host_struct *ping_host, int locked)
|
|
|
{
|
|
|
- pthread_mutex_lock(&ping.map_lock);
|
|
|
- if (atomic_dec_and_test(&ping_host->ref)) {
|
|
|
- hash_del(&ping_host->host_node);
|
|
|
- hash_del(&ping_host->addr_node);
|
|
|
- } else {
|
|
|
- ping_host = NULL;
|
|
|
- }
|
|
|
- pthread_mutex_unlock(&ping.map_lock);
|
|
|
-
|
|
|
- if (ping_host == NULL) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- struct timeval tv;
|
|
|
- tv.tv_sec = 0;
|
|
|
- tv.tv_usec = 0;
|
|
|
-
|
|
|
- ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tv, ping_host->userptr);
|
|
|
-
|
|
|
- free(ping_host);
|
|
|
+ if (locked) {
|
|
|
+ if (atomic_dec_and_test(&ping_host->ref)) {
|
|
|
+ hash_del(&ping_host->host_node);
|
|
|
+ hash_del(&ping_host->addr_node);
|
|
|
+ } else {
|
|
|
+ ping_host = NULL;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ pthread_mutex_lock(&ping.map_lock);
|
|
|
+ if (atomic_dec_and_test(&ping_host->ref)) {
|
|
|
+ hash_del(&ping_host->host_node);
|
|
|
+ hash_del(&ping_host->addr_node);
|
|
|
+ } else {
|
|
|
+ ping_host = NULL;
|
|
|
+ }
|
|
|
+ pthread_mutex_unlock(&ping.map_lock);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ping_host == NULL) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ struct timeval tv;
|
|
|
+ tv.tv_sec = 0;
|
|
|
+ tv.tv_usec = 0;
|
|
|
+
|
|
|
+ ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tv, ping_host->userptr);
|
|
|
+
|
|
|
+ if (ping_host->fd > 0) {
|
|
|
+ close(ping_host->fd);
|
|
|
+ ping_host->fd = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ free(ping_host);
|
|
|
}
|
|
|
|
|
|
-static void _fast_ping_host_put_locked(struct ping_host_struct *ping_host)
|
|
|
+static void _fast_ping_host_put(struct ping_host_struct *ping_host)
|
|
|
{
|
|
|
- if (atomic_dec_and_test(&ping_host->ref)) {
|
|
|
- hash_del(&ping_host->host_node);
|
|
|
- hash_del(&ping_host->addr_node);
|
|
|
- } else {
|
|
|
- ping_host = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (ping_host == NULL) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- struct timeval tv;
|
|
|
- tv.tv_sec = 0;
|
|
|
- tv.tv_usec = 0;
|
|
|
-
|
|
|
- ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tv, ping_host->userptr);
|
|
|
-
|
|
|
- free(ping_host);
|
|
|
+ _fast_ping_host_put_locked(ping_host, 0);
|
|
|
}
|
|
|
|
|
|
static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
|
|
|
{
|
|
|
- struct fast_ping_packet *packet = &ping_host->packet;
|
|
|
- struct icmp6_hdr *icmp6 = &packet->icmp6;
|
|
|
- int len = 0;
|
|
|
-
|
|
|
- ping_host->seq++;
|
|
|
- memset(icmp6, 0, sizeof(*icmp6));
|
|
|
- icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
|
|
|
- icmp6->icmp6_code = 0;
|
|
|
- icmp6->icmp6_cksum = 0;
|
|
|
- icmp6->icmp6_id = getpid();
|
|
|
- icmp6->icmp6_seq = htons(ping_host->seq);
|
|
|
-
|
|
|
- gettimeofday(&packet->msg.tv, 0);
|
|
|
- packet->msg.sid = ping_host->sid;
|
|
|
- packet->msg.seq = ping_host->seq;
|
|
|
- icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
|
|
|
-
|
|
|
- len = sendto(ping_host->fd, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
|
|
- if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
|
|
- if (errno == ENETUNREACH) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
- char ping_host_name[PING_MAX_HOSTLEN];
|
|
|
- tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
|
|
|
- strerror(errno));
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
+ struct fast_ping_packet *packet = &ping_host->packet;
|
|
|
+ struct icmp6_hdr *icmp6 = &packet->icmp6;
|
|
|
+ int len = 0;
|
|
|
+
|
|
|
+ ping_host->seq++;
|
|
|
+ memset(icmp6, 0, sizeof(*icmp6));
|
|
|
+ icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
|
|
|
+ icmp6->icmp6_code = 0;
|
|
|
+ icmp6->icmp6_cksum = 0;
|
|
|
+ icmp6->icmp6_id = getpid();
|
|
|
+ icmp6->icmp6_seq = htons(ping_host->seq);
|
|
|
+
|
|
|
+ gettimeofday(&packet->msg.tv, 0);
|
|
|
+ packet->msg.sid = ping_host->sid;
|
|
|
+ packet->msg.seq = ping_host->seq;
|
|
|
+ icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
|
|
|
+
|
|
|
+ len = sendto(ping.fd_icmp6, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
|
|
+ if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
|
|
+ if (errno == ENETUNREACH) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ char ping_host_name[PING_MAX_HOSTLEN];
|
|
|
+ tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
|
|
|
+ strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
|
|
|
errout:
|
|
|
- return -1;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
|
|
|
{
|
|
|
- struct fast_ping_packet *packet = &ping_host->packet;
|
|
|
- struct icmp *icmp = &packet->icmp;
|
|
|
- int len;
|
|
|
-
|
|
|
- ping_host->seq++;
|
|
|
- memset(icmp, 0, sizeof(*icmp));
|
|
|
- icmp->icmp_type = ICMP_ECHO;
|
|
|
- icmp->icmp_code = 0;
|
|
|
- icmp->icmp_cksum = 0;
|
|
|
- icmp->icmp_id = ping.ident;
|
|
|
- icmp->icmp_seq = htons(ping_host->seq);
|
|
|
-
|
|
|
- gettimeofday(&packet->msg.tv, 0);
|
|
|
- packet->msg.sid = ping_host->sid;
|
|
|
- packet->msg.seq = ping_host->seq;
|
|
|
- icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
|
|
|
-
|
|
|
- len = sendto(ping_host->fd, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
|
|
- if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
|
|
- if (errno == ENETUNREACH) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
- char ping_host_name[PING_MAX_HOSTLEN];
|
|
|
- tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
|
|
|
- strerror(errno));
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
+ struct fast_ping_packet *packet = &ping_host->packet;
|
|
|
+ struct icmp *icmp = &packet->icmp;
|
|
|
+ int len;
|
|
|
+
|
|
|
+ ping_host->seq++;
|
|
|
+ memset(icmp, 0, sizeof(*icmp));
|
|
|
+ icmp->icmp_type = ICMP_ECHO;
|
|
|
+ icmp->icmp_code = 0;
|
|
|
+ icmp->icmp_cksum = 0;
|
|
|
+ icmp->icmp_id = ping.ident;
|
|
|
+ icmp->icmp_seq = htons(ping_host->seq);
|
|
|
+
|
|
|
+ gettimeofday(&packet->msg.tv, 0);
|
|
|
+ packet->msg.sid = ping_host->sid;
|
|
|
+ packet->msg.seq = ping_host->seq;
|
|
|
+ icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
|
|
|
+
|
|
|
+ len = sendto(ping.fd_icmp, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
|
|
+ if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
|
|
+ if (errno == ENETUNREACH) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ char ping_host_name[PING_MAX_HOSTLEN];
|
|
|
+ tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
|
|
|
+ strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
|
|
|
errout:
|
|
|
- return -1;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
-static int _fast_ping_sendping(struct ping_host_struct *ping_host)
|
|
|
+static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host)
|
|
|
{
|
|
|
- int ret = -1;
|
|
|
+ struct epoll_event event;
|
|
|
+ int flags;
|
|
|
+ int fd = 0;
|
|
|
+
|
|
|
+ fd = socket(ping_host->ss_family, SOCK_STREAM, 0);
|
|
|
+ if (fd < 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ flags = fcntl(fd, F_GETFL, 0);
|
|
|
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
|
+
|
|
|
+ ping_host->seq++;
|
|
|
+ if (connect(fd, (struct sockaddr *)&ping_host->addr, ping_host->addr_len) != 0) {
|
|
|
+ if (errno != EINPROGRESS) {
|
|
|
+ char ping_host_name[PING_MAX_HOSTLEN];
|
|
|
+ if (errno == ENETUNREACH) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ tlog(TLOG_ERROR, "connect %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
|
|
|
+ strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (ping_host->type == FAST_PING_ICMP) {
|
|
|
- ret = _fast_ping_sendping_v4(ping_host);
|
|
|
- } else if (ping_host->type == FAST_PING_ICMP6) {
|
|
|
- ret = _fast_ping_sendping_v6(ping_host);
|
|
|
- }
|
|
|
+ event.events = EPOLLIN | EPOLLOUT;
|
|
|
+ event.data.ptr = ping_host;
|
|
|
+ if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
|
|
|
- ping_host->send = 1;
|
|
|
- gettimeofday(&ping_host->last, 0);
|
|
|
+ if (ping_host->fd > 0) {
|
|
|
+ close(ping_host->fd);
|
|
|
+ }
|
|
|
+ ping_host->fd = fd;
|
|
|
|
|
|
- if (ret != 0) {
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
|
|
|
- return 0;
|
|
|
+errout:
|
|
|
+ if (fd > 0) {
|
|
|
+ close(fd);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
-static int _fast_ping_create_sock(FAST_PING_TYPE type)
|
|
|
+static int _fast_ping_sendping(struct ping_host_struct *ping_host)
|
|
|
{
|
|
|
- int fd = -1;
|
|
|
- struct ping_host_struct *icmp_host = NULL;
|
|
|
- struct epoll_event event;
|
|
|
- int buffsize = 64 * 1024;
|
|
|
- socklen_t optlen = sizeof(buffsize);
|
|
|
-
|
|
|
- switch (type) {
|
|
|
- case FAST_PING_ICMP:
|
|
|
- fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
|
|
- if (fd < 0) {
|
|
|
- tlog(TLOG_ERROR, "create icmp socket failed.\n");
|
|
|
- goto errout;
|
|
|
- }
|
|
|
- _fast_ping_install_filter_v4(fd);
|
|
|
- icmp_host = &ping.icmp_host;
|
|
|
- break;
|
|
|
- case FAST_PING_ICMP6:
|
|
|
- fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
|
|
- if (fd < 0) {
|
|
|
- tlog(TLOG_ERROR, "create icmp socket failed.\n");
|
|
|
- goto errout;
|
|
|
- }
|
|
|
- _fast_ping_install_filter_v6(fd);
|
|
|
- icmp_host = &ping.icmp6_host;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ int ret = -1;
|
|
|
|
|
|
- setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&buffsize, optlen);
|
|
|
- setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&buffsize, optlen);
|
|
|
+ if (ping_host->type == FAST_PING_ICMP) {
|
|
|
+ ret = _fast_ping_sendping_v4(ping_host);
|
|
|
+ } else if (ping_host->type == FAST_PING_ICMP6) {
|
|
|
+ ret = _fast_ping_sendping_v6(ping_host);
|
|
|
+ } else if (ping_host->type == FAST_PING_TCP) {
|
|
|
+ ret = _fast_ping_sendping_tcp(ping_host);
|
|
|
+ }
|
|
|
|
|
|
- event.events = EPOLLIN;
|
|
|
- event.data.ptr = icmp_host;
|
|
|
- if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
+ ping_host->send = 1;
|
|
|
+ gettimeofday(&ping_host->last, 0);
|
|
|
|
|
|
- icmp_host->fd = fd;
|
|
|
- icmp_host->type = type;
|
|
|
- return fd;
|
|
|
+ if (ret != 0) {
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
-errout:
|
|
|
- close(fd);
|
|
|
- return -1;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static int _fast_ping_create_icmp(FAST_PING_TYPE type)
|
|
|
+static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
|
|
|
{
|
|
|
- int fd = 0;
|
|
|
- int *set_fd = NULL;
|
|
|
-
|
|
|
- pthread_mutex_lock(&ping.lock);
|
|
|
- switch (type) {
|
|
|
- case FAST_PING_ICMP:
|
|
|
- set_fd = &ping.fd_icmp;
|
|
|
- break;
|
|
|
- case FAST_PING_ICMP6:
|
|
|
- set_fd = &ping.fd_icmp6;
|
|
|
- break;
|
|
|
- default:
|
|
|
- goto errout;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (*set_fd > 0) {
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ int fd = -1;
|
|
|
+ struct ping_host_struct *icmp_host = NULL;
|
|
|
+ struct epoll_event event;
|
|
|
+ int buffsize = 64 * 1024;
|
|
|
+ socklen_t optlen = sizeof(buffsize);
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case FAST_PING_ICMP:
|
|
|
+ fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
|
|
+ if (fd < 0) {
|
|
|
+ tlog(TLOG_ERROR, "create icmp socket failed.\n");
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ _fast_ping_install_filter_v4(fd);
|
|
|
+ icmp_host = &ping.icmp_host;
|
|
|
+ break;
|
|
|
+ case FAST_PING_ICMP6:
|
|
|
+ fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
|
|
+ if (fd < 0) {
|
|
|
+ tlog(TLOG_ERROR, "create icmp socket failed.\n");
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ _fast_ping_install_filter_v6(fd);
|
|
|
+ icmp_host = &ping.icmp6_host;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&buffsize, optlen);
|
|
|
+ setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&buffsize, optlen);
|
|
|
+
|
|
|
+ event.events = EPOLLIN;
|
|
|
+ event.data.ptr = icmp_host;
|
|
|
+ if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ icmp_host->fd = fd;
|
|
|
+ icmp_host->type = type;
|
|
|
+ return fd;
|
|
|
|
|
|
- fd = _fast_ping_create_sock(type);
|
|
|
- if (fd < 0) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
+errout:
|
|
|
+ close(fd);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
|
|
|
- *set_fd = fd;
|
|
|
+static int _fast_ping_create_icmp(FAST_PING_TYPE type)
|
|
|
+{
|
|
|
+ int fd = 0;
|
|
|
+ int *set_fd = NULL;
|
|
|
+
|
|
|
+ pthread_mutex_lock(&ping.lock);
|
|
|
+ switch (type) {
|
|
|
+ case FAST_PING_ICMP:
|
|
|
+ set_fd = &ping.fd_icmp;
|
|
|
+ break;
|
|
|
+ case FAST_PING_ICMP6:
|
|
|
+ set_fd = &ping.fd_icmp6;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ goto errout;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (*set_fd > 0) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ fd = _fast_ping_create_icmp_sock(type);
|
|
|
+ if (fd < 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ *set_fd = fd;
|
|
|
out:
|
|
|
- pthread_mutex_unlock(&ping.lock);
|
|
|
- return *set_fd;
|
|
|
+ pthread_mutex_unlock(&ping.lock);
|
|
|
+ return *set_fd;
|
|
|
errout:
|
|
|
- if (fd > 0) {
|
|
|
- close(fd);
|
|
|
- }
|
|
|
- pthread_mutex_unlock(&ping.lock);
|
|
|
- return -1;
|
|
|
+ if (fd > 0) {
|
|
|
+ close(fd);
|
|
|
+ }
|
|
|
+ pthread_mutex_unlock(&ping.lock);
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
void fast_ping_print_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno,
|
|
|
- struct timeval *tv, void *userptr)
|
|
|
+ struct timeval *tv, void *userptr)
|
|
|
{
|
|
|
- if (result == PING_RESULT_RESPONSE) {
|
|
|
- double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0;
|
|
|
- tlog(TLOG_INFO, "from %15s: seq=%d time=%.3f\n", host, seqno, rtt);
|
|
|
- } else if (result == PING_RESULT_TIMEOUT) {
|
|
|
- tlog(TLOG_INFO, "from %15s: seq=%d timeout\n", host, seqno);
|
|
|
- }
|
|
|
+ if (result == PING_RESULT_RESPONSE) {
|
|
|
+ double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0;
|
|
|
+ tlog(TLOG_INFO, "from %15s: seq=%d time=%.3f\n", host, seqno, rtt);
|
|
|
+ } else if (result == PING_RESULT_TIMEOUT) {
|
|
|
+ tlog(TLOG_INFO, "from %15s: seq=%d timeout\n", host, seqno);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
struct ping_host_struct *fast_ping_start(const char *host, int count, int interval, int timeout, fast_ping_result ping_callback, void *userptr)
|
|
|
{
|
|
|
- struct ping_host_struct *ping_host = NULL;
|
|
|
- struct addrinfo *gai = NULL;
|
|
|
- int domain = -1;
|
|
|
- int icmp_proto = 0;
|
|
|
- uint32_t hostkey;
|
|
|
- uint32_t addrkey;
|
|
|
- int fd = -1;
|
|
|
- FAST_PING_TYPE type;
|
|
|
-
|
|
|
- domain = _fast_ping_getdomain(host);
|
|
|
- if (domain < 0) {
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- switch (domain) {
|
|
|
- case AF_INET:
|
|
|
- icmp_proto = IPPROTO_ICMP;
|
|
|
- type = FAST_PING_ICMP;
|
|
|
- break;
|
|
|
- case AF_INET6:
|
|
|
- icmp_proto = IPPROTO_ICMPV6;
|
|
|
- type = FAST_PING_ICMP6;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return NULL;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- fd = _fast_ping_create_icmp(type);
|
|
|
- if (fd < 0) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- gai = _fast_ping_getaddr(host, SOCK_RAW, icmp_proto);
|
|
|
- if (gai == NULL) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- ping_host = malloc(sizeof(*ping_host));
|
|
|
- if (ping_host == NULL) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- memset(ping_host, 0, sizeof(*ping_host));
|
|
|
- strncpy(ping_host->host, host, PING_MAX_HOSTLEN);
|
|
|
- ping_host->fd = fd;
|
|
|
- ping_host->timeout = timeout;
|
|
|
- ping_host->count = count;
|
|
|
- ping_host->type = type;
|
|
|
- ping_host->userptr = userptr;
|
|
|
- atomic_set(&ping_host->ref, 0);
|
|
|
- ping_host->sid = atomic_inc_return(&ping_sid);
|
|
|
- if (ping_callback) {
|
|
|
- ping_host->ping_callback = ping_callback;
|
|
|
- } else {
|
|
|
- ping_host->ping_callback = fast_ping_print_result;
|
|
|
- }
|
|
|
- ping_host->interval = (timeout > interval) ? timeout : interval;
|
|
|
- ping_host->addr_len = gai->ai_addrlen;
|
|
|
- if (gai->ai_addrlen > sizeof(struct sockaddr_in6)) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
- memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen);
|
|
|
-
|
|
|
- tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid);
|
|
|
- if (_fast_ping_sendping(ping_host) != 0) {
|
|
|
- goto errout1;
|
|
|
- }
|
|
|
-
|
|
|
- hostkey = hash_string(ping_host->host);
|
|
|
- addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0);
|
|
|
- addrkey = jhash(&ping_host->sid, sizeof(ping_host->sid), addrkey);
|
|
|
- pthread_mutex_lock(&ping.map_lock);
|
|
|
- _fast_ping_host_get(ping_host);
|
|
|
- hash_add(ping.hostmap, &ping_host->host_node, hostkey);
|
|
|
- hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
|
|
|
- pthread_mutex_unlock(&ping.map_lock);
|
|
|
-
|
|
|
- freeaddrinfo(gai);
|
|
|
-
|
|
|
-
|
|
|
- return ping_host;
|
|
|
+ struct ping_host_struct *ping_host = NULL;
|
|
|
+ struct addrinfo *gai = NULL;
|
|
|
+ int domain = -1;
|
|
|
+ int icmp_proto = 0;
|
|
|
+ uint32_t hostkey;
|
|
|
+ uint32_t addrkey;
|
|
|
+ char ip_str[PING_MAX_HOSTLEN];
|
|
|
+ char port_str[MAX_IP_LEN];
|
|
|
+ char *service = NULL;
|
|
|
+ int port = -1;
|
|
|
+ FAST_PING_TYPE type;
|
|
|
+ int socktype = 0;
|
|
|
+
|
|
|
+ if (parse_ip(host, ip_str, &port) != 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (port > 0) {
|
|
|
+ icmp_proto = 0;
|
|
|
+ socktype = SOCK_STREAM;
|
|
|
+ snprintf(port_str, MAX_IP_LEN, "%d", port);
|
|
|
+ service = port_str;
|
|
|
+ type = FAST_PING_TCP;
|
|
|
+
|
|
|
+ gai = _fast_ping_getaddr(ip_str, service, socktype, icmp_proto);
|
|
|
+ if (gai == NULL) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ socktype = SOCK_RAW;
|
|
|
+ domain = _fast_ping_getdomain(ip_str);
|
|
|
+ if (domain < 0) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (domain) {
|
|
|
+ case AF_INET:
|
|
|
+ icmp_proto = IPPROTO_ICMP;
|
|
|
+ type = FAST_PING_ICMP;
|
|
|
+ break;
|
|
|
+ case AF_INET6:
|
|
|
+ icmp_proto = IPPROTO_ICMPV6;
|
|
|
+ type = FAST_PING_ICMP6;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return NULL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_fast_ping_create_icmp(type) < 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ gai = _fast_ping_getaddr(ip_str, service, socktype, icmp_proto);
|
|
|
+ if (gai == NULL) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ping_host = malloc(sizeof(*ping_host));
|
|
|
+ if (ping_host == NULL) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(ping_host, 0, sizeof(*ping_host));
|
|
|
+ strncpy(ping_host->host, host, PING_MAX_HOSTLEN);
|
|
|
+ ping_host->fd = -1;
|
|
|
+ ping_host->timeout = timeout;
|
|
|
+ ping_host->count = count;
|
|
|
+ ping_host->type = type;
|
|
|
+ ping_host->userptr = userptr;
|
|
|
+ atomic_set(&ping_host->ref, 0);
|
|
|
+ ping_host->sid = atomic_inc_return(&ping_sid);
|
|
|
+ if (ping_callback) {
|
|
|
+ ping_host->ping_callback = ping_callback;
|
|
|
+ } else {
|
|
|
+ ping_host->ping_callback = fast_ping_print_result;
|
|
|
+ }
|
|
|
+ ping_host->interval = (timeout > interval) ? timeout : interval;
|
|
|
+ ping_host->addr_len = gai->ai_addrlen;
|
|
|
+ ping_host->port = port;
|
|
|
+ ping_host->ss_family = gai->ai_family;
|
|
|
+ if (gai->ai_addrlen > sizeof(struct sockaddr_in6)) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen);
|
|
|
+
|
|
|
+ tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid);
|
|
|
+ if (_fast_ping_sendping(ping_host) != 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ hostkey = hash_string(ping_host->host);
|
|
|
+ addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0);
|
|
|
+ addrkey = jhash(&ping_host->sid, sizeof(ping_host->sid), addrkey);
|
|
|
+ pthread_mutex_lock(&ping.map_lock);
|
|
|
+ _fast_ping_host_get(ping_host);
|
|
|
+ hash_add(ping.hostmap, &ping_host->host_node, hostkey);
|
|
|
+ hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
|
|
|
+ pthread_mutex_unlock(&ping.map_lock);
|
|
|
+
|
|
|
+ freeaddrinfo(gai);
|
|
|
+
|
|
|
+ return ping_host;
|
|
|
errout:
|
|
|
- if (fd > 0) {
|
|
|
- close(fd);
|
|
|
- }
|
|
|
-errout1:
|
|
|
- if (gai) {
|
|
|
- freeaddrinfo(gai);
|
|
|
- }
|
|
|
+ if (gai) {
|
|
|
+ freeaddrinfo(gai);
|
|
|
+ }
|
|
|
|
|
|
- if (ping_host) {
|
|
|
- free(ping_host);
|
|
|
- }
|
|
|
+ if (ping_host) {
|
|
|
+ free(ping_host);
|
|
|
+ }
|
|
|
|
|
|
- return NULL;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
int fast_ping_stop(struct ping_host_struct *ping_host)
|
|
|
{
|
|
|
- _fast_ping_host_put(ping_host);
|
|
|
- return 0;
|
|
|
+ _fast_ping_host_put(ping_host);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static void tv_sub(struct timeval *out, struct timeval *in)
|
|
|
{
|
|
|
- if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
|
|
|
- --out->tv_sec;
|
|
|
- out->tv_usec += 1000000;
|
|
|
- }
|
|
|
- out->tv_sec -= in->tv_sec;
|
|
|
+ if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
|
|
|
+ --out->tv_sec;
|
|
|
+ out->tv_usec += 1000000;
|
|
|
+ }
|
|
|
+ out->tv_sec -= in->tv_sec;
|
|
|
}
|
|
|
|
|
|
static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len)
|
|
|
{
|
|
|
- int icmp_len;
|
|
|
- struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
|
|
|
- struct icmp6_hdr *icmp6 = &packet->icmp6;
|
|
|
-
|
|
|
- if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) {
|
|
|
- tlog(TLOG_DEBUG, "icmp6 type faild, %d:%d", icmp6->icmp6_type, ICMP6_ECHO_REPLY);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- icmp_len = data_len;
|
|
|
- if (icmp_len < 16) {
|
|
|
- tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (icmp6->icmp6_id != ping.ident) {
|
|
|
- tlog(TLOG_ERROR, "ident failed, %d:%d", icmp6->icmp6_id, ping.ident);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- return packet;
|
|
|
+ int icmp_len;
|
|
|
+ struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
|
|
|
+ struct icmp6_hdr *icmp6 = &packet->icmp6;
|
|
|
+
|
|
|
+ if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) {
|
|
|
+ tlog(TLOG_DEBUG, "icmp6 type faild, %d:%d", icmp6->icmp6_type, ICMP6_ECHO_REPLY);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ icmp_len = data_len;
|
|
|
+ if (icmp_len < 16) {
|
|
|
+ tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (icmp6->icmp6_id != ping.ident) {
|
|
|
+ tlog(TLOG_ERROR, "ident failed, %d:%d", icmp6->icmp6_id, ping.ident);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return packet;
|
|
|
}
|
|
|
|
|
|
static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len)
|
|
|
{
|
|
|
- struct ip *ip = (struct ip *)packet_data;
|
|
|
- struct fast_ping_packet *packet;
|
|
|
- struct icmp *icmp;
|
|
|
- int hlen;
|
|
|
- int icmp_len;
|
|
|
-
|
|
|
- if (ip->ip_p != IPPROTO_ICMP) {
|
|
|
- tlog(TLOG_ERROR, "ip type faild, %d:%d", ip->ip_p, IPPROTO_ICMP);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- hlen = ip->ip_hl << 2;
|
|
|
- packet = (struct fast_ping_packet *)(packet_data + hlen);
|
|
|
- icmp = &packet->icmp;
|
|
|
- icmp_len = data_len - hlen;
|
|
|
-
|
|
|
- if (icmp_len < 16) {
|
|
|
- tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (icmp->icmp_type != ICMP_ECHOREPLY) {
|
|
|
- tlog(TLOG_DEBUG, "icmp type faild, %d:%d", icmp->icmp_type, ICMP_ECHOREPLY);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (icmp->icmp_id != ping.ident) {
|
|
|
- tlog(TLOG_ERROR, "ident failed, %d:%d", icmp->icmp_id, ping.ident);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
-
|
|
|
- return packet;
|
|
|
+ struct ip *ip = (struct ip *)packet_data;
|
|
|
+ struct fast_ping_packet *packet;
|
|
|
+ struct icmp *icmp;
|
|
|
+ int hlen;
|
|
|
+ int icmp_len;
|
|
|
+
|
|
|
+ if (ip->ip_p != IPPROTO_ICMP) {
|
|
|
+ tlog(TLOG_ERROR, "ip type faild, %d:%d", ip->ip_p, IPPROTO_ICMP);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ hlen = ip->ip_hl << 2;
|
|
|
+ packet = (struct fast_ping_packet *)(packet_data + hlen);
|
|
|
+ icmp = &packet->icmp;
|
|
|
+ icmp_len = data_len - hlen;
|
|
|
+
|
|
|
+ if (icmp_len < 16) {
|
|
|
+ tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (icmp->icmp_type != ICMP_ECHOREPLY) {
|
|
|
+ tlog(TLOG_DEBUG, "icmp type faild, %d:%d", icmp->icmp_type, ICMP_ECHOREPLY);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (icmp->icmp_id != ping.ident) {
|
|
|
+ tlog(TLOG_ERROR, "ident failed, %d:%d", icmp->icmp_id, ping.ident);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return packet;
|
|
|
}
|
|
|
|
|
|
struct fast_ping_packet *_fast_ping_recv_packet(struct ping_host_struct *ping_host, u_char *inpacket, int len, struct timeval *tvrecv)
|
|
|
{
|
|
|
- struct fast_ping_packet *packet = NULL;
|
|
|
-
|
|
|
- if (ping_host->type == FAST_PING_ICMP6) {
|
|
|
- packet = _fast_ping_icmp6_packet(ping_host, inpacket, len);
|
|
|
- if (packet == NULL) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
- } else if (ping_host->type == FAST_PING_ICMP) {
|
|
|
- packet = _fast_ping_icmp_packet(ping_host, inpacket, len);
|
|
|
- if (packet == NULL) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
- } else {
|
|
|
- tlog(TLOG_ERROR, "ping host type is invalid, %d", ping_host->type);
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- return packet;
|
|
|
+ struct fast_ping_packet *packet = NULL;
|
|
|
+
|
|
|
+ if (ping_host->type == FAST_PING_ICMP6) {
|
|
|
+ packet = _fast_ping_icmp6_packet(ping_host, inpacket, len);
|
|
|
+ if (packet == NULL) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ } else if (ping_host->type == FAST_PING_ICMP) {
|
|
|
+ packet = _fast_ping_icmp_packet(ping_host, inpacket, len);
|
|
|
+ if (packet == NULL) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ tlog(TLOG_ERROR, "ping host type is invalid, %d", ping_host->type);
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ return packet;
|
|
|
errout:
|
|
|
- return NULL;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct timeval *now)
|
|
|
{
|
|
|
- int len;
|
|
|
- u_char inpacket[ICMP_INPACKET_SIZE];
|
|
|
- struct sockaddr_storage from;
|
|
|
- struct ping_host_struct *recv_ping_host;
|
|
|
- struct fast_ping_packet *packet = NULL;
|
|
|
- socklen_t from_len = sizeof(from);
|
|
|
- uint32_t addrkey;
|
|
|
- struct timeval tvresult = *now;
|
|
|
- struct timeval *tvsend = NULL;
|
|
|
- unsigned int sid;
|
|
|
- unsigned int seq;
|
|
|
-
|
|
|
- len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
|
|
|
- if (len < 0) {
|
|
|
- tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno));
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- packet = _fast_ping_recv_packet(ping_host, inpacket, len, now);
|
|
|
- if (packet == NULL) {
|
|
|
- char name[PING_MAX_HOSTLEN];
|
|
|
- tlog(TLOG_DEBUG, "recv ping packet from %s failed.", gethost_by_addr(name, (struct sockaddr *)&from, from_len));
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- addrkey = jhash(&from, from_len, 0);
|
|
|
- tvsend = &packet->msg.tv;
|
|
|
- sid = packet->msg.sid;
|
|
|
- seq = packet->msg.seq;
|
|
|
- addrkey = jhash(&sid, sizeof(sid), addrkey);
|
|
|
- pthread_mutex_lock(&ping.map_lock);
|
|
|
- hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
|
|
|
- {
|
|
|
- if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0 && recv_ping_host->sid == sid) {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- pthread_mutex_unlock(&ping.map_lock);
|
|
|
-
|
|
|
- if (recv_ping_host == NULL) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- if (recv_ping_host->seq != seq) {
|
|
|
- tlog(TLOG_ERROR, "seq num mismatch, expect %u, real %u", recv_ping_host->seq, seq);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- tv_sub(&tvresult, tvsend);
|
|
|
- if (recv_ping_host->ping_callback) {
|
|
|
- recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len,
|
|
|
- recv_ping_host->seq, &tvresult, recv_ping_host->userptr);
|
|
|
- }
|
|
|
-
|
|
|
- recv_ping_host->send = 0;
|
|
|
-
|
|
|
- if (recv_ping_host->count == 1) {
|
|
|
- _fast_ping_host_put(recv_ping_host);
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
+ int len;
|
|
|
+ u_char inpacket[ICMP_INPACKET_SIZE];
|
|
|
+ struct sockaddr_storage from;
|
|
|
+ struct ping_host_struct *recv_ping_host;
|
|
|
+ struct fast_ping_packet *packet = NULL;
|
|
|
+ socklen_t from_len = sizeof(from);
|
|
|
+ uint32_t addrkey;
|
|
|
+ struct timeval tvresult = *now;
|
|
|
+ struct timeval *tvsend = NULL;
|
|
|
+ unsigned int sid;
|
|
|
+ unsigned int seq;
|
|
|
+
|
|
|
+ len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
|
|
|
+ if (len < 0) {
|
|
|
+ tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ packet = _fast_ping_recv_packet(ping_host, inpacket, len, now);
|
|
|
+ if (packet == NULL) {
|
|
|
+ char name[PING_MAX_HOSTLEN];
|
|
|
+ tlog(TLOG_DEBUG, "recv ping packet from %s failed.", gethost_by_addr(name, (struct sockaddr *)&from, from_len));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ addrkey = jhash(&from, from_len, 0);
|
|
|
+ tvsend = &packet->msg.tv;
|
|
|
+ sid = packet->msg.sid;
|
|
|
+ seq = packet->msg.seq;
|
|
|
+ addrkey = jhash(&sid, sizeof(sid), addrkey);
|
|
|
+ pthread_mutex_lock(&ping.map_lock);
|
|
|
+ hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
|
|
|
+ {
|
|
|
+ if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0 && recv_ping_host->sid == sid) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_mutex_unlock(&ping.map_lock);
|
|
|
+
|
|
|
+ if (recv_ping_host == NULL) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (recv_ping_host->seq != seq) {
|
|
|
+ tlog(TLOG_ERROR, "seq num mismatch, expect %u, real %u", recv_ping_host->seq, seq);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ tv_sub(&tvresult, tvsend);
|
|
|
+ if (recv_ping_host->ping_callback) {
|
|
|
+ recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len,
|
|
|
+ recv_ping_host->seq, &tvresult, recv_ping_host->userptr);
|
|
|
+ }
|
|
|
+
|
|
|
+ recv_ping_host->send = 0;
|
|
|
+
|
|
|
+ if (recv_ping_host->count == 1) {
|
|
|
+ _fast_ping_host_put(recv_ping_host);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
errout:
|
|
|
- return -1;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
-static int _fast_ping_process(struct ping_host_struct *ping_host, struct timeval *now)
|
|
|
+static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epoll_event *event, struct timeval *now)
|
|
|
{
|
|
|
- int ret = -1;
|
|
|
-
|
|
|
- switch (ping_host->type) {
|
|
|
- case FAST_PING_ICMP6:
|
|
|
- case FAST_PING_ICMP:
|
|
|
- ret = _fast_ping_process_icmp(ping_host, now);
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
+ struct timeval tvresult = *now;
|
|
|
+ struct timeval *tvsend = &ping_host->last;
|
|
|
+ int connect_error = 0;
|
|
|
+ socklen_t len = sizeof(connect_error);
|
|
|
+
|
|
|
+ if (event->events & EPOLLIN || event->events & EPOLLERR) {
|
|
|
+ if (getsockopt(ping_host->fd, SOL_SOCKET, SO_ERROR, (char *)&connect_error, &len) != 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ if (connect_error != 0 && connect_error != ECONNREFUSED) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ tv_sub(&tvresult, tvsend);
|
|
|
+ if (ping_host->ping_callback) {
|
|
|
+ ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr, ping_host->addr_len,
|
|
|
+ ping_host->seq, &tvresult, ping_host->userptr);
|
|
|
+ }
|
|
|
+
|
|
|
+ ping_host->send = 0;
|
|
|
+
|
|
|
+ if (ping_host->fd > 0) {
|
|
|
+ close(ping_host->fd);
|
|
|
+ ping_host->fd = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ping_host->count == 1) {
|
|
|
+ _fast_ping_host_put(ping_host);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+errout:
|
|
|
+ if (ping_host->fd > 0) {
|
|
|
+ close(ping_host->fd);
|
|
|
+ ping_host->fd = -1;
|
|
|
+ }
|
|
|
|
|
|
- return ret;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
-static void _fast_ping_period_run()
|
|
|
+static int _fast_ping_process(struct ping_host_struct *ping_host, struct epoll_event *event, struct timeval *now)
|
|
|
{
|
|
|
- struct ping_host_struct *ping_host;
|
|
|
- struct hlist_node *tmp;
|
|
|
- int i = 0;
|
|
|
- struct timeval now;
|
|
|
- struct timeval interval;
|
|
|
- int64_t millisecond;
|
|
|
- gettimeofday(&now, 0);
|
|
|
-
|
|
|
- pthread_mutex_lock(&ping.map_lock);
|
|
|
- hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node)
|
|
|
- {
|
|
|
- interval = now;
|
|
|
- tv_sub(&interval, &ping_host->last);
|
|
|
- millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
|
|
|
- if (millisecond >= ping_host->timeout && ping_host->send == 1) {
|
|
|
- ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, &interval,
|
|
|
- ping_host->userptr);
|
|
|
- ping_host->send = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (millisecond < ping_host->interval) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if (ping_host->count > 0) {
|
|
|
- if (ping_host->count == 1) {
|
|
|
- hash_del(&ping_host->host_node);
|
|
|
- hash_del(&ping_host->addr_node);
|
|
|
- _fast_ping_host_put_locked(ping_host);
|
|
|
- continue;
|
|
|
- }
|
|
|
- ping_host->count--;
|
|
|
- }
|
|
|
+ int ret = -1;
|
|
|
+
|
|
|
+ switch (ping_host->type) {
|
|
|
+ case FAST_PING_ICMP6:
|
|
|
+ case FAST_PING_ICMP:
|
|
|
+ ret = _fast_ping_process_icmp(ping_host, now);
|
|
|
+ break;
|
|
|
+ case FAST_PING_TCP:
|
|
|
+ ret = _fast_ping_process_tcp(ping_host, event, now);
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
|
|
|
- _fast_ping_sendping(ping_host);
|
|
|
- }
|
|
|
- pthread_mutex_unlock(&ping.map_lock);
|
|
|
+static void _fast_ping_period_run()
|
|
|
+{
|
|
|
+ struct ping_host_struct *ping_host;
|
|
|
+ struct hlist_node *tmp;
|
|
|
+ int i = 0;
|
|
|
+ struct timeval now;
|
|
|
+ struct timeval interval;
|
|
|
+ int64_t millisecond;
|
|
|
+ gettimeofday(&now, 0);
|
|
|
+
|
|
|
+ pthread_mutex_lock(&ping.map_lock);
|
|
|
+ hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node)
|
|
|
+ {
|
|
|
+ interval = now;
|
|
|
+ tv_sub(&interval, &ping_host->last);
|
|
|
+ millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
|
|
|
+ if (millisecond >= ping_host->timeout && ping_host->send == 1) {
|
|
|
+ ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, &interval,
|
|
|
+ ping_host->userptr);
|
|
|
+ ping_host->send = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (millisecond < ping_host->interval) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ping_host->count > 0) {
|
|
|
+ if (ping_host->count == 1) {
|
|
|
+ hash_del(&ping_host->host_node);
|
|
|
+ hash_del(&ping_host->addr_node);
|
|
|
+ _fast_ping_host_put_locked(ping_host, 1);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ ping_host->count--;
|
|
|
+ }
|
|
|
+
|
|
|
+ _fast_ping_sendping(ping_host);
|
|
|
+ }
|
|
|
+ pthread_mutex_unlock(&ping.map_lock);
|
|
|
}
|
|
|
|
|
|
static void *_fast_ping_work(void *arg)
|
|
|
{
|
|
|
- struct epoll_event events[PING_MAX_EVENTS + 1];
|
|
|
- int num;
|
|
|
- int i;
|
|
|
- struct timeval last = {0};
|
|
|
- struct timeval now = {0};
|
|
|
- struct timeval diff = {0};
|
|
|
- uint millisec = 0;
|
|
|
-
|
|
|
- while (ping.run) {
|
|
|
- diff = now;
|
|
|
- tv_sub(&diff, &last);
|
|
|
- millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000;
|
|
|
- if (millisec >= 100) {
|
|
|
- _fast_ping_period_run();
|
|
|
- last = now;
|
|
|
- }
|
|
|
-
|
|
|
- num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, 100);
|
|
|
- if (num < 0) {
|
|
|
- gettimeofday(&now, 0);
|
|
|
- usleep(100000);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if (num == 0) {
|
|
|
- gettimeofday(&now, 0);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- gettimeofday(&now, 0);
|
|
|
- for (i = 0; i < num; i++) {
|
|
|
- struct epoll_event *event = &events[i];
|
|
|
- struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr;
|
|
|
- _fast_ping_process(ping_host, &now);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- close(ping.epoll_fd);
|
|
|
- ping.epoll_fd = -1;
|
|
|
-
|
|
|
- return NULL;
|
|
|
+ struct epoll_event events[PING_MAX_EVENTS + 1];
|
|
|
+ int num;
|
|
|
+ int i;
|
|
|
+ struct timeval last = { 0 };
|
|
|
+ struct timeval now = { 0 };
|
|
|
+ struct timeval diff = { 0 };
|
|
|
+ uint millisec = 0;
|
|
|
+
|
|
|
+ while (ping.run) {
|
|
|
+ diff = now;
|
|
|
+ tv_sub(&diff, &last);
|
|
|
+ millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000;
|
|
|
+ if (millisec >= 100) {
|
|
|
+ _fast_ping_period_run();
|
|
|
+ last = now;
|
|
|
+ }
|
|
|
+
|
|
|
+ num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, 100);
|
|
|
+ if (num < 0) {
|
|
|
+ gettimeofday(&now, 0);
|
|
|
+ usleep(100000);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (num == 0) {
|
|
|
+ gettimeofday(&now, 0);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ gettimeofday(&now, 0);
|
|
|
+ for (i = 0; i < num; i++) {
|
|
|
+ struct epoll_event *event = &events[i];
|
|
|
+ struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr;
|
|
|
+ _fast_ping_process(ping_host, event, &now);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ close(ping.epoll_fd);
|
|
|
+ ping.epoll_fd = -1;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
int fast_ping_init()
|
|
|
{
|
|
|
- pthread_attr_t attr;
|
|
|
- int epollfd = -1;
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (ping.epoll_fd > 0) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- memset(&ping, 0, sizeof(ping));
|
|
|
- pthread_attr_init(&attr);
|
|
|
-
|
|
|
- epollfd = epoll_create1(EPOLL_CLOEXEC);
|
|
|
- if (epollfd < 0) {
|
|
|
- tlog(TLOG_ERROR, "create epoll failed, %s\n", strerror(errno));
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- pthread_mutex_init(&ping.map_lock, 0);
|
|
|
- pthread_mutex_init(&ping.lock, 0);
|
|
|
- hash_init(ping.hostmap);
|
|
|
- hash_init(ping.addrmap);
|
|
|
- ping.epoll_fd = epollfd;
|
|
|
- ping.ident = getpid();
|
|
|
- ping.run = 1;
|
|
|
- ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
|
|
|
- if (ret != 0) {
|
|
|
- tlog(TLOG_ERROR, "create ping work thread failed, %s\n", strerror(errno));
|
|
|
- goto errout;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
+ pthread_attr_t attr;
|
|
|
+ int epollfd = -1;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (ping.epoll_fd > 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(&ping, 0, sizeof(ping));
|
|
|
+ pthread_attr_init(&attr);
|
|
|
+
|
|
|
+ epollfd = epoll_create1(EPOLL_CLOEXEC);
|
|
|
+ if (epollfd < 0) {
|
|
|
+ tlog(TLOG_ERROR, "create epoll failed, %s\n", strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_mutex_init(&ping.map_lock, 0);
|
|
|
+ pthread_mutex_init(&ping.lock, 0);
|
|
|
+ hash_init(ping.hostmap);
|
|
|
+ hash_init(ping.addrmap);
|
|
|
+ ping.epoll_fd = epollfd;
|
|
|
+ ping.ident = getpid();
|
|
|
+ ping.run = 1;
|
|
|
+ ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
|
|
|
+ if (ret != 0) {
|
|
|
+ tlog(TLOG_ERROR, "create ping work thread failed, %s\n", strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
errout:
|
|
|
- if (ping.tid > 0) {
|
|
|
- void *retval = NULL;
|
|
|
- ping.run = 0;
|
|
|
- pthread_join(ping.tid, &retval);
|
|
|
- }
|
|
|
+ if (ping.tid > 0) {
|
|
|
+ void *retval = NULL;
|
|
|
+ ping.run = 0;
|
|
|
+ pthread_join(ping.tid, &retval);
|
|
|
+ }
|
|
|
|
|
|
- if (epollfd) {
|
|
|
- close(epollfd);
|
|
|
- }
|
|
|
+ if (epollfd) {
|
|
|
+ close(epollfd);
|
|
|
+ }
|
|
|
|
|
|
- pthread_mutex_destroy(&ping.lock);
|
|
|
- pthread_mutex_destroy(&ping.map_lock);
|
|
|
+ pthread_mutex_destroy(&ping.lock);
|
|
|
+ pthread_mutex_destroy(&ping.map_lock);
|
|
|
|
|
|
- return -1;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
void fast_ping_exit()
|
|
|
{
|
|
|
- if (ping.tid > 0) {
|
|
|
- void *ret = NULL;
|
|
|
- ping.run = 0;
|
|
|
- pthread_join(ping.tid, &ret);
|
|
|
- }
|
|
|
-
|
|
|
- if (ping.fd_icmp > 0) {
|
|
|
- close(ping.fd_icmp);
|
|
|
- ping.fd_icmp = -1;
|
|
|
- }
|
|
|
-
|
|
|
- if (ping.fd_icmp6 > 0) {
|
|
|
- close(ping.fd_icmp6);
|
|
|
- ping.fd_icmp6 = -1;
|
|
|
- }
|
|
|
-
|
|
|
- pthread_mutex_destroy(&ping.lock);
|
|
|
- pthread_mutex_destroy(&ping.map_lock);
|
|
|
+ if (ping.tid > 0) {
|
|
|
+ void *ret = NULL;
|
|
|
+ ping.run = 0;
|
|
|
+ pthread_join(ping.tid, &ret);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ping.fd_icmp > 0) {
|
|
|
+ close(ping.fd_icmp);
|
|
|
+ ping.fd_icmp = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ping.fd_icmp6 > 0) {
|
|
|
+ close(ping.fd_icmp6);
|
|
|
+ ping.fd_icmp6 = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_mutex_destroy(&ping.lock);
|
|
|
+ pthread_mutex_destroy(&ping.map_lock);
|
|
|
}
|