netsnmp 0.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +42 -0
- data/AUTHORS +1 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +201 -0
- data/README.md +162 -0
- data/Rakefile +26 -0
- data/lib/netsnmp.rb +16 -0
- data/lib/netsnmp/client.rb +131 -0
- data/lib/netsnmp/core.rb +12 -0
- data/lib/netsnmp/core/client.rb +15 -0
- data/lib/netsnmp/core/constants.rb +153 -0
- data/lib/netsnmp/core/inline.rb +20 -0
- data/lib/netsnmp/core/libc.rb +48 -0
- data/lib/netsnmp/core/libsnmp.rb +44 -0
- data/lib/netsnmp/core/structures.rb +167 -0
- data/lib/netsnmp/core/utilities.rb +13 -0
- data/lib/netsnmp/errors.rb +8 -0
- data/lib/netsnmp/handlers/celluloid.rb +27 -0
- data/lib/netsnmp/handlers/em.rb +56 -0
- data/lib/netsnmp/oid.rb +94 -0
- data/lib/netsnmp/pdu.rb +105 -0
- data/lib/netsnmp/session.rb +306 -0
- data/lib/netsnmp/varbind.rb +181 -0
- data/lib/netsnmp/version.rb +3 -0
- data/netsnmp.gemspec +36 -0
- data/spec/client_spec.rb +90 -0
- data/spec/core/libc_spec.rb +2 -0
- data/spec/core/libsnmp_spec.rb +32 -0
- data/spec/core/structures_spec.rb +54 -0
- data/spec/handlers/celluloid_spec.rb +29 -0
- data/spec/handlers/em_client_spec.rb +34 -0
- data/spec/oid_spec.rb +9 -0
- data/spec/pdu_spec.rb +29 -0
- data/spec/session_spec.rb +34 -0
- data/spec/spec_helper.rb +114 -0
- data/spec/support/Dockerfile +14 -0
- data/spec/support/celluloid.rb +22 -0
- data/spec/support/start_docker.sh +4 -0
- data/spec/support/stop_docker.sh +5 -0
- data/spec/varbind_spec.rb +54 -0
- metadata +187 -0
@@ -0,0 +1,306 @@
|
|
1
|
+
module NETSNMP
|
2
|
+
# The Entity abstracts the C net-snmp session, and the lifecycle steps.
|
3
|
+
#
|
4
|
+
# For example, a session must be initialized (memory allocated) and opened
|
5
|
+
# (authentication, encryption, signature)
|
6
|
+
#
|
7
|
+
# The session uses the signature to send and receive PDUs. They are built somewhere else.
|
8
|
+
#
|
9
|
+
# After the session is established, a socket handle is read from the structure. This will
|
10
|
+
# be later used for non-blocking behaviour. It's important to notice, there is no
|
11
|
+
# usage of the C net-snmp sync API, we always do async send/response, even if the
|
12
|
+
# ruby API "feels" blocking. This was done so that the GIL can be released between
|
13
|
+
# sends and receives, and the load can be shared through different threads possibly.
|
14
|
+
# As we use the session abstraction, this means we ONLY use the thread-safe API.
|
15
|
+
#
|
16
|
+
class Session
|
17
|
+
|
18
|
+
attr_reader :host, :signature
|
19
|
+
|
20
|
+
# @param [String] host the host IP/hostname
|
21
|
+
# @param [Hash] opts the options set
|
22
|
+
#
|
23
|
+
def initialize(host, opts)
|
24
|
+
@host = host
|
25
|
+
@options = opts
|
26
|
+
@request = nil
|
27
|
+
# For now, let's eager load the signature
|
28
|
+
@signature = build_signature(@options)
|
29
|
+
if @signature.null?
|
30
|
+
raise ConnectionFailed, "could not connect to #{host}"
|
31
|
+
end
|
32
|
+
@requests ||= {}
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO: do we need this?
|
36
|
+
def reachable?
|
37
|
+
!!transport
|
38
|
+
end
|
39
|
+
|
40
|
+
# Closes the session
|
41
|
+
def close
|
42
|
+
return unless @signature
|
43
|
+
if @transport
|
44
|
+
transport.close rescue nil
|
45
|
+
end
|
46
|
+
if Core::LibSNMP.snmp_sess_close(@signature) == 0
|
47
|
+
raise Error, "#@host: Couldn't clean up session properly"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# sends a request PDU and waits for the response
|
52
|
+
#
|
53
|
+
# @param [RequestPDU] pdu a request pdu
|
54
|
+
# @param [Hash] opts additional options
|
55
|
+
# @option opts [true, false] :async if true, it doesn't wait for response (defaults to false)
|
56
|
+
def send(pdu, **opts)
|
57
|
+
write(pdu)
|
58
|
+
read
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def transport
|
64
|
+
@transport ||= fetch_transport
|
65
|
+
end
|
66
|
+
|
67
|
+
def write(pdu)
|
68
|
+
wait_writable
|
69
|
+
async_send(pdu)
|
70
|
+
end
|
71
|
+
|
72
|
+
def async_send(pdu)
|
73
|
+
if ( @reqid = Core::LibSNMP.snmp_sess_async_send(@signature, pdu.pointer, session_callback, nil) ) == 0
|
74
|
+
# it's interesting, pdu's are only fred if the async send is successful... netsnmp 1 - me 0
|
75
|
+
Core::LibSNMP.snmp_free_pdu(pdu.pointer)
|
76
|
+
raise SendError, "#@host: Failed to send pdu"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def read
|
81
|
+
receive # trigger callback ahead of time and wait for it
|
82
|
+
handle_response
|
83
|
+
end
|
84
|
+
|
85
|
+
def handle_response
|
86
|
+
operation, response_pdu = @requests.delete(@reqid)
|
87
|
+
case operation
|
88
|
+
when :send_failed
|
89
|
+
raise ReceiveError, "#@host: Failed to receive pdu"
|
90
|
+
when :timeout
|
91
|
+
raise Timeout::Error, "#@host: timed out while waiting for pdu response"
|
92
|
+
when :success
|
93
|
+
response_pdu
|
94
|
+
else
|
95
|
+
raise Error, "#@host: unrecognized operation for request #{@reqid}: #{operation} for #{response_pdu}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def receive
|
100
|
+
readers, _ = wait_readable
|
101
|
+
case readers.size
|
102
|
+
when 1..Float::INFINITY
|
103
|
+
# triggers callback
|
104
|
+
async_read
|
105
|
+
when 0
|
106
|
+
Core::LibSNMP.snmp_sess_timeout(@signature)
|
107
|
+
else
|
108
|
+
raise ReceiveError, "#@host: error receiving data"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def async_read
|
113
|
+
if Core::LibSNMP.snmp_sess_read(@signature, get_selectable_sockets.pointer) != 0
|
114
|
+
raise ReceiveError, "#@host: Failed to receive pdu response"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def timeout
|
119
|
+
Core::LibSNMP.snmp_sess_timeout(@signature)
|
120
|
+
end
|
121
|
+
|
122
|
+
def wait_writable
|
123
|
+
IO.select([],[transport])
|
124
|
+
end
|
125
|
+
|
126
|
+
def wait_readable
|
127
|
+
IO.select([transport])
|
128
|
+
end
|
129
|
+
|
130
|
+
def get_selectable_sockets
|
131
|
+
fdset = Core::C::FDSet.new
|
132
|
+
fdset.clear
|
133
|
+
num_fds = FFI::MemoryPointer.new(:int)
|
134
|
+
tv_sec = 0
|
135
|
+
tv_usec = 0
|
136
|
+
tval = Core::C::Timeval.new
|
137
|
+
tval[:tv_sec] = tv_sec
|
138
|
+
tval[:tv_usec] = tv_usec
|
139
|
+
block = FFI::MemoryPointer.new(:int)
|
140
|
+
block.write_int(0)
|
141
|
+
Core::LibSNMP.snmp_sess_select_info(@signature, num_fds, fdset.pointer, tval.pointer, block )
|
142
|
+
fdset
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
# @param [Core::Structures::Session] session the snmp session structure
|
147
|
+
# @param [Hash] options session options with authorization parameters
|
148
|
+
# @option options [String] :version the snmp protocol version (if < 3, forget the rest)
|
149
|
+
# @option options [Integer, nil] :security_level the SNMP security level (defaults to authPriv)
|
150
|
+
# @option options [Symbol, nil] :auth_protocol the authorization protocol (ex: :md5, :sha1)
|
151
|
+
# @option options [Symbol, nil] :priv_protocol the privacy protocol (ex: :aes, :des)
|
152
|
+
# @option options [String, nil] :context the authoritative context
|
153
|
+
# @option options [String] :version the snmp protocol version (defaults to 3, if not 3, you actually don't need the rest)
|
154
|
+
# @option options [String] :username the username to login with
|
155
|
+
# @option options [String] :auth_password the authorization password
|
156
|
+
# @option options [String] :priv_password the privacy password
|
157
|
+
def session_authorization(session, options)
|
158
|
+
# we support version 3 by default
|
159
|
+
session[:version] = case options[:version]
|
160
|
+
when /v?1/ then Core::Constants::SNMP_VERSION_1
|
161
|
+
when /v?2c?/ then Core::Constants::SNMP_VERSION_2c
|
162
|
+
when /v?3/, nil then Core::Constants::SNMP_VERSION_3
|
163
|
+
end
|
164
|
+
return unless session[:version] == Core::Constants::SNMP_VERSION_3
|
165
|
+
|
166
|
+
|
167
|
+
# Security Authorization
|
168
|
+
session[:securityLevel] = options[:security_level] || Core::Constants::SNMP_SEC_LEVEL_AUTHPRIV
|
169
|
+
auth_protocol_oid = case options[:auth_protocol]
|
170
|
+
when :md5 then MD5OID.new
|
171
|
+
when :sha1 then SHA1OID.new
|
172
|
+
when nil then NoAuthOID.new
|
173
|
+
else raise Error, "#@host: #{options[:auth_protocol]} is an unsupported authorization protocol"
|
174
|
+
end
|
175
|
+
|
176
|
+
session[:securityAuthProto] = auth_protocol_oid.pointer
|
177
|
+
|
178
|
+
# Priv Protocol
|
179
|
+
priv_protocol_oid = case options[:priv_protocol]
|
180
|
+
when :aes then AESOID.new
|
181
|
+
when :des then DESOID.new
|
182
|
+
when nil then NoPrivOID.new
|
183
|
+
else raise Error, "#@host: #{options[:priv_protocol]} is an unsupported privacy protocol"
|
184
|
+
end
|
185
|
+
session[:securityPrivProto] = priv_protocol_oid.pointer
|
186
|
+
|
187
|
+
# other necessary lengths
|
188
|
+
session[:securityAuthProtoLen] = 10
|
189
|
+
session[:securityAuthKeyLen] = Core::Constants::USM_AUTH_KU_LEN
|
190
|
+
session[:securityPrivProtoLen] = 10
|
191
|
+
session[:securityPrivKeyLen] = Core::Constants::USM_PRIV_KU_LEN
|
192
|
+
|
193
|
+
|
194
|
+
if options[:context]
|
195
|
+
session[:contextName] = FFI::MemoryPointer.from_string(options[:context])
|
196
|
+
session[:contextNameLen] = options[:context].length
|
197
|
+
end
|
198
|
+
|
199
|
+
# Authentication
|
200
|
+
# Do not generate_Ku, unless we're Auth or AuthPriv
|
201
|
+
auth_user, auth_pass = options.values_at(:username, :auth_password)
|
202
|
+
raise Error, "#@host: no given Authorization User" unless auth_user
|
203
|
+
session[:securityName] = FFI::MemoryPointer.from_string(auth_user)
|
204
|
+
session[:securityNameLen] = auth_user.length
|
205
|
+
|
206
|
+
auth_len_ptr = FFI::MemoryPointer.new(:size_t)
|
207
|
+
auth_len_ptr.write_int(Core::Constants::USM_AUTH_KU_LEN)
|
208
|
+
auth_key_result = Core::LibSNMP.generate_Ku(session[:securityAuthProto],
|
209
|
+
session[:securityAuthProtoLen],
|
210
|
+
auth_pass,
|
211
|
+
auth_pass.length,
|
212
|
+
session[:securityAuthKey],
|
213
|
+
auth_len_ptr)
|
214
|
+
session[:securityAuthKeyLen] = auth_len_ptr.read_int
|
215
|
+
|
216
|
+
priv_len_ptr = FFI::MemoryPointer.new(:size_t)
|
217
|
+
priv_len_ptr.write_int(Core::Constants::USM_PRIV_KU_LEN)
|
218
|
+
|
219
|
+
priv_pass = options[:priv_password]
|
220
|
+
# NOTE I know this is handing off the AuthProto, but generates a proper
|
221
|
+
# key for encryption, and using PrivProto does not.
|
222
|
+
priv_key_result = Core::LibSNMP.generate_Ku(session[:securityAuthProto],
|
223
|
+
session[:securityAuthProtoLen],
|
224
|
+
priv_pass,
|
225
|
+
priv_pass.length,
|
226
|
+
session[:securityPrivKey],
|
227
|
+
priv_len_ptr)
|
228
|
+
session[:securityPrivKeyLen] = priv_len_ptr.read_int
|
229
|
+
|
230
|
+
unless auth_key_result == Core::Constants::SNMPERR_SUCCESS and
|
231
|
+
priv_key_result == Core::Constants::SNMPERR_SUCCESS
|
232
|
+
raise AuthenticationFailed, "failed to authenticate #{auth_user} in #{@host}"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
|
237
|
+
# @param [Hash] options options to open the net-snmp session
|
238
|
+
# @option options [String] :community the snmp community string (defaults to public)
|
239
|
+
# @option options [Integer] :timeout number of millisecs until first timeout
|
240
|
+
# @option options [Integer] :retries number of retries before timeout
|
241
|
+
# @return [FFI::Pointer] a pointer to the validated session signature, which will therefore be used in all _sess_ methods from libnetsnmp
|
242
|
+
def build_signature(options)
|
243
|
+
# allocate new session
|
244
|
+
session = Core::Structures::Session.new(nil)
|
245
|
+
Core::LibSNMP.snmp_sess_init(session.pointer)
|
246
|
+
|
247
|
+
# initialize session
|
248
|
+
if options[:community]
|
249
|
+
community = options[:community]
|
250
|
+
session[:community] = FFI::MemoryPointer.from_string(community)
|
251
|
+
session[:community_len] = community.length
|
252
|
+
end
|
253
|
+
|
254
|
+
peername = host
|
255
|
+
unless peername[':']
|
256
|
+
port = options[:port] || '161'.freeze
|
257
|
+
peername = "#{peername}:#{port}"
|
258
|
+
end
|
259
|
+
|
260
|
+
session[:peername] = FFI::MemoryPointer.from_string(peername)
|
261
|
+
|
262
|
+
session[:timeout] = options[:timeout] if options.has_key?(:timeout)
|
263
|
+
session[:retries] = options[:retries] if options.has_key?(:retries)
|
264
|
+
|
265
|
+
session_authorization(session, options)
|
266
|
+
Core::LibSNMP.snmp_sess_open(session.pointer)
|
267
|
+
end
|
268
|
+
|
269
|
+
def fetch_transport
|
270
|
+
return unless @signature
|
271
|
+
list = Core::Structures::SessionList.new @signature
|
272
|
+
return if not list or list.pointer.null?
|
273
|
+
t = Core::Structures::Transport.new list[:transport]
|
274
|
+
IO.new(t[:sock])
|
275
|
+
end
|
276
|
+
|
277
|
+
# @param [Core::Structures::Session] session the snmp session structure
|
278
|
+
def session_callback
|
279
|
+
@callback ||= FFI::Function.new(:int, [:int, :pointer, :int, :pointer, :pointer]) do |operation, session, reqid, pdu_ptr, magic|
|
280
|
+
op = case operation
|
281
|
+
when Core::Constants::NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE then :success
|
282
|
+
when Core::Constants::NETSNMP_CALLBACK_OP_TIMED_OUT then :timeout
|
283
|
+
when Core::Constants::NETSNMP_CALLBACK_OP_SEND_FAILED then :send_failed
|
284
|
+
when Core::Constants::NETSNMP_CALLBACK_OP_CONNECT then :connect
|
285
|
+
when Core::Constants::NETSNMP_CALLBACK_OP_DISCONNECT then :disconnect
|
286
|
+
else :unrecognized_operation
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
# TODO: pass exception in case of failure
|
291
|
+
|
292
|
+
if reqid == @reqid
|
293
|
+
response_pdu = ResponsePDU.new(pdu_ptr)
|
294
|
+
# probably pass the result as a yield from a fiber
|
295
|
+
@requests[@reqid] = [op, response_pdu]
|
296
|
+
|
297
|
+
op.eql?(:unrecognized_operation) ? 0 : 1
|
298
|
+
else
|
299
|
+
puts "wow, unexpected #{op}.... #{reqid} different than #{@reqid}"
|
300
|
+
0
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
module NETSNMP
|
2
|
+
# Abstracts the PDU variable structure into a ruby object
|
3
|
+
#
|
4
|
+
class Varbind
|
5
|
+
Error = Class.new(Error)
|
6
|
+
|
7
|
+
attr_reader :struct
|
8
|
+
|
9
|
+
# @param [FFI::Pointer] pointer to the variable list
|
10
|
+
def initialize(pointer)
|
11
|
+
@struct = Core::Structures::VariableList.new(pointer)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# Abstracts the Varbind used for the PDU Request
|
17
|
+
class RequestVarbind < Varbind
|
18
|
+
|
19
|
+
# @param [RequestPDU] pdu the request pdu for this varbind
|
20
|
+
# @param [OID] oid the oid for this varbind
|
21
|
+
# @param [Object] value the value for the oid
|
22
|
+
# @param [Hash] options additional options
|
23
|
+
# @option options [Symbol, Integer, nil] :type C net-snmp type flag,
|
24
|
+
# type-label for value (see #convert_type), if not set it's inferred from the value
|
25
|
+
#
|
26
|
+
def initialize(pdu, oid, value, options={})
|
27
|
+
type = case options[:type]
|
28
|
+
when Integer then options[:type] # assume that the code is properly passed
|
29
|
+
when Symbol then convert_type(options[:type]) # DSL-specific API
|
30
|
+
when nil then infer_from_value(value)
|
31
|
+
else
|
32
|
+
raise Error, "#{options[:type]} is an unsupported type"
|
33
|
+
end
|
34
|
+
|
35
|
+
value_length = case type
|
36
|
+
when Core::Constants::ASN_NULL,
|
37
|
+
Core::Constants::SNMP_NOSUCHOBJECT,
|
38
|
+
Core::Constants::SNMP_NOSUCHINSTANCE,
|
39
|
+
Core::Constants::SNMP_ENDOFMIBVIEW
|
40
|
+
0
|
41
|
+
else value ? value.size : 0
|
42
|
+
end
|
43
|
+
value = convert_value(value, type)
|
44
|
+
|
45
|
+
pointer = Core::LibSNMP.snmp_pdu_add_variable(pdu.pointer, oid.pointer, oid.length, type, value, value_length)
|
46
|
+
super(pointer)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# @param [Object] value value to infer the type from
|
53
|
+
# @return [Integer] the C net-snmp flag indicating the type
|
54
|
+
# @raise [Error] when the value is from an unexpected type
|
55
|
+
#
|
56
|
+
def infer_from_value(value)
|
57
|
+
case value
|
58
|
+
when String then Core::Constants::ASN_OCTET_STR
|
59
|
+
when Fixnum then Core::Constants::ASN_INTEGER
|
60
|
+
when OID then Core::Constants::ASN_OBJECT_ID
|
61
|
+
when nil then Core::Constants::ASN_NULL
|
62
|
+
else raise Error, "#{value} is from an unsupported type"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [Symbol] symbol_type symbol representing the type
|
67
|
+
# @return [Integer] the C net-snmp flag indicating the type
|
68
|
+
# @raise [Error] when the symbol is unsupported
|
69
|
+
#
|
70
|
+
def convert_type(symbol_type)
|
71
|
+
case symbol_type
|
72
|
+
when :integer then Core::Constants::ASN_INTEGER
|
73
|
+
when :gauge then Core::Constants::ASN_GAUGE
|
74
|
+
when :counter then Core::Constants::ASN_COUNTER
|
75
|
+
when :timeticks then Core::Constants::ASN_TIMETICKS
|
76
|
+
when :unsigned then Core::Constants::ASN_UNSIGNED
|
77
|
+
when :boolean then Core::Constants::ASN_BOOLEAN
|
78
|
+
when :string then Core::Constants::ASN_OCTET_STR
|
79
|
+
when :binary then Core::Constants::ASN_BIT_STR
|
80
|
+
when :ip_address then Core::Constants::ASN_IPADDRESS
|
81
|
+
else
|
82
|
+
raise Error, "#{symbol_type} cannot be converted"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# @param [Object] value the value to convert
|
87
|
+
# @param [Integer] type the C net-snmp level object type flakg
|
88
|
+
#
|
89
|
+
# @return [FFI::Pointer] pointer to the memory location where the value is stored
|
90
|
+
#
|
91
|
+
def convert_value(value, type)
|
92
|
+
case type
|
93
|
+
when Core::Constants::ASN_INTEGER,
|
94
|
+
Core::Constants::ASN_GAUGE,
|
95
|
+
Core::Constants::ASN_COUNTER,
|
96
|
+
Core::Constants::ASN_TIMETICKS,
|
97
|
+
Core::Constants::ASN_UNSIGNED
|
98
|
+
new_val = FFI::MemoryPointer.new(:long)
|
99
|
+
new_val.write_long(value)
|
100
|
+
new_val
|
101
|
+
when Core::Constants::ASN_OCTET_STR,
|
102
|
+
Core::Constants::ASN_BIT_STR,
|
103
|
+
Core::Constants::ASN_OPAQUE
|
104
|
+
value
|
105
|
+
when Core::Constants::ASN_IPADDRESS
|
106
|
+
# TODO
|
107
|
+
when Core::Constants::ASN_OBJECT_ID
|
108
|
+
value.pointer
|
109
|
+
when Core::Constants::ASN_NULL,
|
110
|
+
Core::Constants::SNMP_NOSUCHOBJECT,
|
111
|
+
Core::Constants::SNMP_NOSUCHINSTANCE,
|
112
|
+
Core::Constants::SNMP_ENDOFMIBVIEW
|
113
|
+
nil
|
114
|
+
else
|
115
|
+
raise Error, "Unknown variable type: #{type}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Abstracts the Varbind used for the PDU Response
|
121
|
+
#
|
122
|
+
class ResponseVarbind < Varbind
|
123
|
+
|
124
|
+
attr_reader :value, :oid_code
|
125
|
+
|
126
|
+
# @param [FFI::Pointer] pointer pointer to the response varbind structure
|
127
|
+
#
|
128
|
+
# @note it loads the value and oid code on initialization
|
129
|
+
#
|
130
|
+
def initialize(pointer)
|
131
|
+
super
|
132
|
+
@value = load_varbind_value
|
133
|
+
@oid_code = load_oid_code
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
# @return [String] the oid code from the varbind
|
139
|
+
def load_oid_code
|
140
|
+
OID.read_pointer(@struct[:name], @struct[:name_length])
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [Object] the value for the varbind (a ruby type, a string, an integer, a symbol etc...)
|
144
|
+
#
|
145
|
+
def load_varbind_value
|
146
|
+
object_type = @struct[:type]
|
147
|
+
case object_type
|
148
|
+
when Core::Constants::ASN_OCTET_STR,
|
149
|
+
Core::Constants::ASN_OPAQUE
|
150
|
+
@struct[:val][:string].read_string(@struct[:val_len])
|
151
|
+
when Core::Constants::ASN_INTEGER
|
152
|
+
@struct[:val][:integer].read_long
|
153
|
+
when Core::Constants::ASN_UINTEGER,
|
154
|
+
Core::Constants::ASN_TIMETICKS,
|
155
|
+
Core::Constants::ASN_COUNTER,
|
156
|
+
Core::Constants::ASN_GAUGE
|
157
|
+
@struct[:val][:integer].read_ulong
|
158
|
+
when Core::Constants::ASN_IPADDRESS
|
159
|
+
@struct[:val][:objid].read_string(@struct[:val_len]).unpack('CCCC').join(".")
|
160
|
+
when Core::Constants::ASN_NULL
|
161
|
+
nil
|
162
|
+
when Core::Constants::ASN_OBJECT_ID
|
163
|
+
OID.from_pointer(@struct[:val][:objid], @struct[:val_len] / OID.default_size)
|
164
|
+
when Core::Constants::ASN_COUNTER64
|
165
|
+
counter = Core::Structures::Counter64.new(@struct[:val][:counter64])
|
166
|
+
counter[:high] * 2^32 + counter[:low]
|
167
|
+
when Core::Constants::ASN_BIT_STR
|
168
|
+
# XXX not sure what to do here. Is this obsolete?
|
169
|
+
when Core::Constants::SNMP_ENDOFMIBVIEW
|
170
|
+
:endofmibview
|
171
|
+
when Core::Constants::SNMP_NOSUCHOBJECT
|
172
|
+
:nosuchobject
|
173
|
+
when Core::Constants::SNMP_NOSUCHINSTANCE
|
174
|
+
:nosuchinstance
|
175
|
+
else
|
176
|
+
raise Error, "#{object_type} is an invalid type"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|