stomp 1.2.9 → 1.2.10

Sign up to get free protection for your applications and to get access to all the features.
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