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
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'socket'
|
3
|
+
require 'diameter/message'
|
4
|
+
require 'diameter/avp'
|
5
|
+
|
6
|
+
if RUBY_ENGINE != 'jruby'
|
7
|
+
ServerSocket = Socket
|
8
|
+
end
|
9
|
+
|
10
|
+
module Diameter
|
11
|
+
module Internals
|
12
|
+
# @private
|
13
|
+
class StackHelper
|
14
|
+
def initialize(stack)
|
15
|
+
@all_connections = []
|
16
|
+
@listen_connections = []
|
17
|
+
@data = {}
|
18
|
+
@stack = stack
|
19
|
+
@loop_thread = nil
|
20
|
+
@accept_loop_thread = nil
|
21
|
+
@connection_lock = Mutex.new
|
22
|
+
@wakeup_pipe_rd, @wakeup_pipe_wr = IO.pipe
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_main_loop
|
26
|
+
@loop_thread = Thread.new do
|
27
|
+
loop do
|
28
|
+
main_loop
|
29
|
+
end
|
30
|
+
end
|
31
|
+
@loop_thread.abort_on_exception = true
|
32
|
+
end
|
33
|
+
|
34
|
+
def wakeup
|
35
|
+
@wakeup_pipe_wr.puts "wakeup"
|
36
|
+
end
|
37
|
+
|
38
|
+
def main_loop
|
39
|
+
rs, _ws, es = IO.select(@all_connections + [@wakeup_pipe_rd], [], @all_connections)
|
40
|
+
|
41
|
+
es.each do |e|
|
42
|
+
Diameter.logger.log(Logger::WARN, "Exception on connection #{e}")
|
43
|
+
end
|
44
|
+
|
45
|
+
rs.each do |r|
|
46
|
+
if r == @wakeup_pipe_rd
|
47
|
+
r.gets
|
48
|
+
next
|
49
|
+
end
|
50
|
+
|
51
|
+
existing_data = @data[r]
|
52
|
+
if existing_data.length < 4
|
53
|
+
msg, _src = r.recv_nonblock(4 - existing_data.length)
|
54
|
+
if msg == ''
|
55
|
+
Diameter.logger.warn('Received 0 bytes on read, closing connection')
|
56
|
+
close(r)
|
57
|
+
else
|
58
|
+
existing_data += msg
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
expected_len = -1
|
63
|
+
if existing_data.length >= 4
|
64
|
+
expected_len = Message.length_from_header(existing_data[0..4])
|
65
|
+
Diameter.logger.debug("Read 4 bytes #{existing_data[0..4].inspect}, " \
|
66
|
+
"reading full message of length #{expected_len}")
|
67
|
+
msg, _src = r.recv_nonblock(expected_len - existing_data.length)
|
68
|
+
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
|
+
end
|
75
|
+
|
76
|
+
if existing_data.length == expected_len
|
77
|
+
@stack.handle_message(existing_data, r)
|
78
|
+
@data[r] = ''
|
79
|
+
else
|
80
|
+
@data[r] = existing_data
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def send(bytes, connection)
|
86
|
+
connection.send(bytes, 0)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# @private
|
91
|
+
class TCPStackHelper < StackHelper
|
92
|
+
def setup_new_connection(host, port)
|
93
|
+
sd = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
94
|
+
sd.connect(Socket.pack_sockaddr_in(port, host))
|
95
|
+
@all_connections.push sd
|
96
|
+
@data[sd] = ''
|
97
|
+
wakeup
|
98
|
+
sd
|
99
|
+
end
|
100
|
+
|
101
|
+
def shutdown
|
102
|
+
@accept_loop_thread.kill if @accept_loop_thread
|
103
|
+
@loop_thread.kill if @loop_thread
|
104
|
+
|
105
|
+
@all_connections.each { |c| close(c) }
|
106
|
+
@listen_connections.each { |c| close(c) }
|
107
|
+
@all_connections = []
|
108
|
+
@listen_connections = []
|
109
|
+
end
|
110
|
+
|
111
|
+
def close(connection)
|
112
|
+
connection.close
|
113
|
+
@all_connections.delete connection
|
114
|
+
@listen_connections.delete connection
|
115
|
+
@data.delete connection
|
116
|
+
rescue IOError
|
117
|
+
# It's OK if this is already closed
|
118
|
+
end
|
119
|
+
|
120
|
+
def setup_new_listen_connection(host, port)
|
121
|
+
sd = ServerSocket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
122
|
+
# reuse = [1,0].pack('ii')
|
123
|
+
sd.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
|
124
|
+
sd.bind(Socket.pack_sockaddr_in(port, host))
|
125
|
+
sd.listen(100)
|
126
|
+
@listen_connections.push sd
|
127
|
+
@accept_loop_thread = Thread.new do
|
128
|
+
loop do
|
129
|
+
accept_loop
|
130
|
+
end
|
131
|
+
end
|
132
|
+
@accept_loop_thread.abort_on_exception = true
|
133
|
+
end
|
134
|
+
|
135
|
+
def accept_loop
|
136
|
+
rs, _ws, es = IO.select(@listen_connections, [], @listen_connections)
|
137
|
+
es.each do |e|
|
138
|
+
Diameter.logger.log(Logger::WARN, "Exception on connection #{e}")
|
139
|
+
end
|
140
|
+
|
141
|
+
rs.each do |r|
|
142
|
+
sock, addr = r.accept
|
143
|
+
Diameter.logger.debug("Accepting connection from #{addr}")
|
144
|
+
@data[sock] = ''
|
145
|
+
@all_connections.push sock
|
146
|
+
wakeup
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
=begin
|
152
|
+
# @private
|
153
|
+
class SCTPStackHelper
|
154
|
+
def setup_new_connection(host, port)
|
155
|
+
sd = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
156
|
+
sd.connect(Socket.pack_sockaddr_in(port, host))
|
157
|
+
end
|
158
|
+
|
159
|
+
def setup_new_listen_connection(_host, _port)
|
160
|
+
end
|
161
|
+
|
162
|
+
def send(_bytes, _connection)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
=end
|
166
|
+
end
|
167
|
+
end
|
data/lib/diameter/u24.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Diameter
|
2
|
+
module Internals
|
3
|
+
|
4
|
+
# @private
|
5
|
+
# Methods for handling 24-bit unsigned integers, used for length and
|
6
|
+
# Command-Codes but not representable by String#unpack or Array#pack.
|
7
|
+
module UInt24
|
8
|
+
# @api private
|
9
|
+
#
|
10
|
+
# Generates an unsigned integer from two other unsigned integers
|
11
|
+
# (one representing the top 8 bits, one representing the bottom 16
|
12
|
+
# bits).
|
13
|
+
#
|
14
|
+
# @param eightb [Fixnum] The top 8 bits (max 255)
|
15
|
+
# @param sixteenb [Fixnum] The low 16 bits (max 2^16-1)
|
16
|
+
# @return [Fixnum] (max 2^24-1)
|
17
|
+
def self.from_u8_and_u16(eightb, sixteenb)
|
18
|
+
(eightb << 16) + sixteenb
|
19
|
+
end
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
# Converts an unsigned integer to two other unsigned integers (one
|
24
|
+
# representing the top 8 bits, one representing the bottom 16 bits).
|
25
|
+
#
|
26
|
+
# @param twentyfourb [Fixnum] The original number (max 2^24-1)
|
27
|
+
# @return [[Fixnum, Fixnum]] Separate integers representing the
|
28
|
+
# top 8 and low 16 bits.
|
29
|
+
def self.to_u8_and_u16(twentyfourb)
|
30
|
+
top_eight = twentyfourb >> 16
|
31
|
+
bottom_sixteen = twentyfourb - (top_eight << 16)
|
32
|
+
[top_eight, bottom_sixteen]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/diameter.rb
ADDED
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: diameter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.beta
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rob Day
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: concurrent-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.28'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.28'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mocha
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest-spec-context
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.0.3
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.0.3
|
97
|
+
description:
|
98
|
+
email: ruby-diameter@rkd.me.uk
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- lib/diameter.rb
|
104
|
+
- lib/diameter/avp.rb
|
105
|
+
- lib/diameter/avp_parser.rb
|
106
|
+
- lib/diameter/constants.rb
|
107
|
+
- lib/diameter/diameter_logger.rb
|
108
|
+
- lib/diameter/fsm.rb
|
109
|
+
- lib/diameter/message.rb
|
110
|
+
- lib/diameter/peer.rb
|
111
|
+
- lib/diameter/stack.rb
|
112
|
+
- lib/diameter/stack_transport_helpers.rb
|
113
|
+
- lib/diameter/u24.rb
|
114
|
+
homepage: http://rkday.github.io/ruby-diameter/api-docs/master/
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.3.1
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.4.3
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Pure-Ruby Diameter stack
|
138
|
+
test_files: []
|
139
|
+
has_rdoc:
|