M .ruby-version +1 -1
M LICENSE.txt +1 -1
@@ 1,4 1,4 @@
-Copyright (c) 2020 Ravn Group
+Copyright (c) 2020-2023 Ravn Inc
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
M README.md +26 -2
@@ 28,7 28,7 @@ This example joins the Zyre network and
node = Zyre::Node.new
node.join( 'global' )
node.start
-
+
node.each_event do |event|
event.print
end
@@ 135,7 135,31 @@ development.
## License
-Copyright (c) 2020-2021, Ravn Group
+This project includes code adapted from the ZeroMQ RFC project, used under
+the following license:
+
+> Copyright (c) 2010-2013 iMatix Corporation and Contributors
+>
+> Permission is hereby granted, free of charge, to any person obtaining a copy of
+> this software and associated documentation files (the "Software"), to deal in
+> the Software without restriction, including without limitation the rights to
+> use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+> the Software, and to permit persons to whom the Software is furnished to do so,
+> subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in all
+> copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+> FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+> COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+> IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+> CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Everything else is:
+
+Copyright (c) 2020-2023, Ravn Inc
All rights reserved.
Redistribution and use in source and binary forms, with or without
M certs/ged.pem +12 -12
@@ 1,7 1,7 @@
-----BEGIN CERTIFICATE-----
-MIID+DCCAmCgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdnZWQv
-REM9RmFlcmllTVVEL0RDPW9yZzAeFw0yMDEyMjQyMDU1MjlaFw0yMTEyMjQyMDU1
-MjlaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
+MIID+DCCAmCgAwIBAgIBBTANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQDDBdnZWQv
+REM9RmFlcmllTVVEL0RDPW9yZzAeFw0yMzAxMTYxNzE2MDlaFw0yNDAxMTYxNzE2
+MDlaMCIxIDAeBgNVBAMMF2dlZC9EQz1GYWVyaWVNVUQvREM9b3JnMIIBojANBgkq
hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAvyVhkRzvlEs0fe7145BYLfN6njX9ih5H
L60U0p0euIurpv84op9CNKF9tx+1WKwyQvQP7qFGuZxkSUuWcP/sFhDXL1lWUuIl
M4uHbGCRmOshDrF4dgnBeOvkHr1fIhPlJm5FO+Vew8tSQmlDsosxLUx+VB7DrVFO
@@ 12,13 12,13 @@ dXzdHqq+zbGZVSQ7pRYHYomD0IiDe1DbIouFnPWm
ozilJg4aar2okb/RA6VS87o+d7g6LpDDMMQjH4G9OPnJENLdhu8KnPw/ivSVvQw7
N2I4L/ZOIe2DIVuYH7aLHfjZDQv/mNgpAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYD
VR0PBAQDAgSwMB0GA1UdDgQWBBRyjf55EbrHagiRLqt5YAd3yb8k4DANBgkqhkiG
-9w0BAQsFAAOCAYEAMYegZanJi8zq7QKPT7wqXefX4C88I5JWeBHR3PvvWK0CwyMV
-peyiu5I13w/lYX+HUZjE4qsSpJMJFXWl4WZCOo+AMprOcf0PxfuJpxCej5D4tavf
-vRfhahSw7XJrcZih/3J+/UgoH7R05MJ+8LTcy3HGrB3a0vTafjm8OY7Xpa0LJDoN
-JDqxK321VIHyTibbKeA1hWSE6ljlQDvFbTqiCj3Ulp1jTv3TOlvRl8fqcfhxUJI0
-+5Q82jJODjEN+GaWs0V+NlrbU94cXwS2PH5dXogftB5YYA5Ex8A0ikZ73xns4Hdo
-XxdLdd92F5ovxA23j/rKe/IDwqr6FpDkU3nPXH/Qp0TVGv9zZnVJc/Z6ChkuWj8z
-pW7JAyyiiHZgKKDReDrA2LA7Zs3o/7KA6UtUH0FHf8LYhcK+pfHk6RtjRe65ffw+
-MCh97sQ/Z/MOusb5+QddBmB+k8EicXyGNl4b5L4XpL7fIQu+Y96TB3JEJlShxFD9
-k9FjI4d9EP54gS/4
+9w0BAQsFAAOCAYEARYCeUVBWARNKqF0cvNnLJvFf4hdW2+Rtc7NfC5jQvX9a1oom
+sfVvS96eER/9cbrphu+vc59EELw4zT+RY3/IesnoE7CaX6zIOFmSmG7K61OHsSLR
+KqMygcWwyuPXT2JG7JsGHuxbzgaRWe29HbSjBbLYxiMH8Zxh4tKutxzKF7jb0Ggq
+KAf9MH5LwG8IHVIfV5drT14PvgR3tcvmrn1timPyJl+eZ3LNnm9ofOCweuZCq1cy
+4Q8LV3vP2Cofy9q+az3DHdaUGlmMiZZZqKixDr1KSS9nvh0ZrKMOUL1sWj/IaxrQ
+RV3y6td14q49t+xnbj00hPlbW7uE2nLJLt2NAoXiE1Nonndz1seB2c6HL79W9fps
+E/O12pQjCp/aPUZMt8/8tKW31RIy/KP8XO6OTJNWA8A/oNEI0g5p/LmmEtJKWYr1
+WmEdESlpWhzFECctefIF2lsN9vaOuof57RM77t2otrtcscDtNarIqjZsIyqtDvtL
+DttITiit0Vwz7bY0
-----END CERTIFICATE-----
M ext/zyre_ext/extconf.rb +7 -0
@@ 9,11 9,15 @@ have_library( 'zyre' ) or
abort "No zyre library!"
have_library( 'czmq' ) or
abort "No czmq library!"
+have_library( 'zmq' ) or
+ abort "No zmq library!"
have_header( 'zyre.h' ) or
abort "No zyre.h header!"
have_header( 'czmq.h' ) or
abort "No czmq.h header!"
+have_header( 'zmq.h' ) or
+ abort "No zmq.h header!"
have_header( 'ruby/thread.h' ) or
abort "Your Ruby is too old!"
@@ 23,6 27,9 @@ have_func( 'zyre_set_beacon_peer_port',
have_func( 'zyre_set_contest_in_group', 'zyre.h' )
have_func( 'zyre_set_zcert', 'zyre.h' )
+have_func( 'zmq_z85_encode', 'zmq.h' )
+have_func( 'zmq_z85_decode', 'zmq.h' )
+
have_func( 'zcert_unset_meta', 'czmq.h' )
create_header()
M ext/zyre_ext/zyre_ext.c +87 -1
@@ 5,6 5,12 @@
* Authors:
* * Michael Granger <ged@FaerieMUD.org>
*
+ * Refs:
+ * - https://github.com/zeromq/zyre#api-summary
+ * - http://api.zeromq.org/master:zmq-z85-decode
+ * - http://api.zeromq.org/master:zmq-z85-encode
+ *
+ *
*/
#include "zyre_ext.h"
@@ 148,7 154,7 @@ rzyre_s_zyre_version()
version = zyre_version();
- return INT2NUM( version );
+ return LONG2NUM( version );
}
@@ 180,6 186,7 @@ rzyre_s_interfaces( VALUE module )
const char *netmask_s = ziflist_netmask( iflist );
const VALUE info_hash = rb_hash_new();
+ rzyre_log( "debug", "Getting info for %s", address_s );
rb_hash_aset( info_hash, ID2SYM(rb_intern("address")), rb_usascii_str_new_cstr(address_s) );
rb_hash_aset( info_hash, ID2SYM(rb_intern("broadcast")), rb_usascii_str_new_cstr(broadcast_s) );
rb_hash_aset( info_hash, ID2SYM(rb_intern("netmask")), rb_usascii_str_new_cstr(netmask_s) );
@@ 211,6 218,77 @@ rzyre_s_disable_zsys_handler( VALUE modu
}
+/*
+ * call-seq:
+ * Zyre.z85_encode( data ) -> string
+ *
+ * Return the specified binary +data+ as a Z85-encoded binary string. The size of the data must
+ * be divisible by 4. If there is a problem encoding the data, returns +nil+.
+ *
+ */
+static VALUE
+rzyre_s_z85_encode( VALUE module, VALUE data )
+{
+#if HAVE_ZMQ_Z85_ENCODE
+ const char *data_str = StringValuePtr( data );
+ const long len = RSTRING_LEN( data );
+ const long res_len = (len * 1.25) + 1;
+ char *encoded = NULL;
+ VALUE result = Qnil;
+
+ if ( len % 4 ) return Qnil;
+
+ encoded = RB_ZALLOC_N( char, res_len );
+ zmq_z85_encode( encoded, (unsigned char *)data_str, len );
+
+ if ( encoded != NULL ) {
+ result = rb_usascii_str_new( encoded, res_len - 1 );
+ }
+
+ ruby_xfree( encoded );
+
+ return result;
+#else
+ rb_notimplement();
+#endif
+}
+
+
+/*
+ * call-seq:
+ * Zyre.z85_decode( string ) -> data
+ *
+ * Return the data decoded from the specified Z85-encoded binary +string+. If there is a
+ * problem decoding the string, returns +nil+.
+ *
+ */
+static VALUE
+rzyre_s_z85_decode( VALUE module, VALUE string )
+{
+#if HAVE_ZMQ_Z85_DECODE
+ const char *data_str = StringValueCStr( string );
+ const long len = RSTRING_LEN( string );
+ const long res_len = (len * 0.8) + 1;
+ char *decoded = NULL;
+ VALUE result = Qnil;
+
+ if ( len % 5 ) return Qnil;
+
+ decoded = RB_ZALLOC_N( char, res_len );
+ zmq_z85_decode( (unsigned char *)decoded, data_str );
+
+ if ( decoded != NULL ) {
+ result = rb_str_new( decoded, res_len - 1 );
+ }
+
+ ruby_xfree( decoded );
+
+ return result;
+#else
+ rb_notimplement();
+#endif
+}
+
static VALUE
rzyre_s_start_authenticator( VALUE module )
@@ 225,6 303,11 @@ rzyre_s_start_authenticator( VALUE modul
void
Init_zyre_ext()
{
+ /*
+ * Document-module: Zyre
+ *
+ * The top level namespace for Zyre classes.
+ */
rzyre_mZyre = rb_define_module( "Zyre" );
#ifdef CZMQ_BUILD_DRAFT_API
@@ 242,6 325,9 @@ Init_zyre_ext()
rb_define_singleton_method( rzyre_mZyre, "interfaces", rzyre_s_interfaces, 0 );
rb_define_singleton_method( rzyre_mZyre, "disable_zsys_handler", rzyre_s_disable_zsys_handler, 0 );
+ rb_define_singleton_method( rzyre_mZyre, "z85_encode", rzyre_s_z85_encode, 1 );
+ rb_define_singleton_method( rzyre_mZyre, "z85_decode", rzyre_s_z85_decode, 1 );
+
// :TODO: Allow for startup of the zauth agent. This will require enough of a
// subset of CZMQ that I hesitate to do it in Zyre. Maybe better to just write a
// decent CZMQ library instead?
M ext/zyre_ext/zyre_ext.h +1 -0
@@ 27,6 27,7 @@
#include "zyre.h"
#include "czmq.h"
+#include "zmq.h"
#ifndef TRUE
# define TRUE 1
M lib/zyre/event/exit.rb +0 -1
@@ 11,7 11,6 @@ class Zyre::Event::Exit < Zyre::Event
return "%s (%s) has left the network" % [
self.peer_uuid,
self.peer_name,
- self.headers,
]
end
M spec/spec_helper.rb +1 -1
@@ 49,7 49,7 @@ RSpec.configure do |config|
config.profile_examples = 5
config.run_all_when_everything_filtered = true
config.shared_context_metadata_behavior = :apply_to_host_groups
- # config.warnings = true
+ config.warnings = true
config.before( :suite ) do
Zyre::Testing.check_fdmax
M spec/zyre/node_spec.rb +2 -2
@@ 44,7 44,7 @@ RSpec.describe( Zyre::Node ) do
it "can set headers" do
- node1 = started_node do |n|
+ _node1 = started_node do |n|
n.set_header( 'Protocol-version', '2' )
end
node2 = started_node
@@ 56,7 56,7 @@ RSpec.describe( Zyre::Node ) do
it "can set headers from a hash" do
- node1 = started_node do |n|
+ _node1 = started_node do |n|
n.headers = {
protocol_version: 2,
content_type: 'application/messagepack'
M spec/zyre_spec.rb +64 -1
@@ 5,7 5,7 @@ require_relative 'spec_helper'
require 'zyre'
-RSpec.describe Zyre do
+RSpec.describe( Zyre ) do
# Pattern for matching IPv4 addresses
@@ 63,5 63,68 @@ RSpec.describe Zyre do
expect( described_class.has_draft_apis? ).to eq( true ).or( eq false )
end
+
+ describe "Z85 encoding/decoding" do
+
+ # From the 32/Z85 reference code:
+ # https://github.com/zeromq/rfc/blob/master/src/spec_32.c
+ let( :test_data_1 ) do
+ [0x86, 0x4F, 0xD2, 0x6F, 0xB5, 0x59, 0xF7, 0x5B].pack('C*')
+ end
+ let( :test_data_2 ) do
+ [
+ 0x8E, 0x0B, 0xDD, 0x69, 0x76, 0x28, 0xB9, 0x1D,
+ 0x8F, 0x24, 0x55, 0x87, 0xEE, 0x95, 0xC5, 0xB0,
+ 0x4D, 0x48, 0x96, 0x3F, 0x79, 0x25, 0x98, 0x77,
+ 0xB4, 0x9C, 0xD9, 0x06, 0x3A, 0xEA, 0xD3, 0xB7
+ ].pack('C*')
+ end
+
+
+ it "can round-trip an empty string" do
+ result = described_class.z85_decode( described_class.z85_encode(''.b) )
+ expect( result ).to eq( ''.b )
+ end
+
+
+ it "fails if the data to be encoded is not bounded at 4 bytes" do
+ expect( described_class.z85_encode(test_data_1[0, 3]) ).to be_nil
+ end
+
+
+ it "can round-trip 4-byte-bounded data" do
+ encoded = described_class.z85_encode( test_data_1 )
+
+ expect( encoded ).to eq( 'HelloWorld' )
+ expect( encoded.encoding ).to eq( Encoding::US_ASCII )
+
+ decoded = described_class.z85_decode( encoded )
+
+ expect( decoded ).to eq( test_data_1 )
+ expect( decoded.encoding ).to eq( Encoding::ASCII_8BIT )
+ end
+
+
+ it "can round-trip a ZMQ Curve test key" do
+ encoded = described_class.z85_encode( test_data_2 )
+
+ expect( encoded ).to eq( 'JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6' )
+ expect( encoded.encoding ).to eq( Encoding::US_ASCII )
+
+ decoded = described_class.z85_decode( encoded )
+
+ expect( decoded ).to eq( test_data_2 )
+ expect( decoded.encoding ).to eq( Encoding::ASCII_8BIT )
+ end
+
+
+ it "fails if the data to be decoded is not bounded at 5 bytes" do
+ encoded = 'JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6'
+
+ expect( described_class.z85_decode(encoded[0..-2]) ).to be_nil
+ end
+
+ end
+
end
M zyre.gemspec +13 -26
@@ 1,46 1,33 @@
# -*- encoding: utf-8 -*-
-# stub: zyre 0.5.0.pre.20210316161024 ruby lib
+# stub: zyre 0.5.0.pre.20230119183244 ruby lib
# stub: ext/zyre_ext/extconf.rb
Gem::Specification.new do |s|
s.name = "zyre".freeze
- s.version = "0.5.0.pre.20210316161024"
+ s.version = "0.5.0.pre.20230119183244"
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1".freeze) if s.respond_to? :required_rubygems_version=
s.metadata = { "changelog_uri" => "https://deveiate.org/code/zyre/History_md.html", "documentation_uri" => "https://deveiate.org/code/zyre", "homepage_uri" => "https://gitlab.com/ravngroup/open-source/ruby-zyre", "source_uri" => "https://gitlab.com/ravngroup/open-source/ruby-zyre/-/tree/master" } if s.respond_to? :metadata=
s.require_paths = ["lib".freeze]
s.authors = ["Michael Granger".freeze]
- s.date = "2021-03-16"
+ s.date = "2023-01-19"
s.description = "A ZRE library for Ruby. This is a Ruby (MRI) binding for the Zyre library for reliable group messaging over local area networks, an implementation of the ZeroMQ Realtime Exchange protocol.".freeze
s.email = ["ged@faeriemud.org".freeze]
s.extensions = ["ext/zyre_ext/extconf.rb".freeze]
s.files = ["Authentication.md".freeze, "History.md".freeze, "LICENSE.txt".freeze, "README.md".freeze, "ext/zyre_ext/cert.c".freeze, "ext/zyre_ext/event.c".freeze, "ext/zyre_ext/extconf.rb".freeze, "ext/zyre_ext/node.c".freeze, "ext/zyre_ext/poller.c".freeze, "ext/zyre_ext/zyre_ext.c".freeze, "ext/zyre_ext/zyre_ext.h".freeze, "lib/observability/instrumentation/zyre.rb".freeze, "lib/zyre.rb".freeze, "lib/zyre/cert.rb".freeze, "lib/zyre/event.rb".freeze, "lib/zyre/event/enter.rb".freeze, "lib/zyre/event/evasive.rb".freeze, "lib/zyre/event/exit.rb".freeze, "lib/zyre/event/join.rb".freeze, "lib/zyre/event/leader.rb".freeze, "lib/zyre/event/leave.rb".freeze, "lib/zyre/event/shout.rb".freeze, "lib/zyre/event/silent.rb".freeze, "lib/zyre/event/stop.rb".freeze, "lib/zyre/event/whisper.rb".freeze, "lib/zyre/node.rb".freeze, "lib/zyre/poller.rb".freeze, "lib/zyre/testing.rb".freeze, "spec/observability/instrumentation/zyre_spec.rb".freeze, "spec/spec_helper.rb".freeze, "spec/zyre/cert_spec.rb".freeze, "spec/zyre/event_spec.rb".freeze, "spec/zyre/node_spec.rb".freeze, "spec/zyre/poller_spec.rb".freeze, "spec/zyre/testing_spec.rb".freeze, "spec/zyre_spec.rb".freeze]
s.homepage = "https://gitlab.com/ravngroup/open-source/ruby-zyre".freeze
s.licenses = ["BSD-3-Clause".freeze]
- s.rubygems_version = "3.2.3".freeze
+ s.rubygems_version = "3.4.2".freeze
s.summary = "A ZRE library for Ruby.".freeze
- if s.respond_to? :specification_version then
- s.specification_version = 4
- end
+ s.specification_version = 4
- if s.respond_to? :add_runtime_dependency then
- s.add_runtime_dependency(%q<loggability>.freeze, ["~> 0.18"])
- s.add_development_dependency(%q<rake-deveiate>.freeze, ["~> 0.15", ">= 0.15.1"])
- s.add_development_dependency(%q<rake-compiler>.freeze, ["~> 1.1"])
- s.add_development_dependency(%q<rubocop>.freeze, ["~> 0.91"])
- s.add_development_dependency(%q<rspec_junit_formatter>.freeze, ["~> 0.4"])
- s.add_development_dependency(%q<simplecov-cobertura>.freeze, ["~> 1.4"])
- s.add_development_dependency(%q<observability>.freeze, ["~> 0.3"])
- s.add_development_dependency(%q<rspec-wait>.freeze, ["~> 0.0"])
- else
- s.add_dependency(%q<loggability>.freeze, ["~> 0.18"])
- s.add_dependency(%q<rake-deveiate>.freeze, ["~> 0.15", ">= 0.15.1"])
- s.add_dependency(%q<rake-compiler>.freeze, ["~> 1.1"])
- s.add_dependency(%q<rubocop>.freeze, ["~> 0.91"])
- s.add_dependency(%q<rspec_junit_formatter>.freeze, ["~> 0.4"])
- s.add_dependency(%q<simplecov-cobertura>.freeze, ["~> 1.4"])
- s.add_dependency(%q<observability>.freeze, ["~> 0.3"])
- s.add_dependency(%q<rspec-wait>.freeze, ["~> 0.0"])
- end
+ s.add_runtime_dependency(%q<loggability>.freeze, ["~> 0.18", ">= 0.18.2"])
+ s.add_development_dependency(%q<rake-deveiate>.freeze, ["~> 0.15", ">= 0.15.1"])
+ s.add_development_dependency(%q<rake-compiler>.freeze, ["~> 1.1"])
+ s.add_development_dependency(%q<rubocop>.freeze, ["~> 0.91"])
+ s.add_development_dependency(%q<rspec_junit_formatter>.freeze, ["~> 0.4"])
+ s.add_development_dependency(%q<simplecov-cobertura>.freeze, ["~> 1.4"])
+ s.add_development_dependency(%q<observability>.freeze, ["~> 0.3"])
+ s.add_development_dependency(%q<rspec-wait>.freeze, ["~> 0.0"])
end