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 CHANGED
@@ -1,3 +1,9 @@
1
+ == 1.2.10 20130708
2
+
3
+ * Issue #57, reconnect delays not honored if erroneous headers
4
+ * Support fail overs when heartbeat send/receive fails
5
+ * Update callback logger example
6
+
1
7
  == 1.2.9 20130328
2
8
 
3
9
  * Refactoring and documentation updates (glennr)
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
- * Gem version 1.2.9. Miscellaneous fixes and changes. See _CHANGELOG.rdoc_ for details.
14
- * Gem version 1.2.8. Stomp 1.1+ header codec inversion fix, test refactoring. See _CHANGELOG.rdoc_ for details.
15
- * Gem version 1.2.7. Stomp 1.2 support and miscellaneous fixes. See _CHANGELOG.rdoc_ for details.
16
- * Gem version 1.2.6. Miscellaneous fixes and changes. See _CHANGELOG.rdoc_ for details.
17
- * Gem version 1.2.5. Restructure. Forks with modifcations will be affected. See _CHANGELOG.rdoc_ for details.
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 is announced as of gem version 1.2.1.
22
- * Support of Stomp protocol level 1.1 is announced as of gem version 1.2.0.
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
@@ -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
- ts_flist << "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt"
29
- ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","))
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},
@@ -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
- ts_flist << "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt"
29
- ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","), :ciphers => ciphers_list)
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
- ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
30
- :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt")
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 => [
@@ -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
- ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
28
- :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt", :ciphers => ciphers_list)
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
- ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
30
- :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt",
31
- :ts_files => "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt")
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},
@@ -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
- ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
28
- :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt",
29
- :ts_files => "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt",
30
- :ciphers => ciphers_list)
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 > (@hbsend_interval - (@hbsend_interval/5.0)) / 1000000.0 # Be tolerant (minus)
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
- @ls = curt # Update last send
110
- @hb_sent = true # Reset if necessary
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" => @hbsend_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
- delta = curt - @lr
140
- if delta > ((@hbrecv_interval + (@hbrecv_interval/5.0)) / 1000000.0) # Be tolerant (plus)
141
- if @logger && @logger.respond_to?(:on_hbfire)
142
- @logger.on_hbfire(log_params, "receive_heartbeat", curt)
143
- end
144
- # Client code could be off doing something else (that is, no reading of
145
- # the socket has been requested by the caller). Try to handle that case.
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
- @read_semaphore.unlock
156
- @hbrecv_count += 1
157
- else
158
- # Shrug. Have not received one. Just set warning flag.
159
- @hb_received = false
160
- if @logger && @logger.respond_to?(:on_hbread_fail)
161
- @logger.on_hbread_fail(log_params, {"ticker_interval" => @hbrecv_interval})
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
- Thread.pass
168
- end
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
@@ -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 { |k,v| _transmit(used_socket, Stomp::CMD_SUBSCRIBE, v) }
357
+ @subscriptions.each {|k,v|
358
+ _transmit(used_socket, Stomp::CMD_SUBSCRIBE, v)
359
+ }
355
360
  end
356
361
 
357
362
  end # class Connection
@@ -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
- @closed = true
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
@@ -55,6 +55,8 @@ module Stomp
55
55
  # :hbser => false,
56
56
  # :stompconn => false,
57
57
  # :usecrlf => false,
58
+ # :max_hbread_fails => 0,
59
+ # :max_hbrlck_fails => 0,
58
60
  # }
59
61
  #
60
62
  # e.g. c = Stomp::Client.new(hash)
@@ -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
- @socket = nil
381
- super_result = __old_receive
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 detectd during a connect.
76
- class ProtocolErrorConnect < RuntimeError
82
+ # * Incomplete Stomp 1.1 headers are detected during a connect.
83
+ class ProtocolErrorConnect < ProtocolError11p
77
84
  def message
78
- "protocol error on CONNECT"
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 < RuntimeError
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 < RuntimeError
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
@@ -6,7 +6,7 @@ module Stomp
6
6
  module Version #:nodoc: all
7
7
  MAJOR = 1
8
8
  MINOR = 2
9
- PATCH = 9
9
+ PATCH = 10
10
10
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
11
11
  end
12
12
  end
@@ -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
- #backup and timeout are not implemented yet
305
+ #
306
306
  @parameters = {
307
307
  :initial_reconnect_delay => 5.0,
308
308
  :max_reconnect_delay => 60.0,
@@ -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 => false,
376
- :stompconn => false,
377
- :usecrlf => false,
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.9"
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-03-28}
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",
@@ -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: 13
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 2
9
- - 9
10
- version: 1.2.9
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-03-28 00:00:00 -04:00
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