zyre 0.1.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -2
- data.tar.gz.sig +0 -0
- data/Authentication.md +30 -0
- data/History.md +36 -0
- data/README.md +70 -6
- data/ext/zyre_ext/cert.c +504 -0
- data/ext/zyre_ext/event.c +105 -33
- data/ext/zyre_ext/extconf.rb +5 -0
- data/ext/zyre_ext/node.c +283 -38
- data/ext/zyre_ext/poller.c +6 -7
- data/ext/zyre_ext/zyre_ext.c +104 -1
- data/ext/zyre_ext/zyre_ext.h +25 -2
- data/lib/observability/instrumentation/zyre.rb +4 -4
- data/lib/zyre.rb +38 -14
- data/lib/zyre/cert.rb +75 -0
- data/lib/zyre/event.rb +9 -0
- data/lib/zyre/event/leader.rb +18 -0
- data/lib/zyre/event/stop.rb +5 -0
- data/lib/zyre/testing.rb +36 -3
- data/spec/observability/instrumentation/zyre_spec.rb +2 -2
- data/spec/spec_helper.rb +4 -0
- data/spec/zyre/cert_spec.rb +218 -0
- data/spec/zyre/event_spec.rb +62 -0
- data/spec/zyre/node_spec.rb +195 -8
- data/spec/zyre/testing_spec.rb +72 -0
- data/spec/zyre_spec.rb +12 -0
- metadata +22 -17
- metadata.gz.sig +0 -0
data/ext/zyre_ext/poller.c
CHANGED
@@ -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
|
-
|
24
|
-
|
25
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
23
|
+
.data = NULL,
|
24
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
26
25
|
};
|
27
26
|
|
28
27
|
|
data/ext/zyre_ext/zyre_ext.c
CHANGED
@@ -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
|
|
data/ext/zyre_ext/zyre_ext.h
CHANGED
@@ -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,
|
42
|
-
Observability.observer.add( peer_uuid: peer_uuid,
|
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,
|
48
|
-
Observability.observer.add( group: group,
|
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
|
-
|
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
|
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
|
-
|
23
|
-
|
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
|