mosquitto 0.2 → 0.3
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.
- 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
|
}
|