mosquitto 0.2

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.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +29 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +25 -0
  6. data/LICENSE.md +13 -0
  7. data/README.md +244 -0
  8. data/Rakefile +42 -0
  9. data/TODO.md +19 -0
  10. data/examples/pub_sub.rb +41 -0
  11. data/ext/mosquitto/client.c +2163 -0
  12. data/ext/mosquitto/client.h +145 -0
  13. data/ext/mosquitto/extconf.rb +31 -0
  14. data/ext/mosquitto/message.c +168 -0
  15. data/ext/mosquitto/message.h +16 -0
  16. data/ext/mosquitto/mosquitto_ext.c +88 -0
  17. data/ext/mosquitto/mosquitto_ext.h +35 -0
  18. data/ext/mosquitto/mosquitto_prelude.h +26 -0
  19. data/ext/mosquitto/rubinius.h +6 -0
  20. data/ext/mosquitto/ruby18.h +6 -0
  21. data/ext/mosquitto/ruby19.h +9 -0
  22. data/ext/mosquitto/ruby2.h +6 -0
  23. data/lib/mosquitto.rb +11 -0
  24. data/lib/mosquitto/client.rb +8 -0
  25. data/lib/mosquitto/logging.rb +32 -0
  26. data/lib/mosquitto/version.rb +5 -0
  27. data/mosquitto.gemspec +23 -0
  28. data/test/helper.rb +59 -0
  29. data/test/ssl/all-ca.crt +75 -0
  30. data/test/ssl/client-expired.crt +61 -0
  31. data/test/ssl/client-revoked.crt +61 -0
  32. data/test/ssl/client-revoked.csr +12 -0
  33. data/test/ssl/client-revoked.key +15 -0
  34. data/test/ssl/client.crt +61 -0
  35. data/test/ssl/client.csr +12 -0
  36. data/test/ssl/client.key +15 -0
  37. data/test/ssl/crl.pem +10 -0
  38. data/test/ssl/demoCA/crlnumber +1 -0
  39. data/test/ssl/demoCA/index.txt +1 -0
  40. data/test/ssl/demoCA/index.txt.attr +1 -0
  41. data/test/ssl/demoCA/serial +1 -0
  42. data/test/ssl/gen.sh +70 -0
  43. data/test/ssl/mosquitto.org.crt +18 -0
  44. data/test/ssl/openssl.cnf +406 -0
  45. data/test/ssl/readme.txt +2 -0
  46. data/test/ssl/rootCA/crlnumber +1 -0
  47. data/test/ssl/rootCA/index.txt +2 -0
  48. data/test/ssl/rootCA/index.txt.attr +1 -0
  49. data/test/ssl/rootCA/serial +1 -0
  50. data/test/ssl/server-expired.crt +0 -0
  51. data/test/ssl/server.crt +60 -0
  52. data/test/ssl/server.csr +12 -0
  53. data/test/ssl/server.key +15 -0
  54. data/test/ssl/signingCA/crlnumber +1 -0
  55. data/test/ssl/signingCA/index.txt +4 -0
  56. data/test/ssl/signingCA/index.txt.attr +1 -0
  57. data/test/ssl/signingCA/serial +1 -0
  58. data/test/ssl/test-alt-ca.crt +58 -0
  59. data/test/ssl/test-alt-ca.key +15 -0
  60. data/test/ssl/test-bad-root-ca.crt +17 -0
  61. data/test/ssl/test-bad-root-ca.key +15 -0
  62. data/test/ssl/test-ca.srl +1 -0
  63. data/test/ssl/test-fake-root-ca.crt +17 -0
  64. data/test/ssl/test-fake-root-ca.key +15 -0
  65. data/test/ssl/test-root-ca.crt +17 -0
  66. data/test/ssl/test-root-ca.key +15 -0
  67. data/test/ssl/test-signing-ca.crt +58 -0
  68. data/test/ssl/test-signing-ca.key +15 -0
  69. data/test/test_callbacks.rb +93 -0
  70. data/test/test_client.rb +141 -0
  71. data/test/test_custom_logger.rb +30 -0
  72. data/test/test_integration.rb +572 -0
  73. data/test/test_loops.rb +56 -0
  74. data/test/test_mosquitto.rb +28 -0
  75. data/test/test_pub_sub.rb +51 -0
  76. data/test/test_threads.rb +69 -0
  77. data/test/test_tls.rb +67 -0
  78. metadata +203 -0
@@ -0,0 +1,145 @@
1
+ #ifndef MOSQUITTO_CLIENT_H
2
+ #define MOSQUITTO_CLIENT_H
3
+
4
+ typedef struct mosquitto_callback_t mosquitto_callback_t;
5
+
6
+ typedef struct {
7
+ struct mosquitto *mosq;
8
+ VALUE connect_cb;
9
+ VALUE disconnect_cb;
10
+ VALUE publish_cb;
11
+ VALUE message_cb;
12
+ VALUE subscribe_cb;
13
+ VALUE unsubscribe_cb;
14
+ VALUE log_cb;
15
+ VALUE callback_thread;
16
+ pthread_mutex_t callback_mutex;
17
+ pthread_cond_t callback_cond;
18
+ mosquitto_callback_t *callback_queue;
19
+ } mosquitto_client_wrapper;
20
+
21
+ #define MosquittoGetClient(obj) \
22
+ mosquitto_client_wrapper *client = NULL; \
23
+ Data_Get_Struct(obj, mosquitto_client_wrapper, client); \
24
+ if (!client) rb_raise(rb_eTypeError, "uninitialized Mosquitto client!");
25
+
26
+ #define MosquittoAssertCallback(cb, arity) \
27
+ if (NIL_P(cb)){ \
28
+ cb = proc; \
29
+ } else { \
30
+ if (rb_class_of(cb) != rb_cProc) \
31
+ rb_raise(rb_eTypeError, "Expected a Proc callback"); \
32
+ if (rb_proc_arity(cb) != arity) \
33
+ rb_raise(rb_eArgError, "Callback expects %d argument(s), got %d", arity, NUM2INT(rb_proc_arity(cb))); \
34
+ }
35
+
36
+ // TODO: xmalloc, the Ruby VM's preferred allocation method for managing memory pressure fails under GC stress when callbacks
37
+ // fire on a non-Ruby thread ( mosquitto_loop_start )
38
+ #define MOSQ_ALLOC(type) ((type*)malloc(sizeof(type)))
39
+
40
+ #define ON_CONNECT_CALLBACK 0x00
41
+ #define ON_DISCONNECT_CALLBACK 0x01
42
+ #define ON_PUBLISH_CALLBACK 0x02
43
+ #define ON_MESSAGE_CALLBACK 0x04
44
+ #define ON_SUBSCRIBE_CALLBACK 0x08
45
+ #define ON_UNSUBSCRIBE_CALLBACK 0x10
46
+ #define ON_LOG_CALLBACK 0x20
47
+
48
+ typedef struct on_connect_callback_args_t on_connect_callback_args_t;
49
+ struct on_connect_callback_args_t {
50
+ int rc;
51
+ };
52
+
53
+ typedef struct on_disconnect_callback_args_t on_disconnect_callback_args_t;
54
+ struct on_disconnect_callback_args_t {
55
+ int rc;
56
+ };
57
+
58
+ typedef struct on_publish_callback_args_t on_publish_callback_args_t;
59
+ struct on_publish_callback_args_t {
60
+ int mid;
61
+ };
62
+
63
+ typedef struct on_message_callback_args_t on_message_callback_args_t;
64
+ struct on_message_callback_args_t {
65
+ struct mosquitto_message *msg;
66
+ };
67
+
68
+ typedef struct on_subscribe_callback_args_t on_subscribe_callback_args_t;
69
+ struct on_subscribe_callback_args_t {
70
+ int mid;
71
+ int qos_count;
72
+ const int *granted_qos;
73
+ };
74
+
75
+ typedef struct on_unsubscribe_callback_args_t on_unsubscribe_callback_args_t;
76
+ struct on_unsubscribe_callback_args_t {
77
+ int mid;
78
+ };
79
+
80
+ typedef struct on_log_callback_args_t on_log_callback_args_t;
81
+ struct on_log_callback_args_t {
82
+ int level;
83
+ char *str;
84
+ };
85
+
86
+ struct mosquitto_callback_t {
87
+ int type;
88
+ mosquitto_client_wrapper *client;
89
+ void *data;
90
+ mosquitto_callback_t *next;
91
+ };
92
+
93
+ typedef struct mosquitto_callback_waiting_t mosquitto_callback_waiting_t;
94
+ struct mosquitto_callback_waiting_t {
95
+ mosquitto_callback_t *callback;
96
+ mosquitto_client_wrapper *client;
97
+ bool abort;
98
+ };
99
+
100
+ struct nogvl_connect_args {
101
+ struct mosquitto *mosq;
102
+ char *host;
103
+ int port;
104
+ int keepalive;
105
+ char *bind_address;
106
+ };
107
+
108
+ struct nogvl_loop_stop_args {
109
+ struct mosquitto *mosq;
110
+ bool force;
111
+ };
112
+
113
+ struct nogvl_loop_args {
114
+ struct mosquitto *mosq;
115
+ int timeout;
116
+ int max_packets;
117
+ };
118
+
119
+ struct nogvl_reinitialise_args {
120
+ struct mosquitto *mosq;
121
+ char *client_id;
122
+ bool clean_session;
123
+ void *obj;
124
+ };
125
+
126
+ struct nogvl_publish_args {
127
+ struct mosquitto *mosq;
128
+ int *mid;
129
+ char *topic;
130
+ int payloadlen;
131
+ const void *payload;
132
+ int qos;
133
+ bool retain;
134
+ };
135
+
136
+ struct nogvl_subscribe_args {
137
+ struct mosquitto *mosq;
138
+ int *mid;
139
+ const char *subscription;
140
+ int qos;
141
+ };
142
+
143
+ void _init_rb_mosquitto_client();
144
+
145
+ #endif
@@ -0,0 +1,31 @@
1
+ require 'mkmf'
2
+
3
+ RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
4
+
5
+ dir_config('mosquitto')
6
+
7
+ # detect homebrew installs, via @brianmario
8
+ if !have_library 'mosquitto'
9
+ base = if !`which brew`.empty?
10
+ `brew --prefix`.strip
11
+ elsif File.exists?("/usr/local/Cellar/mosquitto")
12
+ '/usr/local/Cellar'
13
+ end
14
+
15
+ if base and mosquitto = Dir[File.join(base, 'Cellar/mosquitto/*')].sort.last
16
+ $INCFLAGS << " -I#{mosquitto}/include "
17
+ $LDFLAGS << " -L#{mosquitto}/lib "
18
+ end
19
+ end
20
+
21
+ (have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')) || have_func('rb_thread_blocking_region')
22
+
23
+ (have_header("mosquitto.h") && have_library('mosquitto')) or abort("libmosquitto missing!")
24
+ have_header("pthread.h") or abort('pthread support required!')
25
+ have_macro("LIBMOSQUITTO_VERSION_NUMBER", "mosquitto.h")
26
+
27
+ $defs << "-pedantic"
28
+ $CFLAGS << ' -Wall -funroll-loops'
29
+ $CFLAGS << ' -Wextra -O0 -ggdb3' if ENV['DEBUG']
30
+
31
+ create_makefile('mosquitto_ext')
@@ -0,0 +1,168 @@
1
+ #include "mosquitto_ext.h"
2
+
3
+ /*
4
+ * :nodoc:
5
+ * GC callback for releasing an out of scope Mosquitto::Message object
6
+ *
7
+ */
8
+ static void rb_mosquitto_free_message(void *ptr)
9
+ {
10
+ mosquitto_message_wrapper *message = (mosquitto_message_wrapper *)ptr;
11
+ if (message) {
12
+ mosquitto_message_free(&message->msg);
13
+ xfree(message);
14
+ }
15
+ }
16
+
17
+ /*
18
+ * :nodoc:
19
+ * Allocator function for Mosquitto::Message. This is only ever called from within an on_message callback
20
+ * within the binding scope, NEVER by the user.
21
+ *
22
+ */
23
+ VALUE rb_mosquitto_message_alloc(const struct mosquitto_message *msg)
24
+ {
25
+ VALUE message;
26
+ mosquitto_message_wrapper *wrapper = NULL;
27
+ message = Data_Make_Struct(rb_cMosquittoMessage, mosquitto_message_wrapper, 0, rb_mosquitto_free_message, wrapper);
28
+ wrapper->msg = msg;
29
+ rb_obj_call_init(message, 0, NULL);
30
+ return message;
31
+ }
32
+
33
+ /*
34
+ * call-seq:
35
+ * msg.mid -> Integer
36
+ *
37
+ * Message identifier for this message. Note that although the MQTT protocol doesn't use message ids
38
+ * for messages with QoS=0, libmosquitto assigns them message ids so they can be tracked with this parameter.
39
+ *
40
+ * @return [Integer] message identifier
41
+ * @example
42
+ * msg.mid -> 2
43
+ *
44
+ */
45
+ static VALUE rb_mosquitto_message_mid(VALUE obj)
46
+ {
47
+ struct mosquitto_message *msg;
48
+ MosquittoGetMessage(obj);
49
+ msg = message->msg;
50
+ return INT2NUM(msg->mid);
51
+ }
52
+
53
+ /*
54
+ * call-seq:
55
+ * msg.topic -> String
56
+ *
57
+ * Topic this message was published on.
58
+ *
59
+ * @return [String] topic
60
+ * @example
61
+ * msg.topic -> "test"
62
+ *
63
+ */
64
+ static VALUE rb_mosquitto_message_topic(VALUE obj)
65
+ {
66
+ struct mosquitto_message *msg;
67
+ MosquittoGetMessage(obj);
68
+ msg = message->msg;
69
+ return MosquittoEncode(rb_str_new2(msg->topic));
70
+ }
71
+
72
+ /*
73
+ * call-seq:
74
+ * msg.to_s -> String
75
+ *
76
+ * Coerces the Mosquitto::Message payload to a Ruby string.
77
+ *
78
+ * @return [String] message payload
79
+ * @example
80
+ * msg.to_s -> "message"
81
+ *
82
+ */
83
+ static VALUE rb_mosquitto_message_to_s(VALUE obj)
84
+ {
85
+ struct mosquitto_message *msg;
86
+ MosquittoGetMessage(obj);
87
+ msg = message->msg;
88
+ return MosquittoEncode(rb_str_new(msg->payload, msg->payloadlen));
89
+ }
90
+
91
+ /*
92
+ * call-seq:
93
+ * msg.length -> Integer
94
+ *
95
+ * The length of the message payload
96
+ *
97
+ * @return [Integer] message length
98
+ * @example
99
+ * msg.length -> 7
100
+ *
101
+ */
102
+ static VALUE rb_mosquitto_message_length(VALUE obj)
103
+ {
104
+ struct mosquitto_message *msg;
105
+ MosquittoGetMessage(obj);
106
+ msg = message->msg;
107
+ return INT2NUM(msg->payloadlen);
108
+ }
109
+
110
+ /*
111
+ * call-seq:
112
+ * msg.qos -> Integer
113
+ *
114
+ * Quality of Service used for the message
115
+ *
116
+ * @see Mosquitto::AT_MOST_ONCE
117
+ * @see Mosquitto::AT_LEAST_ONCE
118
+ * @see Mosquitto::EXACTLY_ONCE
119
+ *
120
+ * @return [Integer] message quality of service
121
+ * @example
122
+ * msg.qos -> Mosquitto::AT_MOST_ONCE
123
+ *
124
+ */
125
+ static VALUE rb_mosquitto_message_qos(VALUE obj)
126
+ {
127
+ struct mosquitto_message *msg;
128
+ MosquittoGetMessage(obj);
129
+ msg = message->msg;
130
+ return INT2NUM(msg->qos);
131
+ }
132
+
133
+ /*
134
+ * call-seq:
135
+ * msg.retain? -> Boolean
136
+ *
137
+ * Set to true if this message was flagged to retain.
138
+ *
139
+ * @return [true, false] retention flag
140
+ * @example
141
+ * msg.retain? -> true
142
+ *
143
+ */
144
+ static VALUE rb_mosquitto_message_retain_p(VALUE obj)
145
+ {
146
+ struct mosquitto_message *msg;
147
+ MosquittoGetMessage(obj);
148
+ msg = message->msg;
149
+ return (msg->retain == true) ? Qtrue : Qfalse;
150
+ }
151
+
152
+ /*
153
+ * Represents libmosquitto messages. They cannot be allocated or initialized from user code - they are
154
+ * spawned exclusively from within on_message callbacks and are thus read-only wrapper objects.
155
+ *
156
+ */
157
+
158
+ void _init_rb_mosquitto_message()
159
+ {
160
+ rb_cMosquittoMessage = rb_define_class_under(rb_mMosquitto, "Message", rb_cObject);
161
+
162
+ rb_define_method(rb_cMosquittoMessage, "mid", rb_mosquitto_message_mid, 0);
163
+ rb_define_method(rb_cMosquittoMessage, "topic", rb_mosquitto_message_topic, 0);
164
+ rb_define_method(rb_cMosquittoMessage, "to_s", rb_mosquitto_message_to_s, 0);
165
+ rb_define_method(rb_cMosquittoMessage, "length", rb_mosquitto_message_length, 0);
166
+ rb_define_method(rb_cMosquittoMessage, "qos", rb_mosquitto_message_qos, 0);
167
+ rb_define_method(rb_cMosquittoMessage, "retain?", rb_mosquitto_message_retain_p, 0);
168
+ }
@@ -0,0 +1,16 @@
1
+ #ifndef MOSQUITTO_MESSAGE_H
2
+ #define MOSQUITTO_MESSAGE_H
3
+
4
+ typedef struct {
5
+ struct mosquitto_message *msg;
6
+ } mosquitto_message_wrapper;
7
+
8
+ #define MosquittoGetMessage(obj) \
9
+ mosquitto_message_wrapper *message = NULL; \
10
+ Data_Get_Struct(obj, mosquitto_message_wrapper, message); \
11
+ if (!message) rb_raise(rb_eTypeError, "uninitialized Mosquitto message!");
12
+
13
+ VALUE rb_mosquitto_message_alloc(const struct mosquitto_message *msg);
14
+ void _init_rb_mosquitto_message();
15
+
16
+ #endif
@@ -0,0 +1,88 @@
1
+ #include "mosquitto_ext.h"
2
+
3
+ VALUE rb_mMosquitto;
4
+ VALUE rb_eMosquittoError;
5
+ VALUE rb_cMosquittoClient;
6
+ VALUE rb_cMosquittoMessage;
7
+
8
+ VALUE intern_call;
9
+
10
+ rb_encoding *binary_encoding;
11
+
12
+ /*
13
+ * call-seq:
14
+ * Mosquitto.version -> Integer
15
+ *
16
+ * The libmosquitto version linked against. It returns for libmosquitto 1.2.3 an integer as :
17
+ *
18
+ * 1002003
19
+ *
20
+ * === Examples
21
+ * Mosquitto.version -> 1002003
22
+ *
23
+ */
24
+ static VALUE rb_mosquitto_version(MOSQ_UNUSED VALUE obj)
25
+ {
26
+ return INT2NUM(mosquitto_lib_version(NULL, NULL, NULL));
27
+ }
28
+
29
+ /*
30
+ * call-seq:
31
+ * Mosquitto.cleanup -> nil
32
+ *
33
+ * Release resources associated with the libmosquitto library.
34
+ *
35
+ * === Examples
36
+ * Mosquitto.cleanup -> nil
37
+ *
38
+ */
39
+ static VALUE rb_mosquitto_cleanup(MOSQ_UNUSED VALUE obj)
40
+ {
41
+ mosquitto_lib_cleanup();
42
+ return Qnil;
43
+ }
44
+
45
+ void Init_mosquitto_ext()
46
+ {
47
+ mosquitto_lib_init();
48
+
49
+ intern_call = rb_intern("call");
50
+
51
+ binary_encoding = rb_enc_find("binary");
52
+
53
+ rb_mMosquitto = rb_define_module("Mosquitto");
54
+
55
+ /*
56
+ * Message QOS specific constants
57
+ */
58
+ rb_define_const(rb_mMosquitto, "AT_MOST_ONCE", INT2NUM(0));
59
+ rb_define_const(rb_mMosquitto, "AT_LEAST_ONCE", INT2NUM(1));
60
+ rb_define_const(rb_mMosquitto, "EXACTLY_ONCE", INT2NUM(2));
61
+
62
+ /*
63
+ * Log specific constants *
64
+ */
65
+ rb_define_const(rb_mMosquitto, "LOG_NONE", INT2NUM(0x00));
66
+ rb_define_const(rb_mMosquitto, "LOG_INFO", INT2NUM(0x01));
67
+ rb_define_const(rb_mMosquitto, "LOG_NOTICE", INT2NUM(0x02));
68
+ rb_define_const(rb_mMosquitto, "LOG_WARNING", INT2NUM(0x04));
69
+ rb_define_const(rb_mMosquitto, "LOG_ERR", INT2NUM(0x08));
70
+ rb_define_const(rb_mMosquitto, "LOG_DEBUG", INT2NUM(0x10));
71
+ rb_define_const(rb_mMosquitto, "LOG_SUBSCRIBE", INT2NUM(0x20));
72
+ rb_define_const(rb_mMosquitto, "LOG_UNSUBSCRIBE", INT2NUM(0x40));
73
+ rb_define_const(rb_mMosquitto, "LOG_ALL", INT2NUM(0xFFFF));
74
+
75
+ /*
76
+ * TLS specific constants
77
+ */
78
+ rb_define_const(rb_mMosquitto, "SSL_VERIFY_NONE", INT2NUM(0));
79
+ rb_define_const(rb_mMosquitto, "SSL_VERIFY_PEER", INT2NUM(1));
80
+
81
+ rb_eMosquittoError = rb_define_class_under(rb_mMosquitto, "Error", rb_eStandardError);
82
+
83
+ rb_define_module_function(rb_mMosquitto, "version", rb_mosquitto_version, 0);
84
+ rb_define_module_function(rb_mMosquitto, "cleanup", rb_mosquitto_cleanup, 0);
85
+
86
+ _init_rb_mosquitto_client();
87
+ _init_rb_mosquitto_message();
88
+ }