zyre 0.1.0 → 0.4.1

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.
@@ -15,14 +15,13 @@ VALUE rzyre_cZyrePoller;
15
15
  static void rzyre_poller_free( void *ptr );
16
16
 
17
17
  static const rb_data_type_t rzyre_poller_t = {
18
- "Zyre::Poller",
19
- {
20
- NULL,
21
- rzyre_poller_free
18
+ .wrap_struct_name = "Zyre::Poller",
19
+ .function = {
20
+ .dmark = NULL,
21
+ .dfree = rzyre_poller_free,
22
22
  },
23
- 0,
24
- 0,
25
- RUBY_TYPED_FREE_IMMEDIATELY,
23
+ .data = NULL,
24
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
26
25
  };
27
26
 
28
27
 
@@ -68,6 +68,67 @@ rzyre_log( const char *level, const char *fmt, va_dcl )
68
68
  }
69
69
 
70
70
 
71
+ /* --------------------------------------------------------------
72
+ * Utility functions
73
+ * -------------------------------------------------------------- */
74
+
75
+ // Struct for passing arguments through rb_protect to rzyre_add_frames_to_zmsg()
76
+ struct add_frames_to_zmsg_call {
77
+ zmsg_t *msg;
78
+ VALUE msg_parts;
79
+ };
80
+ typedef struct add_frames_to_zmsg_call add_frames_to_zmsg_call_t;
81
+
82
+
83
+ /*
84
+ * Add a frame for each object in an Array.
85
+ */
86
+ static VALUE
87
+ rzyre_add_frames_to_zmsg( VALUE call )
88
+ {
89
+ add_frames_to_zmsg_call_t *call_ptr = (add_frames_to_zmsg_call_t *)call;
90
+ VALUE msg_part, msg_str;
91
+ zframe_t *frame;
92
+
93
+ for ( long i = 0 ; i < RARRAY_LEN(call_ptr->msg_parts) ; i++ ) {
94
+ msg_part = rb_ary_entry(call_ptr->msg_parts, i);
95
+ msg_str = StringValue( msg_part );
96
+ frame = zframe_new( RSTRING_PTR(msg_str), RSTRING_LEN(msg_str) );
97
+ zmsg_append( call_ptr->msg, &frame );
98
+ }
99
+
100
+ return Qtrue;
101
+ }
102
+
103
+
104
+ /*
105
+ * Make and return a zmsg, with one frame per object in +messages+. Caller owns the returned
106
+ * zmsg. Can raise a TypeError if one of the +messages+ can't be stringified.
107
+ */
108
+ zmsg_t *
109
+ rzyre_make_zmsg_from( VALUE messages )
110
+ {
111
+ VALUE msgarray = rb_Array( messages );
112
+ zmsg_t *msg = zmsg_new();
113
+ static add_frames_to_zmsg_call_t call;
114
+ int state;
115
+
116
+ call.msg = msg;
117
+ call.msg_parts = msgarray;
118
+
119
+ rb_protect( rzyre_add_frames_to_zmsg, (VALUE)&call, &state );
120
+
121
+ if ( state ) {
122
+ zmsg_destroy( &msg );
123
+ rb_jump_tag( state );
124
+ }
125
+
126
+ return msg;
127
+ }
128
+
129
+
130
+
131
+
71
132
 
72
133
  /* --------------------------------------------------------------
73
134
  * Module methods
@@ -107,7 +168,7 @@ rzyre_s_zyre_version()
107
168
  * }
108
169
  */
109
170
  static VALUE
110
- rzyre_s_interfaces()
171
+ rzyre_s_interfaces( VALUE module )
111
172
  {
112
173
  ziflist_t *iflist = ziflist_new();
113
174
  const VALUE rval = rb_hash_new();
@@ -134,6 +195,30 @@ rzyre_s_interfaces()
134
195
  }
135
196
 
136
197
 
198
+ /*
199
+ * call-seq:
200
+ * Zyre.disable_zsys_handler
201
+ *
202
+ * Disable CZMQ's default signal handler, which allows for handling it in Ruby instead.
203
+ *
204
+ */
205
+ static VALUE
206
+ rzyre_s_disable_zsys_handler( VALUE module )
207
+ {
208
+ rzyre_log( "info", "Disabling zsys INT/TERM handler." );
209
+ zsys_handler_set( NULL );
210
+ return Qtrue;
211
+ }
212
+
213
+
214
+
215
+ static VALUE
216
+ rzyre_s_start_authenticator( VALUE module )
217
+ {
218
+ return Qnil;
219
+ }
220
+
221
+
137
222
  /*
138
223
  * Zyre extension init function
139
224
  */
@@ -142,13 +227,31 @@ Init_zyre_ext()
142
227
  {
143
228
  rzyre_mZyre = rb_define_module( "Zyre" );
144
229
 
230
+ #ifdef CZMQ_BUILD_DRAFT_API
231
+ rb_define_const( rzyre_mZyre, "BUILT_WITH_DRAFT_CZMQ_API", Qtrue );
232
+ #else
233
+ rb_define_const( rzyre_mZyre, "BUILT_WITH_DRAFT_CZMQ_API", Qfalse );
234
+ #endif
235
+ #ifdef ZYRE_BUILD_DRAFT_API
236
+ rb_define_const( rzyre_mZyre, "BUILT_WITH_DRAFT_API", Qtrue );
237
+ #else
238
+ rb_define_const( rzyre_mZyre, "BUILT_WITH_DRAFT_API", Qfalse );
239
+ #endif
240
+
145
241
  rb_define_singleton_method( rzyre_mZyre, "zyre_version", rzyre_s_zyre_version, 0 );
146
242
  rb_define_singleton_method( rzyre_mZyre, "interfaces", rzyre_s_interfaces, 0 );
243
+ rb_define_singleton_method( rzyre_mZyre, "disable_zsys_handler", rzyre_s_disable_zsys_handler, 0 );
244
+
245
+ // :TODO: Allow for startup of the zauth agent. This will require enough of a
246
+ // subset of CZMQ that I hesitate to do it in Zyre. Maybe better to just write a
247
+ // decent CZMQ library instead?
248
+ rb_define_singleton_method( rzyre_mZyre, "start_authenticator", rzyre_s_start_authenticator, 0 );
147
249
 
148
250
  // :TODO: set up zsys_set_logsender()
149
251
 
150
252
  rzyre_init_node();
151
253
  rzyre_init_event();
152
254
  rzyre_init_poller();
255
+ rzyre_init_cert();
153
256
  }
154
257
 
@@ -10,13 +10,23 @@
10
10
  #ifndef ZYRE_EXT_H_90322ABD
11
11
  #define ZYRE_EXT_H_90322ABD
12
12
 
13
+ #include "extconf.h"
14
+
13
15
  #include <ruby.h>
14
16
  #include <ruby/intern.h>
15
17
  #include <ruby/thread.h>
18
+ #include <ruby/encoding.h>
19
+ #include <ruby/version.h>
20
+
21
+ #ifdef HAVE_ZCERT_UNSET_META
22
+ # define CZMQ_BUILD_DRAFT_API 1
23
+ #endif
24
+ #ifdef HAVE_ZYRE_SET_BEACON_PEER_PORT
25
+ # define ZYRE_BUILD_DRAFT_API 1
26
+ #endif
16
27
 
17
28
  #include "zyre.h"
18
29
  #include "czmq.h"
19
- #include "extconf.h"
20
30
 
21
31
  #ifndef TRUE
22
32
  # define TRUE 1
@@ -27,7 +37,8 @@
27
37
  #endif
28
38
 
29
39
 
30
- // For synthesized events
40
+ // For synthesized events, sizeof calculations, copied from the czmq and zyre
41
+ // source
31
42
  struct _zyre_event_t {
32
43
  char *type; // Event type as string
33
44
  char *peer_uuid; // Sender UUID as string
@@ -39,6 +50,7 @@ struct _zyre_event_t {
39
50
  };
40
51
 
41
52
 
53
+
42
54
  /* --------------------------------------------------------------
43
55
  * Declarations
44
56
  * -------------------------------------------------------------- */
@@ -73,6 +85,9 @@ extern VALUE rzyre_mZyre;
73
85
  extern VALUE rzyre_cZyreNode;
74
86
  extern VALUE rzyre_cZyreEvent;
75
87
  extern VALUE rzyre_cZyrePoller;
88
+ extern VALUE rzyre_cZyreCert;
89
+
90
+ extern zactor_t *auth_actor;
76
91
 
77
92
 
78
93
  /* --------------------------------------------------------------
@@ -82,6 +97,12 @@ extern VALUE rzyre_cZyrePoller;
82
97
  #define IsZyreNode( obj ) rb_obj_is_kind_of( (obj), rzyre_cZyreNode )
83
98
  #define IsZyreEvent( obj ) rb_obj_is_kind_of( (obj), rzyre_cZyreEvent )
84
99
  #define IsZyrePoller( obj ) rb_obj_is_kind_of( (obj), rzyre_cZyrePoller )
100
+ #define IsZyreCert( obj ) rb_obj_is_kind_of( (obj), rzyre_cZyreCert )
101
+
102
+ /* --------------------------------------------------------------
103
+ * Utility functions
104
+ * -------------------------------------------------------------- */
105
+ extern zmsg_t * rzyre_make_zmsg_from _(( VALUE ));
85
106
 
86
107
 
87
108
  /* -------------------------------------------------------
@@ -92,8 +113,10 @@ extern void Init_zyre_ext _(( void ));
92
113
  extern void rzyre_init_node _(( void ));
93
114
  extern void rzyre_init_event _(( void ));
94
115
  extern void rzyre_init_poller _(( void ));
116
+ extern void rzyre_init_cert _(( void ));
95
117
 
96
118
  extern zyre_t * rzyre_get_node _(( VALUE ));
119
+ extern zcert_t * rzyre_get_cert _(( VALUE ));
97
120
 
98
121
  #endif /* end of include guard: ZYRE_EXT_H_90322ABD */
99
122
 
@@ -38,14 +38,14 @@ module Observability::Instrumentation::Zyre
38
38
  ###############
39
39
 
40
40
  ### Observer callback for the #whisper method.
41
- def observe_whisper( peer_uuid, msg )
42
- Observability.observer.add( peer_uuid: peer_uuid, message: msg )
41
+ def observe_whisper( peer_uuid, *msgs )
42
+ Observability.observer.add( peer_uuid: peer_uuid, messages: msgs )
43
43
  end
44
44
 
45
45
 
46
46
  ### Observer callback for the #shout method.
47
- def observe_shout( group, msg )
48
- Observability.observer.add( group: group, message: msg )
47
+ def observe_shout( group, *msgs )
48
+ Observability.observer.add( group: group, messages: msgs )
49
49
  end
50
50
 
51
51
  end # module Observability::Instrumentation::Zyre
data/lib/zyre.rb CHANGED
@@ -1,35 +1,27 @@
1
1
  # -*- ruby -*-
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'set'
4
5
  require 'loggability'
5
6
 
6
7
  require_relative 'zyre_ext'
7
8
 
8
9
 
9
- # A binding to libzyre
10
+ #--
11
+ # See also: ext/zyre_ext/zyre_ext.c
10
12
  module Zyre
11
13
  extend Loggability
12
14
 
13
15
 
14
16
  # Gem version (semver)
15
- VERSION = '0.1.0'
16
-
17
+ VERSION = '0.4.1'
17
18
 
18
19
  # Set up a logger for Zyre classes
19
20
  log_as :zyre
20
21
 
21
22
 
22
- ### Wait on one or more +nodes+ to become readable, returning the first one that does
23
- ### or +nil+ if the +timeout+ is zero or greater and at least that many seconds elapse.
24
- ### Specify a +timeout+ of -1 to wait indefinitely. The timeout is in floating-point
25
- ### seconds.
26
- ###
27
- ### Raises an Interrupt if the call is interrupted or the ZMQ context is destroyed.
28
- def self::wait( *nodes, timeout: -1 )
29
- nodes = nodes.flatten
30
- return nil if nodes.empty?
31
- return self.wait2( nodes, timeout )
32
- end
23
+ @whitelisted_ips = Set.new
24
+ @blacklisted_ips = Set.new
33
25
 
34
26
 
35
27
  ### If the given +key+ is a Symbol, transform it into an RFC822-style header key. If
@@ -50,4 +42,36 @@ module Zyre
50
42
  transform_values {|v| v.to_s.encode('us-ascii') }
51
43
  end
52
44
 
45
+
46
+ ### Allow (whitelist) a list of IP +addresses+. For NULL, all clients from
47
+ ### these addresses will be accepted. For PLAIN and CURVE, they will be
48
+ ### allowed to continue with authentication. You can call this method
49
+ ### multiple times to whitelist more IP addresses. If you whitelist one
50
+ ### or more addresses, any non-whitelisted addresses are treated as
51
+ ### blacklisted:
52
+ def self::allow( *addresses )
53
+ @whitelisted_ips.merge( addresses )
54
+ end
55
+
56
+
57
+ ### Deny (blacklist) a list of IP +addresses+. For all security mechanisms,
58
+ ### this rejects the connection without any further authentication. Use
59
+ ### either a whitelist, or a blacklist, not not both. If you define both
60
+ ### a whitelist and a blacklist, only the whitelist takes effect:
61
+ def self::deny( *addresses )
62
+ @blacklisted_ips.merge( addresses )
63
+ end
64
+
65
+
66
+ ### Returns +true+ if the underlying Czmq library was built with draft APIs.
67
+ def self::has_draft_czmq_apis?
68
+ return Zyre::BUILT_WITH_DRAFT_CZMQ_API ? true : false
69
+ end
70
+
71
+
72
+ ### Returns +true+ if the underlying Zyre library was built with draft APIs.
73
+ def self::has_draft_apis?
74
+ return Zyre::BUILT_WITH_DRAFT_API ? true : false
75
+ end
76
+
53
77
  end # module Zyre
data/lib/zyre/cert.rb ADDED
@@ -0,0 +1,75 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'loggability'
5
+
6
+ require 'zyre' unless defined?( Zyre )
7
+
8
+
9
+ #--
10
+ # See also: ext/zyre_ext/cert.c
11
+ class Zyre::Cert
12
+ extend Loggability
13
+
14
+
15
+ # The placeholder key that is set as the secret key for a public certificate.
16
+ EMPTY_KEY = "\x00" * 32
17
+
18
+
19
+ # Use the Zyre module's logger
20
+ log_to :zyre
21
+
22
+
23
+ # Set up some more Rubyish aliases
24
+ alias_method :private_key, :secret_key
25
+ alias_method :==, :eql?
26
+
27
+
28
+ ### Fetch the value for the cert metadata with the given +name+.
29
+ def []( name )
30
+ return self.meta( name.to_s )
31
+ end
32
+
33
+
34
+ ### Set the value for the cert metadata with the given +name+ to +value+.
35
+ def []=( name, value )
36
+ return self.set_meta( name.to_s, value.to_s )
37
+ end
38
+
39
+
40
+ ### Return the metadata from the cert as a Hash.
41
+ def meta_hash
42
+ hash = self.meta_keys.each_with_object( {} ) do |key, h|
43
+ h[ key ] = self[ key ]
44
+ end
45
+ hash.freeze
46
+ return hash
47
+ end
48
+
49
+
50
+ ### Delete the value for the cert metadata with the given +name+. Requires
51
+ ### CZMQ to have been built with Draft APIs.
52
+ def delete( name )
53
+ name = name.to_s
54
+
55
+ deleted_val = self[ name ]
56
+ self.unset_meta( name )
57
+
58
+ return deleted_val
59
+ end
60
+
61
+
62
+ ### Returns +true+ if the certificate has a secret key.
63
+ def have_secret_key?
64
+ return self.secret_key != EMPTY_KEY
65
+ end
66
+
67
+
68
+ ### Apply the certificate to the specified +zyre_node+, i.e. use the
69
+ ### cert for CURVE security. If the receiving certificate doesn't have a
70
+ ### private key, an exception will be raised.
71
+ def apply( zyre_node )
72
+ return zyre_node.zcert = self
73
+ end
74
+
75
+ end # class Zyre::Cert
data/lib/zyre/event.rb CHANGED
@@ -25,6 +25,7 @@ class Zyre::Event
25
25
  autoload :Exit, 'zyre/event/exit'
26
26
  autoload :Join, 'zyre/event/join'
27
27
  autoload :Leave, 'zyre/event/leave'
28
+ autoload :Leader, 'zyre/event/leader'
28
29
  autoload :Shout, 'zyre/event/shout'
29
30
  autoload :Silent, 'zyre/event/silent'
30
31
  autoload :Stop, 'zyre/event/stop'
@@ -60,6 +61,14 @@ class Zyre::Event
60
61
  end
61
62
 
62
63
 
64
+ ### Returns +true+ if the receiving event has a multipart message.
65
+ def multipart?
66
+ size = self.msg_size
67
+ return size && size > 1
68
+ end
69
+ alias_method :is_multipart?, :multipart?
70
+
71
+
63
72
  ### Return a string describing this event, suitable for debugging.
64
73
  def inspect
65
74
  details = self.inspect_details
@@ -0,0 +1,18 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'zyre/event' unless defined?( Zyre::Event )
5
+
6
+
7
+ class Zyre::Event::Leader < Zyre::Event
8
+
9
+ ### Provide the details of the inspect message.
10
+ def inspect_details
11
+ return "%s (%s) has been elected leader of «%s»" % [
12
+ self.peer_uuid,
13
+ self.peer_name,
14
+ self.group
15
+ ]
16
+ end
17
+
18
+ end # class Zyre::Event::Leader