mosquitto 0.2

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