… | |
… | |
110 | typedef uint8_t addr_tt[16]; |
110 | typedef uint8_t addr_tt[16]; |
111 | |
111 | |
112 | typedef struct |
112 | typedef struct |
113 | { |
113 | { |
114 | tstamp next; |
114 | tstamp next; |
115 | double interval; |
115 | tstamp interval; |
116 | int addrlen; |
116 | int addrlen; |
117 | |
117 | |
118 | addr_tt lo, hi; /* only if !addrcnt */ |
118 | addr_tt lo, hi; /* only if !addrcnt */ |
119 | |
119 | |
120 | int addrcnt; |
120 | int addrcnt; |
… | |
… | |
124 | typedef struct |
124 | typedef struct |
125 | { |
125 | { |
126 | RANGE **ranges; |
126 | RANGE **ranges; |
127 | int rangecnt, rangemax; |
127 | int rangecnt, rangemax; |
128 | |
128 | |
|
|
129 | tstamp next; |
129 | tstamp interval; |
130 | tstamp interval; |
|
|
131 | |
130 | tstamp maxrtt; |
132 | tstamp maxrtt; |
|
|
133 | |
131 | uint16_t magic1; |
134 | uint16_t magic1; |
132 | uint16_t magic2; |
135 | uint16_t magic2; |
133 | uint16_t magic3; |
136 | uint16_t magic3; |
134 | |
137 | |
135 | int id; |
138 | int id; |
… | |
… | |
357 | PINGER *self = (PINGER *)self_; |
360 | PINGER *self = (PINGER *)self_; |
358 | PKT pkt; |
361 | PKT pkt; |
359 | |
362 | |
360 | memset (&pkt, 0, sizeof (pkt)); |
363 | memset (&pkt, 0, sizeof (pkt)); |
361 | |
364 | |
362 | tstamp now = NOW (); |
365 | tstamp now = NOW (); |
363 | tstamp next = now; |
|
|
364 | |
366 | |
365 | pkt.code = 0; |
367 | pkt.code = 0; |
366 | pkt.id = self->magic1; |
368 | pkt.id = self->magic1; |
367 | pkt.seq = self->magic2; |
369 | pkt.seq = self->magic2; |
368 | pkt.magic = self->magic3; |
370 | pkt.magic = self->magic3; |
369 | pkt.pinger = self->id; |
371 | pkt.pinger = self->id; |
|
|
372 | |
|
|
373 | if (self->next < now) |
|
|
374 | self->next = now; |
370 | |
375 | |
371 | while (self->rangecnt) |
376 | while (self->rangecnt) |
372 | { |
377 | { |
373 | RANGE *range = self->ranges [0]; |
378 | RANGE *range = self->ranges [0]; |
374 | int n, k; |
|
|
375 | |
379 | |
376 | // ranges [0] is always the next range to ping |
380 | // ranges [0] is always the next range to ping |
377 | tstamp wait = range->next - now; |
381 | tstamp wait = range->next - now; |
378 | |
382 | |
379 | // compare with the global frequency limit |
383 | // compare with the global frequency limit |
380 | { |
384 | { |
381 | tstamp diff = next - now; |
385 | tstamp diff = self->next - now; |
382 | |
386 | |
383 | if (wait < diff) |
387 | if (wait < diff) |
384 | wait = diff; |
388 | wait = diff; // global rate limit overrides |
385 | else if (range) |
389 | else |
386 | next = range->next; |
390 | self->next = range->next; // fast forward |
387 | } |
391 | } |
388 | |
392 | |
389 | if (wait > 0.) |
393 | if (wait > 0.) |
390 | ssleep (wait); |
394 | ssleep (wait); |
391 | |
395 | |
… | |
… | |
397 | { |
401 | { |
398 | self->ranges [0] = self->ranges [--self->rangecnt]; |
402 | self->ranges [0] = self->ranges [--self->rangecnt]; |
399 | range_free (range); |
403 | range_free (range); |
400 | } |
404 | } |
401 | else |
405 | else |
402 | { |
|
|
403 | range->next = next; |
|
|
404 | range->next += range->interval; |
406 | range->next = self->next + range->interval; |
405 | } |
|
|
406 | |
407 | |
407 | downheap (self); |
408 | downheap (self); |
408 | |
409 | |
409 | next += self->interval; |
410 | self->next += self->interval; |
|
|
411 | now = NOW (); |
410 | } |
412 | } |
411 | |
413 | |
412 | ssleep (self->maxrtt); |
414 | ssleep (self->maxrtt); |
413 | |
415 | |
414 | { |
416 | { |
… | |
… | |
482 | } |
484 | } |
483 | |
485 | |
484 | pingers [self->id] = self; |
486 | pingers [self->id] = self; |
485 | |
487 | |
486 | self->recvcb = &PL_sv_undef; |
488 | self->recvcb = &PL_sv_undef; |
|
|
489 | self->next = 0.; |
487 | self->interval = MIN_INTERVAL; |
490 | self->interval = MIN_INTERVAL; |
488 | self->maxrtt = 0.5; |
491 | self->maxrtt = 0.5; |
489 | self->rangemax = 16; |
492 | self->rangemax = 16; |
490 | self->ranges = malloc (sizeof (self->ranges [0]) * self->rangemax); |
493 | self->ranges = malloc (sizeof (self->ranges [0]) * self->rangemax); |
491 | } |
494 | } |
… | |
… | |
643 | |
646 | |
644 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP4_FD", 1), icmp4_fd); |
647 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP4_FD", 1), icmp4_fd); |
645 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP6_FD", 1), icmp6_fd); |
648 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP6_FD", 1), icmp6_fd); |
646 | } |
649 | } |
647 | |
650 | |
|
|
651 | #define NOT_RUNNING \ |
|
|
652 | if (self->running) \ |
|
|
653 | croak ("AnyEvent::FastPing object has been started - you have to sotp t first before calling this method, caught"); |
|
|
654 | |
648 | MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_ |
655 | MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_ |
649 | |
656 | |
650 | BOOT: |
657 | BOOT: |
651 | { |
658 | { |
652 | HV *stash = gv_stashpv ("AnyEvent::FastPing", 1); |
659 | HV *stash = gv_stashpv ("AnyEvent::FastPing", 1); |
… | |
… | |
748 | _new (SV *klass, UV magic1, UV magic2, UV magic3) |
755 | _new (SV *klass, UV magic1, UV magic2, UV magic3) |
749 | PPCODE: |
756 | PPCODE: |
750 | { |
757 | { |
751 | SV *pv = NEWSV (0, sizeof (PINGER)); |
758 | SV *pv = NEWSV (0, sizeof (PINGER)); |
752 | PINGER *self = (PINGER *)SvPVX (pv); |
759 | PINGER *self = (PINGER *)SvPVX (pv); |
|
|
760 | |
753 | SvPOK_only (pv); |
761 | SvPOK_only (pv); |
754 | XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), gv_stashpv (SvPVutf8_nolen (klass), 1)))); |
762 | XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), gv_stashpv (SvPVutf8_nolen (klass), 1)))); |
755 | pinger_init (self); |
763 | pinger_init (self); |
756 | self->magic1 = magic1; |
764 | self->magic1 = magic1; |
757 | self->magic2 = magic2; |
765 | self->magic2 = magic2; |
… | |
… | |
781 | pinger_stop (pingers [id]); |
789 | pinger_stop (pingers [id]); |
782 | |
790 | |
783 | void |
791 | void |
784 | interval (PINGER *self, NV interval) |
792 | interval (PINGER *self, NV interval) |
785 | CODE: |
793 | CODE: |
|
|
794 | NOT_RUNNING; |
786 | self->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL; |
795 | self->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL; |
787 | |
796 | |
788 | void |
797 | void |
789 | max_rtt (PINGER *self, NV maxrtt) |
798 | max_rtt (PINGER *self, NV maxrtt) |
790 | CODE: |
799 | CODE: |
|
|
800 | NOT_RUNNING; |
791 | self->maxrtt = maxrtt; |
801 | self->maxrtt = maxrtt; |
792 | |
802 | |
793 | void |
803 | void |
|
|
804 | on_recv (PINGER *self, SV *cb) |
|
|
805 | CODE: |
|
|
806 | SvREFCNT_dec (self->recvcb); |
|
|
807 | self->recvcb = newSVsv (cb); |
|
|
808 | |
|
|
809 | void |
794 | add_range (PINGER *self, SV *lo_, SV *hi_, NV interval) |
810 | add_range (PINGER *self, SV *lo_, SV *hi_, NV interval = 0) |
795 | CODE: |
811 | CODE: |
796 | { |
812 | { |
797 | STRLEN lo_len, hi_len; |
813 | STRLEN lo_len, hi_len; |
798 | char *lo = SvPVbyte (lo_, lo_len); |
814 | char *lo = SvPVbyte (lo_, lo_len); |
799 | char *hi = SvPVbyte (hi_, hi_len); |
815 | char *hi = SvPVbyte (hi_, hi_len); |
800 | RANGE *range; |
816 | RANGE *range; |
|
|
817 | NOT_RUNNING; |
801 | |
818 | |
802 | if (lo_len != hi_len || (lo_len != 4 && lo_len != 16)) |
819 | if (lo_len != hi_len || (lo_len != 4 && lo_len != 16)) |
803 | croak ("AnyEvent::FastPing::add_range address range must be specified as two binary IPv4 or IPv6 addresses"); |
820 | croak ("AnyEvent::FastPing::add_range address range must be specified as two binary IPv4 or IPv6 addresses"); |
804 | |
821 | |
805 | if (lo_len == 4 && icmp4_fd < 0) croak ("IPv4 support unavailable"); |
822 | if (lo_len == 4 && icmp4_fd < 0) croak ("IPv4 support unavailable"); |
… | |
… | |
819 | |
836 | |
820 | pinger_add_range (self, range); |
837 | pinger_add_range (self, range); |
821 | } |
838 | } |
822 | |
839 | |
823 | void |
840 | void |
824 | add_hosts (PINGER *self, SV *addrs, NV interval) |
841 | add_hosts (PINGER *self, SV *addrs, NV interval = 0, UV interleave = 1) |
825 | CODE: |
842 | CODE: |
826 | { |
843 | { |
827 | AV *av; |
844 | AV *av; |
828 | int i; |
845 | int i, j, k; |
829 | int cnt; |
846 | int cnt; |
830 | int addrlen; |
847 | int addrlen; |
831 | RANGE *range; |
848 | RANGE *range; |
|
|
849 | NOT_RUNNING; |
832 | |
850 | |
833 | if (!SvROK (addrs) || SvTYPE (SvRV (addrs)) != SVt_PVAV) |
851 | if (!SvROK (addrs) || SvTYPE (SvRV (addrs)) != SVt_PVAV) |
834 | croak ("AnyEvent::FastPing::add_hosst expects an arrayref with binary IPv4 or IPv6 addresses"); |
852 | croak ("AnyEvent::FastPing::add_hosts expects an arrayref with binary IPv4 or IPv6 addresses"); |
835 | |
853 | |
836 | av = (AV *)SvRV (addrs); |
854 | av = (AV *)SvRV (addrs); |
837 | cnt = av_len (av) + 1; |
855 | cnt = av_len (av) + 1; |
838 | |
856 | |
839 | if (!cnt) |
857 | if (!cnt) |
… | |
… | |
857 | range->next = 0; |
875 | range->next = 0; |
858 | range->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL; |
876 | range->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL; |
859 | range->addrlen = addrlen; |
877 | range->addrlen = addrlen; |
860 | range->addrcnt = cnt; |
878 | range->addrcnt = cnt; |
861 | |
879 | |
862 | for (i = cnt; i--; ) |
880 | if (interleave == 0) |
|
|
881 | interleave = cnt <= 256 * 256 ? 256 : (int)sqrtf (cnt); |
|
|
882 | |
|
|
883 | k = cnt; |
|
|
884 | for (j = 0; j < interleave; ++j) |
|
|
885 | for (i = j; i < cnt; i += interleave) |
863 | memcpy ((uint8_t *)(range + 1) + (cnt - 1 - i) * addrlen, |
886 | memcpy ((uint8_t *)(range + 1) + --k * addrlen, |
864 | SvPVbyte_nolen (*av_fetch (av, i, 1)), |
887 | SvPVbyte_nolen (*av_fetch (av, i, 1)), |
865 | addrlen); |
888 | addrlen); |
866 | |
889 | |
867 | pinger_add_range (self, range); |
890 | pinger_add_range (self, range); |
868 | } |
891 | } |
869 | |
892 | |
870 | void |
|
|
871 | on_recv (PINGER *self, SV *cb) |
|
|
872 | CODE: |
|
|
873 | SvREFCNT_dec (self->recvcb); |
|
|
874 | self->recvcb = newSVsv (cb); |
|
|
875 | |
|
|