Class: Net::SNMP::Session
- Inherits:
-
Object
- Object
- Net::SNMP::Session
- Extended by:
- Forwardable
- Includes:
- Debug
- Defined in:
- lib/net/snmp/session.rb
Direct Known Subclasses
Class Attribute Summary collapse
-
.lock ⇒ Object
Returns the value of attribute lock.
-
.sessions ⇒ Object
Returns the value of attribute sessions.
Instance Attribute Summary collapse
-
#callback ⇒ Object
Returns the value of attribute callback.
-
#community ⇒ Object
Returns the value of attribute community.
-
#peername ⇒ Object
Returns the value of attribute peername.
-
#requests ⇒ Object
Returns the value of attribute requests.
-
#struct ⇒ Object
Returns the value of attribute struct.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
Class Method Summary collapse
-
.open(options = {}) ⇒ Object
Open a new session.
Instance Method Summary collapse
-
#close ⇒ Object
Close the snmp session and free associated resources.
- #default_max_repeaters ⇒ Object
- #errno ⇒ Object
-
#error(msg, options = {}) ⇒ Object
Raise a NET::SNMP::Error with the session attached.
-
#error_message ⇒ Object
The SNMP Session error message.
-
#get(oidlist, &block) ⇒ Object
Issue an SNMP GET Request.
-
#get_bulk(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GETBULK Request See #send_pdu.
-
#get_next(oidlist, &block) ⇒ Object
Issue an SNMP GETNEXT Request See #send_pdu.
-
#get_table(table_name, options = {}) ⇒ Object
XXX This needs work.
-
#initialize(options = {}) ⇒ Session
constructor
A new instance of Session.
- #method_missing(m, *args) ⇒ Object
-
#select(timeout = nil) ⇒ Object
(also: #poll)
Check the session for SNMP responses from asynchronous SNMP requests This method will check for new responses and call the associated response callbacks.
-
#send_pdu(pdu, &callback) ⇒ Object
Send a PDU
pduThe Net::SNMP::PDU object to send. -
#set(oidlist, &block) ⇒ Object
Issue an SNMP Set Request See #send_pdu.
-
#snmp_err ⇒ Object
The SNMP Session error code.
Methods included from Debug
Constructor Details
#initialize(options = {}) ⇒ Session
Returns a new instance of Session.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/net/snmp/session.rb', line 54 def initialize( = {}) #puts "in initialize" @timeout = [:timeout] || 1 @retries = [:retries] || 5 @requests = {} @peername = [:peername] || 'localhost' @peername = "#{@peername}:#{[:port]}" if [:port] @community = [:community] || "public" [:community_len] = @community.length @version = [:version] || 1 [:version] ||= Constants::SNMP_VERSION_1 @version = [:version] || 1 #self.class.sessions << self @sess = Wrapper::SnmpSession.new(nil) Wrapper.snmp_sess_init(@sess.pointer) #options.each_pair {|k,v| ptr.send("#{k}=", v)} @sess.community = FFI::MemoryPointer.from_string(@community) @sess.community_len = @community.length @sess.peername = FFI::MemoryPointer.from_string(@peername) #@sess.remote_port = options[:port] || 162 @sess.version = case [:version].to_s when '1' Constants::SNMP_VERSION_1 when '2', '2c' Constants::SNMP_VERSION_2c when '3' Constants::SNMP_VERSION_3 else Constants::SNMP_VERSION_1 end debug "setting timeout = #{@timeout} retries = #{@retries}" @sess.timeout = @timeout * 1000000 @sess.retries = @retries if @sess.version == Constants::SNMP_VERSION_3 @sess.securityLevel = [:security_level] || Constants::SNMP_SEC_LEVEL_NOAUTH @sess.securityAuthProto = case [:auth_protocol] when :sha1 OID.new("1.3.6.1.6.3.10.1.1.3").pointer when :md5 OID.new("1.3.6.1.6.3.10.1.1.2").pointer when nil OID.new("1.3.6.1.6.3.10.1.1.1").pointer end @sess.securityAuthProtoLen = 10 @sess.securityAuthKeyLen = Constants::USM_AUTH_KU_LEN if [:context] @sess.contextName = FFI::MemoryPointer.from_string([:context]) @sess.contextNameLen = [:context].length end if [:username] @sess.securityName = FFI::MemoryPointer.from_string([:username]) @sess.securityNameLen = [:username].length end auth_len_ptr = FFI::MemoryPointer.new(:size_t) auth_len_ptr.write_int(Constants::USM_AUTH_KU_LEN) key_result = Wrapper.generate_Ku(@sess.securityAuthProto, @sess.securityAuthProtoLen, [:password], [:password].length, @sess.securityAuthKey, auth_len_ptr) @sess.securityAuthKeyLen = auth_len_ptr.read_int unless key_result == Constants::SNMPERR_SUCCESS Wrapper.snmp_perror("netsnmp") end end # General callback just takes the pdu, calls the session callback if any, then the request specific callback. @struct = Wrapper.snmp_sess_open(@sess.pointer) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(m, *args) ⇒ Object
184 185 186 187 188 189 190 |
# File 'lib/net/snmp/session.rb', line 184 def method_missing(m, *args) if @struct.respond_to?(m) @struct.send(m, *args) else super end end |
Class Attribute Details
.lock ⇒ Object
Returns the value of attribute lock.
20 21 22 |
# File 'lib/net/snmp/session.rb', line 20 def lock @lock end |
.sessions ⇒ Object
Returns the value of attribute sessions.
20 21 22 |
# File 'lib/net/snmp/session.rb', line 20 def sessions @sessions end |
Instance Attribute Details
#callback ⇒ Object
Returns the value of attribute callback.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def callback @callback end |
#community ⇒ Object
Returns the value of attribute community.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def community @community end |
#peername ⇒ Object
Returns the value of attribute peername.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def peername @peername end |
#requests ⇒ Object
Returns the value of attribute requests.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def requests @requests end |
#struct ⇒ Object
Returns the value of attribute struct.
12 13 14 |
# File 'lib/net/snmp/session.rb', line 12 def struct @struct end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
13 14 15 |
# File 'lib/net/snmp/session.rb', line 13 def version @version end |
Class Method Details
.open(options = {}) ⇒ Object
Open a new session. Accepts a block which yields the session.
Net::SNMP::Session.open(:peername => 'test.net-snmp.org', :community => 'public') do |sess|
pdu = sess.get(["sysDescr.0"])
pdu.print
end
Options:
-
peername- hostname -
community- snmp community string. Default is public -
version- snmp version. Possible values include 1, ‘2c’, and 3. Default is 1. -
timeout- snmp timeout in seconds -
retries- snmp retries. default = 5
Returns: Net::SNMP::Session
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/net/snmp/session.rb', line 37 def open( = {}) #puts "building session" session = new() if Net::SNMP::thread_safe Net::SNMP::Session.lock.synchronize { Net::SNMP::Session.sessions[session.sessid] = session } else Net::SNMP::Session.sessions[session.sessid] = session end if block_given? yield session end session end |
Instance Method Details
#close ⇒ Object
Close the snmp session and free associated resources.
126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/net/snmp/session.rb', line 126 def close if Net::SNMP.thread_safe self.class.lock.synchronize { Wrapper.snmp_sess_close(@struct) self.class.sessions.delete(self.sessid) } else Wrapper.snmp_sess_close(@struct) self.class.sessions.delete(self.sessid) end end |
#default_max_repeaters ⇒ Object
195 196 197 198 |
# File 'lib/net/snmp/session.rb', line 195 def default_max_repeaters # We could do something based on transport here. 25 seems safe 25 end |
#errno ⇒ Object
333 334 335 336 |
# File 'lib/net/snmp/session.rb', line 333 def errno get_error @errno end |
#error(msg, options = {}) ⇒ Object
Raise a NET::SNMP::Error with the session attached
203 204 205 206 |
# File 'lib/net/snmp/session.rb', line 203 def error(msg, = {}) #Wrapper.snmp_sess_perror(msg, @sess.pointer) raise Error.new({:session => self}.merge()), msg end |
#error_message ⇒ Object
The SNMP Session error message
345 346 347 348 |
# File 'lib/net/snmp/session.rb', line 345 def get_error @snmp_msg end |
#get(oidlist, &block) ⇒ Object
Issue an SNMP GET Request. See #send_pdu
140 141 142 143 144 145 146 147 |
# File 'lib/net/snmp/session.rb', line 140 def get(oidlist, &block) pdu = PDU.new(Constants::SNMP_MSG_GET) oidlist = [oidlist] unless oidlist.kind_of?(Array) oidlist.each do |oid| pdu.add_varbind(:oid => oid) end send_pdu(pdu, &block) end |
#get_bulk(oidlist, options = {}, &block) ⇒ Object
Issue an SNMP GETBULK Request See #send_pdu
162 163 164 165 166 167 168 169 170 171 |
# File 'lib/net/snmp/session.rb', line 162 def get_bulk(oidlist, = {}, &block) pdu = PDU.new(Constants::SNMP_MSG_GETBULK) oidlist = [oidlist] unless oidlist.kind_of?(Array) oidlist.each do |oid| pdu.add_varbind(:oid => oid) end pdu.non_repeaters = [:non_repeaters] || 0 pdu.max_repetitions = [:max_repetitions] || 10 send_pdu(pdu,&block) end |
#get_next(oidlist, &block) ⇒ Object
Issue an SNMP GETNEXT Request See #send_pdu
151 152 153 154 155 156 157 158 |
# File 'lib/net/snmp/session.rb', line 151 def get_next(oidlist, &block) pdu = PDU.new(Constants::SNMP_MSG_GETNEXT) oidlist = [oidlist] unless oidlist.kind_of?(Array) oidlist.each do |oid| pdu.add_varbind(:oid => oid) end send_pdu(pdu, &block) end |
#get_table(table_name, options = {}) ⇒ Object
XXX This needs work. Need to use getbulk for speed, guess maxrepeaters, etc.. Also need to figure out how we can tell column names from something like ifTable instead of ifEntry. Needs to handle errors, there are probably offset problems in cases of bad data, and various other problems. Also need to add async support. Maybe return a hash with index as key?
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
# File 'lib/net/snmp/session.rb', line 395 def get_table(table_name, = {}) column_names = [:columns] || MIB::Node.get_node(table_name).children.collect {|c| c.label } results = [] # repeat_count = if @version.to_s == '1' || options[:no_getbulk] # 1 # elsif options[:repeat_count] # options[:repeat_count] # else # (1000 / 36 / (column_names.size + 1)).to_i # end # # res = if @version.to_s != '1' && !options[:no_getbulk] # get_bulk(column_names, :max_repetitions => repeat_count) # else # get_next(column_names) # end first_result = get_next(column_names) oidlist = [] good_column_names = [] row = {} first_result.varbinds.each_with_index do |vb, idx| oid = vb.oid if oid.label[0..column_names[idx].length - 1] == column_names[idx] oidlist << oid.label good_column_names << column_names[idx] row[column_names[idx]] = vb.value end end results << row catch :break_main_loop do while(result = get_next(oidlist)) oidlist = [] row = {} result.varbinds.each_with_index do |vb, idx| #puts "got #{vb.oid.label} #{vb.value.inspect}, type = #{vb.object_type}" row[good_column_names[idx]] = vb.value oidlist << vb.oid.label if vb.oid.label[0..good_column_names[idx].length - 1] != good_column_names[idx] throw :break_main_loop end end results << row end end results end |
#select(timeout = nil) ⇒ Object Also known as: poll
Check the session for SNMP responses from asynchronous SNMP requests This method will check for new responses and call the associated response callbacks. timeout A timeout of nil indicates a poll and will return immediately. A value of false will block until data is available. Otherwise, pass the number of seconds to block. Returns the number of file descriptors handled.
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/net/snmp/session.rb', line 216 def select(timeout = nil) fdset = FFI::MemoryPointer.new(:pointer, Net::SNMP::Inline.fd_setsize / 8) num_fds = FFI::MemoryPointer.new(:int) tv_sec = timeout ? timeout.round : 0 tv_usec = timeout ? (timeout - timeout.round) * 1000000 : 0 tval = Wrapper::TimeVal.new(:tv_sec => tv_sec, :tv_usec => tv_usec) block = FFI::MemoryPointer.new(:int) if timeout.nil? block.write_int(0) else block.write_int(1) end Wrapper.snmp_sess_select_info(@struct, num_fds, fdset, tval.pointer, block ) tv = (timeout == false ? nil : tval) debug "Calling select #{Time.now}" num_ready = FFI::LibC.select(num_fds.read_int, fdset, nil, nil, tv) debug "Done select #{Time.now}" if num_ready > 0 Wrapper.snmp_sess_read(@struct, fdset) elsif num_ready == 0 Wrapper.snmp_sess_timeout(@struct) elsif num_ready == -1 # error. check snmp_error? error("select") else error("wtf is wrong with select?") end num_ready end |
#send_pdu(pdu, &callback) ⇒ Object
Send a PDU pdu The Net::SNMP::PDU object to send. Usually created by Session.get, Session.getnext, etc. callback An optional callback. It should take two parameters, status and response_pdu. If no callback is given, the call will block until the response is available and will return the response pdu. If an error occurs, a Net::SNMP::Error will be thrown. If callback is passed, the PDU will be sent and send_pdu will return immediately. You must then call Session.select to invoke the callback. This is usually done in some sort of event loop. See Net::SNMP::Dispatcher.
If you’re running inside eventmachine and have fibers (ruby 1.9, jruby, etc), sychronous calls will actually run asynchronously behind the scenes. Just run Net::SNMP::Dispatcher.fiber_loop in your reactor.
pdu = Net::SNMP::PDU.new(Constants::SNMP_MSG_GET)
pdu.add_varbind(:oid => 'sysDescr.0')
session.send_pdu(pdu) do |status, pdu|
if status == :success
pdu.print
elsif status == :timeout
puts "Timed Out"
else
puts "A problem occurred"
end
end
session.select(false) #block until data is ready. Callback will be called.
begin
result = session.send_pdu(pdu)
puts result.inspect
rescue Net::SNMP::Error => e
puts e.
end
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/net/snmp/session.rb', line 282 def send_pdu(pdu, &callback) #puts "send_pdu #{Fiber.current.inspect}" if block_given? @requests[pdu.reqid] = callback puts "calling async_send" if Wrapper.snmp_sess_async_send(@struct, pdu.pointer, sess_callback, nil) == 0 error("snmp_get async failed") end #pdu.free nil else if defined?(EM) && EM.reactor_running? && defined?(Fiber) f = Fiber.current send_pdu pdu do | op, response_pdu | f.resume([op, response_pdu]) end op, result = Fiber.yield case op when :timeout raise TimeoutError.new, "timeout" when :send_failed error "send failed" when :success result when :connect, :disconnect nil #does this ever happen? else error "unknown operation #{op}" end else response_ptr = FFI::MemoryPointer.new(:pointer) if [Constants::SNMP_MSG_TRAP, Constants::SNMP_MSG_TRAP2].include?(pdu.command) status = Wrapper.snmp_sess_send(@struct, pdu.pointer) if status == 0 error("snmp_sess_send") end else status = Wrapper.snmp_sess_synch_response(@struct, pdu.pointer, response_ptr) unless status == Constants::STAT_SUCCESS error("snmp_sess_synch_response", :status => status) end end if [Constants::SNMP_MSG_TRAP, Constants::SNMP_MSG_TRAP2].include?(pdu.command) 1 else PDU.new(response_ptr.read_pointer) end end end end |
#set(oidlist, &block) ⇒ Object
Issue an SNMP Set Request See #send_pdu
176 177 178 179 180 181 182 |
# File 'lib/net/snmp/session.rb', line 176 def set(oidlist, &block) pdu = PDU.new(Constants::SNMP_MSG_SET) oidlist.each do |oid| pdu.add_varbind(:oid => oid[0], :type => oid[1], :value => oid[2]) end send_pdu(pdu, &block) end |
#snmp_err ⇒ Object
The SNMP Session error code
339 340 341 342 |
# File 'lib/net/snmp/session.rb', line 339 def snmp_err get_error @snmp_err end |