zyre 0.1.0 → 0.4.1

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