krakatoa-icmp4em 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem "eventmachine", ">= 1.0.0.beta.4"
7
+
8
+ # Add dependencies to develop your gem here.
9
+ # Include everything needed to run rake, tests, features, etc.
10
+ group :development do
11
+ gem "shoulda", ">= 0"
12
+ gem "bundler", "~> 1.1.0"
13
+ gem "jeweler", "~> 1.6.4"
14
+ gem "simplecov"
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ eventmachine (1.0.0.beta.4)
5
+ git (1.2.5)
6
+ jeweler (1.6.4)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ multi_json (1.1.0)
11
+ rake (0.9.2.2)
12
+ shoulda (3.0.1)
13
+ shoulda-context (~> 1.0.0)
14
+ shoulda-matchers (~> 1.0.0)
15
+ shoulda-context (1.0.0)
16
+ shoulda-matchers (1.0.0)
17
+ simplecov (0.6.1)
18
+ multi_json (~> 1.0)
19
+ simplecov-html (~> 0.5.3)
20
+ simplecov-html (0.5.3)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ bundler (~> 1.1.0)
27
+ eventmachine (>= 1.0.0.beta.4)
28
+ jeweler (~> 1.6.4)
29
+ shoulda
30
+ simplecov
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "krakatoa-icmp4em"
18
+ gem.homepage = "http://github.com/krakatoa/icmp4em"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Asynchronous implementation of ICMP ping over EventMachine}
21
+ gem.description = %Q{Asynchronous implementation of ICMP ping using EventMachine. Can be used to ping many hosts at once in a non-blocking fashion, with callbacks for success, timeout, and host failure/recovery based on specified threshold numbers.}
22
+ gem.email = "krakatoa1987@gmail.com"
23
+ gem.authors = ["Jake Douglas", "Fernando Alonso"]
24
+ gem.add_dependency "eventmachine", ">= 1.0.0.beta.4"
25
+ gem.require_paths = ["lib"]
26
+ # dependencies defined in Gemfile
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ #require 'rcov/rcovtask'
38
+ #Rcov::RcovTask.new do |test|
39
+ # test.libs << 'test'
40
+ # test.pattern = 'test/**/test_*.rb'
41
+ # test.verbose = true
42
+ # test.rcov_opts << '--exclude "gems/*"'
43
+ #end
44
+
45
+ task :default => :test
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "bliss #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.3
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'icmp4em'
3
+
4
+ # This is an example of non-stateful usage. Only the callbacks provided in on_success and on_expire are used,
5
+ # and the object does not keep track of up/down or execute callbacks on_failure/on_recovery.
6
+ # The data string can be set to anything, as long as the total packet size is less than MTU of the network.
7
+
8
+ pings = []
9
+ pings << ICMP4EM::ICMPv4.new("google.com")
10
+ pings << ICMP4EM::ICMPv4.new("slashdot.org")
11
+ pings << ICMP4EM::ICMPv4.new("10.99.99.99") # host that will not respond.
12
+
13
+ Signal.trap("INT") { EventMachine::stop_event_loop }
14
+
15
+ EM.run {
16
+ pings.each do |ping|
17
+ ping.data = "bar of foozz"
18
+ ping.on_success {|host, seq, latency| puts "SUCCESS from #{host}, sequence number #{seq}, Latency #{latency}ms"}
19
+ ping.on_expire {|host, seq, exception| puts "FAILURE from #{host}, sequence number #{seq}, Reason: #{exception.to_s}"}
20
+ ping.schedule
21
+ end
22
+ }
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'icmp4em'
3
+
4
+ # This example shows stateful usage, which tracks up/down state of the host based on consecutive number
5
+ # of successful or failing pings specified in failures_required and recoveries_required. Hosts start in
6
+ # 'up' state.
7
+
8
+ pings = []
9
+ pings << ICMP4EM::ICMPv4.new("google.com", :stateful => true)
10
+ pings << ICMP4EM::ICMPv4.new("10.1.0.175", :stateful => true) # host that will not respond.
11
+
12
+ Signal.trap("INT") { EventMachine::stop_event_loop }
13
+
14
+ EM.run {
15
+ pings.each do |ping|
16
+ ping.on_success {|host, seq, latency, count_to_recovery| puts "SUCCESS from #{host}, sequence number #{seq}, Latency #{latency}ms, Recovering in #{count_to_recovery} more"}
17
+ ping.on_expire {|host, seq, exception, count_to_failure| puts "FAILURE from #{host}, sequence number #{seq}, Reason: #{exception.to_s}, Failing in #{count_to_failure} more"}
18
+ ping.on_failure {|host| puts "HOST STATE WENT TO DOWN: #{host} at #{Time.now}"}
19
+ ping.on_recovery {|host| puts "HOST STATE WENT TO UP: #{host} at #{Time.now}"}
20
+ ping.schedule
21
+ end
22
+ }
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "krakatoa-icmp4em"
8
+ s.version = "0.0.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jake Douglas", "Fernando Alonso"]
12
+ s.date = "2012-03-23"
13
+ s.description = "Asynchronous implementation of ICMP ping using EventMachine. Can be used to ping many hosts at once in a non-blocking fashion, with callbacks for success, timeout, and host failure/recovery based on specified threshold numbers."
14
+ s.email = "krakatoa1987@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ "Gemfile",
20
+ "Gemfile.lock",
21
+ "README",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "examples/simple_example.rb",
25
+ "examples/stateful_example.rb",
26
+ "krakatoa-icmp4em.gemspec",
27
+ "lib/icmp4em.rb",
28
+ "lib/icmp4em/common.rb",
29
+ "lib/icmp4em/handler.rb",
30
+ "lib/icmp4em/icmpv4.rb"
31
+ ]
32
+ s.homepage = "http://github.com/krakatoa/icmp4em"
33
+ s.licenses = ["MIT"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = "1.8.10"
36
+ s.summary = "Asynchronous implementation of ICMP ping over EventMachine"
37
+
38
+ if s.respond_to? :specification_version then
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<eventmachine>, [">= 1.0.0.beta.4"])
43
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
44
+ s.add_development_dependency(%q<bundler>, ["~> 1.1.0"])
45
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
46
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
47
+ s.add_runtime_dependency(%q<eventmachine>, [">= 1.0.0.beta.4"])
48
+ else
49
+ s.add_dependency(%q<eventmachine>, [">= 1.0.0.beta.4"])
50
+ s.add_dependency(%q<shoulda>, [">= 0"])
51
+ s.add_dependency(%q<bundler>, ["~> 1.1.0"])
52
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
53
+ s.add_dependency(%q<simplecov>, [">= 0"])
54
+ s.add_dependency(%q<eventmachine>, [">= 1.0.0.beta.4"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<eventmachine>, [">= 1.0.0.beta.4"])
58
+ s.add_dependency(%q<shoulda>, [">= 0"])
59
+ s.add_dependency(%q<bundler>, ["~> 1.1.0"])
60
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
61
+ s.add_dependency(%q<simplecov>, [">= 0"])
62
+ s.add_dependency(%q<eventmachine>, [">= 1.0.0.beta.4"])
63
+ end
64
+ end
65
+
data/lib/icmp4em.rb ADDED
@@ -0,0 +1,6 @@
1
+ $:.unshift File.expand_path(File.dirname(File.expand_path(__FILE__)))
2
+ require 'eventmachine'
3
+ require 'socket'
4
+ require 'icmp4em/common'
5
+ require 'icmp4em/handler'
6
+ require 'icmp4em/icmpv4'
@@ -0,0 +1,140 @@
1
+ module ICMP4EM
2
+
3
+ class Timeout < Exception; end;
4
+
5
+ module Common
6
+
7
+ ICMP_ECHOREPLY = 0
8
+ ICMP_ECHO = 8
9
+ ICMP_SUBCODE = 0
10
+
11
+ private
12
+
13
+ # Perform a checksum on the message. This is the sum of all the short
14
+ # words and it folds the high order bits into the low order bits.
15
+ # (This method was stolen directly from net-ping - yaki)
16
+ def generate_checksum(msg)
17
+ length = msg.length
18
+ num_short = length / 2
19
+ check = 0
20
+
21
+ msg.unpack("n#{num_short}").each do |short|
22
+ check += short
23
+ end
24
+
25
+ if length % 2 > 0
26
+ check += msg[length-1, 1].unpack('C').first << 8
27
+ end
28
+
29
+ check = (check >> 16) + (check & 0xffff)
30
+ return (~((check >> 16) + check) & 0xffff)
31
+ end
32
+
33
+ end
34
+
35
+ module HostCommon
36
+
37
+ # Set failure callback. The provided Proc or block will be called and yielded the host and sequence number, whenever the failure count exceeds the defined threshold.
38
+ def on_failure(proc = nil, &block)
39
+ @failure = proc || block unless proc.nil? and block.nil?
40
+ @failure
41
+ end
42
+
43
+ # Set recovery callback. The provided Proc or block will be called and yielded the host and sequence number, whenever the recovery count exceeds the defined threshold.
44
+ def on_recovery(proc = nil, &block)
45
+ @recovery = proc || block unless proc.nil? and block.nil?
46
+ @recovery
47
+ end
48
+
49
+ # Set success callback. This will be called and yielded the host, sequence number, and latency every time a ping returns successfully.
50
+ def on_success(proc = nil, &block)
51
+ @success = proc || block unless proc.nil? and block.nil?
52
+ @success
53
+ end
54
+
55
+ # Set 'expiry' callback. This will be called and yielded the host, sequence number, and Exception every time a ping fails.
56
+ # This is not just for timeouts! This can be triggered by failure of the ping for any reason.
57
+ def on_expire(proc = nil, &block)
58
+ @expiry = proc || block unless proc.nil? and block.nil?
59
+ @expiry
60
+ end
61
+
62
+ # Set the number of consecutive 'failure' pings required to switch host state to 'down' and trigger failure callback, assuming the host is up.
63
+ def failures_required=(failures)
64
+ @failures_required = failures
65
+ end
66
+
67
+ # Set the number of consecutive 'recovery' pings required to switch host state to 'up' and trigger recovery callback, assuming the host is down.
68
+ def recoveries_required=(recoveries)
69
+ @recoveries_required = recoveries
70
+ end
71
+
72
+ private
73
+
74
+ def success(seq, latency)
75
+ if @success
76
+ if @stateful
77
+ count_to_recover = @up ? 0 : @recoveries_required - @failcount.abs
78
+ @success.call(@host, seq, latency, count_to_recover)
79
+ else
80
+ @success.call(@host, seq, latency)
81
+ end
82
+ end
83
+ end
84
+
85
+ def expiry(seq, reason)
86
+ if @expiry
87
+ if @stateful
88
+ count_to_fail = @up ? @failures_required - @failcount : 0
89
+ @expiry.call(@host, seq, reason, count_to_fail)
90
+ else
91
+ @expiry.call(@host, seq, reason)
92
+ end
93
+ end
94
+ end
95
+
96
+ # Executes specified failure callback, passing the host to the block.
97
+ def fail
98
+ @failure.call(@host) if @failure
99
+ @up = false
100
+ end
101
+
102
+ # Executes specified recovery callback, passing the host to the block.
103
+ def recover
104
+ @recovery.call(@host) if @recovery
105
+ @up = true
106
+ end
107
+
108
+ # Trigger failure/recovery if either threshold is exceeded...
109
+ def check_for_fail_or_recover
110
+ if @failcount > 0
111
+ fail if @failcount >= @failures_required && @up
112
+ elsif @failcount <= -1
113
+ recover if @failcount.abs >= @recoveries_required && !@up
114
+ end
115
+ end
116
+
117
+ # Adjusts the failure counter after each ping. The failure counter is incremented positively to count failures,
118
+ # and decremented into negative numbers to indicate successful pings towards recovery after a failure.
119
+ # This is an awful mess..just like the rest of this file.
120
+ def adjust_failure_count(direction)
121
+ if direction == :down
122
+ if @failcount > -1
123
+ @failcount += 1
124
+ elsif @failcount <= -1
125
+ @failcount = 1
126
+ end
127
+ elsif direction == :up && !@up
128
+ if @failcount > 0
129
+ @failcount = -1
130
+ elsif @failcount <= -1
131
+ @failcount -= 1
132
+ end
133
+ else
134
+ @failcount = 0
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+ end
@@ -0,0 +1,53 @@
1
+ module ICMP4EM
2
+
3
+ module Handler
4
+
5
+ include Common
6
+
7
+ def initialize(socket)
8
+ @socket = socket
9
+ end
10
+
11
+ def notify_readable
12
+ receive(@socket)
13
+ end
14
+
15
+ def unbind
16
+ @socket.close if @socket
17
+ end
18
+
19
+ private
20
+
21
+ def receive(socket)
22
+ # The data was available now
23
+ time = Time.now
24
+ # Get data
25
+ host, data = read_socket(socket)
26
+ # Rebuild message array
27
+ msg = data[20,30].unpack("C2 n3 A*")
28
+ # Verify the packet type is echo reply and verify integrity against the checksum it provided
29
+ return unless msg.first == ICMP_ECHOREPLY && verify_checksum?(msg)
30
+ # Find which object it is supposed to go to
31
+ recipient = ICMPv4.instances[msg[3]]
32
+ # Send time and seq number to recipient object
33
+ recipient.send(:receive, msg[4], time) unless recipient.nil?
34
+ end
35
+
36
+ def read_socket(socket)
37
+ # Recieve a common MTU, 1500 bytes.
38
+ data, sender = socket.recvfrom(1500)
39
+ # Get the host in case we want to use that later.
40
+ host = Socket.unpack_sockaddr_in(sender).last
41
+ [host, data]
42
+ end
43
+
44
+ def verify_checksum?(ary)
45
+ cs = ary[2]
46
+ ary_copy = ary.dup
47
+ ary_copy[2] = 0
48
+ cs == generate_checksum(ary_copy.pack("C2 n3 A*"))
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,174 @@
1
+ module ICMP4EM
2
+
3
+ class ICMPv4
4
+
5
+ include Common
6
+ include HostCommon
7
+
8
+ @instances = {}
9
+ @recvsocket = nil
10
+
11
+ class << self
12
+
13
+ attr_reader :instances
14
+ attr_accessor :recvsocket, :handler
15
+
16
+ end
17
+
18
+ attr_accessor :bind_host, :interval, :threshold, :timeout, :data, :block
19
+ attr_reader :id, :failures_required, :recoveries_required, :seq
20
+
21
+ # Create a new ICMP object (host). This takes a host and an optional hash of options for modifying the behavior. They are:
22
+ # * :bind_host
23
+ # Bind the socket to this address. The operating system will figure this out on it's own unless you need to set it for a special situation.
24
+ # * :timeout
25
+ # Timeout, in seconds, before the ping is considered expired and the appropriate callbacks are executed. This should be a numeric class.
26
+ # * :block
27
+ # True or false, default is false. True enables a blocking receive mode, for when accurate latency measurement is important. Due to the nature
28
+ # of event loop architecture, a noticable delay in latency can be added when other things are going on in the reactor.
29
+ # * :interval
30
+ # Interval, in seconds, for how often the ping should be sent. Should be a numeric class.
31
+ # * :stateful
32
+ # True or false, default is false. Indicates whether or not this ping object should keep track of it's successes and failures and execute
33
+ # the on_failure/on_recovery callbacks when the specified limits are hit.
34
+ # * :failures_required
35
+ # Indicates how many consequtive failures are required to switch to the 'failed' state and execute the on_failure callback. Applies only when :stateful => true
36
+ # * :recoveries_required
37
+ # Indicates how many consequtive successes are required to switch to the 'recovered' state and execute the on_recovery callback. Applies only when :stateful => true
38
+ def initialize(host, options = {})
39
+ raise 'requires root privileges' if Process.euid > 0
40
+ @host = host
41
+ @ipv4_sockaddr = Socket.pack_sockaddr_in(0, @host)
42
+ @interval = options[:interval] || 1
43
+ @timeout = options[:timeout] || 1
44
+ @stateful = options[:stateful] || false
45
+ @bind_host = options[:bind_host] || nil
46
+ @block = options[:block] || false
47
+ @recoveries_required = options[:recoveries_required] || 5
48
+ @failures_required = options[:failures_required] || 5
49
+ @up = true
50
+ @waiting = {}
51
+ set_id
52
+ @seq, @failcount = 0, 0
53
+ @data = "Ping from EventMachine"
54
+ end
55
+
56
+ # This must be called when the object will no longer be used, to remove
57
+ # the object from the class variable hash that is searched for recipients when
58
+ # an ICMP echo comes in. Also cancels the periodic timer. Better way to do this whole thing?...
59
+ def stop
60
+ @ptimer.cancel if @ptimer
61
+ self.class.instances[@id] = nil
62
+ end
63
+
64
+ # Send the echo request to @host and add sequence number to the waiting queue.
65
+ def ping
66
+ raise "EM not running" unless EM.reactor_running?
67
+ init_handler if self.class.recvsocket.nil?
68
+ @seq = ping_send
69
+ if @block
70
+ blocking_receive
71
+ else
72
+ EM.add_timer(@timeout) { self.send(:expire, @seq, Timeout.new("Ping timed out")) } unless @timeout == 0
73
+ end
74
+ @seq
75
+ end
76
+
77
+ # Uses a periodic timer to ping the host at @interval.
78
+ def schedule
79
+ raise "EM not running" unless EM.reactor_running?
80
+ @ptimer = EM::PeriodicTimer.new(@interval) { self.ping }
81
+ end
82
+
83
+ private
84
+
85
+ # Expire a sequence number from the waiting queue.
86
+ # Should only be called by the timer setup in #ping or the rescue Exception in #ping_send.
87
+ def expire(seq, exception = nil)
88
+ waiting = @waiting[seq]
89
+ if waiting
90
+ @waiting[seq] = nil
91
+ adjust_failure_count(:down) if @stateful
92
+ expiry(seq, exception)
93
+ check_for_fail_or_recover if @stateful
94
+ end
95
+ end
96
+
97
+ # Should only be called by the Handler. Passes the receive time and sequence number.
98
+ def receive(seq, time)
99
+ waiting = @waiting[seq]
100
+ if waiting
101
+ latency = (time - waiting) * 1000
102
+ adjust_failure_count(:up) if @stateful
103
+ success(seq, latency)
104
+ check_for_fail_or_recover if @stateful
105
+ @waiting[seq] = nil
106
+ end
107
+ end
108
+
109
+ # Construct and send the ICMP echo request packet.
110
+ def ping_send
111
+ seq = (@seq + 1) % 65536
112
+
113
+ socket = self.class.recvsocket
114
+
115
+ # Generate msg with checksum
116
+ msg = [ICMP_ECHO, ICMP_SUBCODE, 0, @id, seq, @data].pack("C2 n3 A*")
117
+ msg[2..3] = [generate_checksum(msg)].pack('n')
118
+
119
+ # Enqueue so we can expire properly if there is an exception raised during #send
120
+ @waiting[seq] = Time.now
121
+
122
+ begin
123
+ # Fire it off
124
+ socket.send(msg, 0, @ipv4_sockaddr)
125
+ # Re-enqueue AFTER sendto() returns. This ensures we aren't adding latency if the socket blocks.
126
+ @waiting[seq] = Time.now
127
+ # Return sequence number to caller
128
+ seq
129
+ rescue Exception => err
130
+ expire(seq, err)
131
+ seq
132
+ end
133
+ end
134
+
135
+ # Initialize the receiving socket and handler for incoming ICMP packets.
136
+ def init_handler
137
+ self.class.recvsocket = Socket.new(
138
+ Socket::PF_INET,
139
+ Socket::SOCK_RAW,
140
+ Socket::IPPROTO_ICMP
141
+ )
142
+ if @bind_host
143
+ saddr = Socket.pack_sockaddr_in(0, @bind_host)
144
+ self.class.recvsocket.bind(saddr)
145
+ end
146
+ self.class.handler = EM.watch self.class.recvsocket, Handler, self.class.recvsocket
147
+ self.class.handler.notify_readable = true
148
+ end
149
+
150
+ # Sets the instance id to a unique 16 bit integer so it can fit inside relevent the ICMP field.
151
+ # Also adds self to the pool so that incoming messages that it requested can be delivered.
152
+ def set_id
153
+ while @id.nil?
154
+ id = rand(65535)
155
+ unless self.class.instances[id]
156
+ @id = id
157
+ self.class.instances[@id] = self
158
+ end
159
+ end
160
+ end
161
+
162
+ def blocking_receive
163
+ r = select([self.class.recvsocket], nil, nil, @timeout)
164
+
165
+ if r and r.first.include?(self.class.recvsocket)
166
+ self.class.handler.notify_readable
167
+ else
168
+ expire(@seq, Timeout.new("Ping timed out"))
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: krakatoa-icmp4em
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jake Douglas
9
+ - Fernando Alonso
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-03-23 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: eventmachine
17
+ requirement: &27867940 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.0.beta.4
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *27867940
26
+ - !ruby/object:Gem::Dependency
27
+ name: shoulda
28
+ requirement: &27867460 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *27867460
37
+ - !ruby/object:Gem::Dependency
38
+ name: bundler
39
+ requirement: &27866980 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 1.1.0
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *27866980
48
+ - !ruby/object:Gem::Dependency
49
+ name: jeweler
50
+ requirement: &27866500 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 1.6.4
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *27866500
59
+ - !ruby/object:Gem::Dependency
60
+ name: simplecov
61
+ requirement: &27866020 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *27866020
70
+ - !ruby/object:Gem::Dependency
71
+ name: eventmachine
72
+ requirement: &27865540 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 1.0.0.beta.4
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: *27865540
81
+ description: Asynchronous implementation of ICMP ping using EventMachine. Can be used
82
+ to ping many hosts at once in a non-blocking fashion, with callbacks for success,
83
+ timeout, and host failure/recovery based on specified threshold numbers.
84
+ email: krakatoa1987@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files:
88
+ - README
89
+ files:
90
+ - Gemfile
91
+ - Gemfile.lock
92
+ - README
93
+ - Rakefile
94
+ - VERSION
95
+ - examples/simple_example.rb
96
+ - examples/stateful_example.rb
97
+ - krakatoa-icmp4em.gemspec
98
+ - lib/icmp4em.rb
99
+ - lib/icmp4em/common.rb
100
+ - lib/icmp4em/handler.rb
101
+ - lib/icmp4em/icmpv4.rb
102
+ homepage: http://github.com/krakatoa/icmp4em
103
+ licenses:
104
+ - MIT
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ segments:
116
+ - 0
117
+ hash: 701688465436271762
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 1.8.10
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: Asynchronous implementation of ICMP ping over EventMachine
130
+ test_files: []