protocol-zmtp 0.3.0 → 0.5.0
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/connection.rb +90 -15
- data/lib/protocol/zmtp/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f82192f566af0256273b9dd794ad7032c5b1f3d1b2f8a58c37235847715f6fc
|
|
4
|
+
data.tar.gz: b74e78954d38be3f239d96cbcac676dc564b9ab56dff16f1beff8fbcedb77b8b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 985cc52f11cc1ad7d24bdbec3916ee5485bda72a396413b3735254ae97430117b40ae3fd6331107e953c0b99bc3c05a997c368eeae642e64b023dd3d744381eb
|
|
7
|
+
data.tar.gz: 100df0f00b447bbc6799c4468b040f15e8fe633bf25d736b44931683772d5f52a50fa2646e8ce3f4768f6076d47482a9a004944f55f42a3d35720ca3f6ede27e
|
|
@@ -52,6 +52,11 @@ module Protocol
|
|
|
52
52
|
@mutex = Mutex.new
|
|
53
53
|
@max_message_size = max_message_size
|
|
54
54
|
@last_received_at = nil
|
|
55
|
+
|
|
56
|
+
# Reusable scratch buffer for frame headers. Array#pack(buffer:)
|
|
57
|
+
# writes in place so the per-message 2-or-9 byte String allocation
|
|
58
|
+
# in write_frames disappears on the hot send path.
|
|
59
|
+
@header_buf = String.new(capacity: 9, encoding: Encoding::BINARY)
|
|
55
60
|
end
|
|
56
61
|
|
|
57
62
|
|
|
@@ -90,9 +95,11 @@ module Protocol
|
|
|
90
95
|
# @param parts [Array<String>] message frames
|
|
91
96
|
# @return [void]
|
|
92
97
|
def send_message(parts)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
with_deferred_cancel do
|
|
99
|
+
@mutex.synchronize do
|
|
100
|
+
write_frames(parts)
|
|
101
|
+
@io.flush
|
|
102
|
+
end
|
|
96
103
|
end
|
|
97
104
|
end
|
|
98
105
|
|
|
@@ -103,8 +110,33 @@ module Protocol
|
|
|
103
110
|
# @param parts [Array<String>] message frames
|
|
104
111
|
# @return [void]
|
|
105
112
|
def write_message(parts)
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
with_deferred_cancel do
|
|
114
|
+
@mutex.synchronize do
|
|
115
|
+
write_frames(parts)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# Writes a batch of multi-frame messages to the buffer under a
|
|
122
|
+
# single mutex acquisition. Used by work-stealing send pumps that
|
|
123
|
+
# dequeue up to N messages at once — avoids the N lock/unlock
|
|
124
|
+
# pairs per batch that a plain `batch.each { write_message }`
|
|
125
|
+
# would incur.
|
|
126
|
+
#
|
|
127
|
+
# @param messages [Array<Array<String>>] each element is one
|
|
128
|
+
# multi-frame message
|
|
129
|
+
# @return [void]
|
|
130
|
+
def write_messages(messages)
|
|
131
|
+
with_deferred_cancel do
|
|
132
|
+
@mutex.synchronize do
|
|
133
|
+
i = 0
|
|
134
|
+
n = messages.size
|
|
135
|
+
while i < n
|
|
136
|
+
write_frames(messages[i])
|
|
137
|
+
i += 1
|
|
138
|
+
end
|
|
139
|
+
end
|
|
108
140
|
end
|
|
109
141
|
end
|
|
110
142
|
|
|
@@ -115,8 +147,10 @@ module Protocol
|
|
|
115
147
|
# @param wire_bytes [String] ZMTP wire-format bytes
|
|
116
148
|
# @return [void]
|
|
117
149
|
def write_wire(wire_bytes)
|
|
118
|
-
|
|
119
|
-
@
|
|
150
|
+
with_deferred_cancel do
|
|
151
|
+
@mutex.synchronize do
|
|
152
|
+
@io.write(wire_bytes)
|
|
153
|
+
end
|
|
120
154
|
end
|
|
121
155
|
end
|
|
122
156
|
|
|
@@ -165,13 +199,15 @@ module Protocol
|
|
|
165
199
|
# @param command [Codec::Command]
|
|
166
200
|
# @return [void]
|
|
167
201
|
def send_command(command)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
@
|
|
171
|
-
|
|
172
|
-
|
|
202
|
+
with_deferred_cancel do
|
|
203
|
+
@mutex.synchronize do
|
|
204
|
+
if @mechanism.encrypted?
|
|
205
|
+
@io.write(@mechanism.encrypt(command.to_body, command: true))
|
|
206
|
+
else
|
|
207
|
+
@io.write(command.to_frame.to_wire)
|
|
208
|
+
end
|
|
209
|
+
@io.flush
|
|
173
210
|
end
|
|
174
|
-
@io.flush
|
|
175
211
|
end
|
|
176
212
|
end
|
|
177
213
|
|
|
@@ -240,14 +276,53 @@ module Protocol
|
|
|
240
276
|
|
|
241
277
|
private
|
|
242
278
|
|
|
279
|
+
# Defers task cancellation around a block of wire writes so the
|
|
280
|
+
# peer never sees a half-written frame. Without this, an
|
|
281
|
+
# +Async::Cancel+ arriving between the header write and the body
|
|
282
|
+
# write (the unencrypted path issues two separate +@io.write+
|
|
283
|
+
# calls per frame) would desync the peer's framer
|
|
284
|
+
# unrecoverably.
|
|
285
|
+
#
|
|
286
|
+
# When called outside an Async task (test fixtures, blocking
|
|
287
|
+
# callers), the block runs directly -- there is no task to defer
|
|
288
|
+
# on. Cancellation arriving from inside the block (peer
|
|
289
|
+
# disconnect raising +EPIPE+/+EOFError+) propagates normally.
|
|
290
|
+
def with_deferred_cancel
|
|
291
|
+
if defined?(Async::Task) && (task = Async::Task.current?)
|
|
292
|
+
task.defer_cancel { yield }
|
|
293
|
+
else
|
|
294
|
+
yield
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
|
|
243
299
|
# Writes message parts as ZMTP frames, encrypting if needed.
|
|
300
|
+
#
|
|
301
|
+
# For the unencrypted path, writes the frame header and body
|
|
302
|
+
# separately to the IO instead of allocating a wire String. This
|
|
303
|
+
# avoids copying the body just to glue a 1- or 9-byte header onto
|
|
304
|
+
# it -- significant for large messages where the body copy was
|
|
305
|
+
# the dominant allocation per send.
|
|
244
306
|
def write_frames(parts)
|
|
307
|
+
encrypted = @mechanism.encrypted?
|
|
308
|
+
buf = @header_buf
|
|
309
|
+
|
|
245
310
|
parts.each_with_index do |part, i|
|
|
246
311
|
more = i < parts.size - 1
|
|
247
|
-
if
|
|
312
|
+
if encrypted
|
|
248
313
|
@io.write(@mechanism.encrypt(part.b, more: more))
|
|
249
314
|
else
|
|
250
|
-
|
|
315
|
+
body = part.b
|
|
316
|
+
size = body.bytesize
|
|
317
|
+
flags = more ? Codec::Frame::FLAGS_MORE : 0
|
|
318
|
+
buf.clear
|
|
319
|
+
if size > Codec::Frame::SHORT_MAX
|
|
320
|
+
[flags | Codec::Frame::FLAGS_LONG, size].pack("CQ>", buffer: buf)
|
|
321
|
+
else
|
|
322
|
+
[flags, size].pack("CC", buffer: buf)
|
|
323
|
+
end
|
|
324
|
+
@io.write(buf)
|
|
325
|
+
@io.write(body)
|
|
251
326
|
end
|
|
252
327
|
end
|
|
253
328
|
end
|