protocol-zmtp 0.7.1 → 0.8.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.
- checksums.yaml +4 -4
- data/lib/protocol/zmtp/codec/command.rb +5 -5
- data/lib/protocol/zmtp/codec/frame.rb +32 -6
- data/lib/protocol/zmtp/codec/greeting.rb +32 -1
- data/lib/protocol/zmtp/codec/subscription.rb +69 -0
- data/lib/protocol/zmtp/codec.rb +1 -0
- data/lib/protocol/zmtp/connection.rb +35 -4
- data/lib/protocol/zmtp/mechanism/curve.rb +10 -2
- data/lib/protocol/zmtp/mechanism/null.rb +4 -3
- data/lib/protocol/zmtp/mechanism/plain.rb +1 -2
- data/lib/protocol/zmtp/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 81270e34092271f0e0aaceed0ce882885751def59b75716872d074952e4d6b41
|
|
4
|
+
data.tar.gz: ccbf823376d70d8654384b99c1bb30b270dc9493cd432c524a3caab175eaa364
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f148b0ac01768320f35f2edf7ac67f3d51ad3e5daa4a9c9dafccb57168e8e9f616f6f27425c00b82edcd7e0af898188ae37ea3a78f404a786bdd9a94c01cb675
|
|
7
|
+
data.tar.gz: bdab4d4b763394ea1f11aec4503a74d68f499671c93851adc96c2e34bcd7134de837b71941119a1aa029a0966c4ed4cfea8def3f5140244e50f9c2a9b3b0355d
|
|
@@ -130,9 +130,9 @@ module Protocol
|
|
|
130
130
|
# @param ttl [Numeric] time-to-live in seconds (sent as deciseconds)
|
|
131
131
|
# @param context [String] optional context bytes (up to 16 bytes)
|
|
132
132
|
# @return [Command]
|
|
133
|
-
def self.ping(ttl: 0, context:
|
|
133
|
+
def self.ping(ttl: 0, context: EMPTY_BINARY)
|
|
134
134
|
ttl_ds = (ttl * 10).to_i
|
|
135
|
-
new("PING", [ttl_ds].pack("n") + context.b)
|
|
135
|
+
new("PING", [ttl_ds].pack("n") + (context.encoding == Encoding::BINARY ? context : context.b))
|
|
136
136
|
end
|
|
137
137
|
|
|
138
138
|
|
|
@@ -140,8 +140,8 @@ module Protocol
|
|
|
140
140
|
#
|
|
141
141
|
# @param context [String] context bytes echoed from the PING
|
|
142
142
|
# @return [Command]
|
|
143
|
-
def self.pong(context:
|
|
144
|
-
new("PONG", context.b)
|
|
143
|
+
def self.pong(context: EMPTY_BINARY)
|
|
144
|
+
new("PONG", context.encoding == Encoding::BINARY ? context : context.b)
|
|
145
145
|
end
|
|
146
146
|
|
|
147
147
|
|
|
@@ -150,7 +150,7 @@ module Protocol
|
|
|
150
150
|
# @return [Array(Numeric, String)] [ttl_seconds, context_bytes]
|
|
151
151
|
def ping_ttl_and_context
|
|
152
152
|
ttl_ds = @data.unpack1("n")
|
|
153
|
-
context = @data.bytesize > 2 ? @data.byteslice(2..) :
|
|
153
|
+
context = @data.bytesize > 2 ? @data.byteslice(2..) : EMPTY_BINARY
|
|
154
154
|
[ttl_ds / 10.0, context]
|
|
155
155
|
end
|
|
156
156
|
|
|
@@ -31,21 +31,28 @@ module Protocol
|
|
|
31
31
|
# @return [String] frame body (binary)
|
|
32
32
|
attr_reader :body
|
|
33
33
|
|
|
34
|
+
|
|
34
35
|
# @param body [String] frame body
|
|
35
36
|
# @param more [Boolean] more frames follow
|
|
36
37
|
# @param command [Boolean] this is a command frame
|
|
37
38
|
def initialize(body, more: false, command: false)
|
|
38
|
-
@body = body.b
|
|
39
|
+
@body = body.encoding == Encoding::BINARY ? body : body.b
|
|
39
40
|
@more = more
|
|
40
41
|
@command = command
|
|
41
42
|
end
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
# @return [Boolean] true if more frames follow in this message
|
|
45
|
-
def more?
|
|
46
|
+
def more?
|
|
47
|
+
@more
|
|
48
|
+
end
|
|
49
|
+
|
|
46
50
|
|
|
47
51
|
# @return [Boolean] true if this is a command frame
|
|
48
|
-
def command?
|
|
52
|
+
def command?
|
|
53
|
+
@command
|
|
54
|
+
end
|
|
55
|
+
|
|
49
56
|
|
|
50
57
|
# Encodes to wire bytes.
|
|
51
58
|
#
|
|
@@ -57,9 +64,11 @@ module Protocol
|
|
|
57
64
|
flags |= FLAGS_COMMAND if @command
|
|
58
65
|
|
|
59
66
|
if size > SHORT_MAX
|
|
60
|
-
|
|
67
|
+
buf = String.new(capacity: 9 + size, encoding: Encoding::BINARY)
|
|
68
|
+
buf << FLAG_BYTES[flags | FLAGS_LONG] << [size].pack("Q>") << @body
|
|
61
69
|
else
|
|
62
|
-
|
|
70
|
+
buf = String.new(capacity: 2 + size, encoding: Encoding::BINARY)
|
|
71
|
+
buf << FLAG_BYTES[flags] << FLAG_BYTES[size] << @body
|
|
63
72
|
end
|
|
64
73
|
end
|
|
65
74
|
|
|
@@ -72,14 +81,29 @@ module Protocol
|
|
|
72
81
|
# @return [String] frozen binary wire representation
|
|
73
82
|
#
|
|
74
83
|
def self.encode_message(parts)
|
|
75
|
-
|
|
84
|
+
if parts.size == 1
|
|
85
|
+
s = parts[0].bytesize
|
|
86
|
+
wire_size = s > SHORT_MAX ? 9 + s : 2 + s
|
|
87
|
+
else
|
|
88
|
+
wire_size = 0
|
|
89
|
+
j = 0
|
|
90
|
+
while j < parts.size
|
|
91
|
+
s = parts[j].bytesize
|
|
92
|
+
wire_size += s > SHORT_MAX ? 9 + s : 2 + s
|
|
93
|
+
j += 1
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
buf = String.new(capacity: wire_size, encoding: Encoding::BINARY)
|
|
76
98
|
last = parts.size - 1
|
|
77
99
|
i = 0
|
|
100
|
+
|
|
78
101
|
while i < parts.size
|
|
79
102
|
body = parts[i]
|
|
80
103
|
body = body.b unless body.encoding == Encoding::BINARY
|
|
81
104
|
size = body.bytesize
|
|
82
105
|
flags = i < last ? FLAGS_MORE : 0
|
|
106
|
+
|
|
83
107
|
if size > SHORT_MAX
|
|
84
108
|
buf << FLAG_BYTES[flags | FLAGS_LONG] << [size].pack("Q>") << body
|
|
85
109
|
else
|
|
@@ -87,6 +111,7 @@ module Protocol
|
|
|
87
111
|
end
|
|
88
112
|
i += 1
|
|
89
113
|
end
|
|
114
|
+
|
|
90
115
|
buf.freeze
|
|
91
116
|
end
|
|
92
117
|
|
|
@@ -137,6 +162,7 @@ module Protocol
|
|
|
137
162
|
(rest.getbyte(4) << 16) | (rest.getbyte(5) << 8) |
|
|
138
163
|
rest.getbyte(6)
|
|
139
164
|
end
|
|
165
|
+
|
|
140
166
|
end
|
|
141
167
|
end
|
|
142
168
|
end
|
|
@@ -18,6 +18,11 @@ module Protocol
|
|
|
18
18
|
#
|
|
19
19
|
module Greeting
|
|
20
20
|
SIZE = 64
|
|
21
|
+
# Bytes 0..10 cover the 10-byte signature plus the major-version
|
|
22
|
+
# byte at offset 10. ZMTP 2.0 peers only send an 11-byte signature
|
|
23
|
+
# phase (their full greeting is shorter than 64), so we must
|
|
24
|
+
# sniff the major version before committing to reading 64 bytes.
|
|
25
|
+
SIGNATURE_SIZE = 11
|
|
21
26
|
SIGNATURE_START = 0xFF
|
|
22
27
|
SIGNATURE_END = 0x7F
|
|
23
28
|
VERSION_MAJOR = 3
|
|
@@ -41,6 +46,32 @@ module Protocol
|
|
|
41
46
|
end
|
|
42
47
|
|
|
43
48
|
|
|
49
|
+
# Reads and decodes a ZMTP 3.x greeting from +io+, sniffing the
|
|
50
|
+
# major version after the first 11 bytes so a ZMTP 2.0 peer
|
|
51
|
+
# (which would never send the full 64 bytes) is detected and
|
|
52
|
+
# rejected without blocking forever on +read_exactly+.
|
|
53
|
+
#
|
|
54
|
+
# @param io [#read_exactly]
|
|
55
|
+
# @return [Hash] { major:, minor:, mechanism:, as_server: }
|
|
56
|
+
# @raise [Error] on invalid signature or unsupported version
|
|
57
|
+
#
|
|
58
|
+
def self.read_from(io)
|
|
59
|
+
sig = io.read_exactly(SIGNATURE_SIZE).b
|
|
60
|
+
major = sig.getbyte(10)
|
|
61
|
+
|
|
62
|
+
unless sig.getbyte(0) == SIGNATURE_START && sig.getbyte(9) == SIGNATURE_END
|
|
63
|
+
raise Error, "invalid greeting signature"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
unless major >= 3
|
|
67
|
+
raise Error, "unsupported ZMTP revision 0x%02x (ZMTP/%d.x); need revision >= 3" %
|
|
68
|
+
[major, major == 1 ? 2 : major]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
decode(sig + io.read_exactly(SIZE - SIGNATURE_SIZE))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
44
75
|
# Decodes a ZMTP greeting.
|
|
45
76
|
#
|
|
46
77
|
# @param data [String] 64-byte binary greeting
|
|
@@ -59,7 +90,7 @@ module Protocol
|
|
|
59
90
|
minor = data.getbyte(11)
|
|
60
91
|
|
|
61
92
|
unless major >= 3
|
|
62
|
-
raise Error, "unsupported ZMTP
|
|
93
|
+
raise Error, "unsupported ZMTP revision 0x%02x (need revision >= 3)" % major
|
|
63
94
|
end
|
|
64
95
|
|
|
65
96
|
mechanism = data.byteslice(MECHANISM_OFFSET, MECHANISM_LENGTH).delete("\x00")
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protocol
|
|
4
|
+
module ZMTP
|
|
5
|
+
module Codec
|
|
6
|
+
|
|
7
|
+
# ZMTP subscription encoding.
|
|
8
|
+
#
|
|
9
|
+
# Two wire formats exist and both are in active use:
|
|
10
|
+
#
|
|
11
|
+
# * **Message form (ZMTP 3.0 legacy, RFC 23).** A regular data
|
|
12
|
+
# frame whose body is `\x01` + prefix (subscribe) or `\x00` +
|
|
13
|
+
# prefix (cancel). libzmq, JeroMQ, pyzmq, CZMQ, NetMQ all send
|
|
14
|
+
# subscriptions in this form by default, and all accept it.
|
|
15
|
+
#
|
|
16
|
+
# * **Command form (ZMTP 3.1, RFC 37).** A COMMAND-flagged frame
|
|
17
|
+
# whose body is a Command named "SUBSCRIBE" or "CANCEL" with
|
|
18
|
+
# the prefix as the command data.
|
|
19
|
+
#
|
|
20
|
+
# Interop requires sending the message form (understood by every
|
|
21
|
+
# ZMTP 3.0+ peer) and accepting both forms on the receiving side.
|
|
22
|
+
#
|
|
23
|
+
module Subscription
|
|
24
|
+
FLAG_SUBSCRIBE = "\x01".b.freeze
|
|
25
|
+
FLAG_CANCEL = "\x00".b.freeze
|
|
26
|
+
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
# Builds the body of a subscription message in the legacy
|
|
30
|
+
# message form.
|
|
31
|
+
#
|
|
32
|
+
# @param prefix [String] topic prefix
|
|
33
|
+
# @param cancel [Boolean] true to build an unsubscribe
|
|
34
|
+
# @return [String] binary frame body
|
|
35
|
+
def body(prefix, cancel: false)
|
|
36
|
+
flag = cancel ? FLAG_CANCEL : FLAG_SUBSCRIBE
|
|
37
|
+
flag + (prefix.encoding == Encoding::BINARY ? prefix : prefix.b)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Attempts to parse a frame as a subscription. Accepts both the
|
|
42
|
+
# legacy message form and the ZMTP 3.1 command form.
|
|
43
|
+
#
|
|
44
|
+
# @param frame [Frame]
|
|
45
|
+
# @return [Array(Symbol, String), nil] `[:subscribe, prefix]`,
|
|
46
|
+
# `[:cancel, prefix]`, or `nil` if the frame is not a
|
|
47
|
+
# subscription
|
|
48
|
+
def parse(frame)
|
|
49
|
+
if frame.command?
|
|
50
|
+
cmd = Command.from_body(frame.body)
|
|
51
|
+
case cmd.name
|
|
52
|
+
when "SUBSCRIBE" then [:subscribe, cmd.data]
|
|
53
|
+
when "CANCEL" then [:cancel, cmd.data]
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
body = frame.body
|
|
57
|
+
return nil if body.empty?
|
|
58
|
+
|
|
59
|
+
prefix = body.byteslice(1..) || "".b
|
|
60
|
+
case body.getbyte(0)
|
|
61
|
+
when 0x01 then [:subscribe, prefix]
|
|
62
|
+
when 0x00 then [:cancel, prefix]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/protocol/zmtp/codec.rb
CHANGED
|
@@ -15,25 +15,41 @@ module Protocol
|
|
|
15
15
|
# @return [String] peer's socket type (from READY handshake)
|
|
16
16
|
attr_reader :peer_socket_type
|
|
17
17
|
|
|
18
|
+
|
|
18
19
|
# @return [String] peer's identity (from READY handshake)
|
|
19
20
|
attr_reader :peer_identity
|
|
20
21
|
|
|
22
|
+
|
|
21
23
|
# @return [Integer] peer's QoS level (from READY handshake, 0 if absent)
|
|
22
24
|
attr_reader :peer_qos
|
|
23
25
|
|
|
26
|
+
|
|
24
27
|
# @return [String] peer's supported hash algorithms in preference order
|
|
25
28
|
attr_reader :peer_qos_hash
|
|
26
29
|
|
|
30
|
+
|
|
27
31
|
# @return [Hash{String => String}, nil] full peer READY property hash
|
|
28
32
|
# (set after a successful handshake; nil before)
|
|
29
33
|
attr_reader :peer_properties
|
|
30
34
|
|
|
35
|
+
|
|
36
|
+
# @return [Integer, nil] peer ZMTP major version (from greeting)
|
|
37
|
+
attr_reader :peer_major
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# @return [Integer, nil] peer ZMTP minor version (from greeting);
|
|
41
|
+
# 0 for ZMTP 3.0 peers, 1 for ZMTP 3.1+
|
|
42
|
+
attr_reader :peer_minor
|
|
43
|
+
|
|
44
|
+
|
|
31
45
|
# @return [Object] transport IO (#read_exactly, #write, #flush, #close)
|
|
32
46
|
attr_reader :io
|
|
33
47
|
|
|
48
|
+
|
|
34
49
|
# @return [Float, nil] monotonic timestamp of last received frame
|
|
35
50
|
attr_reader :last_received_at
|
|
36
51
|
|
|
52
|
+
|
|
37
53
|
# @param io [#read_exactly, #write, #flush, #close] transport IO
|
|
38
54
|
# @param socket_type [String] our socket type name (e.g. "REQ")
|
|
39
55
|
# @param identity [String] our identity
|
|
@@ -52,6 +68,8 @@ module Protocol
|
|
|
52
68
|
@peer_qos = nil
|
|
53
69
|
@peer_qos_hash = nil
|
|
54
70
|
@peer_properties = nil
|
|
71
|
+
@peer_major = nil
|
|
72
|
+
@peer_minor = nil
|
|
55
73
|
@qos = qos
|
|
56
74
|
@qos_hash = qos_hash
|
|
57
75
|
@mutex = Mutex.new
|
|
@@ -70,20 +88,20 @@ module Protocol
|
|
|
70
88
|
# @return [void]
|
|
71
89
|
# @raise [Error] on handshake failure
|
|
72
90
|
def handshake!
|
|
73
|
-
result = @mechanism.handshake!
|
|
74
|
-
@io,
|
|
91
|
+
result = @mechanism.handshake! @io,
|
|
75
92
|
as_server: @as_server,
|
|
76
93
|
socket_type: @socket_type,
|
|
77
94
|
identity: @identity,
|
|
78
95
|
qos: @qos,
|
|
79
|
-
qos_hash: @qos_hash
|
|
80
|
-
)
|
|
96
|
+
qos_hash: @qos_hash
|
|
81
97
|
|
|
82
98
|
@peer_socket_type = result[:peer_socket_type]
|
|
83
99
|
@peer_identity = result[:peer_identity]
|
|
84
100
|
@peer_qos = result[:peer_qos] || 0
|
|
85
101
|
@peer_qos_hash = result[:peer_qos_hash] || ""
|
|
86
102
|
@peer_properties = result[:peer_properties]
|
|
103
|
+
@peer_major = result[:peer_major]
|
|
104
|
+
@peer_minor = result[:peer_minor]
|
|
87
105
|
|
|
88
106
|
unless @peer_socket_type
|
|
89
107
|
raise Error, "peer READY missing Socket-Type"
|
|
@@ -187,15 +205,19 @@ module Protocol
|
|
|
187
205
|
# @raise [EOFError] if connection is closed
|
|
188
206
|
def receive_message
|
|
189
207
|
frames = []
|
|
208
|
+
|
|
190
209
|
loop do
|
|
191
210
|
frame = read_frame
|
|
211
|
+
|
|
192
212
|
if frame.command?
|
|
193
213
|
yield frame if block_given?
|
|
194
214
|
next
|
|
195
215
|
end
|
|
216
|
+
|
|
196
217
|
frames << frame.body.freeze
|
|
197
218
|
break unless frame.more?
|
|
198
219
|
end
|
|
220
|
+
|
|
199
221
|
frames.freeze
|
|
200
222
|
end
|
|
201
223
|
|
|
@@ -233,6 +255,7 @@ module Protocol
|
|
|
233
255
|
close
|
|
234
256
|
raise
|
|
235
257
|
end
|
|
258
|
+
|
|
236
259
|
touch_heartbeat
|
|
237
260
|
|
|
238
261
|
frame = @mechanism.decrypt(frame) if @mechanism.encrypted?
|
|
@@ -248,6 +271,7 @@ module Protocol
|
|
|
248
271
|
next
|
|
249
272
|
end
|
|
250
273
|
end
|
|
274
|
+
|
|
251
275
|
return frame
|
|
252
276
|
end
|
|
253
277
|
end
|
|
@@ -315,9 +339,11 @@ module Protocol
|
|
|
315
339
|
last = parts.size - 1
|
|
316
340
|
|
|
317
341
|
i = 0
|
|
342
|
+
|
|
318
343
|
while i < parts.size
|
|
319
344
|
part = parts[i]
|
|
320
345
|
more = i < last
|
|
346
|
+
|
|
321
347
|
if encrypted
|
|
322
348
|
body = part.encoding == Encoding::BINARY ? part : part.b
|
|
323
349
|
@io.write(@mechanism.encrypt(body, more: more))
|
|
@@ -325,18 +351,23 @@ module Protocol
|
|
|
325
351
|
body = part.encoding == Encoding::BINARY ? part : part.b
|
|
326
352
|
size = body.bytesize
|
|
327
353
|
flags = more ? Codec::Frame::FLAGS_MORE : 0
|
|
354
|
+
|
|
328
355
|
buf.clear
|
|
356
|
+
|
|
329
357
|
if size > Codec::Frame::SHORT_MAX
|
|
330
358
|
[flags | Codec::Frame::FLAGS_LONG, size].pack("CQ>", buffer: buf)
|
|
331
359
|
else
|
|
332
360
|
[flags, size].pack("CC", buffer: buf)
|
|
333
361
|
end
|
|
362
|
+
|
|
334
363
|
@io.write(buf)
|
|
335
364
|
@io.write(body)
|
|
336
365
|
end
|
|
366
|
+
|
|
337
367
|
i += 1
|
|
338
368
|
end
|
|
339
369
|
end
|
|
370
|
+
|
|
340
371
|
end
|
|
341
372
|
end
|
|
342
373
|
end
|
|
@@ -233,10 +233,12 @@ module Protocol
|
|
|
233
233
|
|
|
234
234
|
io.write(Codec::Greeting.encode(mechanism: MECHANISM_NAME, as_server: false))
|
|
235
235
|
io.flush
|
|
236
|
-
peer_greeting = Codec::Greeting.
|
|
236
|
+
peer_greeting = Codec::Greeting.read_from(io)
|
|
237
237
|
unless peer_greeting[:mechanism] == MECHANISM_NAME
|
|
238
238
|
raise Error, "expected CURVE mechanism, got #{peer_greeting[:mechanism]}"
|
|
239
239
|
end
|
|
240
|
+
@peer_major = peer_greeting[:major]
|
|
241
|
+
@peer_minor = peer_greeting[:minor]
|
|
240
242
|
|
|
241
243
|
|
|
242
244
|
# --- HELLO ---
|
|
@@ -348,6 +350,8 @@ module Protocol
|
|
|
348
350
|
peer_qos: peer_qos,
|
|
349
351
|
peer_qos_hash: peer_qos_hash,
|
|
350
352
|
peer_properties: props,
|
|
353
|
+
peer_major: @peer_major,
|
|
354
|
+
peer_minor: @peer_minor,
|
|
351
355
|
}
|
|
352
356
|
end
|
|
353
357
|
|
|
@@ -359,10 +363,12 @@ module Protocol
|
|
|
359
363
|
def server_handshake!(io, socket_type:, identity:, qos: 0, qos_hash: "")
|
|
360
364
|
io.write(Codec::Greeting.encode(mechanism: MECHANISM_NAME, as_server: true))
|
|
361
365
|
io.flush
|
|
362
|
-
peer_greeting = Codec::Greeting.
|
|
366
|
+
peer_greeting = Codec::Greeting.read_from(io)
|
|
363
367
|
unless peer_greeting[:mechanism] == MECHANISM_NAME
|
|
364
368
|
raise Error, "expected CURVE mechanism, got #{peer_greeting[:mechanism]}"
|
|
365
369
|
end
|
|
370
|
+
@peer_major = peer_greeting[:major]
|
|
371
|
+
@peer_minor = peer_greeting[:minor]
|
|
366
372
|
|
|
367
373
|
|
|
368
374
|
# --- Read HELLO ---
|
|
@@ -514,6 +520,8 @@ module Protocol
|
|
|
514
520
|
peer_qos: (props["X-QoS"] || "0").to_i,
|
|
515
521
|
peer_qos_hash: props["X-QoS-Hash"] || "",
|
|
516
522
|
peer_properties: props,
|
|
523
|
+
peer_major: @peer_major,
|
|
524
|
+
peer_minor: @peer_minor,
|
|
517
525
|
}
|
|
518
526
|
end
|
|
519
527
|
|
|
@@ -32,14 +32,13 @@ module Protocol
|
|
|
32
32
|
# @param as_server [Boolean]
|
|
33
33
|
# @param socket_type [String]
|
|
34
34
|
# @param identity [String]
|
|
35
|
-
# @return [Hash] { peer_socket_type:, peer_identity:, peer_qos:, peer_qos_hash:, peer_properties: }
|
|
35
|
+
# @return [Hash] { peer_socket_type:, peer_identity:, peer_qos:, peer_qos_hash:, peer_properties:, peer_major:, peer_minor: }
|
|
36
36
|
# @raise [Error]
|
|
37
37
|
def handshake!(io, as_server:, socket_type:, identity:, qos: 0, qos_hash: "")
|
|
38
38
|
io.write(Codec::Greeting.encode(mechanism: MECHANISM_NAME, as_server: as_server))
|
|
39
39
|
io.flush
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
peer_greeting = Codec::Greeting.decode(greeting_data)
|
|
41
|
+
peer_greeting = Codec::Greeting.read_from(io)
|
|
43
42
|
|
|
44
43
|
unless peer_greeting[:mechanism] == MECHANISM_NAME
|
|
45
44
|
raise Error, "unsupported mechanism: #{peer_greeting[:mechanism]}"
|
|
@@ -81,6 +80,8 @@ module Protocol
|
|
|
81
80
|
peer_qos: peer_qos,
|
|
82
81
|
peer_qos_hash: peer_qos_hash,
|
|
83
82
|
peer_properties: props,
|
|
83
|
+
peer_major: peer_greeting[:major],
|
|
84
|
+
peer_minor: peer_greeting[:minor],
|
|
84
85
|
}
|
|
85
86
|
end
|
|
86
87
|
|
|
@@ -47,8 +47,7 @@ module Protocol
|
|
|
47
47
|
io.write(Codec::Greeting.encode(mechanism: MECHANISM_NAME, as_server: as_server))
|
|
48
48
|
io.flush
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
peer_greeting = Codec::Greeting.decode(greeting_data)
|
|
50
|
+
peer_greeting = Codec::Greeting.read_from(io)
|
|
52
51
|
|
|
53
52
|
unless peer_greeting[:mechanism] == MECHANISM_NAME
|
|
54
53
|
raise Error, "unsupported mechanism: #{peer_greeting[:mechanism]}"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: protocol-zmtp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrik Wenger
|
|
@@ -25,6 +25,7 @@ files:
|
|
|
25
25
|
- lib/protocol/zmtp/codec/command.rb
|
|
26
26
|
- lib/protocol/zmtp/codec/frame.rb
|
|
27
27
|
- lib/protocol/zmtp/codec/greeting.rb
|
|
28
|
+
- lib/protocol/zmtp/codec/subscription.rb
|
|
28
29
|
- lib/protocol/zmtp/connection.rb
|
|
29
30
|
- lib/protocol/zmtp/error.rb
|
|
30
31
|
- lib/protocol/zmtp/mechanism/curve.rb
|