diameter 0.1.0.beta → 0.1.0.pre1
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 +17 -24
- data/lib/diameter/message.rb +23 -32
- data/lib/diameter/stack.rb +17 -101
- data/lib/diameter/stack_transport_helpers.rb +10 -15
- metadata +26 -27
- data/lib/diameter.rb +0 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e140baae5544d85586d01a9dbd1000c63d95aab0
|
|
4
|
+
data.tar.gz: c8407d154a3498d9d159acf99c1222043a288760
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5e8e0a512e7b9ec8111a7e8d8e70252a6e0deaad7b966013a8a80be8bfb8f0d84dcfcfa65caa7264e7798ab4b39f08ed1fdcb616cc0307914b4ff9534e86722b
|
|
7
|
+
data.tar.gz: 44f4430b63e1c4a02c6f477ac89e37a2f0b94897a39e51ccae13eee62e73c0eba8f48ac7a35f74106b8d4cfa01312fa59b9128d40c53dd7be70cc57160d05a29
|
data/lib/diameter/avp.rb
CHANGED
|
@@ -51,14 +51,12 @@ module Diameter
|
|
|
51
51
|
|
|
52
52
|
include AVPParser
|
|
53
53
|
|
|
54
|
-
# @api private
|
|
55
|
-
#
|
|
56
|
-
# Prefer {AVP.create} where possible.
|
|
57
54
|
def initialize(code, options = {})
|
|
58
55
|
@code = code
|
|
59
56
|
@vendor_id = options[:vendor_id] || 0
|
|
60
57
|
@content = options[:content] || ''
|
|
61
|
-
@mandatory = options
|
|
58
|
+
@mandatory = options[:mandatory]
|
|
59
|
+
@mandatory = true if @mandatory.nil?
|
|
62
60
|
end
|
|
63
61
|
|
|
64
62
|
# Creates an AVP by name, and assigns it a value.
|
|
@@ -68,10 +66,6 @@ module Diameter
|
|
|
68
66
|
# that AVP - e.g. a Fixnum for an AVP defined as Unsigned32, a
|
|
69
67
|
# String for an AVP defined as OctetString, or an IPAddr for an AVP
|
|
70
68
|
# defined as IPAddress.
|
|
71
|
-
# @option opts [true, false] mandatory
|
|
72
|
-
# Whether understanding this AVP is mandatory within this
|
|
73
|
-
# application.
|
|
74
|
-
#
|
|
75
69
|
# @return [AVP] The AVP that was created.
|
|
76
70
|
def self.create(name, val, options = {})
|
|
77
71
|
code, type, vendor = AVPNames.get(name)
|
|
@@ -109,7 +103,22 @@ module Diameter
|
|
|
109
103
|
to_wire_novendor
|
|
110
104
|
end
|
|
111
105
|
end
|
|
106
|
+
|
|
107
|
+
def to_wire_novendor
|
|
108
|
+
length_8, length_16 = UInt24.to_u8_and_u16(@content.length + 8)
|
|
109
|
+
avp_flags = @mandatory ? '01000000' : '00000000'
|
|
110
|
+
header = [@code, avp_flags, length_8, length_16].pack('NB8Cn')
|
|
111
|
+
header + padded_content
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def to_wire_vendor
|
|
115
|
+
length_8, length_16 = UInt24.to_u8_and_u16(@content.length + 12)
|
|
116
|
+
avp_flags = @mandatory ? '11000000' : '10000000'
|
|
117
|
+
header = [@code, avp_flags, length_8, length_16, @vendor_id].pack('NB8CnN')
|
|
118
|
+
header + padded_content
|
|
119
|
+
end
|
|
112
120
|
|
|
121
|
+
|
|
113
122
|
# Guessing the type of an AVP and displaying it sensibly is complex,
|
|
114
123
|
# so this is a complex method (but one that has a unity of purpose,
|
|
115
124
|
# so can't easily be broken down). Disable several Rubocop
|
|
@@ -207,8 +216,6 @@ module Diameter
|
|
|
207
216
|
grouped_value.select { |a| a.code == code }
|
|
208
217
|
end
|
|
209
218
|
|
|
210
|
-
alias_method :[], :inner_avp
|
|
211
|
-
|
|
212
219
|
# Even though it is just "the raw bytes in the content",
|
|
213
220
|
# octet_string is only one way of interpreting the AVP content and
|
|
214
221
|
# shouldn't be treated differently to the others, so disable the
|
|
@@ -364,20 +371,6 @@ module Diameter
|
|
|
364
371
|
end
|
|
365
372
|
end
|
|
366
373
|
|
|
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
374
|
protected
|
|
382
375
|
|
|
383
376
|
def padded_content
|
data/lib/diameter/message.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'diameter/avp_parser'
|
|
2
2
|
require 'diameter/u24'
|
|
3
3
|
|
|
4
|
-
# The Diameter module
|
|
5
4
|
module Diameter
|
|
6
5
|
# A Diameter message.
|
|
7
6
|
#
|
|
@@ -18,14 +17,16 @@ module Diameter
|
|
|
18
17
|
# The end-to-end identifier of this message.
|
|
19
18
|
# @!attribute [r] request
|
|
20
19
|
# Whether this message is a request.
|
|
21
|
-
# @!attribute [r] answer
|
|
22
|
-
# Whether this message is an answer.
|
|
23
20
|
class Message
|
|
24
|
-
attr_reader :version, :command_code, :app_id, :hbh, :ete, :request
|
|
21
|
+
attr_reader :version, :command_code, :app_id, :hbh, :ete, :request
|
|
25
22
|
include Internals
|
|
23
|
+
|
|
24
|
+
# @!attribute [r] answer
|
|
25
|
+
# Whether this message is an answer.
|
|
26
|
+
def answer
|
|
27
|
+
!@request
|
|
28
|
+
end
|
|
26
29
|
|
|
27
|
-
# Creates a new Diameter message.
|
|
28
|
-
#
|
|
29
30
|
# @option opts [Fixnum] command_code
|
|
30
31
|
# The Diameter Command-Code of this messsage.
|
|
31
32
|
# @option opts [Fixnum] app_id
|
|
@@ -51,7 +52,6 @@ module Diameter
|
|
|
51
52
|
@ete = options[:ete] || Message.next_ete
|
|
52
53
|
|
|
53
54
|
@request = options.fetch(:request, true)
|
|
54
|
-
@answer = !@request
|
|
55
55
|
@proxyable = options.fetch(:proxyable, false)
|
|
56
56
|
@retransmitted = false
|
|
57
57
|
@error = false
|
|
@@ -90,10 +90,8 @@ module Diameter
|
|
|
90
90
|
# Returns the first AVP with the given name. Only covers "top-level"
|
|
91
91
|
# AVPs - it won't look inside Grouped AVPs.
|
|
92
92
|
#
|
|
93
|
-
# Also available as [], e.g. message['Result-Code']
|
|
94
|
-
#
|
|
95
93
|
# @param name [String] The AVP name, either one predefined in
|
|
96
|
-
# {
|
|
94
|
+
# {AVPNames::AVAILABLE_AVPS} or user-defined with {AVP.define}
|
|
97
95
|
#
|
|
98
96
|
# @return [AVP] if there is an AVP with that name
|
|
99
97
|
# @return [nil] if there is not an AVP with that name
|
|
@@ -106,7 +104,7 @@ module Diameter
|
|
|
106
104
|
# AVPs - it won't look inside Grouped AVPs.
|
|
107
105
|
#
|
|
108
106
|
# @param name [String] The AVP name, either one predefined in
|
|
109
|
-
# {
|
|
107
|
+
# {AVPNames::AVAILABLE_AVPS} or user-defined with {AVP.define}
|
|
110
108
|
#
|
|
111
109
|
# @return [Array<AVP>]
|
|
112
110
|
def all_avps_by_name(name)
|
|
@@ -115,12 +113,8 @@ module Diameter
|
|
|
115
113
|
end
|
|
116
114
|
|
|
117
115
|
alias_method :avp, :avp_by_name
|
|
118
|
-
alias_method :[], :
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
# @private
|
|
122
|
-
# Prefer AVP.define and the by-name versions to this
|
|
123
|
-
#
|
|
116
|
+
alias_method :[], :all_avps_by_name
|
|
117
|
+
|
|
124
118
|
# Returns the first AVP with the given code and vendor. Only covers "top-level"
|
|
125
119
|
# AVPs - it won't look inside Grouped AVPs.
|
|
126
120
|
#
|
|
@@ -138,9 +132,6 @@ module Diameter
|
|
|
138
132
|
end
|
|
139
133
|
end
|
|
140
134
|
|
|
141
|
-
# @private
|
|
142
|
-
# Prefer AVP.define and the by-name versions to this
|
|
143
|
-
#
|
|
144
135
|
# Returns all AVPs with the given code and vendor. Only covers "top-level"
|
|
145
136
|
# AVPs - it won't look inside Grouped AVPs.
|
|
146
137
|
#
|
|
@@ -162,24 +153,25 @@ module Diameter
|
|
|
162
153
|
|
|
163
154
|
# Does this message contain a (top-level) AVP with this name?
|
|
164
155
|
# @param name [String] The AVP name, either one predefined in
|
|
165
|
-
# {
|
|
156
|
+
# {AVPNames::AVAILABLE_AVPS} or user-defined with {AVP.define}
|
|
166
157
|
#
|
|
167
158
|
# @return [true, false]
|
|
168
159
|
def has_avp?(name)
|
|
169
160
|
!!avp(name)
|
|
170
161
|
end
|
|
171
162
|
|
|
172
|
-
# @private
|
|
173
|
-
#
|
|
174
|
-
# Not recommended for normal use - all AVPs should be given to the
|
|
175
|
-
# constructor. Used to allow the stack to add appropriate
|
|
176
|
-
# Origin-Host/Origin-Realm AVPs to outbound messages.
|
|
163
|
+
# @api private
|
|
177
164
|
#
|
|
178
|
-
#
|
|
179
|
-
#
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
165
|
+
# Adds an AVP to this message. Not recommended for normal use -
|
|
166
|
+
# all AVPs should be given to the constructor. Used to allow the
|
|
167
|
+
# stack to add appropriate Origin-Host/Origin-Realm AVPs to outbound
|
|
168
|
+
# messages.
|
|
169
|
+
# @param name [String] The AVP name, either one predefined in
|
|
170
|
+
# {AVPNames::AVAILABLE_AVPS} or user-defined with {AVP.define}
|
|
171
|
+
# @param value [Object] The AVP value, with type dependent on the
|
|
172
|
+
# AVP itself.
|
|
173
|
+
def add_avp(name, value)
|
|
174
|
+
@avps << AVP.create(name, value)
|
|
183
175
|
end
|
|
184
176
|
|
|
185
177
|
# @!endgroup
|
|
@@ -214,7 +206,6 @@ module Diameter
|
|
|
214
206
|
avps = Internals::AVPParser.parse_avps_int(bytes[20..-1])
|
|
215
207
|
Message.new(version: version, command_code: command_code, app_id: app_id, hbh: hbh, ete: ete, request: request, proxyable: proxyable, retransmitted: false, error: false, avps: avps)
|
|
216
208
|
end
|
|
217
|
-
|
|
218
209
|
# @!endgroup
|
|
219
210
|
|
|
220
211
|
# Generates an answer to this request, filling in a Result-Code or
|
data/lib/diameter/stack.rb
CHANGED
|
@@ -9,21 +9,10 @@ require 'concurrent'
|
|
|
9
9
|
module Diameter
|
|
10
10
|
class Stack
|
|
11
11
|
include Internals
|
|
12
|
-
|
|
13
|
-
# @!group Setup methods
|
|
14
|
-
|
|
15
|
-
# Stack constructor.
|
|
16
|
-
#
|
|
17
|
-
# @note The stack does not advertise any applications to peers by
|
|
18
|
-
# default - {#add_handler} must be called early on.
|
|
19
|
-
#
|
|
20
|
-
# @param host [String] The Diameter Identity of this stack (for
|
|
21
|
-
# the Origin-Host AVP).
|
|
22
|
-
# @param realm [String] The Diameter realm of this stack (for
|
|
23
|
-
# the Origin-Realm AVP).
|
|
24
|
-
def initialize(host, realm)
|
|
12
|
+
def initialize(host, realm, opts={})
|
|
25
13
|
@local_host = host
|
|
26
14
|
@local_realm = realm
|
|
15
|
+
@local_port = opts[:port] || 3868
|
|
27
16
|
|
|
28
17
|
@auth_apps = []
|
|
29
18
|
@acct_apps = []
|
|
@@ -33,55 +22,18 @@ module Diameter
|
|
|
33
22
|
@tcp_helper = TCPStackHelper.new(self)
|
|
34
23
|
@peer_table = {}
|
|
35
24
|
@handlers = {}
|
|
36
|
-
|
|
37
|
-
@threadpool = pool = Concurrent::ThreadPoolExecutor.new(
|
|
38
|
-
min_threads: 5,
|
|
39
|
-
max_threads: 5,
|
|
40
|
-
max_queue: 100,
|
|
41
|
-
overflow_policy: :caller_runs
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
45
25
|
Diameter.logger.log(Logger::INFO, 'Stack initialized')
|
|
46
26
|
end
|
|
47
27
|
|
|
48
|
-
#
|
|
28
|
+
# @!group Setup methods
|
|
49
29
|
def start
|
|
50
30
|
@tcp_helper.start_main_loop
|
|
51
31
|
end
|
|
52
32
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
# @param port [Fixnum] The TCP port to listen on (default 3868)
|
|
57
|
-
def listen_for_tcp(port=3868)
|
|
58
|
-
@tcp_helper.setup_new_listen_connection("0.0.0.0", port)
|
|
33
|
+
def listen_for_tcp
|
|
34
|
+
@tcp_helper.setup_new_listen_connection("0.0.0.0", @local_port)
|
|
59
35
|
end
|
|
60
36
|
|
|
61
|
-
# Adds a handler for a specific Diameter application.
|
|
62
|
-
#
|
|
63
|
-
# @note If you expect to only send requests for this application,
|
|
64
|
-
# not receive them, the block can be a no-op (e.g. `{ nil }`)
|
|
65
|
-
#
|
|
66
|
-
# @param app_id [Fixnum] The Diameter application ID.
|
|
67
|
-
# @option opts [true, false] auth
|
|
68
|
-
# Whether we should advertise support for this application in
|
|
69
|
-
# the Auth-Application-ID AVP. Note that at least one of auth or
|
|
70
|
-
# acct must be specified.
|
|
71
|
-
# @option opts [true, false] acct
|
|
72
|
-
# Whether we should advertise support for this application in
|
|
73
|
-
# the Acct-Application-ID AVP. Note that at least one of auth or
|
|
74
|
-
# acct must be specified.
|
|
75
|
-
# @option opts [Fixnum] vendor
|
|
76
|
-
# If we should advertise support for this application in a
|
|
77
|
-
# Vendor-Specific-Application-Id AVP, this specifies the
|
|
78
|
-
# associated Vendor-Id.
|
|
79
|
-
#
|
|
80
|
-
# @yield [req, cxn] Passes a Diameter message (and its originating
|
|
81
|
-
# connection) for application-specific handling.
|
|
82
|
-
# @yieldparam [Message] req The parsed Diameter message from the peer.
|
|
83
|
-
# @yieldparam [Socket] cxn The TCP connection to the peer, to be
|
|
84
|
-
# passed to {Stack#send_answer}.
|
|
85
37
|
def add_handler(app_id, opts={}, &blk)
|
|
86
38
|
vendor = opts.fetch(:vendor, 0)
|
|
87
39
|
auth = opts.fetch(:auth, false)
|
|
@@ -97,24 +49,10 @@ module Diameter
|
|
|
97
49
|
|
|
98
50
|
# @!endgroup
|
|
99
51
|
|
|
100
|
-
# This shuts the stack down, closing all TCP connections and
|
|
101
|
-
# terminating any background threads still waiting for an answer.
|
|
102
52
|
def shutdown
|
|
103
53
|
@tcp_helper.shutdown
|
|
104
|
-
@pending_ete.each do |ete, q|
|
|
105
|
-
Diameter.logger.debug("Shutting down queue #{q} as no answer has been received with EtE #{ete}")
|
|
106
|
-
q.push :shutdown
|
|
107
|
-
end
|
|
108
|
-
@threadpool.kill
|
|
109
|
-
@threadpool.wait_for_termination(5)
|
|
110
54
|
end
|
|
111
55
|
|
|
112
|
-
# Closes the given connection, blanking out any internal data
|
|
113
|
-
# structures associated with it.
|
|
114
|
-
#
|
|
115
|
-
# Likely to be moved to the Peer object in a future release/
|
|
116
|
-
#
|
|
117
|
-
# @param connection [Socket] The connection to close.
|
|
118
56
|
def close(connection)
|
|
119
57
|
@tcp_helper.close(connection)
|
|
120
58
|
end
|
|
@@ -125,11 +63,12 @@ module Diameter
|
|
|
125
63
|
# network location indicated by peer_uri.
|
|
126
64
|
#
|
|
127
65
|
# @param peer_uri [URI] The aaa:// URI identifying the peer. Should
|
|
128
|
-
# contain a hostname/IP; may contain a port (default 3868)
|
|
66
|
+
# contain a hostname/IP; may contain a port (default 3868) and a
|
|
67
|
+
# transport param indicating TCP or SCTP (default TCP).
|
|
129
68
|
# @param peer_host [String] The DiameterIdentity of this peer, which
|
|
130
69
|
# will uniquely identify it in the peer table.
|
|
131
70
|
# @param realm [String] The Diameter realm of this peer.
|
|
132
|
-
def connect_to_peer(peer_uri, peer_host,
|
|
71
|
+
def connect_to_peer(peer_uri, peer_host, _realm)
|
|
133
72
|
uri = URI(peer_uri)
|
|
134
73
|
cxn = @tcp_helper.setup_new_connection(uri.host, uri.port)
|
|
135
74
|
avps = [AVP.create('Origin-Host', @local_host),
|
|
@@ -148,25 +87,19 @@ module Diameter
|
|
|
148
87
|
# Will move to :UP when the CEA is received
|
|
149
88
|
end
|
|
150
89
|
|
|
151
|
-
# Sends a Diameter request. This is routed to an appropriate peer
|
|
152
|
-
# based on the Destination-Host AVP.
|
|
153
|
-
#
|
|
154
|
-
# This adds this stack's Origin-Host and Origin-Realm AVPs, if
|
|
155
|
-
# those AVPs don't already exist.
|
|
156
|
-
#
|
|
157
|
-
# @param req [Message] The request to send.
|
|
158
90
|
def send_request(req)
|
|
159
91
|
fail "Must pass a request" unless req.request
|
|
160
|
-
req.
|
|
92
|
+
req.add_avp('Origin-Host', @local_host) unless req.has_avp? 'Origin-Host'
|
|
93
|
+
req.add_avp('Origin-Realm', @local_realm) unless req.has_avp? 'Origin-Realm'
|
|
94
|
+
q = Queue.new
|
|
95
|
+
@pending_ete[req.ete] = q
|
|
161
96
|
peer_name = req.avp_by_name('Destination-Host').octet_string
|
|
162
97
|
state = peer_state(peer_name)
|
|
163
98
|
if state == :UP
|
|
164
99
|
peer = @peer_table[peer_name]
|
|
165
100
|
@tcp_helper.send(req.to_wire, peer.cxn)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
p = Concurrent::Promise.execute(executor: @threadpool) {
|
|
169
|
-
Diameter.logger.debug("Waiting for answer to message with EtE #{req.ete}, queue #{q}")
|
|
101
|
+
p = Concurrent::Promise.execute {
|
|
102
|
+
Diameter.logger.debug("Waiting for answer to message with EtE #{req.ete}")
|
|
170
103
|
val = q.pop
|
|
171
104
|
Diameter.logger.debug("Promise fulfilled for message with EtE #{req.ete}")
|
|
172
105
|
val
|
|
@@ -177,28 +110,13 @@ module Diameter
|
|
|
177
110
|
end
|
|
178
111
|
end
|
|
179
112
|
|
|
180
|
-
# Sends a Diameter answer. This is sent over the same connection
|
|
181
|
-
# the request was received on (which needs to be passed into to
|
|
182
|
-
# this method).
|
|
183
|
-
#
|
|
184
|
-
# This adds this stack's Origin-Host and Origin-Realm AVPs, if
|
|
185
|
-
# those AVPs don't already exist.
|
|
186
|
-
#
|
|
187
|
-
# @param ans [Message] The Diameter answer
|
|
188
|
-
# @param original_cxn [Socket] The connection which the request
|
|
189
|
-
# came in on. This will have been passed to the block registered
|
|
190
|
-
# with {Stack#add_handler}.
|
|
191
113
|
def send_answer(ans, original_cxn)
|
|
192
114
|
fail "Must pass an answer" unless ans.answer
|
|
193
|
-
ans.
|
|
115
|
+
ans.add_avp('Origin-Host', @local_host) unless ans.has_avp? 'Origin-Host'
|
|
116
|
+
ans.add_avp('Origin-Realm', @local_realm) unless ans.has_avp? 'Origin-Realm'
|
|
194
117
|
@tcp_helper.send(ans.to_wire, original_cxn)
|
|
195
118
|
end
|
|
196
119
|
|
|
197
|
-
# Retrieves the current state of a peer, defaulting to :CLOSED if
|
|
198
|
-
# the peer does not exist.
|
|
199
|
-
#
|
|
200
|
-
# @param id [String] The Diameter identity of the peer.
|
|
201
|
-
# @return [Keyword] The state of the peer (:UP, :WAITING or :CLOSED).
|
|
202
120
|
def peer_state(id)
|
|
203
121
|
if !@peer_table.key? id
|
|
204
122
|
:CLOSED
|
|
@@ -210,9 +128,6 @@ module Diameter
|
|
|
210
128
|
# @!endgroup
|
|
211
129
|
|
|
212
130
|
# @private
|
|
213
|
-
# Handles a Diameter request straight from a network connection.
|
|
214
|
-
# Intended to be called by TCPStackHelper after it retrieves a
|
|
215
|
-
# message, not directly by users.
|
|
216
131
|
def handle_message(msg_bytes, cxn)
|
|
217
132
|
# Common processing - ensure that this message has come in on this
|
|
218
133
|
# peer's expected connection, and update the last time we saw
|
|
@@ -318,6 +233,7 @@ module Diameter
|
|
|
318
233
|
|
|
319
234
|
def handle_cea(cea)
|
|
320
235
|
peer = cea.avp_by_name('Origin-Host').octet_string
|
|
236
|
+
# puts peer
|
|
321
237
|
if @peer_table.has_key? peer
|
|
322
238
|
@peer_table[peer].state = :UP
|
|
323
239
|
@peer_table[peer].reset_timer
|
|
@@ -3,10 +3,6 @@ require 'socket'
|
|
|
3
3
|
require 'diameter/message'
|
|
4
4
|
require 'diameter/avp'
|
|
5
5
|
|
|
6
|
-
if RUBY_ENGINE != 'jruby'
|
|
7
|
-
ServerSocket = Socket
|
|
8
|
-
end
|
|
9
|
-
|
|
10
6
|
module Diameter
|
|
11
7
|
module Internals
|
|
12
8
|
# @private
|
|
@@ -19,7 +15,6 @@ module Diameter
|
|
|
19
15
|
@loop_thread = nil
|
|
20
16
|
@accept_loop_thread = nil
|
|
21
17
|
@connection_lock = Mutex.new
|
|
22
|
-
@wakeup_pipe_rd, @wakeup_pipe_wr = IO.pipe
|
|
23
18
|
end
|
|
24
19
|
|
|
25
20
|
def start_main_loop
|
|
@@ -32,25 +27,25 @@ module Diameter
|
|
|
32
27
|
end
|
|
33
28
|
|
|
34
29
|
def wakeup
|
|
35
|
-
@
|
|
30
|
+
@loop_thread.raise
|
|
36
31
|
end
|
|
37
32
|
|
|
38
33
|
def main_loop
|
|
39
|
-
|
|
34
|
+
begin
|
|
35
|
+
rs, _ws, es = IO.select(@all_connections, [], @all_connections)
|
|
36
|
+
rescue RuntimeError
|
|
37
|
+
return
|
|
38
|
+
end
|
|
40
39
|
|
|
41
40
|
es.each do |e|
|
|
42
41
|
Diameter.logger.log(Logger::WARN, "Exception on connection #{e}")
|
|
43
42
|
end
|
|
44
43
|
|
|
45
44
|
rs.each do |r|
|
|
46
|
-
if r == @wakeup_pipe_rd
|
|
47
|
-
r.gets
|
|
48
|
-
next
|
|
49
|
-
end
|
|
50
45
|
|
|
51
46
|
existing_data = @data[r]
|
|
52
47
|
if existing_data.length < 4
|
|
53
|
-
msg, _src = r.
|
|
48
|
+
msg, _src = r.recvfrom_nonblock(4 - existing_data.length)
|
|
54
49
|
if msg == ''
|
|
55
50
|
Diameter.logger.warn('Received 0 bytes on read, closing connection')
|
|
56
51
|
close(r)
|
|
@@ -64,7 +59,7 @@ module Diameter
|
|
|
64
59
|
expected_len = Message.length_from_header(existing_data[0..4])
|
|
65
60
|
Diameter.logger.debug("Read 4 bytes #{existing_data[0..4].inspect}, " \
|
|
66
61
|
"reading full message of length #{expected_len}")
|
|
67
|
-
msg, _src = r.
|
|
62
|
+
msg, _src = r.recvfrom_nonblock(expected_len - existing_data.length)
|
|
68
63
|
existing_data += msg
|
|
69
64
|
if msg == ''
|
|
70
65
|
# Connection closed
|
|
@@ -83,7 +78,7 @@ module Diameter
|
|
|
83
78
|
end
|
|
84
79
|
|
|
85
80
|
def send(bytes, connection)
|
|
86
|
-
connection.
|
|
81
|
+
connection.sendmsg(bytes)
|
|
87
82
|
end
|
|
88
83
|
end
|
|
89
84
|
|
|
@@ -118,7 +113,7 @@ module Diameter
|
|
|
118
113
|
end
|
|
119
114
|
|
|
120
115
|
def setup_new_listen_connection(host, port)
|
|
121
|
-
sd =
|
|
116
|
+
sd = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
|
122
117
|
# reuse = [1,0].pack('ii')
|
|
123
118
|
sd.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
|
|
124
119
|
sd.bind(Socket.pack_sockaddr_in(port, host))
|
metadata
CHANGED
|
@@ -1,106 +1,105 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: diameter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.0.
|
|
4
|
+
version: 0.1.0.pre1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rob Day
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-12-
|
|
11
|
+
date: 2014-12-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0
|
|
19
|
+
version: '0'
|
|
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'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rubocop
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0
|
|
33
|
+
version: '0'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0
|
|
40
|
+
version: '0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: yard
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- -
|
|
45
|
+
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0
|
|
47
|
+
version: '0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- -
|
|
52
|
+
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0
|
|
54
|
+
version: '0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: simplecov
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- -
|
|
59
|
+
- - ">="
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0
|
|
61
|
+
version: '0'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- -
|
|
66
|
+
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0
|
|
68
|
+
version: '0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: mocha
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
|
-
- -
|
|
73
|
+
- - ">="
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '
|
|
75
|
+
version: '0'
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
|
-
- -
|
|
80
|
+
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '
|
|
82
|
+
version: '0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: minitest-spec-context
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- -
|
|
87
|
+
- - ">="
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: 0
|
|
89
|
+
version: '0'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
|
-
- -
|
|
94
|
+
- - ">="
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: 0
|
|
96
|
+
version: '0'
|
|
97
97
|
description:
|
|
98
98
|
email: ruby-diameter@rkd.me.uk
|
|
99
99
|
executables: []
|
|
100
100
|
extensions: []
|
|
101
101
|
extra_rdoc_files: []
|
|
102
102
|
files:
|
|
103
|
-
- lib/diameter.rb
|
|
104
103
|
- lib/diameter/avp.rb
|
|
105
104
|
- lib/diameter/avp_parser.rb
|
|
106
105
|
- lib/diameter/constants.rb
|
data/lib/diameter.rb
DELETED