mosquitto 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +11 -8
- data/Gemfile +1 -4
- data/Gemfile.lock +3 -8
- data/README.md +22 -22
- data/Rakefile +16 -12
- data/ext/mosquitto/client.c +108 -40
- data/ext/mosquitto/client.h +12 -2
- data/ext/mosquitto/extconf.rb +29 -10
- data/ext/mosquitto/mosquitto_prelude.h +2 -2
- data/lib/mosquitto/client.rb +22 -0
- data/lib/mosquitto/logging.rb +15 -2
- data/lib/mosquitto/version.rb +1 -1
- data/test/helper.rb +6 -15
- data/test/mosquitto.conf.erb +734 -0
- data/test/test_callbacks.rb +11 -7
- data/test/test_client.rb +12 -10
- data/test/test_custom_logger.rb +7 -2
- data/test/test_integration.rb +45 -19
- data/test/test_loops.rb +22 -10
- data/test/test_mosquitto.rb +1 -1
- data/test/test_pub_sub.rb +18 -4
- data/test/test_threads.rb +10 -6
- data/test/test_tls.rb +3 -2
- metadata +14 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b3853298fbced225fd9fe2c425183e4f95ed036
|
4
|
+
data.tar.gz: 929f570d1f74476e6c21baffbe4c12aedc1d48c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32319113ea684f52dab351e4dbd00c0c93bf8c610e1eb8b8cc2a22cc9e610ab377401a4e77330d046b7749398ca958543ebc71128b6a137e456fcd4905c5e996
|
7
|
+
data.tar.gz: a64bde7305272ce12d885b60c182de90f61387911f413fedf4ad532df72dde881161fa6b464e0c9bb08bcb8a68cc8b6491f290d7f71be0f72a1a0fa5b67acb60
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
language: ruby
|
2
2
|
before_install:
|
3
3
|
- sudo apt-get update -qq
|
4
|
-
- sudo apt-get install pkg-config cmake openssl
|
5
|
-
- wget http://mosquitto.org/files/source/mosquitto-1.
|
4
|
+
- sudo apt-get install pkg-config cmake openssl libc-ares-dev
|
5
|
+
- wget http://mosquitto.org/files/source/mosquitto-1.3.1.tar.gz
|
6
6
|
install:
|
7
|
-
- tar xzf mosquitto-1.
|
8
|
-
- cd mosquitto-1.
|
7
|
+
- tar xzf mosquitto-1.3.1.tar.gz
|
8
|
+
- cd mosquitto-1.3.1
|
9
9
|
- cmake .
|
10
10
|
- sudo make install
|
11
11
|
- bundle install
|
12
|
+
before_script:
|
13
|
+
- erb $TRAVIS_BUILD_DIR/test/mosquitto.conf.erb > $TRAVIS_BUILD_DIR/test/mosquitto.conf
|
14
|
+
- mosquitto -d -c $TRAVIS_BUILD_DIR/test/mosquitto.conf
|
12
15
|
bundler_args: --quiet
|
13
16
|
rvm:
|
14
17
|
- 1.9.3
|
@@ -18,12 +21,12 @@ rvm:
|
|
18
21
|
env:
|
19
22
|
- GC_STRESS=0
|
20
23
|
- GC_STRESS=1
|
21
|
-
script:
|
24
|
+
script:
|
25
|
+
- bundle exec rake test:unit
|
26
|
+
- bundle exec rake test:integration
|
22
27
|
gemfile:
|
23
28
|
- Gemfile
|
24
29
|
notifications:
|
25
30
|
recipients:
|
26
31
|
- lourens@methodmissing.com
|
27
|
-
|
28
|
-
only:
|
29
|
-
- master
|
32
|
+
- errordeveloper@gmail.com
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,25 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mosquitto (0.
|
4
|
+
mosquitto (0.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
|
10
|
-
rake (10.1.1)
|
9
|
+
rake (10.2.2)
|
11
10
|
rake-compiler (0.9.2)
|
12
11
|
rake
|
13
|
-
|
14
|
-
json (~> 1.4)
|
15
|
-
yard (0.8.7.3)
|
12
|
+
yard (0.8.7.4)
|
16
13
|
|
17
14
|
PLATFORMS
|
18
15
|
ruby
|
19
16
|
|
20
17
|
DEPENDENCIES
|
21
18
|
mosquitto!
|
22
|
-
rake
|
23
19
|
rake-compiler (~> 0.9.2)
|
24
|
-
rdoc
|
25
20
|
yard
|
data/README.md
CHANGED
@@ -6,9 +6,9 @@ The mosquitto gem is meant to serve as an easy, performant and standards complia
|
|
6
6
|
|
7
7
|
The API consists of two classes:
|
8
8
|
|
9
|
-
[Mosquitto::Client](http://rubydoc.info/github/
|
9
|
+
[Mosquitto::Client](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client) - the client
|
10
10
|
|
11
|
-
[Mosquitto::Message](http://rubydoc.info/github/
|
11
|
+
[Mosquitto::Message](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Message) - returned from the client
|
12
12
|
|
13
13
|
## About MQTT and libmosquitto
|
14
14
|
|
@@ -37,7 +37,7 @@ See the [project website](http://mosquitto.org/) for more information.
|
|
37
37
|
|
38
38
|
## Requirements
|
39
39
|
|
40
|
-
This gem links against version 1.
|
40
|
+
This gem links against version 1.3.1 of `libmosquitto` . You will need to install additional packages for your system.
|
41
41
|
|
42
42
|
### OS X
|
43
43
|
|
@@ -51,17 +51,17 @@ brew install mosquitto
|
|
51
51
|
|
52
52
|
``` sh
|
53
53
|
sudo apt-get update
|
54
|
-
sudo apt-get install pkg-config cmake openssl
|
54
|
+
sudo apt-get install pkg-config cmake openssl libc-ares-dev
|
55
55
|
```
|
56
56
|
|
57
|
-
The current Ubuntu packages aren't on 1.
|
57
|
+
The current Ubuntu packages aren't on 1.3.1 yet - it's recommended to build libmosquitto from source (see below) until further notice. OpenSSL is an optional dependency - libmosquitto builds without it, however TLS specific features would not be available.
|
58
58
|
|
59
59
|
### Building libmosquitto from source
|
60
60
|
|
61
61
|
``` sh
|
62
|
-
wget http://mosquitto.org/files/source/mosquitto-1.
|
63
|
-
tar xzf mosquitto-1.
|
64
|
-
cd mosquitto-1.
|
62
|
+
wget http://mosquitto.org/files/source/mosquitto-1.3.1.tar.gz
|
63
|
+
tar xzf mosquitto-1.3.1.tar.gz
|
64
|
+
cd mosquitto-1.3.1
|
65
65
|
cmake .
|
66
66
|
sudo make install
|
67
67
|
```
|
@@ -87,7 +87,7 @@ When are requirements or dependencies are met, the following should install mosq
|
|
87
87
|
gem install mosquitto
|
88
88
|
```
|
89
89
|
|
90
|
-
The extension checks for libmosquitto presence as well as a 1.
|
90
|
+
The extension checks for libmosquitto presence as well as a 1.3.1 version.
|
91
91
|
|
92
92
|
## Usage
|
93
93
|
|
@@ -180,17 +180,17 @@ publisher.connect("test.mosquitto.org", 1883, 10)
|
|
180
180
|
|
181
181
|
The following callbacks are supported (please follow links for further documentation) :
|
182
182
|
|
183
|
-
* [connect](http://rubydoc.info/github/
|
184
|
-
* [disconnect](http://rubydoc.info/github/
|
185
|
-
* [log](http://rubydoc.info/github/
|
186
|
-
* [subscribe](http://rubydoc.info/github/
|
187
|
-
* [unsubscribe](http://rubydoc.info/github/
|
188
|
-
* [publish](http://rubydoc.info/github/
|
189
|
-
* [message](http://rubydoc.info/github/
|
183
|
+
* [connect](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client:on_connect) - called when the broker sends a CONNACK message in response to a connection.
|
184
|
+
* [disconnect](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client:on_disconnect) - called when the broker has received the DISCONNECT command and has disconnected the client.
|
185
|
+
* [log](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client:on_log) - should be used if you want event logging information from the client library.
|
186
|
+
* [subscribe](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client:on_subscribe) - called when the broker responds to a subscription request.
|
187
|
+
* [unsubscribe](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client:on_unsubscribe) - called when the broker responds to a unsubscription request.
|
188
|
+
* [publish](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client:on_publish) - called when a message initiated with Mosquitto::Client#publish has been sent to the broker successfully.
|
189
|
+
* [message](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client:on_message) - called when a message is received from the broker.
|
190
190
|
|
191
191
|
### TLS / SSL
|
192
192
|
|
193
|
-
libmosquitto builds with TLS support by default, however [pre-shared key (PSK)](http://rubydoc.info/github/
|
193
|
+
libmosquitto builds with TLS support by default, however [pre-shared key (PSK)](http://rubydoc.info/github/xively/mosquitto/master/Mosquitto/Client:tls_psk_set) support is not available when linked against older OpenSSL versions.
|
194
194
|
|
195
195
|
``` ruby
|
196
196
|
tls_client = Mosquitto::Client.new
|
@@ -207,13 +207,13 @@ tls_client.tls_set('/path/to/mosquitto.org.crt'), nil, nil, nil, nil)
|
|
207
207
|
tls_client.connect('test.mosquitto.org', 8883, 10)
|
208
208
|
```
|
209
209
|
|
210
|
-
See [documentation](http://rubydoc.info/github/
|
210
|
+
See [documentation](http://rubydoc.info/github/xively/mosquitto) for the full API specification.
|
211
211
|
|
212
212
|
## Contact, feedback and bugs
|
213
213
|
|
214
214
|
This extension is currently maintained by Lourens Naudé (http://github.com/methodmissing) and contributors.
|
215
215
|
|
216
|
-
Please file bugs / issues and feature requests on the [issue tracker](https://github.com/
|
216
|
+
Please file bugs / issues and feature requests on the [issue tracker](https://github.com/xively/mosquitto/issues)
|
217
217
|
|
218
218
|
## Development
|
219
219
|
|
@@ -222,9 +222,9 @@ Use 'bundle install' to install the necessary development and testing gems:
|
|
222
222
|
|
223
223
|
``` sh
|
224
224
|
bundle install
|
225
|
-
rake
|
225
|
+
bundle exec rake
|
226
226
|
```
|
227
|
-
Tests by default run against
|
227
|
+
Tests by default run against an MQTT server on localhost, which is expected to support TLS on port 8883 as well.
|
228
228
|
|
229
229
|
``` ruby
|
230
230
|
class MosquittoTestCase < Test::Unit::TestCase
|
@@ -237,7 +237,7 @@ class MosquittoTestCase < Test::Unit::TestCase
|
|
237
237
|
|
238
238
|
## Resources
|
239
239
|
|
240
|
-
Documentation available at http://rubydoc.info/github/
|
240
|
+
Documentation available at http://rubydoc.info/github/xively/mosquitto
|
241
241
|
|
242
242
|
## Special Thanks
|
243
243
|
|
data/Rakefile
CHANGED
@@ -17,18 +17,20 @@ Rake::ExtensionTask.new('mosquitto') do |ext|
|
|
17
17
|
CLEAN.include 'lib/**/mosquitto_ext.*'
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
namespace :test do
|
21
|
+
desc 'Run mosquitto tests'
|
22
|
+
Rake::TestTask.new(:unit) do |t|
|
23
|
+
t.test_files = Dir.glob("test/**/test_*.rb").reject{|t| t =~ /integration/ }
|
24
|
+
t.verbose = true
|
25
|
+
t.warning = true
|
26
|
+
end
|
26
27
|
|
27
|
-
desc 'Run mosquitto integration tests'
|
28
|
-
Rake::TestTask.new(:integration) do |t|
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
desc 'Run mosquitto integration tests'
|
29
|
+
Rake::TestTask.new(:integration) do |t|
|
30
|
+
t.test_files = Dir.glob("test/test_integration.rb")
|
31
|
+
t.verbose = true
|
32
|
+
t.warning = true
|
33
|
+
end
|
32
34
|
end
|
33
35
|
|
34
36
|
namespace :debug do
|
@@ -38,5 +40,7 @@ namespace :debug do
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
|
-
task :
|
43
|
+
task 'test:unit' => :compile
|
44
|
+
task 'test:integration' => :compile
|
45
|
+
task :test => ['test:unit', 'test:integration']
|
42
46
|
task :default => :test
|
data/ext/mosquitto/client.c
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
#include "mosquitto_ext.h"
|
2
2
|
|
3
3
|
static void rb_mosquitto_run_callback(mosquitto_callback_t *callback);
|
4
|
+
static void rb_mosquitto_free_callback(mosquitto_callback_t *callback);
|
5
|
+
static void rb_mosquitto_client_reap_event_thread(mosquitto_client_wrapper *client);
|
4
6
|
|
5
7
|
VALUE mosquitto_tls_password;
|
6
8
|
|
7
9
|
static int rb_mosquitto_tls_password_callback(char *buf, int size, int rwflag, void *obj)
|
8
10
|
{
|
9
11
|
strncpy(buf, StringValueCStr(mosquitto_tls_password), size);
|
10
|
-
return RSTRING_LEN(mosquitto_tls_password);
|
11
12
|
rb_gc_unregister_address(&mosquitto_tls_password);
|
13
|
+
return RSTRING_LEN(mosquitto_tls_password);
|
12
14
|
}
|
13
15
|
|
14
16
|
/*
|
@@ -47,10 +49,10 @@ static mosquitto_callback_t *mosquitto_callback_queue_pop(mosquitto_client_wrapp
|
|
47
49
|
* Only applicable to clients that run with the threaded Mosquitto::Client#loop_start event loop
|
48
50
|
*
|
49
51
|
*/
|
50
|
-
static void *mosquitto_wait_for_callbacks(void *
|
52
|
+
static void *mosquitto_wait_for_callbacks(void *c)
|
51
53
|
{
|
52
|
-
|
53
|
-
|
54
|
+
mosquitto_client_wrapper *client = (mosquitto_client_wrapper *)c;
|
55
|
+
mosquitto_callback_waiting_t *waiter = client->waiter;
|
54
56
|
|
55
57
|
pthread_mutex_lock(&client->callback_mutex);
|
56
58
|
while (!waiter->abort && (waiter->callback = mosquitto_callback_queue_pop(client)) == NULL)
|
@@ -69,13 +71,17 @@ static void *mosquitto_wait_for_callbacks(void *w)
|
|
69
71
|
* Only applicable to clients that run with the threaded Mosquitto::Client#loop_start event loop
|
70
72
|
*
|
71
73
|
*/
|
72
|
-
static void mosquitto_stop_waiting_for_callbacks(void *
|
74
|
+
static void mosquitto_stop_waiting_for_callbacks(void *c)
|
73
75
|
{
|
74
|
-
|
75
|
-
|
76
|
+
mosquitto_client_wrapper *client = (mosquitto_client_wrapper *)c;
|
77
|
+
mosquitto_callback_waiting_t *waiter = client->waiter;
|
78
|
+
mosquitto_callback_t *callback = NULL;
|
76
79
|
|
77
80
|
pthread_mutex_lock(&client->callback_mutex);
|
78
81
|
waiter->abort = 1;
|
82
|
+
while ((callback = mosquitto_callback_queue_pop(client)) != NULL) {
|
83
|
+
rb_mosquitto_free_callback(callback);
|
84
|
+
}
|
79
85
|
pthread_mutex_unlock(&client->callback_mutex);
|
80
86
|
pthread_cond_signal(&client->callback_cond);
|
81
87
|
}
|
@@ -168,18 +174,10 @@ static void rb_mosquitto_handle_callback(int *error_tag, mosquitto_callback_t *c
|
|
168
174
|
args[0] = client->connect_cb;
|
169
175
|
args[1] = (VALUE)1;
|
170
176
|
args[2] = INT2NUM(cb->rc);
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
case 2:
|
176
|
-
MosquittoError("connection refused (identifier rejected)");
|
177
|
-
break;
|
178
|
-
case 3:
|
179
|
-
MosquittoError("connection refused (broker unavailable)");
|
180
|
-
break;
|
181
|
-
default:
|
182
|
-
rb_mosquitto_funcall_protected(error_tag, args);
|
177
|
+
if (cb->rc == 0) {
|
178
|
+
rb_mosquitto_funcall_protected(error_tag, args);
|
179
|
+
} else {
|
180
|
+
MosquittoError(mosquitto_connack_string(cb->rc));
|
183
181
|
}
|
184
182
|
}
|
185
183
|
break;
|
@@ -269,19 +267,17 @@ static void rb_mosquitto_run_callback(mosquitto_callback_t *callback)
|
|
269
267
|
static VALUE rb_mosquitto_callback_thread(void *obj)
|
270
268
|
{
|
271
269
|
mosquitto_client_wrapper *client = (mosquitto_client_wrapper *)obj;
|
272
|
-
mosquitto_callback_waiting_t waiter;
|
273
|
-
waiter
|
274
|
-
waiter
|
275
|
-
waiter
|
276
|
-
while (!waiter.abort)
|
270
|
+
mosquitto_callback_waiting_t *waiter = client->waiter;
|
271
|
+
waiter->callback = NULL;
|
272
|
+
waiter->abort = 0;
|
273
|
+
while (!waiter->abort)
|
277
274
|
{
|
278
|
-
rb_thread_call_without_gvl(mosquitto_wait_for_callbacks, (void *)
|
279
|
-
if (waiter
|
275
|
+
rb_thread_call_without_gvl(mosquitto_wait_for_callbacks, (void *)client, mosquitto_stop_waiting_for_callbacks, (void *)client);
|
276
|
+
if (waiter->callback)
|
280
277
|
{
|
281
|
-
rb_mosquitto_run_callback(waiter
|
278
|
+
rb_mosquitto_run_callback(waiter->callback);
|
282
279
|
}
|
283
280
|
}
|
284
|
-
|
285
281
|
return Qnil;
|
286
282
|
}
|
287
283
|
|
@@ -444,7 +440,14 @@ static void rb_mosquitto_free_client(void *ptr)
|
|
444
440
|
{
|
445
441
|
mosquitto_client_wrapper *client = (mosquitto_client_wrapper *)ptr;
|
446
442
|
if (client) {
|
447
|
-
|
443
|
+
if (client->mosq != NULL) {
|
444
|
+
if (!NIL_P(client->callback_thread)) {
|
445
|
+
mosquitto_stop_waiting_for_callbacks(client);
|
446
|
+
mosquitto_loop_stop(client->mosq, true);
|
447
|
+
rb_mosquitto_client_reap_event_thread(client);
|
448
|
+
}
|
449
|
+
if (client->mosq != NULL) mosquitto_destroy(client->mosq);
|
450
|
+
}
|
448
451
|
xfree(client);
|
449
452
|
}
|
450
453
|
}
|
@@ -508,6 +511,7 @@ static VALUE rb_mosquitto_client_s_new(int argc, VALUE *argv, VALUE client)
|
|
508
511
|
cl->log_cb = Qnil;
|
509
512
|
cl->callback_thread = Qnil;
|
510
513
|
cl->callback_queue = NULL;
|
514
|
+
cl->waiter = NULL;
|
511
515
|
rb_obj_call_init(client, 0, NULL);
|
512
516
|
return client;
|
513
517
|
}
|
@@ -688,7 +692,7 @@ static VALUE rb_mosquitto_client_auth(VALUE obj, VALUE username, VALUE password)
|
|
688
692
|
|
689
693
|
/*
|
690
694
|
* call-seq:
|
691
|
-
* client.tls_set('/certs/all-ca.crt'), '/certs', '/certs/client.crt'), '/certs/client.key') -> Boolean
|
695
|
+
* client.tls_set('/certs/all-ca.crt'), '/certs', '/certs/client.crt'), '/certs/client.key', 'password') -> Boolean
|
692
696
|
*
|
693
697
|
* Configure the client for certificate based SSL/TLS support.
|
694
698
|
*
|
@@ -714,7 +718,7 @@ static VALUE rb_mosquitto_client_auth(VALUE obj, VALUE username, VALUE password)
|
|
714
718
|
* @raise [Mosquitto::Error] on invalid input params or when TLS is not supported
|
715
719
|
* @note This must be called before calling Mosquitto::Client#connect
|
716
720
|
* @example
|
717
|
-
* client.tls_set('/certs/all-ca.crt'), '/certs', '/certs/client.crt'), '/certs/client.key')
|
721
|
+
* client.tls_set('/certs/all-ca.crt'), '/certs', '/certs/client.crt'), '/certs/client.key', 'password')
|
718
722
|
*
|
719
723
|
*/
|
720
724
|
static VALUE rb_mosquitto_client_tls_set(VALUE obj, VALUE cafile, VALUE capath, VALUE certfile, VALUE keyfile, VALUE password)
|
@@ -1175,13 +1179,17 @@ static void *rb_mosquitto_client_disconnect_nogvl(void *ptr)
|
|
1175
1179
|
static VALUE rb_mosquitto_client_disconnect(VALUE obj)
|
1176
1180
|
{
|
1177
1181
|
int ret;
|
1182
|
+
bool retried = false;
|
1183
|
+
struct timeval time;
|
1178
1184
|
MosquittoGetClient(obj);
|
1185
|
+
retry_once:
|
1179
1186
|
ret = (int)rb_thread_call_without_gvl(rb_mosquitto_client_disconnect_nogvl, (void *)client->mosq, RUBY_UBF_IO, 0);
|
1180
1187
|
switch (ret) {
|
1181
1188
|
case MOSQ_ERR_INVAL:
|
1182
1189
|
MosquittoError("invalid input params");
|
1183
1190
|
break;
|
1184
1191
|
case MOSQ_ERR_NO_CONN:
|
1192
|
+
RetryNotConnectedOnce();
|
1185
1193
|
MosquittoError("client not connected to broker");
|
1186
1194
|
break;
|
1187
1195
|
default:
|
@@ -1219,6 +1227,8 @@ static VALUE rb_mosquitto_client_publish(VALUE obj, VALUE mid, VALUE topic, VALU
|
|
1219
1227
|
{
|
1220
1228
|
struct nogvl_publish_args args;
|
1221
1229
|
int ret, msg_id;
|
1230
|
+
struct timeval time;
|
1231
|
+
bool retried = false;
|
1222
1232
|
MosquittoGetClient(obj);
|
1223
1233
|
Check_Type(topic, T_STRING);
|
1224
1234
|
MosquittoEncode(topic);
|
@@ -1236,6 +1246,7 @@ static VALUE rb_mosquitto_client_publish(VALUE obj, VALUE mid, VALUE topic, VALU
|
|
1236
1246
|
args.payload = (const char *)(args.payloadlen == 0 ? NULL : StringValueCStr(payload));
|
1237
1247
|
args.qos = NUM2INT(qos);
|
1238
1248
|
args.retain = (retain == Qtrue) ? true : false;
|
1249
|
+
retry_once:
|
1239
1250
|
ret = (int)rb_thread_call_without_gvl(rb_mosquitto_client_publish_nogvl, (void *)&args, RUBY_UBF_IO, 0);
|
1240
1251
|
switch (ret) {
|
1241
1252
|
case MOSQ_ERR_INVAL:
|
@@ -1245,6 +1256,7 @@ static VALUE rb_mosquitto_client_publish(VALUE obj, VALUE mid, VALUE topic, VALU
|
|
1245
1256
|
rb_memerror();
|
1246
1257
|
break;
|
1247
1258
|
case MOSQ_ERR_NO_CONN:
|
1259
|
+
RetryNotConnectedOnce();
|
1248
1260
|
MosquittoError("client not connected to broker");
|
1249
1261
|
break;
|
1250
1262
|
case MOSQ_ERR_PROTOCOL:
|
@@ -1286,6 +1298,8 @@ static VALUE rb_mosquitto_client_subscribe(VALUE obj, VALUE mid, VALUE subscript
|
|
1286
1298
|
{
|
1287
1299
|
struct nogvl_subscribe_args args;
|
1288
1300
|
int ret, msg_id;
|
1301
|
+
struct timeval time;
|
1302
|
+
bool retried = false;
|
1289
1303
|
MosquittoGetClient(obj);
|
1290
1304
|
Check_Type(subscription, T_STRING);
|
1291
1305
|
MosquittoEncode(subscription);
|
@@ -1298,6 +1312,7 @@ static VALUE rb_mosquitto_client_subscribe(VALUE obj, VALUE mid, VALUE subscript
|
|
1298
1312
|
args.mid = NIL_P(mid) ? NULL : &msg_id;
|
1299
1313
|
args.subscription = StringValueCStr(subscription);
|
1300
1314
|
args.qos = NUM2INT(qos);
|
1315
|
+
retry_once:
|
1301
1316
|
ret = (int)rb_thread_call_without_gvl(rb_mosquitto_client_subscribe_nogvl, (void *)&args, RUBY_UBF_IO, 0);
|
1302
1317
|
switch (ret) {
|
1303
1318
|
case MOSQ_ERR_INVAL:
|
@@ -1307,6 +1322,7 @@ static VALUE rb_mosquitto_client_subscribe(VALUE obj, VALUE mid, VALUE subscript
|
|
1307
1322
|
rb_memerror();
|
1308
1323
|
break;
|
1309
1324
|
case MOSQ_ERR_NO_CONN:
|
1325
|
+
RetryNotConnectedOnce();
|
1310
1326
|
MosquittoError("client not connected to broker");
|
1311
1327
|
break;
|
1312
1328
|
default:
|
@@ -1340,6 +1356,8 @@ static VALUE rb_mosquitto_client_unsubscribe(VALUE obj, VALUE mid, VALUE subscri
|
|
1340
1356
|
{
|
1341
1357
|
struct nogvl_subscribe_args args;
|
1342
1358
|
int ret, msg_id;
|
1359
|
+
struct timeval time;
|
1360
|
+
bool retried = false;
|
1343
1361
|
MosquittoGetClient(obj);
|
1344
1362
|
Check_Type(subscription, T_STRING);
|
1345
1363
|
MosquittoEncode(subscription);
|
@@ -1350,6 +1368,7 @@ static VALUE rb_mosquitto_client_unsubscribe(VALUE obj, VALUE mid, VALUE subscri
|
|
1350
1368
|
args.mosq = client->mosq;
|
1351
1369
|
args.mid = NIL_P(mid) ? NULL : &msg_id;
|
1352
1370
|
args.subscription = StringValueCStr(subscription);
|
1371
|
+
retry_once:
|
1353
1372
|
ret = (int)rb_thread_call_without_gvl(rb_mosquitto_client_unsubscribe_nogvl, (void *)&args, RUBY_UBF_IO, 0);
|
1354
1373
|
switch (ret) {
|
1355
1374
|
case MOSQ_ERR_INVAL:
|
@@ -1359,6 +1378,7 @@ static VALUE rb_mosquitto_client_unsubscribe(VALUE obj, VALUE mid, VALUE subscri
|
|
1359
1378
|
rb_memerror();
|
1360
1379
|
break;
|
1361
1380
|
case MOSQ_ERR_NO_CONN:
|
1381
|
+
RetryNotConnectedOnce();
|
1362
1382
|
MosquittoError("client not connected to broker");
|
1363
1383
|
break;
|
1364
1384
|
default:
|
@@ -1426,12 +1446,15 @@ static VALUE rb_mosquitto_client_loop(VALUE obj, VALUE timeout, VALUE max_packet
|
|
1426
1446
|
{
|
1427
1447
|
struct nogvl_loop_args args;
|
1428
1448
|
int ret;
|
1449
|
+
struct timeval time;
|
1450
|
+
bool retried = false;
|
1429
1451
|
MosquittoGetClient(obj);
|
1430
1452
|
Check_Type(timeout, T_FIXNUM);
|
1431
1453
|
Check_Type(max_packets, T_FIXNUM);
|
1432
1454
|
args.mosq = client->mosq;
|
1433
1455
|
args.timeout = NUM2INT(timeout);
|
1434
1456
|
args.max_packets = NUM2INT(max_packets);
|
1457
|
+
retry_once:
|
1435
1458
|
ret = (int)rb_thread_call_without_gvl(rb_mosquitto_client_loop_nogvl, (void *)&args, RUBY_UBF_IO, 0);
|
1436
1459
|
switch (ret) {
|
1437
1460
|
case MOSQ_ERR_INVAL:
|
@@ -1441,6 +1464,7 @@ static VALUE rb_mosquitto_client_loop(VALUE obj, VALUE timeout, VALUE max_packet
|
|
1441
1464
|
rb_memerror();
|
1442
1465
|
break;
|
1443
1466
|
case MOSQ_ERR_NO_CONN:
|
1467
|
+
RetryNotConnectedOnce();
|
1444
1468
|
MosquittoError("client not connected to broker");
|
1445
1469
|
break;
|
1446
1470
|
case MOSQ_ERR_CONN_LOST:
|
@@ -1493,12 +1517,15 @@ static VALUE rb_mosquitto_client_loop_forever(VALUE obj, VALUE timeout, VALUE ma
|
|
1493
1517
|
{
|
1494
1518
|
struct nogvl_loop_args args;
|
1495
1519
|
int ret;
|
1520
|
+
struct timeval time;
|
1521
|
+
bool retried = false;
|
1496
1522
|
MosquittoGetClient(obj);
|
1497
1523
|
Check_Type(timeout, T_FIXNUM);
|
1498
1524
|
Check_Type(max_packets, T_FIXNUM);
|
1499
1525
|
args.mosq = client->mosq;
|
1500
1526
|
args.timeout = NUM2INT(timeout);
|
1501
1527
|
args.max_packets = NUM2INT(max_packets);
|
1528
|
+
retry_once:
|
1502
1529
|
ret = (int)rb_thread_call_without_gvl(rb_mosquitto_client_loop_forever_nogvl, (void *)&args, rb_mosquitto_client_loop_forever_ubf, client);
|
1503
1530
|
switch (ret) {
|
1504
1531
|
case MOSQ_ERR_INVAL:
|
@@ -1508,6 +1535,7 @@ static VALUE rb_mosquitto_client_loop_forever(VALUE obj, VALUE timeout, VALUE ma
|
|
1508
1535
|
rb_memerror();
|
1509
1536
|
break;
|
1510
1537
|
case MOSQ_ERR_NO_CONN:
|
1538
|
+
RetryNotConnectedOnce();
|
1511
1539
|
MosquittoError("client not connected to broker");
|
1512
1540
|
break;
|
1513
1541
|
case MOSQ_ERR_CONN_LOST:
|
@@ -1559,8 +1587,9 @@ static VALUE rb_mosquitto_client_loop_start(VALUE obj)
|
|
1559
1587
|
MosquittoError("thread support is not available");
|
1560
1588
|
break;
|
1561
1589
|
default:
|
1562
|
-
|
1563
|
-
|
1590
|
+
client->waiter = MOSQ_ALLOC(mosquitto_callback_waiting_t);
|
1591
|
+
if (pthread_mutex_init(&client->callback_mutex, NULL) != 0) MosquittoError("failed to create callback thread mutex");
|
1592
|
+
if (pthread_cond_init(&client->callback_cond, NULL) != 0) MosquittoError("failed to create callback thread condition var");
|
1564
1593
|
client->callback_thread = rb_thread_create(rb_mosquitto_callback_thread, client);
|
1565
1594
|
/* Allow the callback thread some startup time */
|
1566
1595
|
time.tv_sec = 0;
|
@@ -1576,9 +1605,23 @@ static void *rb_mosquitto_client_loop_stop_nogvl(void *ptr)
|
|
1576
1605
|
return (VALUE)mosquitto_loop_stop(args->mosq, args->force);
|
1577
1606
|
}
|
1578
1607
|
|
1608
|
+
static void rb_mosquitto_client_reap_event_thread(mosquitto_client_wrapper *client)
|
1609
|
+
{
|
1610
|
+
struct timeval time;
|
1611
|
+
mosquitto_stop_waiting_for_callbacks(client);
|
1612
|
+
/* Allow the callback thread some shutdown time */
|
1613
|
+
time.tv_sec = 0;
|
1614
|
+
time.tv_usec = 100 * 1000; /* 0.1 sec */
|
1615
|
+
rb_thread_wait_for(time);
|
1616
|
+
if (pthread_mutex_destroy(&client->callback_mutex) == EINVAL) MosquittoError("could not destroy callback thread mutex");
|
1617
|
+
if (pthread_cond_destroy(&client->callback_cond) == EINVAL) MosquittoError("could not destroy callback condition var");
|
1618
|
+
xfree(client->waiter);
|
1619
|
+
client->callback_thread = Qnil;
|
1620
|
+
}
|
1621
|
+
|
1579
1622
|
/*
|
1580
1623
|
* call-seq:
|
1581
|
-
* client.
|
1624
|
+
* client.loop_stop(true) -> Boolean
|
1582
1625
|
*
|
1583
1626
|
* This is part of the threaded client interface. Call this once to stop the
|
1584
1627
|
* network thread previously created with Mosquitto::Client#loop_start. This call
|
@@ -1591,7 +1634,7 @@ static void *rb_mosquitto_client_loop_stop_nogvl(void *ptr)
|
|
1591
1634
|
* @return [true] on success
|
1592
1635
|
* @raise [Mosquitto::Error] on invalid input params or if thread support is not available
|
1593
1636
|
* @example
|
1594
|
-
* client.
|
1637
|
+
* client.loop_stop(true)
|
1595
1638
|
*
|
1596
1639
|
*/
|
1597
1640
|
static VALUE rb_mosquitto_client_loop_stop(VALUE obj, VALUE force)
|
@@ -1604,16 +1647,13 @@ static VALUE rb_mosquitto_client_loop_stop(VALUE obj, VALUE force)
|
|
1604
1647
|
ret = (int)rb_thread_call_without_gvl(rb_mosquitto_client_loop_stop_nogvl, (void *)&args, RUBY_UBF_IO, 0);
|
1605
1648
|
switch (ret) {
|
1606
1649
|
case MOSQ_ERR_INVAL:
|
1607
|
-
MosquittoError("
|
1650
|
+
MosquittoError("Threaded main loop not running for this client. Are you sure you haven't already called Mosquitto::Client#loop_stop ?");
|
1608
1651
|
break;
|
1609
1652
|
case MOSQ_ERR_NOT_SUPPORTED :
|
1610
1653
|
MosquittoError("thread support is not available");
|
1611
1654
|
break;
|
1612
1655
|
default:
|
1613
|
-
|
1614
|
-
pthread_cond_destroy(&client->callback_cond);
|
1615
|
-
rb_thread_kill(client->callback_thread);
|
1616
|
-
client->callback_thread = Qnil;
|
1656
|
+
rb_mosquitto_client_reap_event_thread(client);
|
1617
1657
|
return Qtrue;
|
1618
1658
|
}
|
1619
1659
|
}
|
@@ -1784,6 +1824,30 @@ static VALUE rb_mosquitto_client_want_write(VALUE obj)
|
|
1784
1824
|
return (ret == true) ? Qtrue : Qfalse;
|
1785
1825
|
}
|
1786
1826
|
|
1827
|
+
/*
|
1828
|
+
* call-seq:
|
1829
|
+
* client.destroy -> Boolean
|
1830
|
+
*
|
1831
|
+
* Free memory associated with a mosquitto client instance. Used in integration tests only.
|
1832
|
+
*
|
1833
|
+
* @return [true] true when memory freed
|
1834
|
+
* @example
|
1835
|
+
* client.destroy
|
1836
|
+
*
|
1837
|
+
*/
|
1838
|
+
static VALUE rb_mosquitto_client_destroy(VALUE obj)
|
1839
|
+
{
|
1840
|
+
MosquittoGetClient(obj);
|
1841
|
+
if (!NIL_P(client->callback_thread)) {
|
1842
|
+
mosquitto_stop_waiting_for_callbacks(client);
|
1843
|
+
mosquitto_loop_stop(client->mosq, true);
|
1844
|
+
rb_mosquitto_client_reap_event_thread(client);
|
1845
|
+
}
|
1846
|
+
mosquitto_destroy(client->mosq);
|
1847
|
+
client->mosq = NULL;
|
1848
|
+
return Qtrue;
|
1849
|
+
}
|
1850
|
+
|
1787
1851
|
/*
|
1788
1852
|
* call-seq:
|
1789
1853
|
* client.reconnect_delay_set(2, 10, true) -> Boolean
|
@@ -2160,4 +2224,8 @@ void _init_rb_mosquitto_client()
|
|
2160
2224
|
rb_define_method(rb_cMosquittoClient, "on_subscribe", rb_mosquitto_client_on_subscribe, -1);
|
2161
2225
|
rb_define_method(rb_cMosquittoClient, "on_unsubscribe", rb_mosquitto_client_on_unsubscribe, -1);
|
2162
2226
|
rb_define_method(rb_cMosquittoClient, "on_log", rb_mosquitto_client_on_log, -1);
|
2227
|
+
|
2228
|
+
/* For integration testing only (will) */
|
2229
|
+
rb_define_method(rb_cMosquittoClient, "destroy", rb_mosquitto_client_destroy, 0);
|
2230
|
+
|
2163
2231
|
}
|