fast_ping.c 19 KB

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