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.
@@ -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
@@ -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
@@ -0,0 +1,2 @@
1
+ require 'diameter/stack'
2
+ require 'diameter/message'
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: