fast_ping.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. /*************************************************************************
  2. *
  3. * Copyright (C) 2018 Ruilin Peng (Nick) <[email protected]>.
  4. *
  5. * smartdns is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * smartdns is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "fast_ping.h"
  19. #include "atomic.h"
  20. #include "hashtable.h"
  21. #include "tlog.h"
  22. #include "util.h"
  23. #include <arpa/inet.h>
  24. #include <errno.h>
  25. #include <fcntl.h>
  26. #include <linux/filter.h>
  27. #include <netdb.h>
  28. #include <netinet/icmp6.h>
  29. #include <netinet/ip.h>
  30. #include <netinet/ip6.h>
  31. #include <netinet/ip_icmp.h>
  32. #include <pthread.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <sys/epoll.h>
  37. #include <sys/socket.h>
  38. #include <sys/types.h>
  39. #include <unistd.h>
  40. #define PING_MAX_EVENTS 128
  41. #define PING_MAX_HOSTLEN 128
  42. #define ICMP_PACKET_SIZE (1024 * 64)
  43. #define ICMP_INPACKET_SIZE 1024
  44. struct fast_ping_packet_msg {
  45. struct timeval tv;
  46. unsigned int sid;
  47. unsigned int seq;
  48. };
  49. struct fast_ping_packet {
  50. union {
  51. struct icmp icmp;
  52. struct icmp6_hdr icmp6;
  53. };
  54. struct fast_ping_packet_msg msg;
  55. };
  56. struct ping_host_struct {
  57. atomic_t ref;
  58. struct hlist_node host_node;
  59. struct hlist_node addr_node;
  60. FAST_PING_TYPE type;
  61. void *userptr;
  62. fast_ping_result ping_callback;
  63. char host[PING_MAX_HOSTLEN];
  64. int fd;
  65. unsigned int seq;
  66. struct timeval last;
  67. int interval;
  68. int timeout;
  69. int count;
  70. int send;
  71. unsigned int sid;
  72. unsigned short port;
  73. unsigned short ss_family;
  74. union {
  75. struct sockaddr addr;
  76. struct sockaddr_in6 in6;
  77. struct sockaddr_in in;
  78. };
  79. socklen_t addr_len;
  80. struct fast_ping_packet packet;
  81. };
  82. struct fast_ping_struct {
  83. int run;
  84. pthread_t tid;
  85. pthread_mutex_t lock;
  86. unsigned short ident;
  87. int epoll_fd;
  88. int fd_icmp;
  89. struct ping_host_struct icmp_host;
  90. int fd_icmp6;
  91. struct ping_host_struct icmp6_host;
  92. pthread_mutex_t map_lock;
  93. DECLARE_HASHTABLE(hostmap, 6);
  94. DECLARE_HASHTABLE(addrmap, 6);
  95. };
  96. static struct fast_ping_struct ping;
  97. static atomic_t ping_sid = ATOMIC_INIT(0);
  98. uint16_t _fast_ping_checksum(uint16_t *header, size_t len)
  99. {
  100. uint32_t sum = 0;
  101. int i;
  102. for (i = 0; i < len / sizeof(uint16_t); i++) {
  103. sum += ntohs(header[i]);
  104. }
  105. return htons(~((sum >> 16) + (sum & 0xffff)));
  106. }
  107. void _fast_ping_install_filter_v6(int sock)
  108. {
  109. struct icmp6_filter icmp6_filter;
  110. ICMP6_FILTER_SETBLOCKALL(&icmp6_filter);
  111. ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &icmp6_filter);
  112. setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_filter, sizeof(struct icmp6_filter));
  113. static int once;
  114. static struct sock_filter insns[] = {
  115. BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4), /* Load icmp echo ident */
  116. BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
  117. BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
  118. BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0), /* Load icmp type */
  119. BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */
  120. BPF_STMT(BPF_RET | BPF_K, ~0U), /* No. It passes. This must not happen. */
  121. BPF_STMT(BPF_RET | BPF_K, 0), /* Echo with wrong ident. Reject. */
  122. };
  123. static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns };
  124. if (once) {
  125. return;
  126. }
  127. once = 1;
  128. /* Patch bpflet for current identifier. */
  129. insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
  130. if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
  131. perror("WARNING: failed to install socket filter\n");
  132. }
  133. }
  134. void _fast_ping_install_filter_v4(int sock)
  135. {
  136. static int once;
  137. static struct sock_filter insns[] = {
  138. BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
  139. BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
  140. BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
  141. BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
  142. BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
  143. BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
  144. BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFF), /* No. It passes. */
  145. BPF_STMT(BPF_RET | BPF_K, 0) /* Echo with wrong ident. Reject. */
  146. };
  147. static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns };
  148. if (once) {
  149. return;
  150. }
  151. once = 1;
  152. /* Patch bpflet for current identifier. */
  153. insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
  154. if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
  155. perror("WARNING: failed to install socket filter\n");
  156. }
  157. }
  158. static struct addrinfo *_fast_ping_getaddr(const char *host, const char *port, int type, int protocol)
  159. {
  160. struct addrinfo hints;
  161. struct addrinfo *result = NULL;
  162. memset(&hints, 0, sizeof(hints));
  163. hints.ai_family = AF_UNSPEC;
  164. hints.ai_socktype = type;
  165. hints.ai_protocol = protocol;
  166. if (getaddrinfo(host, port, &hints, &result) != 0) {
  167. tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
  168. goto errout;
  169. }
  170. return result;
  171. errout:
  172. if (result) {
  173. freeaddrinfo(result);
  174. }
  175. return NULL;
  176. }
  177. static int _fast_ping_getdomain(const char *host)
  178. {
  179. struct addrinfo hints;
  180. struct addrinfo *result = NULL;
  181. int domain = -1;
  182. memset(&hints, 0, sizeof(hints));
  183. hints.ai_family = AF_UNSPEC;
  184. hints.ai_socktype = SOCK_STREAM;
  185. hints.ai_protocol = 0;
  186. if (getaddrinfo(host, NULL, &hints, &result) != 0) {
  187. tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
  188. goto errout;
  189. }
  190. domain = result->ai_family;
  191. freeaddrinfo(result);
  192. return domain;
  193. errout:
  194. if (result) {
  195. freeaddrinfo(result);
  196. }
  197. return -1;
  198. }
  199. static void _fast_ping_host_get(struct ping_host_struct *ping_host)
  200. {
  201. atomic_inc(&ping_host->ref);
  202. }
  203. static void _fast_ping_host_put_locked(struct ping_host_struct *ping_host, int locked)
  204. {
  205. if (locked) {
  206. if (atomic_dec_and_test(&ping_host->ref)) {
  207. hash_del(&ping_host->host_node);
  208. hash_del(&ping_host->addr_node);
  209. } else {
  210. ping_host = NULL;
  211. }
  212. } else {
  213. pthread_mutex_lock(&ping.map_lock);
  214. if (atomic_dec_and_test(&ping_host->ref)) {
  215. hash_del(&ping_host->host_node);
  216. hash_del(&ping_host->addr_node);
  217. } else {
  218. ping_host = NULL;
  219. }
  220. pthread_mutex_unlock(&ping.map_lock);
  221. }
  222. if (ping_host == NULL) {
  223. return;
  224. }
  225. struct timeval tv;
  226. tv.tv_sec = 0;
  227. tv.tv_usec = 0;
  228. 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);
  229. if (ping_host->fd > 0) {
  230. close(ping_host->fd);
  231. ping_host->fd = -1;
  232. }
  233. free(ping_host);
  234. }
  235. static void _fast_ping_host_put(struct ping_host_struct *ping_host)
  236. {
  237. _fast_ping_host_put_locked(ping_host, 0);
  238. }
  239. static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
  240. {
  241. struct fast_ping_packet *packet = &ping_host->packet;
  242. struct icmp6_hdr *icmp6 = &packet->icmp6;
  243. int len = 0;
  244. ping_host->seq++;
  245. memset(icmp6, 0, sizeof(*icmp6));
  246. icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
  247. icmp6->icmp6_code = 0;
  248. icmp6->icmp6_cksum = 0;
  249. icmp6->icmp6_id = getpid();
  250. icmp6->icmp6_seq = htons(ping_host->seq);
  251. gettimeofday(&packet->msg.tv, 0);
  252. packet->msg.sid = ping_host->sid;
  253. packet->msg.seq = ping_host->seq;
  254. icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
  255. len = sendto(ping.fd_icmp6, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
  256. if (len < 0 || len != sizeof(struct fast_ping_packet)) {
  257. if (errno == ENETUNREACH) {
  258. goto errout;
  259. }
  260. char ping_host_name[PING_MAX_HOSTLEN];
  261. 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,
  262. strerror(errno));
  263. goto errout;
  264. }
  265. return 0;
  266. errout:
  267. return -1;
  268. }
  269. static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
  270. {
  271. struct fast_ping_packet *packet = &ping_host->packet;
  272. struct icmp *icmp = &packet->icmp;
  273. int len;
  274. ping_host->seq++;
  275. memset(icmp, 0, sizeof(*icmp));
  276. icmp->icmp_type = ICMP_ECHO;
  277. icmp->icmp_code = 0;
  278. icmp->icmp_cksum = 0;
  279. icmp->icmp_id = ping.ident;
  280. icmp->icmp_seq = htons(ping_host->seq);
  281. gettimeofday(&packet->msg.tv, 0);
  282. packet->msg.sid = ping_host->sid;
  283. packet->msg.seq = ping_host->seq;
  284. icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
  285. len = sendto(ping.fd_icmp, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
  286. if (len < 0 || len != sizeof(struct fast_ping_packet)) {
  287. if (errno == ENETUNREACH) {
  288. goto errout;
  289. }
  290. char ping_host_name[PING_MAX_HOSTLEN];
  291. 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,
  292. strerror(errno));
  293. goto errout;
  294. }
  295. return 0;
  296. errout:
  297. return -1;
  298. }
  299. static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host)
  300. {
  301. struct epoll_event event;
  302. int flags;
  303. int fd = 0;
  304. fd = socket(ping_host->ss_family, SOCK_STREAM, 0);
  305. if (fd < 0) {
  306. goto errout;
  307. }
  308. flags = fcntl(fd, F_GETFL, 0);
  309. fcntl(fd, F_SETFL, flags | O_NONBLOCK);
  310. ping_host->seq++;
  311. if (connect(fd, (struct sockaddr *)&ping_host->addr, ping_host->addr_len) != 0) {
  312. if (errno != EINPROGRESS) {
  313. char ping_host_name[PING_MAX_HOSTLEN];
  314. if (errno == ENETUNREACH) {
  315. goto errout;
  316. }
  317. 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,
  318. strerror(errno));
  319. goto errout;
  320. }
  321. }
  322. event.events = EPOLLIN | EPOLLOUT;
  323. event.data.ptr = ping_host;
  324. if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
  325. goto errout;
  326. }
  327. if (ping_host->fd > 0) {
  328. close(ping_host->fd);
  329. }
  330. ping_host->fd = fd;
  331. return 0;
  332. errout:
  333. if (fd > 0) {
  334. close(fd);
  335. }
  336. return -1;
  337. }
  338. static int _fast_ping_sendping(struct ping_host_struct *ping_host)
  339. {
  340. int ret = -1;
  341. if (ping_host->type == FAST_PING_ICMP) {
  342. ret = _fast_ping_sendping_v4(ping_host);
  343. } else if (ping_host->type == FAST_PING_ICMP6) {
  344. ret = _fast_ping_sendping_v6(ping_host);
  345. } else if (ping_host->type == FAST_PING_TCP) {
  346. ret = _fast_ping_sendping_tcp(ping_host);
  347. }
  348. ping_host->send = 1;
  349. gettimeofday(&ping_host->last, 0);
  350. if (ret != 0) {
  351. return ret;
  352. }
  353. return 0;
  354. }
  355. static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
  356. {
  357. int fd = -1;
  358. struct ping_host_struct *icmp_host = NULL;
  359. struct epoll_event event;
  360. int buffsize = 64 * 1024;
  361. socklen_t optlen = sizeof(buffsize);
  362. switch (type) {
  363. case FAST_PING_ICMP:
  364. fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  365. if (fd < 0) {
  366. tlog(TLOG_ERROR, "create icmp socket failed.\n");
  367. goto errout;
  368. }
  369. _fast_ping_install_filter_v4(fd);
  370. icmp_host = &ping.icmp_host;
  371. break;
  372. case FAST_PING_ICMP6:
  373. fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
  374. if (fd < 0) {
  375. tlog(TLOG_ERROR, "create icmp socket failed.\n");
  376. goto errout;
  377. }
  378. _fast_ping_install_filter_v6(fd);
  379. icmp_host = &ping.icmp6_host;
  380. break;
  381. default:
  382. return -1;
  383. }
  384. setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&buffsize, optlen);
  385. setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&buffsize, optlen);
  386. event.events = EPOLLIN;
  387. event.data.ptr = icmp_host;
  388. if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
  389. goto errout;
  390. }
  391. icmp_host->fd = fd;
  392. icmp_host->type = type;
  393. return fd;
  394. errout:
  395. close(fd);
  396. return -1;
  397. }
  398. static int _fast_ping_create_icmp(FAST_PING_TYPE type)
  399. {
  400. int fd = 0;
  401. int *set_fd = NULL;
  402. pthread_mutex_lock(&ping.lock);
  403. switch (type) {
  404. case FAST_PING_ICMP:
  405. set_fd = &ping.fd_icmp;
  406. break;
  407. case FAST_PING_ICMP6:
  408. set_fd = &ping.fd_icmp6;
  409. break;
  410. default:
  411. goto errout;
  412. break;
  413. }
  414. if (*set_fd > 0) {
  415. goto out;
  416. }
  417. fd = _fast_ping_create_icmp_sock(type);
  418. if (fd < 0) {
  419. goto errout;
  420. }
  421. *set_fd = fd;
  422. out:
  423. pthread_mutex_unlock(&ping.lock);
  424. return *set_fd;
  425. errout:
  426. if (fd > 0) {
  427. close(fd);
  428. }
  429. pthread_mutex_unlock(&ping.lock);
  430. return -1;
  431. }
  432. 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,
  433. struct timeval *tv, void *userptr)
  434. {
  435. if (result == PING_RESULT_RESPONSE) {
  436. double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0;
  437. tlog(TLOG_INFO, "from %15s: seq=%d time=%.3f\n", host, seqno, rtt);
  438. } else if (result == PING_RESULT_TIMEOUT) {
  439. tlog(TLOG_INFO, "from %15s: seq=%d timeout\n", host, seqno);
  440. }
  441. }
  442. struct ping_host_struct *fast_ping_start(const char *host, int count, int interval, int timeout, fast_ping_result ping_callback, void *userptr)
  443. {
  444. struct ping_host_struct *ping_host = NULL;
  445. struct addrinfo *gai = NULL;
  446. int domain = -1;
  447. int icmp_proto = 0;
  448. uint32_t hostkey;
  449. uint32_t addrkey;
  450. char ip_str[PING_MAX_HOSTLEN];
  451. char port_str[MAX_IP_LEN];
  452. char *service = NULL;
  453. int port = -1;
  454. FAST_PING_TYPE type;
  455. int socktype = 0;
  456. if (parse_ip(host, ip_str, &port) != 0) {
  457. goto errout;
  458. }
  459. if (port > 0) {
  460. icmp_proto = 0;
  461. socktype = SOCK_STREAM;
  462. snprintf(port_str, MAX_IP_LEN, "%d", port);
  463. service = port_str;
  464. type = FAST_PING_TCP;
  465. gai = _fast_ping_getaddr(ip_str, service, socktype, icmp_proto);
  466. if (gai == NULL) {
  467. goto errout;
  468. }
  469. } else {
  470. socktype = SOCK_RAW;
  471. domain = _fast_ping_getdomain(ip_str);
  472. if (domain < 0) {
  473. return NULL;
  474. }
  475. switch (domain) {
  476. case AF_INET:
  477. icmp_proto = IPPROTO_ICMP;
  478. type = FAST_PING_ICMP;
  479. break;
  480. case AF_INET6:
  481. icmp_proto = IPPROTO_ICMPV6;
  482. type = FAST_PING_ICMP6;
  483. break;
  484. default:
  485. return NULL;
  486. break;
  487. }
  488. if (_fast_ping_create_icmp(type) < 0) {
  489. goto errout;
  490. }
  491. gai = _fast_ping_getaddr(ip_str, service, socktype, icmp_proto);
  492. if (gai == NULL) {
  493. goto errout;
  494. }
  495. }
  496. ping_host = malloc(sizeof(*ping_host));
  497. if (ping_host == NULL) {
  498. goto errout;
  499. }
  500. memset(ping_host, 0, sizeof(*ping_host));
  501. strncpy(ping_host->host, host, PING_MAX_HOSTLEN);
  502. ping_host->fd = -1;
  503. ping_host->timeout = timeout;
  504. ping_host->count = count;
  505. ping_host->type = type;
  506. ping_host->userptr = userptr;
  507. atomic_set(&ping_host->ref, 0);
  508. ping_host->sid = atomic_inc_return(&ping_sid);
  509. if (ping_callback) {
  510. ping_host->ping_callback = ping_callback;
  511. } else {
  512. ping_host->ping_callback = fast_ping_print_result;
  513. }
  514. ping_host->interval = (timeout > interval) ? timeout : interval;
  515. ping_host->addr_len = gai->ai_addrlen;
  516. ping_host->port = port;
  517. ping_host->ss_family = gai->ai_family;
  518. if (gai->ai_addrlen > sizeof(struct sockaddr_in6)) {
  519. goto errout;
  520. }
  521. memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen);
  522. tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid);
  523. if (_fast_ping_sendping(ping_host) != 0) {
  524. goto errout;
  525. }
  526. hostkey = hash_string(ping_host->host);
  527. addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0);
  528. addrkey = jhash(&ping_host->sid, sizeof(ping_host->sid), addrkey);
  529. pthread_mutex_lock(&ping.map_lock);
  530. _fast_ping_host_get(ping_host);
  531. hash_add(ping.hostmap, &ping_host->host_node, hostkey);
  532. hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
  533. pthread_mutex_unlock(&ping.map_lock);
  534. freeaddrinfo(gai);
  535. return ping_host;
  536. errout:
  537. if (gai) {
  538. freeaddrinfo(gai);
  539. }
  540. if (ping_host) {
  541. free(ping_host);
  542. }
  543. return NULL;
  544. }
  545. int fast_ping_stop(struct ping_host_struct *ping_host)
  546. {
  547. _fast_ping_host_put(ping_host);
  548. return 0;
  549. }
  550. static void tv_sub(struct timeval *out, struct timeval *in)
  551. {
  552. if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
  553. --out->tv_sec;
  554. out->tv_usec += 1000000;
  555. }
  556. out->tv_sec -= in->tv_sec;
  557. }
  558. static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len)
  559. {
  560. int icmp_len;
  561. struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
  562. struct icmp6_hdr *icmp6 = &packet->icmp6;
  563. if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) {
  564. tlog(TLOG_DEBUG, "icmp6 type faild, %d:%d", icmp6->icmp6_type, ICMP6_ECHO_REPLY);
  565. return NULL;
  566. }
  567. icmp_len = data_len;
  568. if (icmp_len < 16) {
  569. tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
  570. return NULL;
  571. }
  572. if (icmp6->icmp6_id != ping.ident) {
  573. tlog(TLOG_ERROR, "ident failed, %d:%d", icmp6->icmp6_id, ping.ident);
  574. return NULL;
  575. }
  576. return packet;
  577. }
  578. static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len)
  579. {
  580. struct ip *ip = (struct ip *)packet_data;
  581. struct fast_ping_packet *packet;
  582. struct icmp *icmp;
  583. int hlen;
  584. int icmp_len;
  585. if (ip->ip_p != IPPROTO_ICMP) {
  586. tlog(TLOG_ERROR, "ip type faild, %d:%d", ip->ip_p, IPPROTO_ICMP);
  587. return NULL;
  588. }
  589. hlen = ip->ip_hl << 2;
  590. packet = (struct fast_ping_packet *)(packet_data + hlen);
  591. icmp = &packet->icmp;
  592. icmp_len = data_len - hlen;
  593. if (icmp_len < 16) {
  594. tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
  595. return NULL;
  596. }
  597. if (icmp->icmp_type != ICMP_ECHOREPLY) {
  598. tlog(TLOG_DEBUG, "icmp type faild, %d:%d", icmp->icmp_type, ICMP_ECHOREPLY);
  599. return NULL;
  600. }
  601. if (icmp->icmp_id != ping.ident) {
  602. tlog(TLOG_ERROR, "ident failed, %d:%d", icmp->icmp_id, ping.ident);
  603. return NULL;
  604. }
  605. return packet;
  606. }
  607. struct fast_ping_packet *_fast_ping_recv_packet(struct ping_host_struct *ping_host, u_char *inpacket, int len, struct timeval *tvrecv)
  608. {
  609. struct fast_ping_packet *packet = NULL;
  610. if (ping_host->type == FAST_PING_ICMP6) {
  611. packet = _fast_ping_icmp6_packet(ping_host, inpacket, len);
  612. if (packet == NULL) {
  613. goto errout;
  614. }
  615. } else if (ping_host->type == FAST_PING_ICMP) {
  616. packet = _fast_ping_icmp_packet(ping_host, inpacket, len);
  617. if (packet == NULL) {
  618. goto errout;
  619. }
  620. } else {
  621. tlog(TLOG_ERROR, "ping host type is invalid, %d", ping_host->type);
  622. goto errout;
  623. }
  624. return packet;
  625. errout:
  626. return NULL;
  627. }
  628. static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct timeval *now)
  629. {
  630. int len;
  631. u_char inpacket[ICMP_INPACKET_SIZE];
  632. struct sockaddr_storage from;
  633. struct ping_host_struct *recv_ping_host;
  634. struct fast_ping_packet *packet = NULL;
  635. socklen_t from_len = sizeof(from);
  636. uint32_t addrkey;
  637. struct timeval tvresult = *now;
  638. struct timeval *tvsend = NULL;
  639. unsigned int sid;
  640. unsigned int seq;
  641. len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
  642. if (len < 0) {
  643. tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno));
  644. goto errout;
  645. }
  646. packet = _fast_ping_recv_packet(ping_host, inpacket, len, now);
  647. if (packet == NULL) {
  648. char name[PING_MAX_HOSTLEN];
  649. tlog(TLOG_DEBUG, "recv ping packet from %s failed.", gethost_by_addr(name, (struct sockaddr *)&from, from_len));
  650. goto errout;
  651. }
  652. addrkey = jhash(&from, from_len, 0);
  653. tvsend = &packet->msg.tv;
  654. sid = packet->msg.sid;
  655. seq = packet->msg.seq;
  656. addrkey = jhash(&sid, sizeof(sid), addrkey);
  657. pthread_mutex_lock(&ping.map_lock);
  658. hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
  659. {
  660. if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0 && recv_ping_host->sid == sid) {
  661. break;
  662. }
  663. }
  664. pthread_mutex_unlock(&ping.map_lock);
  665. if (recv_ping_host == NULL) {
  666. return -1;
  667. }
  668. if (recv_ping_host->seq != seq) {
  669. tlog(TLOG_ERROR, "seq num mismatch, expect %u, real %u", recv_ping_host->seq, seq);
  670. return -1;
  671. }
  672. tv_sub(&tvresult, tvsend);
  673. if (recv_ping_host->ping_callback) {
  674. recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len,
  675. recv_ping_host->seq, &tvresult, recv_ping_host->userptr);
  676. }
  677. recv_ping_host->send = 0;
  678. if (recv_ping_host->count == 1) {
  679. _fast_ping_host_put(recv_ping_host);
  680. }
  681. return 0;
  682. errout:
  683. return -1;
  684. }
  685. static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epoll_event *event, struct timeval *now)
  686. {
  687. struct timeval tvresult = *now;
  688. struct timeval *tvsend = &ping_host->last;
  689. int connect_error = 0;
  690. socklen_t len = sizeof(connect_error);
  691. if (event->events & EPOLLIN || event->events & EPOLLERR) {
  692. if (getsockopt(ping_host->fd, SOL_SOCKET, SO_ERROR, (char *)&connect_error, &len) != 0) {
  693. goto errout;
  694. }
  695. if (connect_error != 0 && connect_error != ECONNREFUSED) {
  696. goto errout;
  697. }
  698. }
  699. tv_sub(&tvresult, tvsend);
  700. if (ping_host->ping_callback) {
  701. ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr, ping_host->addr_len,
  702. ping_host->seq, &tvresult, ping_host->userptr);
  703. }
  704. ping_host->send = 0;
  705. if (ping_host->fd > 0) {
  706. close(ping_host->fd);
  707. ping_host->fd = -1;
  708. }
  709. if (ping_host->count == 1) {
  710. _fast_ping_host_put(ping_host);
  711. }
  712. return 0;
  713. errout:
  714. if (ping_host->fd > 0) {
  715. close(ping_host->fd);
  716. ping_host->fd = -1;
  717. }
  718. return -1;
  719. }
  720. static int _fast_ping_process(struct ping_host_struct *ping_host, struct epoll_event *event, struct timeval *now)
  721. {
  722. int ret = -1;
  723. switch (ping_host->type) {
  724. case FAST_PING_ICMP6:
  725. case FAST_PING_ICMP:
  726. ret = _fast_ping_process_icmp(ping_host, now);
  727. break;
  728. case FAST_PING_TCP:
  729. ret = _fast_ping_process_tcp(ping_host, event, now);
  730. default:
  731. break;
  732. }
  733. return ret;
  734. }
  735. static void _fast_ping_period_run()
  736. {
  737. struct ping_host_struct *ping_host;
  738. struct hlist_node *tmp;
  739. int i = 0;
  740. struct timeval now;
  741. struct timeval interval;
  742. int64_t millisecond;
  743. gettimeofday(&now, 0);
  744. pthread_mutex_lock(&ping.map_lock);
  745. hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node)
  746. {
  747. interval = now;
  748. tv_sub(&interval, &ping_host->last);
  749. millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
  750. if (millisecond >= ping_host->timeout && ping_host->send == 1) {
  751. ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, &interval,
  752. ping_host->userptr);
  753. ping_host->send = 0;
  754. }
  755. if (millisecond < ping_host->interval) {
  756. continue;
  757. }
  758. if (ping_host->count > 0) {
  759. if (ping_host->count == 1) {
  760. hash_del(&ping_host->host_node);
  761. hash_del(&ping_host->addr_node);
  762. _fast_ping_host_put_locked(ping_host, 1);
  763. continue;
  764. }
  765. ping_host->count--;
  766. }
  767. _fast_ping_sendping(ping_host);
  768. }
  769. pthread_mutex_unlock(&ping.map_lock);
  770. }
  771. static void *_fast_ping_work(void *arg)
  772. {
  773. struct epoll_event events[PING_MAX_EVENTS + 1];
  774. int num;
  775. int i;
  776. struct timeval last = { 0 };
  777. struct timeval now = { 0 };
  778. struct timeval diff = { 0 };
  779. uint millisec = 0;
  780. while (ping.run) {
  781. diff = now;
  782. tv_sub(&diff, &last);
  783. millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000;
  784. if (millisec >= 100) {
  785. _fast_ping_period_run();
  786. last = now;
  787. }
  788. num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, 100);
  789. if (num < 0) {
  790. gettimeofday(&now, 0);
  791. usleep(100000);
  792. continue;
  793. }
  794. if (num == 0) {
  795. gettimeofday(&now, 0);
  796. continue;
  797. }
  798. gettimeofday(&now, 0);
  799. for (i = 0; i < num; i++) {
  800. struct epoll_event *event = &events[i];
  801. struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr;
  802. _fast_ping_process(ping_host, event, &now);
  803. }
  804. }
  805. close(ping.epoll_fd);
  806. ping.epoll_fd = -1;
  807. return NULL;
  808. }
  809. int fast_ping_init()
  810. {
  811. pthread_attr_t attr;
  812. int epollfd = -1;
  813. int ret;
  814. if (ping.epoll_fd > 0) {
  815. return -1;
  816. }
  817. memset(&ping, 0, sizeof(ping));
  818. pthread_attr_init(&attr);
  819. epollfd = epoll_create1(EPOLL_CLOEXEC);
  820. if (epollfd < 0) {
  821. tlog(TLOG_ERROR, "create epoll failed, %s\n", strerror(errno));
  822. goto errout;
  823. }
  824. pthread_mutex_init(&ping.map_lock, 0);
  825. pthread_mutex_init(&ping.lock, 0);
  826. hash_init(ping.hostmap);
  827. hash_init(ping.addrmap);
  828. ping.epoll_fd = epollfd;
  829. ping.ident = getpid();
  830. ping.run = 1;
  831. ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
  832. if (ret != 0) {
  833. tlog(TLOG_ERROR, "create ping work thread failed, %s\n", strerror(errno));
  834. goto errout;
  835. }
  836. return 0;
  837. errout:
  838. if (ping.tid > 0) {
  839. void *retval = NULL;
  840. ping.run = 0;
  841. pthread_join(ping.tid, &retval);
  842. }
  843. if (epollfd) {
  844. close(epollfd);
  845. }
  846. pthread_mutex_destroy(&ping.lock);
  847. pthread_mutex_destroy(&ping.map_lock);
  848. return -1;
  849. }
  850. void fast_ping_exit()
  851. {
  852. if (ping.tid > 0) {
  853. void *ret = NULL;
  854. ping.run = 0;
  855. pthread_join(ping.tid, &ret);
  856. }
  857. if (ping.fd_icmp > 0) {
  858. close(ping.fd_icmp);
  859. ping.fd_icmp = -1;
  860. }
  861. if (ping.fd_icmp6 > 0) {
  862. close(ping.fd_icmp6);
  863. ping.fd_icmp6 = -1;
  864. }
  865. pthread_mutex_destroy(&ping.lock);
  866. pthread_mutex_destroy(&ping.map_lock);
  867. }