2
0

fast_ping.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. #include "fast_ping.h"
  2. #include "atomic.h"
  3. #include "hashtable.h"
  4. #include <errno.h>
  5. #include <arpa/inet.h>
  6. #include <linux/filter.h>
  7. #include <netdb.h>
  8. #include <netinet/icmp6.h>
  9. #include <netinet/ip.h>
  10. #include <netinet/ip6.h>
  11. #include <netinet/ip_icmp.h>
  12. #include <pthread.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys/epoll.h>
  17. #include <sys/socket.h>
  18. #include <sys/types.h>
  19. #include <unistd.h>
  20. #define PING_MAX_EVENTS 128
  21. #define PING_MAX_HOSTLEN 128
  22. #define ICMP_PACKET_SIZE (1024 * 64)
  23. #define ICMP_INPACKET_SIZE 1024
  24. struct fast_ping_packet_msg {
  25. struct timeval tv;
  26. };
  27. struct fast_ping_packet {
  28. union {
  29. struct icmp icmp;
  30. struct icmp6_hdr icmp6;
  31. };
  32. struct fast_ping_packet_msg msg;
  33. };
  34. struct ping_host_struct {
  35. atomic_t ref;
  36. struct hlist_node host_node;
  37. struct hlist_node addr_node;
  38. int type;
  39. void *userptr;
  40. char host[PING_MAX_HOSTLEN];
  41. int fd;
  42. unsigned int seq;
  43. struct timeval last;
  44. int interval;
  45. int timeout;
  46. int send;
  47. struct sockaddr_storage addr;
  48. socklen_t addr_len;
  49. struct fast_ping_packet packet;
  50. };
  51. struct fast_ping_struct {
  52. int run;
  53. pthread_t tid;
  54. pthread_mutex_t lock;
  55. unsigned short ident;
  56. int epoll_fd;
  57. int fd_icmp;
  58. struct ping_host_struct icmp_host;
  59. int fd_icmp6;
  60. struct ping_host_struct icmp6_host;
  61. pthread_mutex_t map_lock;
  62. DECLARE_HASHTABLE(hostmap, 6);
  63. DECLARE_HASHTABLE(addrmap, 6);
  64. };
  65. static struct fast_ping_struct ping;
  66. static fast_ping_result ping_callback;
  67. uint16_t _fast_ping_checksum(uint16_t *header, size_t len)
  68. {
  69. uint32_t sum = 0;
  70. int i;
  71. for (i = 0; i < len / sizeof(uint16_t); i++) {
  72. sum += ntohs(header[i]);
  73. }
  74. return htons(~((sum >> 16) + (sum & 0xffff)));
  75. }
  76. void fast_ping_result_callback(fast_ping_result result)
  77. {
  78. ping_callback = result;
  79. }
  80. void _fast_ping_install_filter_v6(int sock)
  81. {
  82. struct icmp6_filter icmp6_filter;
  83. ICMP6_FILTER_SETBLOCKALL(&icmp6_filter);
  84. ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &icmp6_filter);
  85. setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_filter, sizeof(struct icmp6_filter));
  86. static int once;
  87. static struct sock_filter insns[] = {
  88. BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4), /* Load icmp echo ident */
  89. BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
  90. BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
  91. BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0), /* Load icmp type */
  92. BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */
  93. BPF_STMT(BPF_RET | BPF_K, ~0U), /* No. It passes. This must not happen. */
  94. BPF_STMT(BPF_RET | BPF_K, 0), /* Echo with wrong ident. Reject. */
  95. };
  96. static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns };
  97. if (once) {
  98. return;
  99. }
  100. once = 1;
  101. /* Patch bpflet for current identifier. */
  102. insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
  103. if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
  104. perror("WARNING: failed to install socket filter\n");
  105. }
  106. }
  107. void _fast_ping_install_filter_v4(int sock)
  108. {
  109. static int once;
  110. static struct sock_filter insns[] = {
  111. BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
  112. BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
  113. BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
  114. BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
  115. BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
  116. BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
  117. BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFF), /* No. It passes. */
  118. BPF_STMT(BPF_RET | BPF_K, 0) /* Echo with wrong ident. Reject. */
  119. };
  120. static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns };
  121. if (once) {
  122. return;
  123. }
  124. once = 1;
  125. /* Patch bpflet for current identifier. */
  126. insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
  127. if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
  128. perror("WARNING: failed to install socket filter\n");
  129. }
  130. }
  131. static struct addrinfo *_fast_ping_getaddr(const char *host, int type, int protocol)
  132. {
  133. struct addrinfo hints;
  134. struct addrinfo *result = NULL;
  135. memset(&hints, 0, sizeof(hints));
  136. hints.ai_family = AF_UNSPEC;
  137. hints.ai_socktype = type;
  138. hints.ai_protocol = protocol;
  139. if (getaddrinfo(host, NULL, &hints, &result) != 0) {
  140. fprintf(stderr, "get addr info failed. %s\n", strerror(errno));
  141. goto errout;
  142. }
  143. return result;
  144. errout:
  145. if (result) {
  146. freeaddrinfo(result);
  147. }
  148. return NULL;
  149. }
  150. static int _fast_ping_getdomain(const char *host)
  151. {
  152. struct addrinfo hints;
  153. struct addrinfo *result = NULL;
  154. int domain = -1;
  155. memset(&hints, 0, sizeof(hints));
  156. hints.ai_family = AF_UNSPEC;
  157. hints.ai_socktype = SOCK_STREAM;
  158. hints.ai_protocol = 0;
  159. if (getaddrinfo(host, NULL, &hints, &result) != 0) {
  160. fprintf(stderr, "get addr info failed. %s\n", strerror(errno));
  161. goto errout;
  162. }
  163. domain = result->ai_family;
  164. freeaddrinfo(result);
  165. return domain;
  166. errout:
  167. if (result) {
  168. freeaddrinfo(result);
  169. }
  170. return -1;
  171. }
  172. static void _fast_ping_host_get(struct ping_host_struct *ping_host)
  173. {
  174. atomic_inc(&ping_host->ref);
  175. }
  176. static void _fast_ping_host_put(struct ping_host_struct *ping_host)
  177. {
  178. pthread_mutex_lock(&ping.map_lock);
  179. if (atomic_dec_and_test(&ping_host->ref)) {
  180. hlist_del(&ping_host->host_node);
  181. hlist_del(&ping_host->addr_node);
  182. } else {
  183. ping_host = NULL;
  184. }
  185. pthread_mutex_unlock(&ping.map_lock);
  186. if (ping_host == NULL) {
  187. return ;
  188. }
  189. free(ping_host);
  190. }
  191. static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
  192. {
  193. struct fast_ping_packet *packet = &ping_host->packet;
  194. struct icmp6_hdr *icmp6 = &packet->icmp6;
  195. int len = 0;
  196. ping_host->seq++;
  197. memset(icmp6, 0, sizeof(*icmp6));
  198. icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
  199. icmp6->icmp6_code = 0;
  200. icmp6->icmp6_cksum = 0;
  201. icmp6->icmp6_id = getpid();
  202. icmp6->icmp6_seq = htons(ping_host->seq);
  203. gettimeofday(&packet->msg.tv, 0);
  204. icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
  205. len = sendto(ping_host->fd, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
  206. if (len < 0 || len != sizeof(struct fast_ping_packet)) {
  207. fprintf(stderr, "sendto %s\n", strerror(errno));
  208. goto errout;
  209. }
  210. return 0;
  211. errout:
  212. return -1;
  213. }
  214. static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
  215. {
  216. struct fast_ping_packet *packet = &ping_host->packet;
  217. struct icmp *icmp = &packet->icmp;
  218. int len;
  219. ping_host->seq++;
  220. memset(icmp, 0, sizeof(*icmp));
  221. icmp->icmp_type = ICMP_ECHO;
  222. icmp->icmp_code = 0;
  223. icmp->icmp_cksum = 0;
  224. icmp->icmp_id = ping.ident;
  225. icmp->icmp_seq = htons(ping_host->seq);
  226. gettimeofday(&packet->msg.tv, 0);
  227. icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
  228. len = sendto(ping_host->fd, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
  229. if (len < 0 || len != sizeof(struct fast_ping_packet)) {
  230. fprintf(stderr, "sendto %s\n", strerror(errno));
  231. goto errout;
  232. }
  233. return 0;
  234. errout:
  235. return -1;
  236. }
  237. static int _fast_ping_sendping(struct ping_host_struct *ping_host)
  238. {
  239. int ret = -1;
  240. if (ping_host->type == AF_INET) {
  241. ret = _fast_ping_sendping_v4(ping_host);
  242. } else if (ping_host->type == AF_INET6) {
  243. ret = _fast_ping_sendping_v6(ping_host);
  244. }
  245. if (ret != 0) {
  246. return ret;
  247. }
  248. ping_host->send = 1;
  249. gettimeofday(&ping_host->last, 0);
  250. return 0;
  251. }
  252. static int _fast_ping_create_sock(int protocol)
  253. {
  254. int fd = -1;
  255. struct ping_host_struct *icmp_host = NULL;
  256. struct epoll_event event;
  257. switch (protocol) {
  258. case IPPROTO_ICMP:
  259. fd = socket(AF_INET, SOCK_RAW, protocol);
  260. if (fd < 0) {
  261. fprintf(stderr, "create icmp socket failed.\n");
  262. goto errout;
  263. }
  264. _fast_ping_install_filter_v4(fd);
  265. icmp_host = &ping.icmp_host;
  266. break;
  267. case IPPROTO_ICMPV6:
  268. fd = socket(AF_INET6, SOCK_RAW, protocol);
  269. if (fd < 0) {
  270. fprintf(stderr, "create icmp socket failed.\n");
  271. goto errout;
  272. }
  273. _fast_ping_install_filter_v6(fd);
  274. icmp_host = &ping.icmp6_host;
  275. break;
  276. }
  277. event.events = EPOLLIN;
  278. event.data.ptr = icmp_host;
  279. if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
  280. goto errout;
  281. }
  282. icmp_host->fd = fd;
  283. icmp_host->type = AF_PACKET;
  284. return fd;
  285. errout:
  286. close(fd);
  287. return -1;
  288. }
  289. static int _fast_ping_create_icmp(int protocol)
  290. {
  291. int fd = 0;
  292. int *set_fd = NULL;
  293. pthread_mutex_lock(&ping.lock);
  294. switch (protocol) {
  295. case IPPROTO_ICMP:
  296. set_fd = &ping.fd_icmp;
  297. break;
  298. case IPPROTO_ICMPV6:
  299. set_fd = &ping.fd_icmp6;
  300. break;
  301. default:
  302. goto errout;
  303. break;
  304. }
  305. if (*set_fd > 0) {
  306. goto out;
  307. }
  308. fd = _fast_ping_create_sock(protocol);
  309. if (fd < 0) {
  310. goto errout;
  311. }
  312. *set_fd = fd;
  313. out:
  314. pthread_mutex_unlock(&ping.lock);
  315. return *set_fd;
  316. errout:
  317. if (fd > 0) {
  318. close(fd);
  319. }
  320. pthread_mutex_unlock(&ping.lock);
  321. return -1;
  322. }
  323. int fast_ping_start(const char *host, int timeout, void *userptr)
  324. {
  325. struct ping_host_struct *ping_host = NULL;
  326. struct addrinfo *gai = NULL;
  327. int domain = -1;
  328. int icmp_proto = 0;
  329. uint32_t hostkey;
  330. uint32_t addrkey;
  331. domain = _fast_ping_getdomain(host);
  332. if (domain < 0) {
  333. return -1;
  334. }
  335. switch (domain) {
  336. case AF_INET:
  337. icmp_proto = IPPROTO_ICMP;
  338. break;
  339. case AF_INET6:
  340. icmp_proto = IPPROTO_ICMPV6;
  341. break;
  342. default:
  343. return -1;
  344. break;
  345. }
  346. gai = _fast_ping_getaddr(host, SOCK_RAW, icmp_proto);
  347. if (gai == NULL) {
  348. return -1;
  349. }
  350. ping_host = malloc(sizeof(*ping_host));
  351. if (ping_host == NULL) {
  352. goto errout;
  353. }
  354. int interval = 1000;
  355. memset(ping_host, 0, sizeof(*ping_host));
  356. strncpy(ping_host->host, host, PING_MAX_HOSTLEN);
  357. ping_host->type = domain;
  358. ping_host->fd = _fast_ping_create_icmp(icmp_proto);
  359. ping_host->timeout = timeout;
  360. ping_host->interval = (timeout > interval) ? timeout : interval;
  361. memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen);
  362. ping_host->addr_len = gai->ai_addrlen;
  363. atomic_set(&ping_host->ref, 0);
  364. hostkey = hash_string(ping_host->host);
  365. addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0);
  366. pthread_mutex_lock(&ping.map_lock);
  367. _fast_ping_host_get(ping_host);
  368. hash_add(ping.hostmap, &ping_host->host_node, hostkey);
  369. hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
  370. pthread_mutex_unlock(&ping.map_lock);
  371. freeaddrinfo(gai);
  372. _fast_ping_sendping(ping_host);
  373. return 0;
  374. errout:
  375. if (gai) {
  376. freeaddrinfo(gai);
  377. }
  378. if (ping_host) {
  379. free(ping_host);
  380. }
  381. return -1;
  382. }
  383. int fast_ping_stop(const char *host)
  384. {
  385. struct ping_host_struct *ping_host;
  386. uint32_t key;
  387. key = hash_string(host);
  388. pthread_mutex_lock(&ping.map_lock);
  389. hash_for_each_possible(ping.hostmap, ping_host, host_node, key)
  390. {
  391. if (strncmp(host, ping_host->host, PING_MAX_HOSTLEN) == 0) {
  392. break;
  393. }
  394. }
  395. if (ping_host == NULL) {
  396. pthread_mutex_unlock(&ping.map_lock);
  397. return -1;
  398. }
  399. pthread_mutex_unlock(&ping.map_lock);
  400. _fast_ping_host_put(ping_host);
  401. return 0;
  402. }
  403. static void tv_sub(struct timeval *out, struct timeval *in)
  404. {
  405. if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
  406. --out->tv_sec;
  407. out->tv_usec += 1000000;
  408. }
  409. out->tv_sec -= in->tv_sec;
  410. }
  411. static int _fast_ping_icmp6_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len, struct timeval *tvrecv)
  412. {
  413. int icmp_len;
  414. struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
  415. struct icmp6_hdr *icmp6 = &packet->icmp6;
  416. struct timeval tvresult = *tvrecv;
  417. if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) {
  418. return -1;
  419. }
  420. icmp_len = data_len;
  421. if (icmp_len < 16) {
  422. return -1;
  423. }
  424. if (icmp6->icmp6_id != ping.ident) {
  425. return -1;
  426. }
  427. struct timeval *tvsend = &packet->msg.tv;
  428. tv_sub(&tvresult, tvsend);
  429. ping_callback(ping_host->host, PING_RESULT_RESPONSE, ping_host->seq, &tvresult, ping_host->userptr);
  430. return 0;
  431. }
  432. static int _fast_ping_icmp_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len, struct timeval *tvrecv)
  433. {
  434. struct ip *ip = (struct ip *)packet_data;
  435. struct fast_ping_packet *packet;
  436. struct icmp *icmp;
  437. struct timeval tvresult = *tvrecv;
  438. int hlen;
  439. int icmp_len;
  440. if (ip->ip_p != IPPROTO_ICMP) {
  441. return -1;
  442. }
  443. hlen = ip->ip_hl << 2;
  444. packet = (struct fast_ping_packet *)(packet_data + hlen);
  445. icmp = &packet->icmp;
  446. icmp_len = data_len - hlen;
  447. if (icmp_len < 16) {
  448. return -1;
  449. }
  450. if (icmp->icmp_type != ICMP_ECHOREPLY) {
  451. return -1;
  452. }
  453. if (icmp->icmp_id != ping.ident) {
  454. return -1;
  455. }
  456. struct timeval *tvsend = &packet->msg.tv;
  457. tv_sub(&tvresult, tvsend);
  458. ping_callback(ping_host->host, PING_RESULT_RESPONSE, ping_host->seq, &tvresult, ping_host->userptr);
  459. return 0;
  460. }
  461. static int _fast_ping_recvping(struct ping_host_struct *ping_host, u_char *inpacket, int len, struct timeval *tvrecv)
  462. {
  463. if (ping_host->type == AF_INET6) {
  464. if (_fast_ping_icmp6_packet(ping_host, inpacket, len, tvrecv)) {
  465. goto errout;
  466. }
  467. } else if (ping_host->type == AF_INET) {
  468. if (_fast_ping_icmp_packet(ping_host, inpacket, len, tvrecv)) {
  469. goto errout;
  470. }
  471. }
  472. return 0;
  473. errout:
  474. return -1;
  475. }
  476. static int _fast_ping_gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len)
  477. {
  478. struct sockaddr_storage *addr_store = (struct sockaddr_storage *)addr;
  479. host[0] = 0;
  480. switch (addr_store->ss_family) {
  481. case AF_INET: {
  482. struct sockaddr_in *addr_in;
  483. addr_in = (struct sockaddr_in *)addr;
  484. inet_ntop(AF_INET, &addr_in->sin_addr, host, addr_len);
  485. } break;
  486. case AF_INET6: {
  487. struct sockaddr_in6 *addr_in6;
  488. addr_in6 = (struct sockaddr_in6 *)addr;
  489. if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
  490. struct sockaddr_in addr_in4;
  491. memset(&addr_in4, 0, sizeof(addr_in4));
  492. memcpy(&addr_in4.sin_addr.s_addr, addr_in6->sin6_addr.s6_addr + 12, sizeof(addr_in4.sin_addr.s_addr));
  493. } else {
  494. inet_ntop(AF_INET6, &addr_in6->sin6_addr, host, addr_len);
  495. }
  496. } break;
  497. default:
  498. goto errout;
  499. break;
  500. }
  501. return 0;
  502. errout:
  503. return -1;
  504. }
  505. static int _fast_ping_process(struct ping_host_struct *ping_host, struct timeval *now)
  506. {
  507. int len;
  508. u_char inpacket[ICMP_INPACKET_SIZE];
  509. struct sockaddr_storage from;
  510. struct ping_host_struct *recv_ping_host;
  511. socklen_t from_len = sizeof(from);
  512. uint32_t addrkey;
  513. len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
  514. if (len < 0) {
  515. fprintf(stderr, "recvfrom failed, %s\n", strerror(errno));
  516. goto errout;
  517. }
  518. addrkey = jhash(&from, from_len, 0);
  519. pthread_mutex_lock(&ping.map_lock);
  520. hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
  521. {
  522. if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0) {
  523. break;
  524. }
  525. }
  526. pthread_mutex_unlock(&ping.map_lock);
  527. if (recv_ping_host == NULL) {
  528. return -1;
  529. }
  530. recv_ping_host->send = 0;
  531. _fast_ping_recvping(recv_ping_host, inpacket, len, now);
  532. return 0;
  533. errout:
  534. return -1;
  535. }
  536. static void _fast_ping_period_run()
  537. {
  538. struct ping_host_struct *ping_host;
  539. struct hlist_node *tmp;
  540. int i = 0;
  541. struct timeval now;
  542. struct timeval interval;
  543. uint64_t millisecond;
  544. gettimeofday(&now, 0);
  545. pthread_mutex_lock(&ping.map_lock);
  546. hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node)
  547. {
  548. interval = now;
  549. tv_sub(&interval, &ping_host->last);
  550. millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
  551. if (millisecond > ping_host->timeout && ping_host->send == 1) {
  552. ping_callback(ping_host->host, PING_RESULT_TIMEOUT, ping_host->seq, &interval, ping_host->userptr);
  553. ping_host->send = 0;
  554. }
  555. if (millisecond >= ping_host->interval) {
  556. _fast_ping_sendping(ping_host);
  557. }
  558. }
  559. pthread_mutex_unlock(&ping.map_lock);
  560. }
  561. static void *_fast_ping_work(void *arg)
  562. {
  563. struct epoll_event events[PING_MAX_EVENTS + 1];
  564. int num;
  565. int i;
  566. struct timeval last = { 0 };
  567. struct timeval now = { 0 };
  568. struct timeval diff = {0};
  569. uint millisec = 0;
  570. while (ping.run) {
  571. diff = now;
  572. tv_sub(&diff, &last);
  573. millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000;
  574. if (millisec >= 100) {
  575. _fast_ping_period_run();
  576. last = now;
  577. }
  578. num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, 100);
  579. if (num < 0) {
  580. gettimeofday(&now, 0);
  581. usleep(100000);
  582. continue;
  583. }
  584. if (num == 0) {
  585. gettimeofday(&now, 0);
  586. continue;
  587. }
  588. gettimeofday(&now, 0);
  589. for (i = 0; i < num; i++) {
  590. struct epoll_event *event = &events[i];
  591. struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr;
  592. _fast_ping_process(ping_host, &now);
  593. }
  594. }
  595. close(ping.epoll_fd);
  596. ping.epoll_fd = -1;
  597. return NULL;
  598. }
  599. int fast_ping_init()
  600. {
  601. pthread_attr_t attr;
  602. int epollfd = -1;
  603. int ret;
  604. if (ping.epoll_fd > 0) {
  605. return -1;
  606. }
  607. memset(&ping, 0, sizeof(ping));
  608. pthread_attr_init(&attr);
  609. epollfd = epoll_create1(EPOLL_CLOEXEC);
  610. if (epollfd < 0) {
  611. fprintf(stderr, "create epoll failed, %s\n", strerror(errno));
  612. goto errout;
  613. }
  614. ping.run = 1;
  615. ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
  616. if (ret != 0) {
  617. fprintf(stderr, "create ping work thread failed, %s\n", strerror(errno));
  618. goto errout;
  619. }
  620. pthread_mutex_init(&ping.map_lock, 0);
  621. pthread_mutex_init(&ping.lock, 0);
  622. hash_init(ping.hostmap);
  623. hash_init(ping.addrmap);
  624. ping.epoll_fd = epollfd;
  625. ping.ident = getpid();
  626. return 0;
  627. errout:
  628. if (ping.tid > 0) {
  629. void *retval = NULL;
  630. ping.run = 0;
  631. pthread_join(ping.tid, &retval);
  632. }
  633. if (epollfd) {
  634. close(epollfd);
  635. }
  636. pthread_mutex_destroy(&ping.lock);
  637. pthread_mutex_destroy(&ping.map_lock);
  638. return -1;
  639. }
  640. void fast_ping_exit()
  641. {
  642. if (ping.tid > 0) {
  643. void *ret = NULL;
  644. ping.run = 0;
  645. pthread_join(ping.tid, &ret);
  646. }
  647. if (ping.fd_icmp > 0) {
  648. close(ping.fd_icmp);
  649. ping.fd_icmp = -1;
  650. }
  651. if (ping.fd_icmp6 > 0) {
  652. close(ping.fd_icmp6);
  653. ping.fd_icmp6 = -1;
  654. }
  655. pthread_mutex_destroy(&ping.lock);
  656. pthread_mutex_destroy(&ping.map_lock);
  657. }