stomp 1.2.9 → 1.2.10
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.
- data/CHANGELOG.rdoc +6 -0
- data/README.rdoc +12 -9
- data/examples/slogger.rb +71 -3
- data/examples/ssl_uc1_ciphers.rb +3 -3
- data/examples/ssl_uc2.rb +7 -2
- data/examples/ssl_uc2_ciphers.rb +11 -5
- data/examples/ssl_uc3.rb +8 -2
- data/examples/ssl_uc3_ciphers.rb +12 -6
- data/examples/ssl_uc4.rb +10 -3
- data/examples/ssl_uc4_ciphers.rb +14 -7
- data/lib/connection/heartbeats.rb +123 -31
- data/lib/connection/netio.rb +6 -1
- data/lib/connection/utils.rb +22 -1
- data/lib/stomp/client.rb +2 -0
- data/lib/stomp/connection.rb +33 -3
- data/lib/stomp/errors.rb +12 -5
- data/lib/stomp/version.rb +1 -1
- data/notes/heartbeat_readme.txt +103 -0
- data/spec/client_spec.rb +1 -1
- data/spec/connection_spec.rb +12 -5
- data/stomp.gemspec +3 -2
- data/test/test_connection1p.rb +28 -1
- data/test/tlogger.rb +4 -2
- metadata +5 -4
data/CHANGELOG.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -10,18 +10,19 @@ An implementation of the Stomp protocol for Ruby. See:
|
|
10
10
|
|
11
11
|
===New
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
* Gem version 1.2.
|
16
|
-
* Gem version 1.2.
|
17
|
-
* Gem version 1.2.
|
13
|
+
See _CHANGELOG.rdoc_ for details.
|
14
|
+
|
15
|
+
* Gem version 1.2.10. Support failover from heartbeat threads.
|
16
|
+
* Gem version 1.2.9. Miscellaneous fixes and changes.
|
17
|
+
* Gem version 1.2.8. Stomp 1.1+ header codec inversion fix, test refactoring.
|
18
|
+
* Gem version 1.2.7. Stomp 1.2 support and miscellaneous fixes.
|
19
|
+
* Gem version 1.2.6. Miscellaneous fixes and changes.
|
20
|
+
* Gem version 1.2.5. Restructure. Forks with modifcations will be affected.
|
18
21
|
* Gem version 1.2.4. Stomp 1.1 heartbeat fix, autoflush capability, miscellaneous fixes.
|
19
22
|
* Gem version 1.2.3. Miscellaneous fixes, see changelog for details.
|
20
23
|
* Gem version 1.2.2. Performance and more SSL enhancements.
|
21
|
-
* Full support of SSL certificates
|
22
|
-
* Support of Stomp protocol level 1.1
|
23
|
-
|
24
|
-
See _CHANGELOG.rdoc_ for details.
|
24
|
+
* Gem version 1.2.1. Full support of SSL certificates.
|
25
|
+
* Gem version 1.2.0. Support of Stomp protocol level 1.1.
|
25
26
|
|
26
27
|
===Hash Login Example Usage (this is the recommended login technique)
|
27
28
|
|
@@ -50,6 +51,8 @@ See _CHANGELOG.rdoc_ for details.
|
|
50
51
|
:hbser => false, # raise on heartbeat send exception
|
51
52
|
:stompconn => false, # Use STOMP instead of CONNECT
|
52
53
|
:usecrlf => false, # Use CRLF command and header line ends (1.2+)
|
54
|
+
:max_hbread_fails => 0, # Max HB read fails before retry. 0 => never retry
|
55
|
+
:max_hbrlck_fails => 0, # Max HB read lock obtain fails before retry. 0 => never retry
|
53
56
|
}
|
54
57
|
|
55
58
|
# for client
|
data/examples/slogger.rb
CHANGED
@@ -15,6 +15,14 @@ require 'logger' # use the standard Ruby logger .....
|
|
15
15
|
#
|
16
16
|
# * on_publish: publish called
|
17
17
|
# * on_subscribe: subscribe called
|
18
|
+
# * on_unsubscribe: unsubscribe called
|
19
|
+
#
|
20
|
+
# * on_begin: begin called
|
21
|
+
# * on_ack: ack called
|
22
|
+
# * on_nack: nack called
|
23
|
+
# * on_commit: commit called
|
24
|
+
# * on_abort: abort called
|
25
|
+
#
|
18
26
|
# * on_receive: receive called and successful
|
19
27
|
#
|
20
28
|
# * on_ssl_connecting: SSL connection starting
|
@@ -80,7 +88,7 @@ class Slogger
|
|
80
88
|
=begin
|
81
89
|
# An example LoggerConnectionError raise
|
82
90
|
@log.debug "Connect Fail, will raise"
|
83
|
-
raise Stomp::Error::LoggerConnectionError.new("quit from connect")
|
91
|
+
raise Stomp::Error::LoggerConnectionError.new("quit from connect fail")
|
84
92
|
=end
|
85
93
|
end
|
86
94
|
|
@@ -113,6 +121,16 @@ class Slogger
|
|
113
121
|
end
|
114
122
|
end
|
115
123
|
|
124
|
+
# Log UnSubscribe
|
125
|
+
def on_unsubscribe(parms, headers)
|
126
|
+
begin
|
127
|
+
@log.debug "UnSubscribe Parms #{info(parms)}"
|
128
|
+
@log.debug "UnSubscribe Headers #{headers}"
|
129
|
+
rescue
|
130
|
+
@log.debug "UnSubscribe oops"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
116
134
|
# Log Publish
|
117
135
|
def on_publish(parms, message, headers)
|
118
136
|
begin
|
@@ -134,11 +152,61 @@ class Slogger
|
|
134
152
|
end
|
135
153
|
end
|
136
154
|
|
155
|
+
# Log Begin
|
156
|
+
def on_begin(parms, headers)
|
157
|
+
begin
|
158
|
+
@log.debug "Begin Parms #{info(parms)}"
|
159
|
+
@log.debug "Begin Result #{headers}"
|
160
|
+
rescue
|
161
|
+
@log.debug "Begin oops"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Log Ack
|
166
|
+
def on_ack(parms, headers)
|
167
|
+
begin
|
168
|
+
@log.debug "Ack Parms #{info(parms)}"
|
169
|
+
@log.debug "Ack Result #{headers}"
|
170
|
+
rescue
|
171
|
+
@log.debug "Ack oops"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Log NAck
|
176
|
+
def on_nack(parms, headers)
|
177
|
+
begin
|
178
|
+
@log.debug "NAck Parms #{info(parms)}"
|
179
|
+
@log.debug "NAck Result #{headers}"
|
180
|
+
rescue
|
181
|
+
@log.debug "NAck oops"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Log Commit
|
186
|
+
def on_commit(parms, headers)
|
187
|
+
begin
|
188
|
+
@log.debug "Commit Parms #{info(parms)}"
|
189
|
+
@log.debug "Commit Result #{headers}"
|
190
|
+
rescue
|
191
|
+
@log.debug "Commit oops"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Log Abort
|
196
|
+
def on_abort(parms, headers)
|
197
|
+
begin
|
198
|
+
@log.debug "Abort Parms #{info(parms)}"
|
199
|
+
@log.debug "Abort Result #{headers}"
|
200
|
+
rescue
|
201
|
+
@log.debug "Abort oops"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
137
205
|
# Stomp 1.1+ - heart beat read (receive) failed.
|
138
206
|
def on_hbread_fail(parms, ticker_data)
|
139
207
|
begin
|
140
208
|
@log.debug "Hbreadf Parms #{info(parms)}"
|
141
|
-
@log.debug "Hbreadf Result #{ticker_data}"
|
209
|
+
@log.debug "Hbreadf Result #{ticker_data.inspect}"
|
142
210
|
rescue
|
143
211
|
@log.debug "Hbreadf oops"
|
144
212
|
end
|
@@ -148,7 +216,7 @@ class Slogger
|
|
148
216
|
def on_hbwrite_fail(parms, ticker_data)
|
149
217
|
begin
|
150
218
|
@log.debug "Hbwritef Parms #{info(parms)}"
|
151
|
-
@log.debug "Hbwritef Result #{ticker_data}"
|
219
|
+
@log.debug "Hbwritef Result #{ticker_data.inspect}"
|
152
220
|
rescue
|
153
221
|
@log.debug "Hbwritef oops"
|
154
222
|
end
|
data/examples/ssl_uc1_ciphers.rb
CHANGED
@@ -19,8 +19,7 @@ class ExampleSSL1C
|
|
19
19
|
end
|
20
20
|
# Run example.
|
21
21
|
def run
|
22
|
-
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
|
23
|
-
["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
22
|
+
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
24
23
|
|
25
24
|
ssl_opts = Stomp::SSLParams.new(:ciphers => ciphers_list)
|
26
25
|
|
@@ -29,7 +28,8 @@ class ExampleSSL1C
|
|
29
28
|
#
|
30
29
|
hash = { :hosts => [
|
31
30
|
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
|
32
|
-
]
|
31
|
+
],
|
32
|
+
:reliable => false, # YMMV, to test this in a sane manner
|
33
33
|
}
|
34
34
|
#
|
35
35
|
puts "Connect starts, SSL Use Case 1"
|
data/examples/ssl_uc2.rb
CHANGED
@@ -25,8 +25,13 @@ class ExampleSSL2
|
|
25
25
|
# Run example.
|
26
26
|
def run
|
27
27
|
ts_flist = []
|
28
|
-
|
29
|
-
|
28
|
+
|
29
|
+
# Change the following to the location of your CA's signed certificate.
|
30
|
+
ts_flist << "/home/gmallard/sslwork/2013/TestCA.crt"
|
31
|
+
|
32
|
+
ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","),
|
33
|
+
:fsck => true,
|
34
|
+
)
|
30
35
|
#
|
31
36
|
hash = { :hosts => [
|
32
37
|
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
|
data/examples/ssl_uc2_ciphers.rb
CHANGED
@@ -19,18 +19,24 @@ class ExampleSSL2C
|
|
19
19
|
end
|
20
20
|
# Run example.
|
21
21
|
def run
|
22
|
-
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
|
23
|
-
["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
22
|
+
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
24
23
|
#
|
25
24
|
# SSL Use Case 2
|
26
25
|
#
|
27
26
|
ts_flist = []
|
28
|
-
|
29
|
-
|
27
|
+
|
28
|
+
# Change the following to the location of your CA's signed certificate.
|
29
|
+
ts_flist << "/home/gmallard/sslwork/2013/TestCA.crt"
|
30
|
+
|
31
|
+
ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","),
|
32
|
+
:ciphers => ciphers_list,
|
33
|
+
:fsck => true
|
34
|
+
)
|
30
35
|
#
|
31
36
|
hash = { :hosts => [
|
32
37
|
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
|
33
|
-
]
|
38
|
+
],
|
39
|
+
:reliable => false, # YMMV, to test this in a sane manner
|
34
40
|
}
|
35
41
|
#
|
36
42
|
puts "Connect starts, SSL Use Case 2"
|
data/examples/ssl_uc3.rb
CHANGED
@@ -26,8 +26,14 @@ class ExampleSSL3
|
|
26
26
|
end
|
27
27
|
# Run example.
|
28
28
|
def run
|
29
|
-
|
30
|
-
|
29
|
+
# Change the following:
|
30
|
+
# * location of your client's signed certificate
|
31
|
+
# * location of tour client's private key.
|
32
|
+
ssl_opts = Stomp::SSLParams.new(
|
33
|
+
:key_file => "/home/gmallard/sslwork/2013/client.key", # the client's private key
|
34
|
+
:cert_file => "/home/gmallard/sslwork/2013/client.crt", # the client's signed certificate
|
35
|
+
:fsck => true # Check that the files exist first
|
36
|
+
)
|
31
37
|
|
32
38
|
#
|
33
39
|
hash = { :hosts => [
|
data/examples/ssl_uc3_ciphers.rb
CHANGED
@@ -19,18 +19,24 @@ class ExampleSSL3C
|
|
19
19
|
end
|
20
20
|
# Run example.
|
21
21
|
def run
|
22
|
-
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
|
23
|
-
["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
22
|
+
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
24
23
|
#
|
25
24
|
# SSL Use Case 3
|
26
25
|
#
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
# Change the following:
|
27
|
+
# * location of your client's signed certificate
|
28
|
+
# * location of tour client's private key.
|
29
|
+
ssl_opts = Stomp::SSLParams.new(
|
30
|
+
:key_file => "/home/gmallard/sslwork/2013/client.key", # the client's private key
|
31
|
+
:cert_file => "/home/gmallard/sslwork/2013/client.crt", # the client's signed certificate
|
32
|
+
:fsck => true, # Check that the files exist first
|
33
|
+
:ciphers => ciphers_list
|
34
|
+
)
|
30
35
|
#
|
31
36
|
hash = { :hosts => [
|
32
37
|
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
|
33
|
-
]
|
38
|
+
],
|
39
|
+
:reliable => false, # YMMV, to test this in a sane manner
|
34
40
|
}
|
35
41
|
#
|
36
42
|
puts "Connect starts, SSL Use Case 3"
|
data/examples/ssl_uc4.rb
CHANGED
@@ -26,9 +26,16 @@ class ExampleSSL4
|
|
26
26
|
end
|
27
27
|
# Run example.
|
28
28
|
def run
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
# Change the following:
|
30
|
+
# * location of the client's private key
|
31
|
+
# * location of the client's signed certificate
|
32
|
+
# * location of the server's CA signed certificate
|
33
|
+
ssl_opts = Stomp::SSLParams.new(
|
34
|
+
:key_file => "/home/gmallard/sslwork/2013/client.key", # The client's private key
|
35
|
+
:cert_file => "/home/gmallard/sslwork/2013/client.crt", # The client's signed certificate
|
36
|
+
:ts_files => "/home/gmallard/sslwork/2013/TestCA.crt", # The CA's signed sertificate
|
37
|
+
:fsck => true # Check that files exist first
|
38
|
+
)
|
32
39
|
#
|
33
40
|
hash = { :hosts => [
|
34
41
|
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
|
data/examples/ssl_uc4_ciphers.rb
CHANGED
@@ -19,19 +19,26 @@ class ExampleSSL4C
|
|
19
19
|
end
|
20
20
|
# Run example.
|
21
21
|
def run
|
22
|
-
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
|
23
|
-
["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
22
|
+
ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
|
24
23
|
#
|
25
24
|
# SSL Use Case 4
|
26
25
|
#
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
# Change the following:
|
27
|
+
# * location of the client's private key
|
28
|
+
# * location of the client's signed certificate
|
29
|
+
# * location of the server's CA signed certificate
|
30
|
+
ssl_opts = Stomp::SSLParams.new(
|
31
|
+
:key_file => "/home/gmallard/sslwork/2013/client.key", # The client's private key
|
32
|
+
:cert_file => "/home/gmallard/sslwork/2013/client.crt", # The client's signed certificate
|
33
|
+
:ts_files => "/home/gmallard/sslwork/2013/TestCA.crt", # The CA's signed sertificate
|
34
|
+
:fsck => true, # Check that files exist first
|
35
|
+
:ciphers => ciphers_list
|
36
|
+
)
|
31
37
|
#
|
32
38
|
hash = { :hosts => [
|
33
39
|
{:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
|
34
|
-
]
|
40
|
+
],
|
41
|
+
:reliable => false, # YMMV, to test this in a sane manner
|
35
42
|
}
|
36
43
|
#
|
37
44
|
puts "Connect starts, SSL Use Case 4"
|
@@ -90,15 +90,17 @@ module Stomp
|
|
90
90
|
# _start_send_ticker starts a thread to send heartbeats when required.
|
91
91
|
def _start_send_ticker()
|
92
92
|
sleeptime = @hbsend_interval / 1000000.0 # Sleep time secs
|
93
|
+
reconn = false
|
93
94
|
@st = Thread.new {
|
94
95
|
while true do
|
95
96
|
sleep sleeptime
|
97
|
+
next unless @socket # nil under some circumstances ??
|
96
98
|
curt = Time.now.to_f
|
97
99
|
if @logger && @logger.respond_to?(:on_hbfire)
|
98
100
|
@logger.on_hbfire(log_params, "send_fire", curt)
|
99
101
|
end
|
100
102
|
delta = curt - @ls
|
101
|
-
if delta >
|
103
|
+
if delta > sleeptime
|
102
104
|
if @logger && @logger.respond_to?(:on_hbfire)
|
103
105
|
@logger.on_hbfire(log_params, "send_heartbeat", curt)
|
104
106
|
end
|
@@ -106,19 +108,31 @@ module Stomp
|
|
106
108
|
@transmit_semaphore.synchronize do
|
107
109
|
begin
|
108
110
|
@socket.puts
|
109
|
-
@
|
110
|
-
@
|
111
|
+
@socket.flush # Do not buffer heartbeats
|
112
|
+
@ls = Time.now.to_f # Update last send
|
113
|
+
@hb_sent = true # Reset if necessary
|
111
114
|
@hbsend_count += 1
|
112
115
|
rescue Exception => sendex
|
113
116
|
@hb_sent = false # Set the warning flag
|
114
117
|
if @logger && @logger.respond_to?(:on_hbwrite_fail)
|
115
|
-
@logger.on_hbwrite_fail(log_params, {"ticker_interval" =>
|
118
|
+
@logger.on_hbwrite_fail(log_params, {"ticker_interval" => sleeptime,
|
116
119
|
"exception" => sendex})
|
117
120
|
end
|
118
121
|
if @hbser
|
119
122
|
raise # Re-raise if user requested this, otherwise ignore
|
120
123
|
end
|
124
|
+
if @reliable
|
125
|
+
reconn = true
|
126
|
+
break # exit the synchronize do
|
127
|
+
end
|
121
128
|
end
|
129
|
+
end # of the synchronize
|
130
|
+
if reconn
|
131
|
+
# Attempt a fail over reconnect. This is 'safe' here because
|
132
|
+
# this thread no longer holds the @transmit_semaphore lock.
|
133
|
+
@rt.kill if @rt # Kill the receiver thread if one exists
|
134
|
+
_reconn_prep_hb() # Drive reconnection logic
|
135
|
+
Thread.exit # This sender thread is done
|
122
136
|
end
|
123
137
|
end
|
124
138
|
Thread.pass
|
@@ -129,44 +143,122 @@ module Stomp
|
|
129
143
|
# _start_receive_ticker starts a thread that receives heartbeats when required.
|
130
144
|
def _start_receive_ticker()
|
131
145
|
sleeptime = @hbrecv_interval / 1000000.0 # Sleep time secs
|
146
|
+
read_fail_count = 0
|
147
|
+
lock_fail_count = 0
|
148
|
+
fail_hard = false
|
132
149
|
@rt = Thread.new {
|
150
|
+
|
151
|
+
#
|
133
152
|
while true do
|
134
153
|
sleep sleeptime
|
154
|
+
next unless @socket # nil under some circumstances ??
|
155
|
+
rdrdy = @socket.ready? ? true : false
|
135
156
|
curt = Time.now.to_f
|
136
157
|
if @logger && @logger.respond_to?(:on_hbfire)
|
137
158
|
@logger.on_hbfire(log_params, "receive_fire", curt)
|
138
159
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
lock = @read_semaphore.try_lock
|
147
|
-
if lock
|
148
|
-
last_char = @socket.getc
|
149
|
-
plc = parse_char(last_char)
|
150
|
-
if plc == "\n" # Server Heartbeat
|
151
|
-
@lr = Time.now.to_f
|
152
|
-
else
|
153
|
-
@socket.ungetc(last_char)
|
160
|
+
|
161
|
+
#
|
162
|
+
begin
|
163
|
+
delta = curt - @lr
|
164
|
+
if delta > sleeptime
|
165
|
+
if @logger && @logger.respond_to?(:on_hbfire)
|
166
|
+
@logger.on_hbfire(log_params, "receive_heartbeat", curt)
|
154
167
|
end
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
@
|
168
|
+
|
169
|
+
# Client code could be off doing something else (that is, no reading of
|
170
|
+
# the socket has been requested by the caller). Try to handle that case.
|
171
|
+
lock = @read_semaphore.try_lock
|
172
|
+
if lock
|
173
|
+
lock_fail_count = 0 # clear
|
174
|
+
rdrdy = @socket.ready? ? true : false # This logic will be bad for JRuby I think
|
175
|
+
if rdrdy
|
176
|
+
read_fail_count = 0 # clear
|
177
|
+
last_char = @socket.getc
|
178
|
+
if last_char.nil? # EOF from broker?
|
179
|
+
fail_hard = true
|
180
|
+
else
|
181
|
+
@lr = Time.now.to_f
|
182
|
+
plc = parse_char(last_char)
|
183
|
+
if plc == "\n" # Server Heartbeat
|
184
|
+
@hbrecv_count += 1
|
185
|
+
@hb_received = true # Reset if necessary
|
186
|
+
else
|
187
|
+
@socket.ungetc(last_char)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
@read_semaphore.unlock # Release read lock
|
191
|
+
else # Socket is not ready
|
192
|
+
@read_semaphore.unlock # Release read lock
|
193
|
+
@hb_received = false
|
194
|
+
read_fail_count += 1
|
195
|
+
if @logger && @logger.respond_to?(:on_hbread_fail)
|
196
|
+
@logger.on_hbread_fail(log_params, {"ticker_interval" => sleeptime,
|
197
|
+
"read_fail_count" => read_fail_count, "lock_fail" => false,
|
198
|
+
"lock_fail_count" => lock_fail_count})
|
199
|
+
end
|
200
|
+
end
|
201
|
+
else # try_lock failed
|
202
|
+
# Shrug. Could not get lock. Client must be actually be reading.
|
203
|
+
@hb_received = false
|
204
|
+
# But notify caller if possible
|
205
|
+
lock_fail_count += 1
|
206
|
+
if @logger && @logger.respond_to?(:on_hbread_fail)
|
207
|
+
@logger.on_hbread_fail(log_params, {"ticker_interval" => sleeptime,
|
208
|
+
"read_fail_count" => read_fail_count, "lock_fail" => true,
|
209
|
+
"lock_fail_count" => lock_fail_count})
|
210
|
+
end
|
211
|
+
end # of the try_lock
|
212
|
+
|
213
|
+
else # delta <= sleeptime
|
214
|
+
@hb_received = true # Reset if necessary
|
215
|
+
read_fail_count = 0 # reset
|
216
|
+
lock_fail_count = 0 # reset
|
217
|
+
end # of the if delta > sleeptime
|
218
|
+
rescue Exception => recvex
|
219
|
+
if @logger && @logger.respond_to?(:on_hbread_fail)
|
220
|
+
@logger.on_hbread_fail(log_params, {"ticker_interval" => sleeptime,
|
221
|
+
"exception" => recvex, "read_fail_count" => read_fail_count,
|
222
|
+
"lock_fail_count" => lock_fail_count})
|
223
|
+
end
|
224
|
+
fail_hard = true
|
225
|
+
end
|
226
|
+
|
227
|
+
# Do we want to attempt a retry?
|
228
|
+
if @reliable
|
229
|
+
# Retry on hard fail or max read fails
|
230
|
+
if fail_hard ||
|
231
|
+
(@max_hbread_fails > 0 && read_fail_count >= @max_hbread_fails)
|
232
|
+
# This is an attempt at a connection retry.
|
233
|
+
@st.kill if @st # Kill the sender thread if one exists
|
234
|
+
_reconn_prep_hb() # Drive reconnection logic
|
235
|
+
Thread.exit # This receiver thread is done
|
236
|
+
end
|
237
|
+
# Retry on max lock fails. Different logic in order to avoid a deadlock.
|
238
|
+
if (@max_hbrlck_fails > 0 && lock_fail_count >= @max_hbrlck_fails)
|
239
|
+
# This is an attempt at a connection retry.
|
240
|
+
begin
|
241
|
+
@socket.close # Attempt a forced close
|
242
|
+
rescue
|
162
243
|
end
|
244
|
+
@st.kill if @st # Kill the sender thread if one exists
|
245
|
+
Thread.exit # This receiver thread is done
|
163
246
|
end
|
164
|
-
else
|
165
|
-
@hb_received = true # Reset if necessary
|
166
247
|
end
|
167
|
-
|
168
|
-
|
169
|
-
|
248
|
+
|
249
|
+
Thread.pass # Prior to next receive loop
|
250
|
+
#
|
251
|
+
end # of the "while true"
|
252
|
+
} # end of the Thread.new
|
253
|
+
end
|
254
|
+
|
255
|
+
# _reconn_prep_hb prepares for a reconnect retry
|
256
|
+
def _reconn_prep_hb()
|
257
|
+
if @parameters
|
258
|
+
change_host()
|
259
|
+
end
|
260
|
+
@socket = nil
|
261
|
+
used_socket = socket()
|
170
262
|
end
|
171
263
|
|
172
264
|
end # class Connection
|
data/lib/connection/netio.rb
CHANGED
@@ -124,6 +124,8 @@ module Stomp
|
|
124
124
|
else
|
125
125
|
$stderr.print errstr
|
126
126
|
end
|
127
|
+
# !!! This loop initiates a re-connect !!!
|
128
|
+
_reconn_prep()
|
127
129
|
end
|
128
130
|
end
|
129
131
|
end
|
@@ -275,6 +277,7 @@ module Stomp
|
|
275
277
|
|
276
278
|
Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
|
277
279
|
ssl = OpenSSL::SSL::SSLSocket.new(open_tcp_socket, ctx)
|
280
|
+
ssl.sync_close = true # Sync ssl close with underlying TCP socket
|
278
281
|
ssl.connect
|
279
282
|
end
|
280
283
|
def ssl.ready?
|
@@ -351,7 +354,9 @@ module Stomp
|
|
351
354
|
@disconnect_receipt = nil
|
352
355
|
@session = @connection_frame.headers["session"] if @connection_frame
|
353
356
|
# replay any subscriptions.
|
354
|
-
@subscriptions.each {
|
357
|
+
@subscriptions.each {|k,v|
|
358
|
+
_transmit(used_socket, Stomp::CMD_SUBSCRIBE, v)
|
359
|
+
}
|
355
360
|
end
|
356
361
|
|
357
362
|
end # class Connection
|
data/lib/connection/utils.rb
CHANGED
@@ -53,6 +53,7 @@ module Stomp
|
|
53
53
|
lparms[:cur_recondelay] = @reconnect_delay
|
54
54
|
lparms[:cur_parseto] = @parse_timeout
|
55
55
|
lparms[:cur_conattempts] = @connection_attempts
|
56
|
+
lparms[:cur_failure] = @failure # To assist in debugging
|
56
57
|
lparms[:openstat] = open?
|
57
58
|
#
|
58
59
|
lparms
|
@@ -122,9 +123,15 @@ module Stomp
|
|
122
123
|
rescue
|
123
124
|
@failure = $!
|
124
125
|
used_socket = nil
|
126
|
+
@closed = true
|
127
|
+
|
125
128
|
raise unless @reliable
|
126
129
|
raise if @failure.is_a?(Stomp::Error::LoggerConnectionError)
|
127
|
-
|
130
|
+
# Catch errors which are:
|
131
|
+
# a) emitted from corrupted 1.1+ 'connect' (caller programming error)
|
132
|
+
# b) should never be retried
|
133
|
+
raise if @failure.is_a?(Stomp::Error::ProtocolError11p)
|
134
|
+
|
128
135
|
if @logger && @logger.respond_to?(:on_connectfail)
|
129
136
|
# on_connectfail may raise
|
130
137
|
begin
|
@@ -172,6 +179,8 @@ module Stomp
|
|
172
179
|
:closed_check => true,
|
173
180
|
:hbser => false,
|
174
181
|
:stompconn => false,
|
182
|
+
:max_hbread_fails => 0,
|
183
|
+
:max_hbrlck_fails => 0,
|
175
184
|
}
|
176
185
|
|
177
186
|
res_params = default_params.merge(params)
|
@@ -229,10 +238,22 @@ module Stomp
|
|
229
238
|
else
|
230
239
|
$stderr.print errstr
|
231
240
|
end
|
241
|
+
# !!! This initiates a re-connect !!!
|
242
|
+
_reconn_prep()
|
232
243
|
end
|
233
244
|
end
|
234
245
|
end
|
235
246
|
|
247
|
+
# _reconn_prep prepares for a reconnect retry
|
248
|
+
def _reconn_prep()
|
249
|
+
if @parameters
|
250
|
+
change_host()
|
251
|
+
end
|
252
|
+
@st.kill if @st # Kill ticker thread if any
|
253
|
+
@rt.kill if @rt # Kill ticker thread if any
|
254
|
+
@socket = nil
|
255
|
+
end
|
256
|
+
|
236
257
|
end # class Connection
|
237
258
|
|
238
259
|
end # module Stomp
|
data/lib/stomp/client.rb
CHANGED
data/lib/stomp/connection.rb
CHANGED
@@ -65,6 +65,8 @@ module Stomp
|
|
65
65
|
# :hbser => false,
|
66
66
|
# :stompconn => false,
|
67
67
|
# :usecrlf => false,
|
68
|
+
# :max_hbread_fails => 0,
|
69
|
+
# :max_hbrlck_fails => 0,
|
68
70
|
# }
|
69
71
|
#
|
70
72
|
# e.g. c = Stomp::Connection.new(hash)
|
@@ -106,6 +108,8 @@ module Stomp
|
|
106
108
|
@hbser = false # Raise if heartbeat send exception
|
107
109
|
@stompconn = false # If true, use STOMP rather than CONNECT
|
108
110
|
@usecrlf = false # If true, use \r\n as line ends (1.2 only)
|
111
|
+
@max_hbread_fails = 0 # 0 means never retry for HB read failures
|
112
|
+
@max_hbrlck_fails = 0 # 0 means never retry for HB read lock failures
|
109
113
|
warn "login looks like a URL, do you have the correct parameters?" if @login =~ /:\/\//
|
110
114
|
end
|
111
115
|
|
@@ -138,6 +142,8 @@ module Stomp
|
|
138
142
|
@hbser = @parameters[:hbser]
|
139
143
|
@stompconn = @parameters[:stompconn]
|
140
144
|
@usecrlf = @parameters[:usecrlf]
|
145
|
+
@max_hbread_fails = @parameters[:max_hbread_fails]
|
146
|
+
@max_hbrlck_fails = @parameters[:max_hbrlck_fails]
|
141
147
|
#sets the first host to connect
|
142
148
|
change_host
|
143
149
|
end
|
@@ -163,6 +169,9 @@ module Stomp
|
|
163
169
|
headers = headers.symbolize_keys
|
164
170
|
headers[:transaction] = name
|
165
171
|
_headerCheck(headers)
|
172
|
+
if @logger && @logger.respond_to?(:on_begin)
|
173
|
+
@logger.on_begin(log_params, headers)
|
174
|
+
end
|
166
175
|
transmit(Stomp::CMD_BEGIN, headers)
|
167
176
|
end
|
168
177
|
|
@@ -193,6 +202,9 @@ module Stomp
|
|
193
202
|
headers[:'message-id'] = message_id
|
194
203
|
end
|
195
204
|
_headerCheck(headers)
|
205
|
+
if @logger && @logger.respond_to?(:on_ack)
|
206
|
+
@logger.on_ack(log_params, headers)
|
207
|
+
end
|
196
208
|
transmit(Stomp::CMD_ACK, headers)
|
197
209
|
end
|
198
210
|
|
@@ -216,6 +228,9 @@ module Stomp
|
|
216
228
|
raise Stomp::Error::SubscriptionRequiredError unless headers[:subscription]
|
217
229
|
end
|
218
230
|
_headerCheck(headers)
|
231
|
+
if @logger && @logger.respond_to?(:on_nack)
|
232
|
+
@logger.on_nack(log_params, headers)
|
233
|
+
end
|
219
234
|
transmit(Stomp::CMD_NACK, headers)
|
220
235
|
end
|
221
236
|
|
@@ -225,6 +240,9 @@ module Stomp
|
|
225
240
|
headers = headers.symbolize_keys
|
226
241
|
headers[:transaction] = name
|
227
242
|
_headerCheck(headers)
|
243
|
+
if @logger && @logger.respond_to?(:on_commit)
|
244
|
+
@logger.on_commit(log_params, headers)
|
245
|
+
end
|
228
246
|
transmit(Stomp::CMD_COMMIT, headers)
|
229
247
|
end
|
230
248
|
|
@@ -234,6 +252,9 @@ module Stomp
|
|
234
252
|
headers = headers.symbolize_keys
|
235
253
|
headers[:transaction] = name
|
236
254
|
_headerCheck(headers)
|
255
|
+
if @logger && @logger.respond_to?(:on_abort)
|
256
|
+
@logger.on_abort(log_params, headers)
|
257
|
+
end
|
237
258
|
transmit(Stomp::CMD_ABORT, headers)
|
238
259
|
end
|
239
260
|
|
@@ -270,8 +291,12 @@ module Stomp
|
|
270
291
|
headers[:destination] = dest
|
271
292
|
if @protocol >= Stomp::SPL_11
|
272
293
|
raise Stomp::Error::SubscriptionRequiredError if (headers[:id].nil? && subId.nil?)
|
294
|
+
headers[:id] = subId unless headers[:id]
|
273
295
|
end
|
274
296
|
_headerCheck(headers)
|
297
|
+
if @logger && @logger.respond_to?(:on_unsubscribe)
|
298
|
+
@logger.on_unsubscribe(log_params, headers)
|
299
|
+
end
|
275
300
|
transmit(Stomp::CMD_UNSUBSCRIBE, headers)
|
276
301
|
if @reliable
|
277
302
|
subId = dest if subId.nil?
|
@@ -369,7 +394,7 @@ module Stomp
|
|
369
394
|
# receive returns the next Message off of the wire.
|
370
395
|
def receive()
|
371
396
|
raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
|
372
|
-
super_result = __old_receive
|
397
|
+
super_result = __old_receive()
|
373
398
|
if super_result.nil? && @reliable && !closed?
|
374
399
|
errstr = "connection.receive returning EOF as nil - resetting connection.\n"
|
375
400
|
if @logger && @logger.respond_to?(:on_miscerr)
|
@@ -377,8 +402,13 @@ module Stomp
|
|
377
402
|
else
|
378
403
|
$stderr.print errstr
|
379
404
|
end
|
380
|
-
|
381
|
-
|
405
|
+
# !!! This initiates a re-connect !!!
|
406
|
+
# The call to __old_receive() will in turn call socket(). Before
|
407
|
+
# that we should change the target host, otherwise the host that
|
408
|
+
# just failed may be attempted first.
|
409
|
+
_reconn_prep()
|
410
|
+
#
|
411
|
+
super_result = __old_receive()
|
382
412
|
end
|
383
413
|
#
|
384
414
|
if @logger && @logger.respond_to?(:on_receive)
|
data/lib/stomp/errors.rb
CHANGED
@@ -71,17 +71,24 @@ module Stomp
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
# ProtocolError11p - base class of 1.1 CONNECT errors
|
75
|
+
class ProtocolError11p < RuntimeError
|
76
|
+
def message
|
77
|
+
"STOMP 1.1+ CONNECT error"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
74
81
|
# ProtocolErrorConnect is raised if:
|
75
|
-
# * Incomplete Stomp 1.1 headers are
|
76
|
-
class ProtocolErrorConnect <
|
82
|
+
# * Incomplete Stomp 1.1 headers are detected during a connect.
|
83
|
+
class ProtocolErrorConnect < ProtocolError11p
|
77
84
|
def message
|
78
|
-
"
|
85
|
+
"STOMP 1.1+ CONNECT error, missing/incorrect CONNECT headers"
|
79
86
|
end
|
80
87
|
end
|
81
88
|
|
82
89
|
# UnsupportedProtocolError is raised if:
|
83
90
|
# * No supported Stomp protocol levels are detected during a connect.
|
84
|
-
class UnsupportedProtocolError <
|
91
|
+
class UnsupportedProtocolError < ProtocolError11p
|
85
92
|
def message
|
86
93
|
"unsupported protocol level(s)"
|
87
94
|
end
|
@@ -89,7 +96,7 @@ module Stomp
|
|
89
96
|
|
90
97
|
# InvalidHeartBeatHeaderError is raised if:
|
91
98
|
# * A "heart-beat" header is present, but the values are malformed.
|
92
|
-
class InvalidHeartBeatHeaderError <
|
99
|
+
class InvalidHeartBeatHeaderError < ProtocolError11p
|
93
100
|
def message
|
94
101
|
"heart-beat header value is malformed"
|
95
102
|
end
|
data/lib/stomp/version.rb
CHANGED
@@ -0,0 +1,103 @@
|
|
1
|
+
Usage notes and comments follow (sorry for the length here, please read carefully).
|
2
|
+
|
3
|
+
Write failures: there is a single type of write failure, and it occurs when
|
4
|
+
an exception of some sort is raised during Heartbeat write.
|
5
|
+
This is the only type of write failure that can be detected.
|
6
|
+
If :reliable is true, an exception on heartbeat write will always causes a fail
|
7
|
+
over attempt.
|
8
|
+
|
9
|
+
Read failures: this is actually more complex than originally envisioned.
|
10
|
+
There are really three distinct types of read 'failures':
|
11
|
+
|
12
|
+
1) An exception is thrown during Heartbeat read. If :reliable is true, this
|
13
|
+
always causes a fail over attempt.
|
14
|
+
|
15
|
+
2) Heartbeat reads can not obtain the read_semaphore lock. This will occur
|
16
|
+
when the main connection thread has:
|
17
|
+
-- Called Connection#receive
|
18
|
+
-- Only heartbeats but no Stomp frames are on the inbound wire
|
19
|
+
-- Last Heartbeat read time is being maintained by the #receive attempt
|
20
|
+
|
21
|
+
3) Heartbeat reads obtain the read_semaphore lock, but the socket shows no
|
22
|
+
data is available (by IO#ready?). This will occur when:
|
23
|
+
-- The main thread has not called Connection#receive (the thread is doing other work)
|
24
|
+
-- There is no heartbeat to receive (IO#ready? indicates no input data available)
|
25
|
+
|
26
|
+
The requirement to handle cases 2) and 3) results in not one, but two different
|
27
|
+
counters being taken in to consideration.
|
28
|
+
|
29
|
+
To handle case 2) add to the connect hash:
|
30
|
+
|
31
|
+
:max_hbrlck_fails => x # x is a number strictly greater than 0. Default is 0,
|
32
|
+
which disables the functionality.
|
33
|
+
|
34
|
+
A running count of this failure type is maintained in the HB read thread. The
|
35
|
+
count is incremented when:
|
36
|
+
|
37
|
+
-- Lock obtain fails, *and*
|
38
|
+
-- A heartbeat is 'late'
|
39
|
+
|
40
|
+
The count is reset to 0 whenever:
|
41
|
+
|
42
|
+
-- A heart beat has been received on a timely basis
|
43
|
+
|
44
|
+
When the running count *reaches* the value specified in :max_hbrlck_fails, a
|
45
|
+
fail over attempt is initiated.
|
46
|
+
|
47
|
+
Advice: do *not* set this to 1 (in order to avoid fail overs on a transient
|
48
|
+
error).
|
49
|
+
|
50
|
+
To handle case 3) add to the connect hash:
|
51
|
+
|
52
|
+
:max_hbread_fails => y # y is a number strictly greater than 0. Default is 0,
|
53
|
+
which disables the functionality.
|
54
|
+
|
55
|
+
A running count of this failure type is maintained in the HB read thread.
|
56
|
+
The count is incremented when:
|
57
|
+
|
58
|
+
-- Lock obtain succeeds, *and*
|
59
|
+
-- IO#ready? indicates no data available
|
60
|
+
|
61
|
+
The count is reset to 0 under two conditions:
|
62
|
+
|
63
|
+
Condition 1)
|
64
|
+
-- A heartbeat is late, *and*
|
65
|
+
-- Lock obtain succeeds, *and*
|
66
|
+
-- IO#ready? indicates data is available, *and*
|
67
|
+
-- A single character is read from the wire
|
68
|
+
|
69
|
+
Condition 2)
|
70
|
+
-- A heartbeat has been received in a timely manner (perhaps by the main thread)
|
71
|
+
|
72
|
+
When the running count *reaches* the value specified in :max_hbread_fails,
|
73
|
+
a fail over attempt is initiated.
|
74
|
+
|
75
|
+
Advice: do *not* set this to 1 (in order to avoid fail overs on a transient
|
76
|
+
error).
|
77
|
+
|
78
|
+
-----------------------------------------------------------
|
79
|
+
|
80
|
+
General notes:
|
81
|
+
|
82
|
+
In your real world apps, think about whether one or both of these parameters
|
83
|
+
are appropriate.
|
84
|
+
|
85
|
+
Please add the:
|
86
|
+
|
87
|
+
-- on_hbread_fail
|
88
|
+
-- on_hbwrite_fail
|
89
|
+
|
90
|
+
methods to a callback logger. In those methods show 'ticker_data.inspect'
|
91
|
+
output. We would want that log output in future problem reports.
|
92
|
+
|
93
|
+
We make the comment about not setting these values to 1 because every server
|
94
|
+
we test with is prone to transient (single event) failures, particularly for
|
95
|
+
client HB reads.
|
96
|
+
|
97
|
+
We have done a variety of informal tests here, using both server kill and
|
98
|
+
packet drop strategies as appropriate. We believe more real world testing is
|
99
|
+
required.
|
100
|
+
|
101
|
+
We already know that the use of IO#ready? will diminish (probably break) JRuby
|
102
|
+
functionality.
|
103
|
+
|
data/spec/client_spec.rb
CHANGED
@@ -302,7 +302,7 @@ describe Stomp::Client do
|
|
302
302
|
|
303
303
|
url = "failover:(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)?#{query}"
|
304
304
|
|
305
|
-
#
|
305
|
+
#
|
306
306
|
@parameters = {
|
307
307
|
:initial_reconnect_delay => 5.0,
|
308
308
|
:max_reconnect_delay => 60.0,
|
data/spec/connection_spec.rb
CHANGED
@@ -25,7 +25,9 @@ describe Stomp::Connection do
|
|
25
25
|
:hbser => false,
|
26
26
|
:stompconn => false,
|
27
27
|
:usecrlf => false,
|
28
|
-
|
28
|
+
:max_hbread_fails => 0,
|
29
|
+
:max_hbrlck_fails => 0,
|
30
|
+
}
|
29
31
|
|
30
32
|
#POG:
|
31
33
|
class Stomp::Connection
|
@@ -90,6 +92,8 @@ describe Stomp::Connection do
|
|
90
92
|
"connect_timeout" => 0,
|
91
93
|
"parse_timeout" => 5,
|
92
94
|
"usecrlf" => false,
|
95
|
+
:max_hbread_fails => 0,
|
96
|
+
:max_hbrlck_fails => 0,
|
93
97
|
}
|
94
98
|
|
95
99
|
@connection = Stomp::Connection.new(used_hash)
|
@@ -338,6 +342,8 @@ describe Stomp::Connection do
|
|
338
342
|
:closed_check => true,
|
339
343
|
:hbser => false,
|
340
344
|
:stompconn => false,
|
345
|
+
:max_hbread_fails => 0,
|
346
|
+
:max_hbrlck_fails => 0,
|
341
347
|
}
|
342
348
|
|
343
349
|
used_hash = {
|
@@ -363,7 +369,6 @@ describe Stomp::Connection do
|
|
363
369
|
:back_off_multiplier => 3,
|
364
370
|
:max_reconnect_attempts => 10,
|
365
371
|
:randomize => true,
|
366
|
-
:backup => false,
|
367
372
|
:reliable => false,
|
368
373
|
:connect_timeout => 0,
|
369
374
|
:parse_timeout => 20,
|
@@ -372,9 +377,11 @@ describe Stomp::Connection do
|
|
372
377
|
:max_redeliveries => 10,
|
373
378
|
:dmh => false,
|
374
379
|
:closed_check => true,
|
375
|
-
:hbser =>
|
376
|
-
:stompconn =>
|
377
|
-
:usecrlf =>
|
380
|
+
:hbser => true,
|
381
|
+
:stompconn => true,
|
382
|
+
:usecrlf => true,
|
383
|
+
:max_hbread_fails => 123,
|
384
|
+
:max_hbrlck_fails => 456,
|
378
385
|
}
|
379
386
|
|
380
387
|
@connection = Stomp::Connection.new(used_hash)
|
data/stomp.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{stomp}
|
8
|
-
s.version = "1.2.
|
8
|
+
s.version = "1.2.10"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Brian McCallister", "Marius Mathiesen", "Thiago Morello", "Guy M. Allard"]
|
12
|
-
s.date = %q{2013-
|
12
|
+
s.date = %q{2013-07-08}
|
13
13
|
s.description = %q{Ruby client for the Stomp messaging protocol. Note that this gem is no longer supported on rubyforge.}
|
14
14
|
s.email = ["brianm@apache.org", "marius@stones.com", "morellon@gmail.com", "allard.guy.m@gmail.com"]
|
15
15
|
s.executables = ["catstomp", "stompcat"]
|
@@ -115,6 +115,7 @@ Gem::Specification.new do |s|
|
|
115
115
|
"lib/stomp/message.rb",
|
116
116
|
"lib/stomp/sslparams.rb",
|
117
117
|
"lib/stomp/version.rb",
|
118
|
+
"notes/heartbeat_readme.txt",
|
118
119
|
"spec/client_shared_examples.rb",
|
119
120
|
"spec/client_spec.rb",
|
120
121
|
"spec/connection_spec.rb",
|
data/test/test_connection1p.rb
CHANGED
@@ -28,7 +28,7 @@ class TestConnection1P < Test::Unit::TestCase
|
|
28
28
|
assert @conn.open?
|
29
29
|
end
|
30
30
|
|
31
|
-
# Test missing connect headers.
|
31
|
+
# Test missing connect headers - part 1.
|
32
32
|
def test_conn_1p_0010
|
33
33
|
@conn.disconnect
|
34
34
|
#
|
@@ -43,6 +43,33 @@ class TestConnection1P < Test::Unit::TestCase
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
# Test missing connect headers - part 2.
|
47
|
+
def test_conn_1p_0015
|
48
|
+
@conn.disconnect
|
49
|
+
#
|
50
|
+
cha = {:host => "localhost"}
|
51
|
+
hash = { :hosts => [
|
52
|
+
{:login => user, :passcode => passcode, :host => host, :port => port, :ssl => nil},
|
53
|
+
],
|
54
|
+
:reliable => true, # Note, issue #57 discussion
|
55
|
+
:connect_headers => cha,
|
56
|
+
:stompconn => get_stomp_conn(),
|
57
|
+
:usecrlf => get_crlf(),
|
58
|
+
:initial_reconnect_delay => 0.1,
|
59
|
+
:max_reconnect_delay => 30,
|
60
|
+
:use_exponential_back_off => true,
|
61
|
+
:back_off_multiplier => 2,
|
62
|
+
:max_reconnect_attempts => 10,
|
63
|
+
}
|
64
|
+
assert_raise Stomp::Error::ProtocolErrorConnect do
|
65
|
+
conn = Stomp::Connection.open(hash)
|
66
|
+
end
|
67
|
+
hash[:connect_headers] = {"accept-version" => "1.1"}
|
68
|
+
assert_raise Stomp::Error::ProtocolErrorConnect do
|
69
|
+
conn = Stomp::Connection.open(hash)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
46
73
|
# Test requesting only a 1.0 connection.
|
47
74
|
def test_conn_1p_0020
|
48
75
|
@conn.disconnect
|
data/test/tlogger.rb
CHANGED
@@ -6,6 +6,8 @@ require 'logger' # use the standard Ruby logger .....
|
|
6
6
|
|
7
7
|
Callback logger for Stomp 1.1+ heartbeat tests.
|
8
8
|
|
9
|
+
See the examples directory for a more robust logger example.
|
10
|
+
|
9
11
|
=end
|
10
12
|
class Tlogger
|
11
13
|
|
@@ -31,7 +33,7 @@ class Tlogger
|
|
31
33
|
def on_hbwrite_fail(parms, ticker_data)
|
32
34
|
begin
|
33
35
|
@log.debug "Hbwritef Parms #{info(parms)}"
|
34
|
-
@log.debug "Hbwritef Result #{ticker_data}"
|
36
|
+
@log.debug "Hbwritef Result #{ticker_data.inspect}"
|
35
37
|
rescue
|
36
38
|
@log.debug "Hbwritef oops"
|
37
39
|
end
|
@@ -42,7 +44,7 @@ class Tlogger
|
|
42
44
|
def on_hbread_fail(parms, ticker_data)
|
43
45
|
begin
|
44
46
|
@log.debug "Hbreadf Parms #{info(parms)}"
|
45
|
-
@log.debug "Hbreadf Result #{ticker_data}"
|
47
|
+
@log.debug "Hbreadf Result #{ticker_data.inspect}"
|
46
48
|
rescue
|
47
49
|
@log.debug "Hbreadf oops"
|
48
50
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stomp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 1.2.
|
9
|
+
- 10
|
10
|
+
version: 1.2.10
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brian McCallister
|
@@ -18,7 +18,7 @@ autorequire:
|
|
18
18
|
bindir: bin
|
19
19
|
cert_chain: []
|
20
20
|
|
21
|
-
date: 2013-
|
21
|
+
date: 2013-07-08 00:00:00 -04:00
|
22
22
|
default_executable:
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|
@@ -148,6 +148,7 @@ files:
|
|
148
148
|
- lib/stomp/message.rb
|
149
149
|
- lib/stomp/sslparams.rb
|
150
150
|
- lib/stomp/version.rb
|
151
|
+
- notes/heartbeat_readme.txt
|
151
152
|
- spec/client_shared_examples.rb
|
152
153
|
- spec/client_spec.rb
|
153
154
|
- spec/connection_spec.rb
|