diameter 0.2.0pre2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/diameter/avp_names.rb +1 -1
- data/lib/diameter/message.rb +3 -1
- data/lib/diameter/peer.rb +2 -1
- data/lib/diameter/stack.rb +53 -49
- metadata +35 -8
- data/lib/diameter/fsm.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78fdef7d94263e4950aec0b5c1dbf6e18925c817
|
4
|
+
data.tar.gz: 6d2d7d32b7701e73474c048cc39cb5e9c0263311
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1cf4fe297f2f6dfa12ccb5645282b4c59bc7f8df21f8a16ec00cfd59580ad02981000d0feac28a0e8afb46a771740917fd4a05c7753557e31f003d66400dde3
|
7
|
+
data.tar.gz: 75d82606e30f397720fd18bbc950cd3e7ce2f00891e79f2983d93a9a94cb93788d3e59f164012317a3d84e620a73fb310fc4e6707c548e20b660c28a7e0b3812
|
data/lib/diameter/avp_names.rb
CHANGED
@@ -10,7 +10,7 @@ module Diameter
|
|
10
10
|
'NAS-Port' => [5, Unsigned32],
|
11
11
|
'Service-Type' => [6, Enumerated],
|
12
12
|
'Framed-Protocol' => [7, Enumerated],
|
13
|
-
'Framed-IP-Address' => [8,
|
13
|
+
'Framed-IP-Address' => [8, OctetString],
|
14
14
|
'Framed-IP-Netmask' => [9, IPAddress],
|
15
15
|
'Framed-Routing' => [10, Enumerated],
|
16
16
|
'Filter-Id' => [11, UTF8String],
|
data/lib/diameter/message.rb
CHANGED
@@ -233,7 +233,9 @@ module Diameter
|
|
233
233
|
def create_answer(result_code, opts={})
|
234
234
|
fail "Cannot answer an answer" if answer
|
235
235
|
|
236
|
-
avps =
|
236
|
+
avps = []
|
237
|
+
avps << avp_by_name("Session-Id") unless avp_by_name("Session-Id").nil?
|
238
|
+
avps += opts.fetch(:avps, [])
|
237
239
|
avps << if opts[:experimental_result_vendor]
|
238
240
|
AVP.create("Experimental-Result",
|
239
241
|
[AVP.create("Experimental-Result-Code", result_code),
|
data/lib/diameter/peer.rb
CHANGED
@@ -25,8 +25,9 @@ module Diameter
|
|
25
25
|
attr_accessor :identity, :static, :cxn, :realm, :expiry_time, :last_message_seen
|
26
26
|
attr_reader :state
|
27
27
|
|
28
|
-
def initialize(identity)
|
28
|
+
def initialize(identity, realm)
|
29
29
|
@identity = identity
|
30
|
+
@realm = realm
|
30
31
|
@state = :CLOSED
|
31
32
|
@state_change_q = Queue.new
|
32
33
|
end
|
data/lib/diameter/stack.rb
CHANGED
@@ -8,21 +8,6 @@ require 'concurrent'
|
|
8
8
|
require 'dnsruby'
|
9
9
|
|
10
10
|
module Diameter
|
11
|
-
class Realm
|
12
|
-
def initialize(peer_name)
|
13
|
-
@peers = []
|
14
|
-
add_peer(peer_name)
|
15
|
-
end
|
16
|
-
|
17
|
-
def add_peer(name)
|
18
|
-
@peers << name
|
19
|
-
end
|
20
|
-
|
21
|
-
def best_peer
|
22
|
-
@peers[0]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
11
|
class Stack
|
27
12
|
include Internals
|
28
13
|
|
@@ -51,7 +36,6 @@ module Diameter
|
|
51
36
|
|
52
37
|
@tcp_helper = TCPStackHelper.new(self)
|
53
38
|
@peer_table = {}
|
54
|
-
@realm_table = {}
|
55
39
|
@handlers = {}
|
56
40
|
|
57
41
|
@answer_timeout = opts.fetch(:timeout, 60)
|
@@ -60,7 +44,7 @@ module Diameter
|
|
60
44
|
min_threads: 5,
|
61
45
|
max_threads: 5,
|
62
46
|
max_queue: 1,
|
63
|
-
|
47
|
+
fallback_policy: :caller_runs
|
64
48
|
)
|
65
49
|
|
66
50
|
@res = Dnsruby::Resolver.new
|
@@ -187,9 +171,7 @@ module Diameter
|
|
187
171
|
cer_bytes = Message.new(version: 1, command_code: 257, app_id: 0, request: true, proxyable: false, retransmitted: false, error: false, avps: avps).to_wire
|
188
172
|
@tcp_helper.send(cer_bytes, cxn)
|
189
173
|
|
190
|
-
@
|
191
|
-
|
192
|
-
@peer_table[peer_host] = Peer.new(peer_host)
|
174
|
+
@peer_table[peer_host] = Peer.new(peer_host, realm)
|
193
175
|
@peer_table[peer_host].state = :WAITING
|
194
176
|
# Will move to :UP when the CEA is received
|
195
177
|
@peer_table[peer_host].cxn = cxn
|
@@ -205,31 +187,40 @@ module Diameter
|
|
205
187
|
# those AVPs don't already exist.
|
206
188
|
#
|
207
189
|
# @param req [Message] The request to send.
|
208
|
-
|
190
|
+
# @param peer [Peer] (Optional) A peer to use as the first hop for the message
|
191
|
+
def send_request(req, options={})
|
209
192
|
fail "Must pass a request" unless req.request
|
210
193
|
req.add_origin_host_and_realm(@local_host, @local_realm)
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
194
|
+
|
195
|
+
peer = options[:peer]
|
196
|
+
|
197
|
+
if peer.nil?
|
198
|
+
peer = if req['Destination-Host']
|
199
|
+
peer_identity = req['Destination-Host'].octet_string
|
200
|
+
Diameter.logger.debug("Selecting peer by Destination-Host (#{peer_identity})")
|
201
|
+
@peer_table[peer_identity]
|
202
|
+
elsif req['Destination-Realm']
|
203
|
+
realm = req['Destination-Realm'].octet_string
|
204
|
+
Diameter.logger.debug("Selecting peer by Destination-Realm (#{realm})")
|
205
|
+
@peer_table.values.select { |p| p.realm == realm }.sample
|
206
|
+
else
|
207
|
+
fail "Request must have Destination-Host or Destination-Realm"
|
208
|
+
end
|
209
|
+
else
|
210
|
+
Diameter.logger.debug("Peer selection forced to #{peer.identity}")
|
211
|
+
end
|
212
|
+
|
213
|
+
if peer.nil?
|
214
|
+
Diameter.logger.warn("No peer is available to send message - cannot route")
|
215
|
+
fail "No acceptable peer"
|
216
|
+
elsif peer.state == :UP
|
227
217
|
q = Queue.new
|
228
218
|
@pending_ete[req.ete] = q
|
219
|
+
@tcp_helper.send(req.to_wire, peer.cxn)
|
229
220
|
|
221
|
+
=begin
|
230
222
|
# Time this request out if no answer is received
|
231
223
|
Diameter.logger.debug("Scheduling timeout for #{@answer_timeout}s time")
|
232
|
-
=begin
|
233
224
|
Concurrent::timer(@answer_timeout) do
|
234
225
|
Diameter.logger.debug("Timing out message with EtE #{req.ete}")
|
235
226
|
q = @pending_ete.delete(req.ete)
|
@@ -247,7 +238,7 @@ module Diameter
|
|
247
238
|
}
|
248
239
|
return p
|
249
240
|
else
|
250
|
-
Diameter.logger.
|
241
|
+
Diameter.logger.warn("Peer #{peer.identity} is in state #{peer.state} - cannot route")
|
251
242
|
end
|
252
243
|
end
|
253
244
|
|
@@ -302,7 +293,7 @@ module Diameter
|
|
302
293
|
end
|
303
294
|
|
304
295
|
if msg.command_code == 257 && msg.answer
|
305
|
-
handle_cea(msg)
|
296
|
+
handle_cea(msg, cxn)
|
306
297
|
elsif msg.command_code == 257 && msg.request
|
307
298
|
handle_cer(msg, cxn)
|
308
299
|
elsif msg.command_code == 280 && msg.request
|
@@ -381,8 +372,9 @@ module Diameter
|
|
381
372
|
|
382
373
|
if rc == 2001
|
383
374
|
peer = cer.avp_by_name('Origin-Host').octet_string
|
384
|
-
|
385
|
-
|
375
|
+
realm = cer.avp_by_name('Origin-Realm').octet_string
|
376
|
+
Diameter.logger.debug("Creating peer table entry for peer #{peer} in realm #{realm}")
|
377
|
+
@peer_table[peer] = Peer.new(peer, realm)
|
386
378
|
@peer_table[peer].state = :UP
|
387
379
|
@peer_table[peer].reset_timer
|
388
380
|
@peer_table[peer].cxn = cxn
|
@@ -391,14 +383,26 @@ module Diameter
|
|
391
383
|
end
|
392
384
|
end
|
393
385
|
|
394
|
-
def handle_cea(cea)
|
395
|
-
|
396
|
-
if @peer_table.has_key?
|
397
|
-
@peer_table[
|
398
|
-
@peer_table[
|
386
|
+
def handle_cea(cea, cxn)
|
387
|
+
host = cea.avp_by_name('Origin-Host').octet_string
|
388
|
+
if @peer_table.has_key? host
|
389
|
+
@peer_table[host].state = :UP
|
390
|
+
@peer_table[host].reset_timer
|
399
391
|
else
|
400
|
-
|
401
|
-
|
392
|
+
entry = @peer_table.find { |h, p| p.cxn == cxn }
|
393
|
+
if entry.nil?
|
394
|
+
Diameter.logger.warn("Ignoring CEA from unknown peer #{host}")
|
395
|
+
Diameter.logger.debug("Known peers are #{@peer_table.keys}")
|
396
|
+
else
|
397
|
+
old_host, peer = entry
|
398
|
+
Diameter.logger.warn("Peer identity changed #{old_host} => #{host}")
|
399
|
+
|
400
|
+
@peer_table.delete(old_host)
|
401
|
+
peer.identity = host
|
402
|
+
@peer_table[host] = peer
|
403
|
+
@peer_table[host].state = :UP
|
404
|
+
@peer_table[host].reset_timer
|
405
|
+
end
|
402
406
|
end
|
403
407
|
end
|
404
408
|
|
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.3.0
|
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: 2016-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.9'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: dnsruby
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rubocop
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,20 @@ dependencies:
|
|
108
122
|
- - '='
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: 0.0.3
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: minitest
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 5.8.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 5.8.0
|
111
139
|
description:
|
112
140
|
email: ruby-diameter@rkd.me.uk
|
113
141
|
executables: []
|
@@ -120,7 +148,6 @@ files:
|
|
120
148
|
- lib/diameter/avp_parser.rb
|
121
149
|
- lib/diameter/constants.rb
|
122
150
|
- lib/diameter/diameter_logger.rb
|
123
|
-
- lib/diameter/fsm.rb
|
124
151
|
- lib/diameter/message.rb
|
125
152
|
- lib/diameter/peer.rb
|
126
153
|
- lib/diameter/stack.rb
|
@@ -141,12 +168,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
141
168
|
version: '0'
|
142
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
170
|
requirements:
|
144
|
-
- - "
|
171
|
+
- - ">="
|
145
172
|
- !ruby/object:Gem::Version
|
146
|
-
version:
|
173
|
+
version: '0'
|
147
174
|
requirements: []
|
148
175
|
rubyforge_project:
|
149
|
-
rubygems_version: 2.4.
|
176
|
+
rubygems_version: 2.4.8
|
150
177
|
signing_key:
|
151
178
|
specification_version: 4
|
152
179
|
summary: Pure-Ruby Diameter stack
|
data/lib/diameter/fsm.rb
DELETED
@@ -1,27 +0,0 @@
|
|
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
|