net-snmp 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -4,6 +4,8 @@ source "http://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  gem 'nice-ffi'
7
+ gem 'ffi-inliner'
8
+ #gem 'ffi-libc'
7
9
  #group :development, :test do
8
10
  # gem 'eventmachine', '1.0.0.beta.3'
9
11
  #end
data/README.rdoc CHANGED
@@ -9,6 +9,7 @@ It provides classes for sessions, pdus, varbinds, and more.
9
9
 
10
10
  * Supports SNMP versions 1, 2c, and 3
11
11
  * Supports both synchronous and asynchronous calls
12
+ * Supports sending of snmpv1 traps and snmpv2 traps/informs using TrapSession
12
13
  * Integrates well with eventmachine, or can be used standalone.
13
14
  * In Ruby 1.9, uses fibers behind the scenes to emulate synchronous calls asynchronously
14
15
 
@@ -44,31 +45,48 @@ functions are defined in Net::SNMP::Wrapper. You can call them like so:
44
45
  == NOTES
45
46
  You must call Session.close when you're done with a session to avoid leaking memory
46
47
 
47
- == EXAMPLES
48
+ == ERROR HANDLING
49
+ In the synchronous versions, all session methods raise Net::SNMP:Error on any error. Timeouts raise Net::SNMP::TimeoutError.
50
+ In the asynchronous versions, the first argument to your callback will be the return status. Possible values include :success, :timeout, and :send_error.
51
+ If you need the underlying net-snmp session errors, you can call session.errno, session.snmp_err, and session.error_message.
52
+
48
53
 
54
+ == EXAMPLES
49
55
 
50
56
  A simple synchronous SNMP-GET
51
57
 
52
58
  session = Net::SNMP::Session.open(:peername => "test.net-snmp.org", :community => "demopublic" )
53
- result = session.get("sysDescr.0")
54
- puts result.varbinds.first.value
59
+ begin
60
+ pdu = session.get("sysDescr.0")
61
+ puts pdu.varbinds.first.value
62
+ rescue Net::SNMP::Error => e
63
+ puts e.message
64
+ end
55
65
  session.close
56
66
 
57
67
  An asynchronous SNMP-GET
58
68
  session = Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :community => 'demopublic') do |session|
59
- session.get(["sysDescr.0", "sysContact.0"]) do |result|
60
- puts result.varbinds[0].value
69
+ session.get(["sysDescr.0", "sysContact.0"]) do |status, pdu|
70
+ if status == :success
71
+ puts pdu.varbinds[0].value
72
+ else
73
+ puts "something went wrong. status is #{status}"
74
+ end
61
75
  end
62
76
  end
63
- Net::SNMP::Dispatcher.poll(false) #Setting timeout to false causes dispatcher to block until data is ready
77
+ Net::SNMP::Dispatcher.select(false) #Setting timeout to false causes dispatcher to block until data is ready
64
78
  session.close
65
79
 
66
80
  Running the dispatcher from eventmachine
67
81
  EM.run do
68
82
  Net::SNMP::Dispatcher.em_loop
69
83
  session = Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :community => 'demopublic') do |session|
70
- session.get("sysDescr.0") do |result|
71
- puts result.varbinds[0].value
84
+ session.get("sysDescr.0") do |status, pdu|
85
+ if status == :success
86
+ puts pdu.varbinds[0].value
87
+ else
88
+ puts "something went wrong. status is #{status}"
89
+ end
72
90
  end
73
91
  end
74
92
  EM.add_timer(2) do
@@ -82,8 +100,12 @@ Using synchronous style with eventmachine in ruby 1.9
82
100
  Net::SNMP::Dispatcher.fiber_loop
83
101
  Fiber.new {
84
102
  session = Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :community => 'demopublic')
85
- result = session.get("sysDescr.0")
86
- puts result.varbinds[0].value
103
+ begin
104
+ pdu = session.get("sysDescr.0")
105
+ puts pdu.varbinds[0].value
106
+ rescue Net::SNMP::Error => e
107
+ puts e.message
108
+ end
87
109
  session.close
88
110
  EM.stop
89
111
  }.resume
@@ -105,14 +127,15 @@ You can also explicitly add MIBs using the MIB api. For example:
105
127
  Net::SNMP::MIB.add_mibdir("/usr/local/share/mibs")
106
128
  Net::SNMP::MIB.read_mib("RFC1213-MIB.txt")
107
129
 
108
- Having the appropriate MIBs loaded will allow you to pass names instead of numeric oids to net-snmp methods. To translate a single oid,
109
- you can call Net::SNMP.get_oid("sysDescr.0"). For more complex MIB parsing needs, see smi-ffi[http://github.com/mixtli/smi-ffi]
110
-
130
+ Having the appropriate MIBs loaded will allow you to pass names instead of numeric oids to net-snmp methods. You can also pass
131
+ Net::SNMP::OID objects. For example
111
132
 
112
- == BUGS
113
- Right now, snmpv3 is only working using synchronous API. Asynchronous calls seem to miss packets.
114
- I have no idea why it would be different for v3 vs v1/v2. If anyone knows, tell me ;)
133
+ oid = Net::SNMP::OID.new('sysDescr.0') # or Net::SNMP::OID.new("1.3.6.1.2.1.1.1.0")
134
+ puts oid.to_s --> '1.3.6.1.2.1.1.1.0'
135
+ puts oid.label --> 'sysDescr.0'
136
+ pdu = session.get([oid])
115
137
 
138
+ For more complex MIB parsing needs, see smi-ffi[http://github.com/mixtli/smi-ffi]
116
139
 
117
140
  == CAVEATS/DISCLAIMER
118
141
 
@@ -128,13 +151,11 @@ break this gem. Please let me know if you find bugs or missing features. Or be
128
151
 
129
152
 
130
153
  == TODO
131
-
132
- * Better error handling.
154
+ * Implement walk and get_table convenience methods.
133
155
  * SNMPv3 support needs testing for various security models
134
156
  * Better documentation
135
157
  * More tests
136
- * Cleanup cruft and unused code
137
- * Implement SNMP traps/informs?
158
+
138
159
 
139
160
  == Note on Patches/Pull Requests
140
161
 
data/lib/net-snmp.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  require 'forwardable'
2
2
  require 'nice-ffi'
3
3
  require 'fiber'
4
-
5
- %w(snmp snmp/version snmp/constants snmp/utility snmp/oid snmp/error snmp/pdu snmp/wrapper snmp/session snmp/varbind snmp/mib snmp/mib/node snmp/dispatcher).each do |f|
4
+ require 'ffi-inliner'
5
+ #require 'ffi/libc'
6
+ %w( snmp snmp/debug snmp/wrapper snmp/version snmp/inline snmp/constants snmp/utility snmp/oid snmp/error snmp/pdu snmp/session snmp/trap_session snmp/varbind snmp/mib snmp/mib/node snmp/dispatcher).each do |f|
6
7
  require "#{File.dirname(__FILE__)}/net/#{f}"
7
8
  end
9
+
10
+
11
+
8
12
  Net::SNMP::MIB.init
9
13
  Net::SNMP::MIB.read_all_mibs
10
14
  Net::SNMP.init
data/lib/net/snmp.rb CHANGED
@@ -2,15 +2,18 @@ require 'net/snmp/constants'
2
2
  module Net
3
3
  module SNMP
4
4
  include Net::SNMP::Constants
5
-
6
-
5
+ @thread_safe = false
7
6
  def self.init(tag="snmp")
8
7
  Wrapper.init_snmp(tag)
9
8
  end
10
9
 
10
+ def self.thread_safe=(val)
11
+ @thread_safe = val
12
+ end
11
13
 
12
-
13
-
14
+ def self.thread_safe
15
+ @thread_safe
16
+ end
14
17
 
15
18
  end
16
19
  end
@@ -2,10 +2,18 @@ module Net
2
2
  module SNMP
3
3
  module Constants
4
4
  MAX_OID_LEN = 128
5
+
6
+ # Return values of various send functions
7
+ STAT_SUCCESS = 0
8
+ STAT_ERROR = 1
9
+ STAT_TIMEOUT = 2
10
+
11
+ # SNMP versions
5
12
  SNMP_VERSION_1 = 0
6
13
  SNMP_VERSION_2c = 1
7
14
  SNMP_VERSION_3 = 3
8
15
 
16
+ # PDU variable types
9
17
  ASN_BOOLEAN = 0x01
10
18
  ASN_INTEGER = 0x02
11
19
  ASN_BIT_STR = 0x03
@@ -34,13 +42,17 @@ module Net
34
42
  ASN_UNSIGNED = (ASN_APPLICATION | 2) # RFC 1902 - same as GAUGE
35
43
  ASN_TIMETICKS = (ASN_APPLICATION | 3)
36
44
  ASN_OPAQUE = (ASN_APPLICATION | 4)
45
+ ASN_NSAP = (ASN_APPLICATION | 5) # historic - don't use
46
+ ASN_COUNTER64 = (ASN_APPLICATION | 6)
47
+ ASN_UINTEGER = (ASN_APPLICATION | 7) # historic - don't use
37
48
 
38
- #define ASN_NSAP (ASN_APPLICATION | 5) /* historic - don't use */
39
- #define ASN_COUNTER64 (ASN_APPLICATION | 6)
40
- #define ASN_UINTEGER (ASN_APPLICATION | 7) /* historic - don't use */
41
-
49
+ # Exception values for SNMPv2 and SNMPv3
50
+ SNMP_NOSUCHOBJECT = (ASN_CONTEXT | ASN_PRIMITIVE | 0x0)
51
+ SNMP_NOSUCHINSTANCE = (ASN_CONTEXT | ASN_PRIMITIVE | 0x1)
52
+ SNMP_ENDOFVIEW = (ASN_CONTEXT | ASN_PRIMITIVE | 0x2)
42
53
 
43
54
 
55
+ # PDU types
44
56
  SNMP_MSG_GET = (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x0)
45
57
  SNMP_MSG_GETNEXT = (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x1)
46
58
  SNMP_MSG_RESPONSE = (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x2)
@@ -51,64 +63,15 @@ module Net
51
63
  SNMP_MSG_TRAP2 = (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x7)
52
64
  SNMP_MSG_REPORT = (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x8)
53
65
 
66
+
67
+ # Callback status codes
54
68
  NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE = 1
55
69
  NETSNMP_CALLBACK_OP_TIMED_OUT = 2
56
70
  NETSNMP_CALLBACK_OP_SEND_FAILED = 3
57
71
  NETSNMP_CALLBACK_OP_CONNECT = 4
58
72
  NETSNMP_CALLBACK_OP_DISCONNECT = 5
59
73
 
60
-
61
-
62
- USM_AUTH_KU_LEN = 32
63
- USM_PRIV_KU_LEN = 32
64
-
65
- SNMP_SEC_LEVEL_NOAUTH = 1
66
- SNMP_SEC_LEVEL_AUTHNOPRIV = 2
67
- SNMP_SEC_LEVEL_AUTHPRIV = 3
68
-
69
- SNMP_DEFAULT_COMMUNITY_LEN = 0
70
- SNMP_DEFAULT_RETRIES = -1
71
- SNMP_DEFAULT_TIMEOUT = -1
72
- SNMP_DEFAULT_REMPORT = 0
73
- SNMP_DEFAULT_REQID = -1
74
- SNMP_DEFAULT_MSGID = -1
75
- SNMP_DEFAULT_ERRSTAT = -1
76
- SNMP_DEFAULT_ERRINDEX = -1
77
- SNMP_DEFAULT_ADDRESS = 0
78
- SNMP_DEFAULT_ENTERPRISE_LENGTH = 0
79
- SNMP_DEFAULT_TIME = 0
80
- SNMP_DEFAULT_VERSION = -1
81
- SNMP_DEFAULT_SECMODEL = -1
82
- SNMP_DEFAULT_CONTEXT =
83
-
84
- SNMP_MAX_MSG_SIZE = 1472
85
- SNMP_MAX_MSG_V3_HDRS = (4+3+4+7+7+3+7+16)
86
- SNMP_MAX_ENG_SIZE = 32
87
- SNMP_MAX_SEC_NAME_SIZE = 256
88
- SNMP_MAX_CONTEXT_SIZE = 256
89
- SNMP_SEC_PARAM_BUF_SIZE = 256
90
- SNMPV3_IGNORE_UNAUTH_REPORTS = 0
91
- SNMP_SESS_NONAUTHORITATIVE = 0
92
- SNMP_SESS_AUTHORITATIVE = 1
93
- SNMP_SESS_UNKNOWNAUTH = 2
94
- REPORT_STATS_LEN = 9
95
- REPORT_snmpUnknownSecurityModels_NUM = 1
96
- REPORT_snmpInvalidMsgs_NUM = 2
97
- REPORT_usmStatsUnsupportedSecLevels_NUM = 1
98
- REPORT_usmStatsNotInTimeWindows_NUM = 2
99
- REPORT_usmStatsUnknownUserNames_NUM = 3
100
- REPORT_usmStatsUnknownEngineIDs_NUM = 4
101
- REPORT_usmStatsWrongDigests_NUM = 5
102
- REPORT_usmStatsDecryptionErrors_NUM = 6
103
- SNMP_DETAIL_SIZE = 512
104
- SNMP_FLAGS_RESP_CALLBACK = 0x400
105
- SNMP_FLAGS_USER_CREATED = 0x200
106
- SNMP_FLAGS_DONT_PROBE = 0x100
107
- SNMP_FLAGS_STREAM_SOCKET = 0x80
108
- SNMP_FLAGS_LISTENING = 0x40
109
- SNMP_FLAGS_SUBSESSION = 0x20
110
- SNMP_FLAGS_STRIKE2 = 0x02
111
- SNMP_FLAGS_STRIKE1 = 0x01
74
+ # SNMP Errors
112
75
  SNMPERR_SUCCESS = (0)
113
76
  SNMPERR_GENERR = (-1)
114
77
  SNMPERR_BAD_LOCPORT = (-2)
@@ -178,6 +141,60 @@ module Net
178
141
  SNMPERR_MAX = (-65)
179
142
 
180
143
 
144
+
145
+ USM_AUTH_KU_LEN = 32
146
+ USM_PRIV_KU_LEN = 32
147
+
148
+ # SNMPv3 Security Levels
149
+ SNMP_SEC_LEVEL_NOAUTH = 1
150
+ SNMP_SEC_LEVEL_AUTHNOPRIV = 2
151
+ SNMP_SEC_LEVEL_AUTHPRIV = 3
152
+
153
+ SNMP_DEFAULT_COMMUNITY_LEN = 0
154
+ SNMP_DEFAULT_RETRIES = -1
155
+ SNMP_DEFAULT_TIMEOUT = -1
156
+ SNMP_DEFAULT_REMPORT = 0
157
+ SNMP_DEFAULT_REQID = -1
158
+ SNMP_DEFAULT_MSGID = -1
159
+ SNMP_DEFAULT_ERRSTAT = -1
160
+ SNMP_DEFAULT_ERRINDEX = -1
161
+ SNMP_DEFAULT_ADDRESS = 0
162
+ SNMP_DEFAULT_ENTERPRISE_LENGTH = 0
163
+ SNMP_DEFAULT_TIME = 0
164
+ SNMP_DEFAULT_VERSION = -1
165
+ SNMP_DEFAULT_SECMODEL = -1
166
+ SNMP_DEFAULT_CONTEXT =
167
+
168
+ SNMP_MAX_MSG_SIZE = 1472
169
+ SNMP_MAX_MSG_V3_HDRS = (4+3+4+7+7+3+7+16)
170
+ SNMP_MAX_ENG_SIZE = 32
171
+ SNMP_MAX_SEC_NAME_SIZE = 256
172
+ SNMP_MAX_CONTEXT_SIZE = 256
173
+ SNMP_SEC_PARAM_BUF_SIZE = 256
174
+ SNMPV3_IGNORE_UNAUTH_REPORTS = 0
175
+ SNMP_SESS_NONAUTHORITATIVE = 0
176
+ SNMP_SESS_AUTHORITATIVE = 1
177
+ SNMP_SESS_UNKNOWNAUTH = 2
178
+ REPORT_STATS_LEN = 9
179
+ REPORT_snmpUnknownSecurityModels_NUM = 1
180
+ REPORT_snmpInvalidMsgs_NUM = 2
181
+ REPORT_usmStatsUnsupportedSecLevels_NUM = 1
182
+ REPORT_usmStatsNotInTimeWindows_NUM = 2
183
+ REPORT_usmStatsUnknownUserNames_NUM = 3
184
+ REPORT_usmStatsUnknownEngineIDs_NUM = 4
185
+ REPORT_usmStatsWrongDigests_NUM = 5
186
+ REPORT_usmStatsDecryptionErrors_NUM = 6
187
+ SNMP_DETAIL_SIZE = 512
188
+ SNMP_FLAGS_RESP_CALLBACK = 0x400
189
+ SNMP_FLAGS_USER_CREATED = 0x200
190
+ SNMP_FLAGS_DONT_PROBE = 0x100
191
+ SNMP_FLAGS_STREAM_SOCKET = 0x80
192
+ SNMP_FLAGS_LISTENING = 0x40
193
+ SNMP_FLAGS_SUBSESSION = 0x20
194
+ SNMP_FLAGS_STRIKE2 = 0x02
195
+ SNMP_FLAGS_STRIKE1 = 0x01
196
+
197
+
181
198
  STAT_SNMPUNKNOWNSECURITYMODELS = 0
182
199
  STAT_SNMPINVALIDMSGS = 1
183
200
  STAT_SNMPUNKNOWNPDUHANDLERS = 2
@@ -0,0 +1,17 @@
1
+ module Net
2
+ module SNMP
3
+ module Debug
4
+ @@debug = false
5
+
6
+ def self.debug=(val)
7
+ @@debug = val
8
+ end
9
+
10
+ def debug(msg)
11
+ if @@debug
12
+ puts msg
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,89 +1,62 @@
1
1
  class Net::SNMP::Dispatcher
2
+ # A class with convenience methods for polling multiple open sessions
2
3
  class << self
3
-
4
- # timeout = nil no block(poll), timeout = false block forever, timeout = int, block int seconds
5
- # def poll(timeout = nil)
6
- # fdset = Net::SNMP::Wrapper.get_fd_set
7
- # num_fds = FFI::MemoryPointer.new(:int)
8
- # tv_sec = timeout ? timeout.round : 0
9
- # tv_usec = timeout ? (timeout - timeout.round) * 1000000 : 0
10
- # tval = Net::SNMP::Wrapper::TimeVal.new(:tv_sec => tv_sec, :tv_usec => tv_usec)
11
- # block = FFI::MemoryPointer.new(:int)
12
- #
13
- # if timeout.nil?
14
- # block.write_int(0)
15
- # else
16
- # block.write_int(1)
17
- # end
18
- # #puts "calling snmp_select_info"
19
- # Net::SNMP::Wrapper.snmp_select_info(num_fds, fdset, tval.pointer, block )
20
- # #puts "done snmp_select_info."
21
- # num_ready = 0
22
- # #puts "block = #{block.read_int}"
23
- #
24
- # #puts "numready = #{num_fds.read_int}"
25
- # #puts "tv = #{tval[:tv_sec]} #{tval[:tv_usec]}"
26
- # #puts "timeout = #{timeout}"
27
- # tv = (timeout == false ? nil : tval)
28
- # #puts "calling select"
29
- # #puts "tv = #{tv.inspect}"
30
- # #puts "calling select with #{num_fds.read_int}"
31
- # #num_ready = RubyWrapper.rb_thread_select(num_fds.read_int, fdset, nil, nil, tv)
32
- # num_ready = Net::SNMP::Wrapper.select(num_fds.read_int, fdset, nil, nil, tv)
33
- # #puts "done select. num_ready = #{num_ready}"
34
- # if num_ready > 0
35
- # Net::SNMP::Wrapper.snmp_read(fdset)
36
- # elsif num_ready == 0
37
- # # timeout. do something here? or just return 0?
38
- # elsif num_ready == -1
39
- # # error. check snmp_error?
40
- # else
41
- # # uhhh
42
- # end
43
- # #puts "done snmp_read"
44
- # num_ready
45
- # end
46
-
47
-
48
- def poll(timeout = nil)
49
- #puts "Dispatcher.poll #{Net::SNMP::Session.sessions.size}"
4
+ # Loop through all sessions, calling select on each.
5
+ def select(timeout = nil)
50
6
  total = 0
51
7
  t = timeout
52
8
  t = nil if t == false
53
9
  catch :got_data do
54
10
  loop do
55
- Net::SNMP::Session.lock.synchronize {
56
- Net::SNMP::Session.sessions.each do |k, sess|
57
- #puts "polling session"
58
- total += sess.poll(t)
11
+ if Net::SNMP.thread_safe
12
+ Net::SNMP::Session.lock.synchronize {
13
+ Net::SNMP::Session.sessions.each do |k, sess|
14
+ total += sess.select(t)
15
+ end
16
+ }
17
+ else
18
+ Net::SNMP::Session.sessions.each do |k, sess|
19
+ total += sess.select(t)
59
20
  end
60
- }
21
+ end
22
+
61
23
  throw :got_data if total > 0
62
24
  throw :got_data unless timeout == false
63
25
  end
64
26
  end
65
- #puts "Done Dispatcher.poll"
66
27
  total
67
28
  end
29
+ alias :poll :select
68
30
 
31
+ # Start a poller loop. Behavior depends upon whether
32
+ # you are running under eventmachine and whether fibers
33
+ # are available.
34
+ # +options+
35
+ # * :timeout Number of seconds to block on select. nil effects a poll. false blocks forever (probably not what you want).
36
+ # * :sleep Number of seconds to sleep if no data is available. Gives other fibers/threads a chance to run.
69
37
  def run_loop(options = {})
70
38
  if defined?(EM) && EM.reactor_running?
71
- fiber_loop(options)
39
+ if defined?(Fiber)
40
+ fiber_loop(options)
41
+ else
42
+ em_loop(options)
43
+ end
72
44
  else
73
45
  thread_loop(options)
74
46
  end
75
47
  end
76
48
 
77
- # You should not pass nil to this as it will peg your cpu
49
+ # Start a poller loop in a seperate thread. You
50
+ # should first call Net::SNMP.thread_safe = true.
51
+ # +options+
52
+ # * :timeout Number of seconds to block on select. Will not block other threads.
53
+ # * :sleep Number of seconds to sleep if no data is available. Allows other threads to run. Default 0.2
78
54
  def thread_loop(options = {})
79
-
80
- timeout = options[:timeout] || 0.1
81
- sleep_time = options[:sleep] || 0.1
55
+ timeout = options[:timeout] || 0.2
56
+ sleep_time = options[:sleep] || 0.2
82
57
  Thread.new do
83
58
  loop do
84
- #puts "polling"
85
- num_ready = poll(timeout)
86
- #puts "num_ready = #{num_ready}"
59
+ num_ready = select(timeout)
87
60
  if num_ready == 0
88
61
  sleep(sleep_time) if sleep_time
89
62
  end
@@ -91,14 +64,16 @@ class Net::SNMP::Dispatcher
91
64
  end
92
65
  end
93
66
 
94
-
67
+ # Start a loop in eventmachine (no fibers)
68
+ # +options+
69
+ # * :sleep Number of seconds to sleep if no data available. So we don't peg the reactor. Default 0.2
95
70
  def em_loop(options = {})
96
71
  timeout = options[:timeout]
97
- sleep_time = options[:sleep_time] || 0.1
72
+ sleep_time = options[:sleep] || 0.2
98
73
  myproc = Proc.new do
99
74
  EM.next_tick do
100
75
  while(true) do
101
- num_ready = poll(timeout)
76
+ num_ready = select(timeout)
102
77
  break if num_ready == 0
103
78
  end
104
79
  EM.add_timer(sleep_time) do
@@ -109,9 +84,12 @@ class Net::SNMP::Dispatcher
109
84
  myproc.call
110
85
  end
111
86
 
87
+ # Start a loop using eventmachine and fibers
88
+ # +options+
89
+ # * :sleep Number of seconds to sleep if no data available, so we don't peg the reactor. Default 0.2
112
90
  def fiber_loop(options = {})
113
91
  timeout = options[:timeout]
114
- sleep_time = options[:sleep] || 0.1
92
+ sleep_time = options[:sleep] || 0.2
115
93
  Fiber.new {
116
94
  loop do
117
95
  num_handled = poll(timeout)