diameter 0.1.0 → 0.2.0pre1
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 +4 -4
- data/lib/diameter/avp.rb +16 -5
- data/lib/diameter/avp_names.rb +996 -0
- data/lib/diameter/constants.rb +15 -33
- data/lib/diameter/message.rb +12 -9
- data/lib/diameter/stack.rb +50 -17
- data/lib/diameter/stack_transport_helpers.rb +12 -13
- metadata +19 -4
data/lib/diameter/constants.rb
CHANGED
@@ -10,45 +10,27 @@ module Diameter
|
|
10
10
|
# as.
|
11
11
|
module AVPType
|
12
12
|
# Represents an AVP of Grouped type
|
13
|
-
|
13
|
+
Grouped = :Grouped
|
14
14
|
|
15
15
|
# Represents an AVP of Unsigned32 type
|
16
|
-
|
16
|
+
Unsigned32 = :Unsigned32
|
17
|
+
Enumerated = Unsigned32
|
17
18
|
|
19
|
+
Unsigned64 = :Unsigned64
|
20
|
+
Integer32 = :Integer32
|
21
|
+
Integer64 = :Integer64
|
22
|
+
Float32 = :Float32
|
23
|
+
Float64 = :Float64
|
24
|
+
|
18
25
|
# Represents an AVP of OctetString type
|
19
|
-
|
26
|
+
OctetString = :OctetString
|
27
|
+
DiameterIdentity = OctetString
|
28
|
+
DiameterURI = OctetString
|
29
|
+
UTF8String = OctetString
|
30
|
+
|
20
31
|
|
21
32
|
# Represents an AVP of IPAddress type
|
22
|
-
|
33
|
+
IPAddress = :Address
|
23
34
|
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
35
|
end
|
54
36
|
end
|
data/lib/diameter/message.rb
CHANGED
@@ -26,22 +26,23 @@ module Diameter
|
|
26
26
|
|
27
27
|
# Creates a new Diameter message.
|
28
28
|
#
|
29
|
-
# @
|
29
|
+
# @param [Hash] options The options
|
30
|
+
# @option options [Fixnum] command_code
|
30
31
|
# The Diameter Command-Code of this messsage.
|
31
|
-
# @option
|
32
|
+
# @option options [Fixnum] app_id
|
32
33
|
# The Diameter application ID of this message, or 0 for base
|
33
34
|
# protocol messages.
|
34
|
-
# @option
|
35
|
+
# @option options [Fixnum] hbh
|
35
36
|
# The hop-by-hop identifier of this message.
|
36
|
-
# @option
|
37
|
+
# @option options [Fixnum] ete
|
37
38
|
# The end-to-end identifier of this message.
|
38
|
-
# @option
|
39
|
+
# @option options [true, false] request
|
39
40
|
# Whether this message is a request. Defaults to true.
|
40
|
-
# @option
|
41
|
+
# @option options [true, false] proxyable
|
41
42
|
# Whether this message can be forwarded on. Defaults to true.
|
42
|
-
# @option
|
43
|
+
# @option options [true, false] error
|
43
44
|
# Whether this message is a Diameter protocol error. Defaults to false.
|
44
|
-
# @option
|
45
|
+
# @option options [Array<AVP>] avps
|
45
46
|
# The list of AVPs to include on this message.
|
46
47
|
def initialize(options = {})
|
47
48
|
@version = 1
|
@@ -234,7 +235,9 @@ module Diameter
|
|
234
235
|
|
235
236
|
avps = opts.fetch(:avps, [])
|
236
237
|
avps << if opts[:experimental_result_vendor]
|
237
|
-
|
238
|
+
AVP.create("Experimental-Result",
|
239
|
+
[AVP.create("Experimental-Result-Code", result_code),
|
240
|
+
AVP.create("Vendor-Id", opts[:experimental_result_vendor])])
|
238
241
|
else
|
239
242
|
AVP.create("Result-Code", result_code)
|
240
243
|
end
|
data/lib/diameter/stack.rb
CHANGED
@@ -5,6 +5,7 @@ require 'diameter/message'
|
|
5
5
|
require 'diameter/stack_transport_helpers'
|
6
6
|
require 'diameter/diameter_logger'
|
7
7
|
require 'concurrent'
|
8
|
+
require 'dnsruby'
|
8
9
|
|
9
10
|
module Diameter
|
10
11
|
class Stack
|
@@ -21,7 +22,10 @@ module Diameter
|
|
21
22
|
# the Origin-Host AVP).
|
22
23
|
# @param realm [String] The Diameter realm of this stack (for
|
23
24
|
# the Origin-Realm AVP).
|
24
|
-
|
25
|
+
# @option opts [Fixnum] timeout (60)
|
26
|
+
# The number of seconds to wait for an answer before notifying
|
27
|
+
# the caller of a timeout and forgetting about the request.
|
28
|
+
def initialize(host, realm, opts={})
|
25
29
|
@local_host = host
|
26
30
|
@local_realm = realm
|
27
31
|
|
@@ -34,14 +38,16 @@ module Diameter
|
|
34
38
|
@peer_table = {}
|
35
39
|
@handlers = {}
|
36
40
|
|
37
|
-
@
|
38
|
-
min_threads: 5,
|
39
|
-
max_threads: 5,
|
40
|
-
max_queue: 100,
|
41
|
-
overflow_policy: :caller_runs
|
42
|
-
)
|
41
|
+
@answer_timeout = opts.fetch(:timeout, 60)
|
43
42
|
|
44
|
-
|
43
|
+
@threadpool = Concurrent::ThreadPoolExecutor.new(
|
44
|
+
min_threads: 5,
|
45
|
+
max_threads: 5,
|
46
|
+
max_queue: 1,
|
47
|
+
overflow_policy: :caller_runs
|
48
|
+
)
|
49
|
+
|
50
|
+
@res = Dnsruby::Resolver.new
|
45
51
|
Diameter.logger.log(Logger::INFO, 'Stack initialized')
|
46
52
|
end
|
47
53
|
|
@@ -120,6 +126,23 @@ module Diameter
|
|
120
126
|
end
|
121
127
|
|
122
128
|
# @!group Peer connections and message sending
|
129
|
+
|
130
|
+
def connect_to_realm(realm)
|
131
|
+
possible_peers = []
|
132
|
+
@res.query("_diameter._tcp.#{realm}", "SRV").each_answer do |a|
|
133
|
+
possible_peers << {name: a.target.to_s, port: a.port, priority: a.priority, weight: a.weight}
|
134
|
+
end
|
135
|
+
|
136
|
+
# Prefer the lowest priority and the highest weight
|
137
|
+
possible_peers.sort!{ |a, b| (a[:priority] <=> b[:priority]) || (b[:weight] <=> a[:weight])}
|
138
|
+
Diameter.logger.debug("Sorted list of peers for realm #{realm} is #{possible_peers.inspect}")
|
139
|
+
|
140
|
+
primary = possible_peers[0]
|
141
|
+
|
142
|
+
url = "aaa://#{primary[:name]}:#{primary[:port]}"
|
143
|
+
Diameter.logger.info("Primary peer for realm #{realm} is #{primary[:name]}, (#{url})")
|
144
|
+
connect_to_peer(url, primary[:name], realm)
|
145
|
+
end
|
123
146
|
|
124
147
|
# Creates a Peer connection to a Diameter agent at the specific
|
125
148
|
# network location indicated by peer_uri.
|
@@ -165,6 +188,15 @@ module Diameter
|
|
165
188
|
@tcp_helper.send(req.to_wire, peer.cxn)
|
166
189
|
q = Queue.new
|
167
190
|
@pending_ete[req.ete] = q
|
191
|
+
|
192
|
+
# Time this request out if no answer is received
|
193
|
+
Concurrent::timer(@answer_timeout) do
|
194
|
+
q = @pending_ete.delete(req.ete)
|
195
|
+
if q
|
196
|
+
q.push(:timeout)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
168
200
|
p = Concurrent::Promise.execute(executor: @threadpool) {
|
169
201
|
Diameter.logger.debug("Waiting for answer to message with EtE #{req.ete}, queue #{q}")
|
170
202
|
val = q.pop
|
@@ -240,7 +272,7 @@ module Diameter
|
|
240
272
|
elsif @handlers.has_key? msg.app_id
|
241
273
|
@handlers[msg.app_id].call(msg, cxn)
|
242
274
|
else
|
243
|
-
|
275
|
+
Diameter.logger.warn("Ignoring message from unrecognised application #{msg.app_id} (Command-Code #{msg.command_code})")
|
244
276
|
end
|
245
277
|
end
|
246
278
|
|
@@ -273,16 +305,17 @@ module Diameter
|
|
273
305
|
end
|
274
306
|
|
275
307
|
def shared_apps(capabilities_msg)
|
276
|
-
peer_apps =
|
277
|
-
peer_apps += capabilities_msg.all_avps_by_name("Acct-Application-Id").collect(&:uint32)
|
308
|
+
peer_apps = []
|
278
309
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
310
|
+
app_avps = ["Auth-Application-Id", "Acct-Application-Id"]
|
311
|
+
|
312
|
+
app_avps.each do |name|
|
313
|
+
peer_apps += capabilities_msg.all_avps_by_name(name).collect(&:uint32)
|
283
314
|
|
284
|
-
|
285
|
-
|
315
|
+
capabilities_msg.all_avps_by_name("Vendor-Specific-Application-Id").each do |avp|
|
316
|
+
if avp.inner_avp(name)
|
317
|
+
peer_apps << avp.inner_avp(name).uint32
|
318
|
+
end
|
286
319
|
end
|
287
320
|
end
|
288
321
|
|
@@ -35,6 +35,15 @@ module Diameter
|
|
35
35
|
@wakeup_pipe_wr.puts "wakeup"
|
36
36
|
end
|
37
37
|
|
38
|
+
def read_from(connection, bytes)
|
39
|
+
msg, src = connection.recv_nonblock(bytes)
|
40
|
+
if msg == ''
|
41
|
+
Diameter.logger.warn('Received 0 bytes on read, closing connection')
|
42
|
+
close(connection)
|
43
|
+
end
|
44
|
+
return msg, src
|
45
|
+
end
|
46
|
+
|
38
47
|
def main_loop
|
39
48
|
rs, _ws, es = IO.select(@all_connections + [@wakeup_pipe_rd], [], @all_connections)
|
40
49
|
|
@@ -50,13 +59,8 @@ module Diameter
|
|
50
59
|
|
51
60
|
existing_data = @data[r]
|
52
61
|
if existing_data.length < 4
|
53
|
-
msg, _src = r
|
54
|
-
|
55
|
-
Diameter.logger.warn('Received 0 bytes on read, closing connection')
|
56
|
-
close(r)
|
57
|
-
else
|
58
|
-
existing_data += msg
|
59
|
-
end
|
62
|
+
msg, _src = read_from(r, 4 - existing_data.length)
|
63
|
+
existing_data += msg
|
60
64
|
end
|
61
65
|
|
62
66
|
expected_len = -1
|
@@ -64,13 +68,8 @@ module Diameter
|
|
64
68
|
expected_len = Message.length_from_header(existing_data[0..4])
|
65
69
|
Diameter.logger.debug("Read 4 bytes #{existing_data[0..4].inspect}, " \
|
66
70
|
"reading full message of length #{expected_len}")
|
67
|
-
msg, _src = r
|
71
|
+
msg, _src = read_from(r, expected_len - existing_data.length)
|
68
72
|
existing_data += msg
|
69
|
-
if msg == ''
|
70
|
-
# Connection closed
|
71
|
-
Diameter.logger.warn('Received 0 bytes on read, closing connection')
|
72
|
-
close(r)
|
73
|
-
end
|
74
73
|
end
|
75
74
|
|
76
75
|
if existing_data.length == expected_len
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: diameter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Day
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dnsruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rubocop
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,6 +116,7 @@ extra_rdoc_files: []
|
|
102
116
|
files:
|
103
117
|
- lib/diameter.rb
|
104
118
|
- lib/diameter/avp.rb
|
119
|
+
- lib/diameter/avp_names.rb
|
105
120
|
- lib/diameter/avp_parser.rb
|
106
121
|
- lib/diameter/constants.rb
|
107
122
|
- lib/diameter/diameter_logger.rb
|
@@ -126,9 +141,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
141
|
version: '0'
|
127
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
143
|
requirements:
|
129
|
-
- - "
|
144
|
+
- - ">"
|
130
145
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
146
|
+
version: 1.3.1
|
132
147
|
requirements: []
|
133
148
|
rubyforge_project:
|
134
149
|
rubygems_version: 2.4.3
|