diameter 0.1.0.beta
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/lib/diameter/avp.rb +391 -0
- data/lib/diameter/avp_parser.rb +81 -0
- data/lib/diameter/constants.rb +54 -0
- data/lib/diameter/diameter_logger.rb +24 -0
- data/lib/diameter/fsm.rb +27 -0
- data/lib/diameter/message.rb +267 -0
- data/lib/diameter/peer.rb +59 -0
- data/lib/diameter/stack.rb +359 -0
- data/lib/diameter/stack_transport_helpers.rb +167 -0
- data/lib/diameter/u24.rb +36 -0
- data/lib/diameter.rb +2 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 155d66671781834056b72ee9fca500a317dd2580
|
4
|
+
data.tar.gz: d2233fc23a94125190656b1f13b73d193e178082
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0193a6fee32495c1566fe839cc3cdfb44f65ce7de5730cc4753b344c8809ea7afe2ce72b385d30f098544586e79c7543005c0198eb453c67cbf19cd3c7199428
|
7
|
+
data.tar.gz: cbed37f246b89602d463fc4cd5ce04d84a464c79e0ea3a054e47b78e37a2b54b3b3516c8c650194ebafd4cf78683b6f61b4b34f70e4db1ef8a68d924aab5c9a3
|
data/lib/diameter/avp.rb
ADDED
@@ -0,0 +1,391 @@
|
|
1
|
+
require 'diameter/avp_parser'
|
2
|
+
require 'diameter/u24'
|
3
|
+
require 'diameter/constants'
|
4
|
+
require 'ipaddr'
|
5
|
+
|
6
|
+
module Diameter
|
7
|
+
module Internals
|
8
|
+
# Maps AVP names to their on-the-wire values and data definitions.
|
9
|
+
class AVPNames
|
10
|
+
include Constants
|
11
|
+
|
12
|
+
@custom_avps = {}
|
13
|
+
|
14
|
+
# Converts an AVP name into its code number, data type, and (if
|
15
|
+
# applicable) vendor ID.
|
16
|
+
#
|
17
|
+
# @param [String] name The AVP name
|
18
|
+
# @return [Array(Fixnum, AVPType)] if this is not vendor-specific
|
19
|
+
# @return [Array(Fixnum, AVPType, Vendor)] if this is vendor-specific
|
20
|
+
def self.get(name)
|
21
|
+
code, type, vendor = @custom_avps.merge(AVAILABLE_AVPS)[name]
|
22
|
+
vendor ||= 0
|
23
|
+
fail "AVP name #{name} not recognised" unless code
|
24
|
+
[code, type, vendor]
|
25
|
+
end
|
26
|
+
|
27
|
+
# @see {AVP.define}
|
28
|
+
def self.add(name, code, type, vendor=nil)
|
29
|
+
@custom_avps[name] = vendor.nil? ? [code, type] : [code, type, vendor]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# The AVP class is a sensible, coherent whole - it's just big,
|
35
|
+
# particularly because of all the various ways to interpret the
|
36
|
+
# content. Ignore the class length guidelines.
|
37
|
+
|
38
|
+
# rubocop:disable Metrics/ClassLength
|
39
|
+
|
40
|
+
# Represents a Diameter AVP. Use this for non-vendor-specific AVPs,
|
41
|
+
# and its subclass VendorSpecificAVP for ones defined for a particular
|
42
|
+
# vendor.
|
43
|
+
# @!attribute [r] code
|
44
|
+
# @return [Fixnum] The AVP Code
|
45
|
+
# @!attribute [r] mandatory
|
46
|
+
# @return [true, false] Whether this AVP is mandatory (i.e. its M flag is set)
|
47
|
+
class AVP
|
48
|
+
include Internals
|
49
|
+
include Constants::AVPType
|
50
|
+
attr_reader :code, :mandatory, :vendor_id
|
51
|
+
|
52
|
+
include AVPParser
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
#
|
56
|
+
# Prefer {AVP.create} where possible.
|
57
|
+
def initialize(code, options = {})
|
58
|
+
@code = code
|
59
|
+
@vendor_id = options[:vendor_id] || 0
|
60
|
+
@content = options[:content] || ''
|
61
|
+
@mandatory = options.fetch(:mandatory, true)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Creates an AVP by name, and assigns it a value.
|
65
|
+
#
|
66
|
+
# @param name The name of the AVP, e.g. "Origin-Host"
|
67
|
+
# @param val The value of the AVP. Must be of the type defined for
|
68
|
+
# that AVP - e.g. a Fixnum for an AVP defined as Unsigned32, a
|
69
|
+
# String for an AVP defined as OctetString, or an IPAddr for an AVP
|
70
|
+
# defined as IPAddress.
|
71
|
+
# @option opts [true, false] mandatory
|
72
|
+
# Whether understanding this AVP is mandatory within this
|
73
|
+
# application.
|
74
|
+
#
|
75
|
+
# @return [AVP] The AVP that was created.
|
76
|
+
def self.create(name, val, options = {})
|
77
|
+
code, type, vendor = AVPNames.get(name)
|
78
|
+
options[:vendor_id] = vendor
|
79
|
+
avp = AVP.new(code, options)
|
80
|
+
|
81
|
+
set_content(avp, type, val)
|
82
|
+
|
83
|
+
avp
|
84
|
+
end
|
85
|
+
|
86
|
+
# Defines a new AVP that can subsequently be created/retrieved by
|
87
|
+
# name.
|
88
|
+
#
|
89
|
+
# @param name [String] The AVP name
|
90
|
+
# @param code [Fixnum] The AVP Code
|
91
|
+
# @param type [AVPType] The type of this AVP's value
|
92
|
+
# @param vendor [Fixnum] Optional vendor ID for a vendor-specific
|
93
|
+
# AVP.
|
94
|
+
# @return [void]
|
95
|
+
def self.define(name, code, type, vendor=nil)
|
96
|
+
AVPNames.add(name, code, type, vendor)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns this AVP encoded properly as bytes in network byte order,
|
100
|
+
# suitable for sending over a TCP or SCTP connection. See
|
101
|
+
# {http://tools.ietf.org/html/rfc6733#section-4.1} for the
|
102
|
+
# format.
|
103
|
+
#
|
104
|
+
# @return [String] The bytes representing this AVP
|
105
|
+
def to_wire
|
106
|
+
if vendor_specific?
|
107
|
+
to_wire_vendor
|
108
|
+
else
|
109
|
+
to_wire_novendor
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Guessing the type of an AVP and displaying it sensibly is complex,
|
114
|
+
# so this is a complex method (but one that has a unity of purpose,
|
115
|
+
# so can't easily be broken down). Disable several Rubocop
|
116
|
+
# complexity metrics to reflect this.
|
117
|
+
|
118
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
119
|
+
# rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
|
120
|
+
|
121
|
+
# Returns a string representation of this AVP. Makes a best-effort
|
122
|
+
# attempt to guess the type of the content (even for unknown AVPs)
|
123
|
+
# and display it sensibly.
|
124
|
+
#
|
125
|
+
# @example
|
126
|
+
# avp.to_s => "AVP 267, mandatory: true, content as int32: 1"
|
127
|
+
def to_s
|
128
|
+
has_all_ascii_values =
|
129
|
+
@content.bytes.reject { |c| (32 < c && c < 126) }.empty?
|
130
|
+
|
131
|
+
could_be_32bit_num = (@content.length == 4)
|
132
|
+
could_be_64bit_num = (@content.length == 8)
|
133
|
+
|
134
|
+
could_be_ip = ((@content.length == 6 && @content[0..1] == "\x00\x01") ||
|
135
|
+
(@content.length == 18 && @content[0..1] == "\x00\x02"))
|
136
|
+
|
137
|
+
maybe_grouped = !(has_all_ascii_values ||
|
138
|
+
could_be_64bit_num ||
|
139
|
+
could_be_32bit_num ||
|
140
|
+
could_be_ip)
|
141
|
+
|
142
|
+
s = vendor_specific? ? "AVP #{@code}, Vendor-ID #{@vendor_id}, mandatory: #{@mandatory}" :
|
143
|
+
"AVP #{@code}, mandatory: #{@mandatory}"
|
144
|
+
s += ", content as string: #{@content}" if has_all_ascii_values
|
145
|
+
s += ", content as int32: #{uint32}" if could_be_32bit_num
|
146
|
+
s += ", content as int64: #{uint64}" if could_be_64bit_num
|
147
|
+
s += ", content as ip: #{ip_address}" if could_be_ip
|
148
|
+
s += ", grouped AVP, #{grouped_value.collect(&:to_s)}" if maybe_grouped
|
149
|
+
|
150
|
+
s
|
151
|
+
end
|
152
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
153
|
+
# rubocop:enable Metrics/MethodLength, Metrics/PerceivedComplexity
|
154
|
+
|
155
|
+
# @!attribute [r] vendor_specific?
|
156
|
+
# @return [true, false] Whether this AVP is mandatory
|
157
|
+
# (i.e. its M flag is set)
|
158
|
+
def vendor_specific?
|
159
|
+
@vendor_id != 0
|
160
|
+
end
|
161
|
+
|
162
|
+
# @!group Data getters/setters for different AVP types
|
163
|
+
|
164
|
+
# Returns this AVP's byte data, interpreted as a
|
165
|
+
# {http://tools.ietf.org/html/rfc6733#section-4.4 Grouped AVP}.
|
166
|
+
#
|
167
|
+
# @return [Array<AVP>] The contained AVPs.
|
168
|
+
def grouped_value
|
169
|
+
AVPParser.parse_avps_int(@content)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Sets this AVP's byte data to a
|
173
|
+
# {http://tools.ietf.org/html/rfc6733#section-4.4 Grouped AVP}.
|
174
|
+
#
|
175
|
+
# @param [Array<AVP>] avps The AVPs that should be contained within
|
176
|
+
# this AVP.
|
177
|
+
# @return [void]
|
178
|
+
def grouped_value=(avps)
|
179
|
+
new_content = ''
|
180
|
+
avps.each { |a| new_content += a.to_wire }
|
181
|
+
@content = new_content
|
182
|
+
end
|
183
|
+
|
184
|
+
# For a grouped AVP, returns the first AVP with this name it
|
185
|
+
# contains.
|
186
|
+
#
|
187
|
+
# @param [String] name The AVP name
|
188
|
+
# @return [AVP] if this AVP is found inside the Grouped AVP
|
189
|
+
# @return [nil] if this AVP is not found inside the Grouped AVP
|
190
|
+
def inner_avp(name)
|
191
|
+
avps = inner_avps(name)
|
192
|
+
|
193
|
+
if avps.empty?
|
194
|
+
nil
|
195
|
+
else
|
196
|
+
avps[0]
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# For a grouped AVP, returns all AVPs it contains with this name.
|
201
|
+
#
|
202
|
+
# @param [String] name The AVP name
|
203
|
+
# @return [Array<AVP>]
|
204
|
+
def inner_avps(name)
|
205
|
+
code, _type, _vendor = AVPNames.get(name)
|
206
|
+
|
207
|
+
grouped_value.select { |a| a.code == code }
|
208
|
+
end
|
209
|
+
|
210
|
+
alias_method :[], :inner_avp
|
211
|
+
|
212
|
+
# Even though it is just "the raw bytes in the content",
|
213
|
+
# octet_string is only one way of interpreting the AVP content and
|
214
|
+
# shouldn't be treated differently to the others, so disable the
|
215
|
+
# TrivialAccessors warning.
|
216
|
+
|
217
|
+
# rubocop:disable Style/TrivialAccessors
|
218
|
+
|
219
|
+
# Returns this AVP's byte data, interpreted as an OctetString.
|
220
|
+
#
|
221
|
+
# @return [String] The contained OctetString.
|
222
|
+
def octet_string
|
223
|
+
@content
|
224
|
+
end
|
225
|
+
|
226
|
+
# Sets this AVP's byte data to an OctetString.
|
227
|
+
#
|
228
|
+
# @param [String] value The octets to use as the value.
|
229
|
+
# @return [void]
|
230
|
+
def octet_string=(value)
|
231
|
+
@content = value
|
232
|
+
end
|
233
|
+
|
234
|
+
# rubocop:enable Style/TrivialAccessors
|
235
|
+
|
236
|
+
# Returns this AVP's byte data, interpreted as an Integer32.
|
237
|
+
#
|
238
|
+
# @return [Fixnum] The contained Integer32.
|
239
|
+
def int32
|
240
|
+
@content.unpack('l>')[0]
|
241
|
+
end
|
242
|
+
|
243
|
+
# Sets this AVP's byte data to an Integer32.
|
244
|
+
#
|
245
|
+
# @param [Fixnum] value
|
246
|
+
# @return [void]
|
247
|
+
def int32=(value)
|
248
|
+
@content = [value].pack('l>')
|
249
|
+
end
|
250
|
+
|
251
|
+
# Returns this AVP's byte data, interpreted as an Integer64.
|
252
|
+
#
|
253
|
+
# @return [Fixnum] The contained Integer64.
|
254
|
+
def int64
|
255
|
+
@content.unpack('q>')[0]
|
256
|
+
end
|
257
|
+
|
258
|
+
# Sets this AVP's byte data to an Integer64.
|
259
|
+
#
|
260
|
+
# @param [Fixnum] value
|
261
|
+
# @return [void]
|
262
|
+
def int64=(value)
|
263
|
+
@content = [value].pack('q>')
|
264
|
+
end
|
265
|
+
|
266
|
+
# Returns this AVP's byte data, interpreted as an Unsigned32.
|
267
|
+
#
|
268
|
+
# @return [Fixnum] The contained Unsigned32.
|
269
|
+
def uint32
|
270
|
+
@content.unpack('N')[0]
|
271
|
+
end
|
272
|
+
|
273
|
+
# Sets this AVP's byte data to an Unsigned32.
|
274
|
+
#
|
275
|
+
# @param [Fixnum] value
|
276
|
+
# @return [void]
|
277
|
+
def uint32=(value)
|
278
|
+
@content = [value].pack('N')
|
279
|
+
end
|
280
|
+
|
281
|
+
# Returns this AVP's byte data, interpreted as an Unsigned64.
|
282
|
+
#
|
283
|
+
# @return [Fixnum] The contained Unsigned64.
|
284
|
+
def uint64
|
285
|
+
@content.unpack('Q>')[0]
|
286
|
+
end
|
287
|
+
|
288
|
+
# Sets this AVP's byte data to an Unsigned64.
|
289
|
+
#
|
290
|
+
# @param [Fixnum] value
|
291
|
+
# @return [void]
|
292
|
+
def uint64=(value)
|
293
|
+
@content = [value].pack('Q>')
|
294
|
+
end
|
295
|
+
|
296
|
+
# Returns this AVP's byte data, interpreted as a Float32.
|
297
|
+
#
|
298
|
+
# @return [Float] The contained Float32.
|
299
|
+
def float32
|
300
|
+
@content.unpack('g')[0]
|
301
|
+
end
|
302
|
+
|
303
|
+
# Sets this AVP's byte data to a Float32.
|
304
|
+
#
|
305
|
+
# @param [Float] value
|
306
|
+
# @return [void]
|
307
|
+
def float32=(value)
|
308
|
+
@content = [value].pack('g')
|
309
|
+
end
|
310
|
+
|
311
|
+
# Returns this AVP's byte data, interpreted as a Float64.
|
312
|
+
#
|
313
|
+
# @return [Float] The contained Float64.
|
314
|
+
def float64
|
315
|
+
@content.unpack('G')[0]
|
316
|
+
end
|
317
|
+
|
318
|
+
# Sets this AVP's byte data to a Float64.
|
319
|
+
#
|
320
|
+
# @param [Float] value
|
321
|
+
# @return [void]
|
322
|
+
def float64=(value)
|
323
|
+
@content = [value].pack('G')
|
324
|
+
end
|
325
|
+
|
326
|
+
# Returns this AVP's byte data, interpreted as an
|
327
|
+
# {http://tools.ietf.org/html/rfc6733#section-4.3.1 Address}.
|
328
|
+
#
|
329
|
+
# @return [IPAddr] The contained
|
330
|
+
# {http://tools.ietf.org/html/rfc6733#section-4.3.1 Address}.
|
331
|
+
def ip_address
|
332
|
+
IPAddr.new_ntoh(@content[2..-1])
|
333
|
+
end
|
334
|
+
|
335
|
+
# Sets this AVP's byte data to an Address.
|
336
|
+
#
|
337
|
+
# @param [IPAddr] value
|
338
|
+
# @return [void]
|
339
|
+
def ip_address=(value)
|
340
|
+
bytes = if value.ipv4?
|
341
|
+
[1].pack('n')
|
342
|
+
else
|
343
|
+
[2].pack('n')
|
344
|
+
end
|
345
|
+
|
346
|
+
bytes += value.hton
|
347
|
+
@content = bytes
|
348
|
+
end
|
349
|
+
|
350
|
+
# @!endgroup
|
351
|
+
|
352
|
+
private
|
353
|
+
|
354
|
+
def self.set_content(avp, type, val)
|
355
|
+
case type
|
356
|
+
when GROUPED
|
357
|
+
avp.grouped_value = val
|
358
|
+
when U32
|
359
|
+
avp.uint32 = val
|
360
|
+
when OCTETSTRING
|
361
|
+
avp.octet_string = val
|
362
|
+
when IPADDR
|
363
|
+
avp.ip_address = val
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
def to_wire_novendor
|
368
|
+
length_8, length_16 = UInt24.to_u8_and_u16(@content.length + 8)
|
369
|
+
avp_flags = @mandatory ? '01000000' : '00000000'
|
370
|
+
header = [@code, avp_flags, length_8, length_16].pack('NB8Cn')
|
371
|
+
header + padded_content
|
372
|
+
end
|
373
|
+
|
374
|
+
def to_wire_vendor
|
375
|
+
length_8, length_16 = UInt24.to_u8_and_u16(@content.length + 12)
|
376
|
+
avp_flags = @mandatory ? '11000000' : '10000000'
|
377
|
+
header = [@code, avp_flags, length_8, length_16, @vendor_id].pack('NB8CnN')
|
378
|
+
header + padded_content
|
379
|
+
end
|
380
|
+
|
381
|
+
protected
|
382
|
+
|
383
|
+
def padded_content
|
384
|
+
wire_content = @content
|
385
|
+
wire_content += "\x00" while ((wire_content.length % 4) != 0)
|
386
|
+
wire_content
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
# rubocop:enable Metrics/ClassLength
|
391
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'diameter/u24'
|
2
|
+
|
3
|
+
module Diameter
|
4
|
+
module Internals
|
5
|
+
# @private
|
6
|
+
# Parser mixin, sharing functionality common to:
|
7
|
+
# * parsing all the AVPs in a message
|
8
|
+
# * parsing the AVPs inside a Grouped AVP
|
9
|
+
module AVPParser
|
10
|
+
# Is the vendor-specific bit (the top bit) set?
|
11
|
+
#
|
12
|
+
# @param flags [String] A string of eight bits, e.g. "00000000"
|
13
|
+
# @return [true, false]
|
14
|
+
def self.vendor_id_bit(flags)
|
15
|
+
flags[0] == '1'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Is the mandatory bit (the second bit) set?
|
19
|
+
#
|
20
|
+
# @param flags [String] A string of eight bits, e.g. "00000000"
|
21
|
+
# @return [true, false]
|
22
|
+
def self.mandatory_bit(flags)
|
23
|
+
flags[1] == '1'
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Array(Fixnum, Fixnum, Bool, Fixnum, Fixnum)] The bytes consumed
|
27
|
+
# (8 or 12), AVP code,
|
28
|
+
# mandatory bit, length and vendor-ID (or 0 in the case of a
|
29
|
+
# non-vendor-specific AVP).
|
30
|
+
def self.parse_avp_header(bytes)
|
31
|
+
first_avp_header = bytes[0..8]
|
32
|
+
# Parse them
|
33
|
+
code, avp_flags, alength_8, alength_16 =
|
34
|
+
first_avp_header.unpack('NB8Cn')
|
35
|
+
|
36
|
+
mandatory = mandatory_bit(avp_flags)
|
37
|
+
length = UInt24.from_u8_and_u16(alength_8, alength_16)
|
38
|
+
|
39
|
+
if vendor_id_bit(avp_flags)
|
40
|
+
avp_vendor_header = bytes[8..12]
|
41
|
+
avp_vendor, = avp_vendor_header.unpack('N')
|
42
|
+
[12, code, mandatory, length, avp_vendor]
|
43
|
+
else
|
44
|
+
[8, code, mandatory, length, 0]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @api private
|
49
|
+
#
|
50
|
+
# @param bytes [String] A sequence of bytes representing a set of AVPs.
|
51
|
+
# @return [Array<AVP>] The AVPs parsed out of the bytes.
|
52
|
+
def self.parse_avps_int(bytes)
|
53
|
+
avps = []
|
54
|
+
position = 0
|
55
|
+
while position < bytes.length
|
56
|
+
# Consume the first 8 octets
|
57
|
+
avp_consumed, code, mandatory, length, avp_vendor = parse_avp_header(bytes[position..-1])
|
58
|
+
position += avp_consumed
|
59
|
+
|
60
|
+
# Read the content, ensuring it aligns to a 32-byte boundary
|
61
|
+
avp_content_length = length - avp_consumed
|
62
|
+
avp_content = bytes[position..(position + avp_content_length) - 1]
|
63
|
+
|
64
|
+
padding = 0
|
65
|
+
padding += 1 until ((avp_content_length + padding) % 4) == 0
|
66
|
+
|
67
|
+
position += avp_content_length + padding
|
68
|
+
|
69
|
+
# Construct an AVP object from the parsed data
|
70
|
+
parsed_avp = AVP.new(code,
|
71
|
+
vendor_id: avp_vendor,
|
72
|
+
mandatory: mandatory,
|
73
|
+
content: avp_content)
|
74
|
+
|
75
|
+
avps.push parsed_avp
|
76
|
+
end
|
77
|
+
avps
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Diameter
|
2
|
+
module Constants
|
3
|
+
# Contains Vendor-ID constants
|
4
|
+
module Vendors
|
5
|
+
# The 3GPP/IMS Vendor-ID
|
6
|
+
TGPP = 10_415
|
7
|
+
end
|
8
|
+
|
9
|
+
# Represents the type of data a particular AVP should be interpreted
|
10
|
+
# as.
|
11
|
+
module AVPType
|
12
|
+
# Represents an AVP of Grouped type
|
13
|
+
GROUPED = :Grouped
|
14
|
+
|
15
|
+
# Represents an AVP of Unsigned32 type
|
16
|
+
U32 = :Unsigned32
|
17
|
+
|
18
|
+
# Represents an AVP of OctetString type
|
19
|
+
OCTETSTRING = :OctetString
|
20
|
+
|
21
|
+
# Represents an AVP of IPAddress type
|
22
|
+
IPADDR = :Address
|
23
|
+
end
|
24
|
+
|
25
|
+
include AVPType
|
26
|
+
include Vendors
|
27
|
+
|
28
|
+
# The AVPs that can be looked up by name.
|
29
|
+
AVAILABLE_AVPS = {
|
30
|
+
'Vendor-Specific-Application-Id' => [260, GROUPED],
|
31
|
+
'Vendor-Id' => [266, U32],
|
32
|
+
'Auth-Application-Id' => [258, U32],
|
33
|
+
'Acct-Application-Id' => [259, U32],
|
34
|
+
'Session-Id' => [263, OCTETSTRING],
|
35
|
+
'Product-Name' => [269, OCTETSTRING],
|
36
|
+
'Auth-Session-State' => [277, U32],
|
37
|
+
'Inband-Security-Id' => [299, U32],
|
38
|
+
'Origin-Host' => [264, OCTETSTRING],
|
39
|
+
'Firmware-Revision' => [267, U32],
|
40
|
+
'Result-Code' => [268, U32],
|
41
|
+
'Origin-Realm' => [296, OCTETSTRING],
|
42
|
+
'Destination-Host' => [293, OCTETSTRING],
|
43
|
+
'Destination-Realm' => [283, OCTETSTRING],
|
44
|
+
'User-Name' => [1, OCTETSTRING],
|
45
|
+
'Host-IP-Address' => [257, IPADDR],
|
46
|
+
'Public-Identity' => [601, OCTETSTRING, TGPP],
|
47
|
+
'Server-Name' => [602, OCTETSTRING, TGPP],
|
48
|
+
'SIP-Number-Auth-Items' => [607, U32, TGPP],
|
49
|
+
'SIP-Auth-Data-Item' => [612, GROUPED, TGPP],
|
50
|
+
'SIP-Item-Number' => [613, U32, TGPP],
|
51
|
+
'SIP-Authentication-Scheme' => [608, OCTETSTRING, TGPP] }
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
# The Diameter namespace
|
4
|
+
module Diameter
|
5
|
+
@int_DiameterLogger = nil
|
6
|
+
|
7
|
+
# Returns the logger to be used by the Diameter stack and associated
|
8
|
+
# objects. If no logger has been set with {Diameter.set_logger},
|
9
|
+
# defaults to writing to ./diameterstack.log
|
10
|
+
#
|
11
|
+
# @return [Logger]
|
12
|
+
def self.logger
|
13
|
+
@int_DiameterLogger ||= Logger.new('./diameterstack.log', 10, (1024^3))
|
14
|
+
@int_DiameterLogger
|
15
|
+
end
|
16
|
+
|
17
|
+
# Sets the logger to be used by the Diameter stack and associated
|
18
|
+
# objects.
|
19
|
+
#
|
20
|
+
# @param value [Logger]
|
21
|
+
def self.set_logger(value)
|
22
|
+
@int_DiameterLogger = value
|
23
|
+
end
|
24
|
+
end
|
data/lib/diameter/fsm.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'micromachine'
|
2
|
+
|
3
|
+
machine = MicroMachine.new(:closed) # Initial state.
|
4
|
+
|
5
|
+
# Define the possible transitions for each event.
|
6
|
+
machine.when(:closed, :start => :wait_conn_ack)
|
7
|
+
machine.when(:closed, :r_conn_cer => :r_open)
|
8
|
+
|
9
|
+
machine.when(:wait_conn_ack, :i_rcv_conn_ack => :wait_i_cea)
|
10
|
+
machine.when(:wait_conn_ack, :i_rcv_conn_nack => :closed)
|
11
|
+
machine.when(:wait_conn_ack, :r_conn_cer => :wait_conn_ack_elect)
|
12
|
+
machine.when(:wait_conn_ack, :timeout => :closed)
|
13
|
+
|
14
|
+
|
15
|
+
machine.when(:reset, :confirmed => :new, :ignored => :new)
|
16
|
+
|
17
|
+
machine.trigger(:confirm) #=> true
|
18
|
+
machine.state #=> :confirmed
|
19
|
+
|
20
|
+
machine.trigger(:ignore) #=> false
|
21
|
+
machine.state #=> :confirmed
|
22
|
+
|
23
|
+
machine.trigger(:reset) #=> true
|
24
|
+
machine.state #=> :new
|
25
|
+
|
26
|
+
machine.trigger(:ignore) #=> true
|
27
|
+
machine.state #=> :ignored
|