ffi-rxs 1.0.0 → 1.0.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.
- data/.gitignore +2 -0
- data/.travis.yml +10 -0
- data/.yardopts +9 -0
- data/CHANGELOG +11 -0
- data/LICENSE +20 -0
- data/README.textile +86 -0
- data/examples/LICENSE +18 -0
- data/examples/README +2 -0
- data/examples/durable_pub.rb +34 -0
- data/examples/durable_sub.rb +29 -0
- data/examples/latency_measurement.rb +140 -0
- data/examples/reply.rb +25 -0
- data/examples/req_rep_poll.rb +71 -0
- data/examples/request.rb +24 -0
- data/examples/task_sink.rb +31 -0
- data/examples/task_vent.rb +34 -0
- data/examples/task_worker.rb +36 -0
- data/examples/throughput_measurement.rb +169 -0
- data/examples/weather_upd_client.rb +47 -0
- data/examples/weather_upd_server.rb +35 -0
- data/examples/xreq_xrep_poll.rb +101 -0
- data/ffi-rxs.gemspec +3 -5
- data/lib/ffi-rxs/constants.rb +15 -11
- data/lib/ffi-rxs/context.rb +54 -60
- data/lib/ffi-rxs/exceptions.rb +7 -5
- data/lib/ffi-rxs/libc.rb +1 -0
- data/lib/ffi-rxs/libxs.rb +2 -0
- data/lib/ffi-rxs/message.rb +79 -50
- data/lib/ffi-rxs/poll.rb +54 -12
- data/lib/ffi-rxs/poll_items.rb +2 -1
- data/lib/ffi-rxs/socket.rb +243 -184
- data/lib/ffi-rxs/util.rb +25 -16
- data/lib/ffi-rxs/version.rb +3 -1
- data/lib/ffi-rxs.rb +8 -14
- data/spec/socket_spec.rb +63 -0
- metadata +31 -19
- data/README.rdoc +0 -86
data/lib/ffi-rxs/socket.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
|
2
3
|
module XS
|
3
4
|
|
@@ -8,47 +9,49 @@ module XS
|
|
8
9
|
|
9
10
|
# Allocates a socket of type +type+ for sending and receiving data.
|
10
11
|
#
|
11
|
-
# +type+ can be one of XS::REQ, XS::REP, XS::PUB,
|
12
|
-
# XS::SUB, XS::PAIR, XS::PULL, XS::PUSH, XS::XREQ, XS::REP,
|
13
|
-
# XS::DEALER or XS::ROUTER.
|
14
|
-
#
|
15
12
|
# By default, this class uses XS::Message for manual
|
16
13
|
# memory management. For automatic garbage collection of received messages,
|
17
14
|
# it is possible to override the :receiver_class to use XS::ManagedMessage.
|
18
15
|
#
|
19
|
-
#
|
16
|
+
# @example Socket creation
|
17
|
+
# sock = Socket.create(Context.create, XS::REQ, :receiver_class => XS::ManagedMessage)
|
20
18
|
#
|
21
19
|
# Advanced users may want to replace the receiver class with their
|
22
20
|
# own custom class. The custom class must conform to the same public API
|
23
21
|
# as XS::Message.
|
24
22
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# if (socket = Socket.new(context.pointer, XS::REQ))
|
26
|
+
# ...
|
27
|
+
# else
|
28
|
+
# STDERR.puts "Socket creation failed"
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# @param pointer
|
32
|
+
# @param [Constant] type
|
33
|
+
# One of @XS::REQ@, @XS::REP@, @XS::PUB@, @XS::SUB@, @XS::PAIR@,
|
34
|
+
# @XS::PULL@, @XS::PUSH@, @XS::XREQ@, @XS::REP@,
|
35
|
+
# @XS::DEALER@ or @XS::ROUTER@
|
36
|
+
# @param [Hash] options
|
37
|
+
#
|
38
|
+
# @return [Socket] when successful
|
39
|
+
# @return nil when unsuccessful
|
34
40
|
def self.create context_ptr, type, opts = {:receiver_class => XS::Message}
|
35
41
|
new(context_ptr, type, opts) rescue nil
|
36
42
|
end
|
37
43
|
|
38
|
-
# To avoid rescuing exceptions, use the factory method #create for
|
39
|
-
# all socket creation.
|
40
|
-
#
|
41
44
|
# Allocates a socket of type +type+ for sending and receiving data.
|
42
45
|
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# XS::DEALER or XS::ROUTER.
|
46
|
+
# To avoid rescuing exceptions, use the factory method #create for
|
47
|
+
# all socket creation.
|
46
48
|
#
|
47
49
|
# By default, this class uses XS::Message for manual
|
48
50
|
# memory management. For automatic garbage collection of received messages,
|
49
51
|
# it is possible to override the :receiver_class to use XS::ManagedMessage.
|
50
52
|
#
|
51
|
-
#
|
53
|
+
# @example Socket creation
|
54
|
+
# sock = Socket.new(Context.new, XS::REQ, :receiver_class => XS::ManagedMessage)
|
52
55
|
#
|
53
56
|
# Advanced users may want to replace the receiver class with their
|
54
57
|
# own custom class. The custom class must conform to the same public API
|
@@ -58,12 +61,22 @@ module XS
|
|
58
61
|
# +context_ptr+ is null or when the allocation of the Crossroads socket within the
|
59
62
|
# context fails.
|
60
63
|
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
64
|
+
# @example
|
65
|
+
# begin
|
66
|
+
# socket = Socket.new(context.pointer, XS::REQ)
|
67
|
+
# rescue ContextError => e
|
68
|
+
# # error handling
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# @param pointer
|
72
|
+
# @param [Constant] type
|
73
|
+
# One of @XS::REQ@, @XS::REP@, @XS::PUB@, @XS::SUB@, @XS::PAIR@,
|
74
|
+
# @XS::PULL@, @XS::PUSH@, @XS::XREQ@, @XS::REP@,
|
75
|
+
# @XS::DEALER@ or @XS::ROUTER@
|
76
|
+
# @param [Hash] options
|
77
|
+
#
|
78
|
+
# @return [Socket] when successful
|
79
|
+
# @return nil when unsuccessful
|
67
80
|
def initialize context_ptr, type, opts = {:receiver_class => XS::Message}
|
68
81
|
# users may override the classes used for receiving; class must conform to the
|
69
82
|
# same public API as XS::Message
|
@@ -90,41 +103,29 @@ module XS
|
|
90
103
|
define_finalizer
|
91
104
|
end
|
92
105
|
|
93
|
-
# Set the queue options on this socket
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
# XS::RCVHWM (version 3 only)
|
110
|
-
# XS::MULTICAST_HOPS (version 3 only)
|
111
|
-
# XS::RCVTIMEO (version 3 only)
|
112
|
-
# XS::SNDTIMEO (version 3 only)
|
113
|
-
#
|
114
|
-
# Valid +name+ values that take a string +value+ are:
|
115
|
-
# XS::IDENTITY (version 2/3 only)
|
116
|
-
# XS::SUBSCRIBE
|
117
|
-
# XS::UNSUBSCRIBE
|
118
|
-
#
|
119
|
-
# Returns 0 when the operation completed successfully.
|
120
|
-
# Returns -1 when this operation failed.
|
106
|
+
# Set the queue options on this socket
|
107
|
+
#
|
108
|
+
# @param [Constant] name numeric values
|
109
|
+
# One of @XS::AFFINITY@, @XS::RATE@, @XS::RECOVERY_IVL@,
|
110
|
+
# @XS::LINGER@, @XS::RECONNECT_IVL@, @XS::BACKLOG@,
|
111
|
+
# @XS::RECONNECT_IVL_MAX@, @XS::MAXMSGSIZE@, @XS::SNDHWM@,
|
112
|
+
# @XS::RCVHWM@, @XS::MULTICAST_HOPS@, @XS::RCVTIMEO@,
|
113
|
+
# @XS::SNDTIMEO@, @XS::IPV4ONLY@, @XS::KEEPALIVE@,
|
114
|
+
# @XS::SUBSCRIBE@, @XS::UNSUBSCRIBE@, @XS::IDENTITY@,
|
115
|
+
# @XS::SNDBUF@, @XS::RCVBUF@
|
116
|
+
# @param [Constant] name string values
|
117
|
+
# One of @XS::IDENTITY@, @XS::SUBSCRIBE@ or @XS::UNSUBSCRIBE@
|
118
|
+
# @param value
|
119
|
+
#
|
120
|
+
# @return 0 when the operation completed successfully
|
121
|
+
# @return -1 when this operation fails
|
121
122
|
#
|
122
123
|
# With a -1 return code, the user must check XS.errno to determine the
|
123
124
|
# cause.
|
124
125
|
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
126
|
+
# @example
|
127
|
+
# rc = socket.setsockopt(XS::LINGER, 1_000)
|
128
|
+
# XS::Util.resultcode_ok?(rc) ? puts("succeeded") : puts("failed")
|
128
129
|
def setsockopt name, value, length = nil
|
129
130
|
if 1 == @option_lookup[name]
|
130
131
|
length = 8
|
@@ -156,18 +157,21 @@ module XS
|
|
156
157
|
# Warning: if the call to #getsockopt fails, this method will return
|
157
158
|
# false and swallow the error.
|
158
159
|
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
160
|
+
# @example
|
161
|
+
# message_parts = []
|
162
|
+
# message = Message.new
|
163
|
+
# rc = socket.recvmsg(message)
|
164
|
+
# if XS::Util.resultcode_ok?(rc)
|
165
|
+
# message_parts << message
|
166
|
+
# while more_parts?
|
167
|
+
# message = Message.new
|
168
|
+
# rc = socket.recvmsg(message)
|
169
|
+
# message_parts.push(message) if resultcode_ok?(rc)
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
#
|
173
|
+
# @return true if more message parts
|
174
|
+
# @return false if not
|
171
175
|
def more_parts?
|
172
176
|
rc = getsockopt XS::RCVMORE, @more_parts_array
|
173
177
|
|
@@ -176,16 +180,23 @@ module XS
|
|
176
180
|
|
177
181
|
# Binds the socket to an +address+.
|
178
182
|
#
|
179
|
-
#
|
183
|
+
# @example
|
184
|
+
# socket.bind("tcp://127.0.0.1:5555")
|
180
185
|
#
|
186
|
+
# @param address
|
181
187
|
def bind address
|
182
188
|
LibXS.xs_bind @socket, address
|
183
189
|
end
|
184
190
|
|
185
191
|
# Connects the socket to an +address+.
|
186
192
|
#
|
187
|
-
#
|
193
|
+
# @example
|
194
|
+
# rc = socket.connect("tcp://127.0.0.1:5555")
|
188
195
|
#
|
196
|
+
# @param address
|
197
|
+
#
|
198
|
+
# @return 0 if successful
|
199
|
+
# @return -1 if unsuccessful
|
189
200
|
def connect address
|
190
201
|
rc = LibXS.xs_connect @socket, address
|
191
202
|
end
|
@@ -193,12 +204,12 @@ module XS
|
|
193
204
|
# Closes the socket. Any unprocessed messages in queue are sent or dropped
|
194
205
|
# depending upon the value of the socket option XS::LINGER.
|
195
206
|
#
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
# rc = socket.close
|
200
|
-
# puts("Given socket was invalid!") unless 0 == rc
|
207
|
+
# @example
|
208
|
+
# rc = socket.close
|
209
|
+
# puts("Given socket was invalid!") unless 0 == rc
|
201
210
|
#
|
211
|
+
# @return 0 upon success *or* when the socket has already been closed
|
212
|
+
# @return -1 when the operation fails. Check XS.errno for the error code
|
202
213
|
def close
|
203
214
|
if @socket
|
204
215
|
remove_finalizer
|
@@ -214,151 +225,155 @@ module XS
|
|
214
225
|
# Queues the message for transmission. Message is assumed to conform to the
|
215
226
|
# same public API as #Message.
|
216
227
|
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
#
|
220
|
-
#
|
228
|
+
# @param message
|
229
|
+
# @param flag
|
230
|
+
# One of @0 (default) - blocking operation@, @XS::NonBlocking - non-blocking operation@,
|
231
|
+
# @XS::SNDMORE - this message is part of a multi-part message@
|
221
232
|
#
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
233
|
+
# @return 0 when the message was successfully enqueued
|
234
|
+
# @return -1 under two conditions
|
235
|
+
# 1. The message could not be enqueued
|
236
|
+
# 2. When +flag+ is set with XS::NonBlocking and the socket returned EAGAIN.
|
226
237
|
#
|
227
238
|
# With a -1 return code, the user must check XS.errno to determine the
|
228
239
|
# cause.
|
229
|
-
|
230
|
-
|
231
|
-
__sendmsg__(@socket, message.address, flags)
|
240
|
+
def sendmsg message, flag = 0
|
241
|
+
__sendmsg__(@socket, message.address, flag)
|
232
242
|
end
|
233
243
|
|
234
244
|
# Helper method to make a new #Message instance out of the +string+ passed
|
235
245
|
# in for transmission.
|
236
246
|
#
|
237
|
-
#
|
247
|
+
# @param message
|
248
|
+
# @param flag
|
249
|
+
# One of @0 (default)@, @XS::NonBlocking@ and @XS::SNDMORE@
|
238
250
|
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
#
|
251
|
+
# @return 0 when the message was successfully enqueued
|
252
|
+
# @return -1 under two conditions
|
253
|
+
# 1. The message could not be enqueued
|
254
|
+
# 2. When +flag+ is set with XS::NonBlocking and the socket returned EAGAIN.
|
243
255
|
#
|
244
256
|
# With a -1 return code, the user must check XS.errno to determine the
|
245
257
|
# cause.
|
246
|
-
|
247
|
-
def send_string string, flags = 0
|
258
|
+
def send_string string, flag = 0
|
248
259
|
message = Message.new string
|
249
|
-
send_and_close message,
|
260
|
+
send_and_close message, flag
|
250
261
|
end
|
251
262
|
|
252
263
|
# Send a sequence of strings as a multipart message out of the +parts+
|
253
264
|
# passed in for transmission. Every element of +parts+ should be
|
254
265
|
# a String.
|
255
266
|
#
|
256
|
-
#
|
267
|
+
# @param [Array] parts
|
268
|
+
# @param flag
|
269
|
+
# One of @0 (default)@ and @XS::NonBlocking@
|
257
270
|
#
|
258
|
-
#
|
259
|
-
#
|
260
|
-
#
|
261
|
-
#
|
271
|
+
# @return 0 when the messages were successfully enqueued
|
272
|
+
# @return -1 under two conditions
|
273
|
+
# 1. A message could not be enqueued
|
274
|
+
# 2. When +flag+ is set with XS::NonBlocking and the socket returned EAGAIN.
|
262
275
|
#
|
263
276
|
# With a -1 return code, the user must check XS.errno to determine the
|
264
277
|
# cause.
|
265
|
-
|
266
|
-
def send_strings parts, flags = 0
|
278
|
+
def send_strings parts, flag = 0
|
267
279
|
return -1 if !parts || parts.empty?
|
268
|
-
|
280
|
+
flag = NonBlocking if dontwait?(flag)
|
269
281
|
|
270
282
|
parts[0..-2].each do |part|
|
271
|
-
rc = send_string part, (
|
283
|
+
rc = send_string part, (flag | XS::SNDMORE)
|
272
284
|
return rc unless Util.resultcode_ok?(rc)
|
273
285
|
end
|
274
286
|
|
275
|
-
send_string parts[-1],
|
287
|
+
send_string parts[-1], flag
|
276
288
|
end
|
277
289
|
|
278
290
|
# Send a sequence of messages as a multipart message out of the +parts+
|
279
291
|
# passed in for transmission. Every element of +parts+ should be
|
280
292
|
# a Message (or subclass).
|
281
293
|
#
|
282
|
-
#
|
294
|
+
# @param [Array] parts
|
295
|
+
# @param flag
|
296
|
+
# One of @0 (default)@ and @XS::NonBlocking@
|
283
297
|
#
|
284
|
-
#
|
285
|
-
#
|
286
|
-
#
|
287
|
-
#
|
298
|
+
# @return 0 when the messages were successfully enqueued
|
299
|
+
# @return -1 under two conditions
|
300
|
+
# 1. A message could not be enqueued
|
301
|
+
# 2. When +flag+ is set with XS::NonBlocking and the socket returned EAGAIN
|
288
302
|
#
|
289
303
|
# With a -1 return code, the user must check XS.errno to determine the
|
290
304
|
# cause.
|
291
|
-
|
292
|
-
def sendmsgs parts, flags = 0
|
305
|
+
def sendmsgs parts, flag = 0
|
293
306
|
return -1 if !parts || parts.empty?
|
294
|
-
|
307
|
+
flag = NonBlocking if dontwait?(flag)
|
295
308
|
|
296
309
|
parts[0..-2].each do |part|
|
297
|
-
rc = sendmsg part, (
|
310
|
+
rc = sendmsg part, (flag | XS::SNDMORE)
|
298
311
|
return rc unless Util.resultcode_ok?(rc)
|
299
312
|
end
|
300
313
|
|
301
|
-
sendmsg parts[-1],
|
314
|
+
sendmsg parts[-1], flag
|
302
315
|
end
|
303
316
|
|
304
317
|
# Sends a message. This will automatically close the +message+ for both successful
|
305
318
|
# and failed sends.
|
306
319
|
#
|
307
|
-
#
|
308
|
-
#
|
309
|
-
#
|
310
|
-
#
|
320
|
+
# @param message
|
321
|
+
# @param flag
|
322
|
+
# One of @0 (default)@ and @XS::NonBlocking
|
323
|
+
#
|
324
|
+
# @return 0 when the message was successfully enqueued
|
325
|
+
# @return -1 under two conditions
|
326
|
+
# 1. The message could not be enqueued
|
327
|
+
# 2. When +flag+ is set with XS::NonBlocking and the socket returned EAGAIN.
|
311
328
|
#
|
312
329
|
# With a -1 return code, the user must check XS.errno to determine the
|
313
330
|
# cause.
|
314
|
-
|
315
|
-
|
316
|
-
rc = sendmsg message, flags
|
331
|
+
def send_and_close message, flag = 0
|
332
|
+
rc = sendmsg message, flag
|
317
333
|
message.close
|
318
334
|
rc
|
319
335
|
end
|
320
336
|
|
321
337
|
# Dequeues a message from the underlying queue. By default, this is a blocking operation.
|
322
338
|
#
|
323
|
-
#
|
324
|
-
#
|
325
|
-
#
|
339
|
+
# @param message
|
340
|
+
# @param flag
|
341
|
+
# One of @0 (default) - blocking operation@ and @XS::NonBlocking - non-blocking operation@
|
326
342
|
#
|
327
|
-
#
|
328
|
-
#
|
329
|
-
#
|
330
|
-
#
|
343
|
+
# @return 0 when the message was successfully dequeued
|
344
|
+
# @return -1 under two conditions
|
345
|
+
# 1. The message could not be dequeued
|
346
|
+
# 2. When +flags+ is set with XS::NonBlocking and the socket returned EAGAIN
|
331
347
|
#
|
332
348
|
# With a -1 return code, the user must check XS.errno to determine the
|
333
349
|
# cause.
|
334
350
|
#
|
335
351
|
# The application code is responsible for handling the +message+ object lifecycle
|
336
352
|
# when #recv returns an error code.
|
337
|
-
|
338
|
-
|
339
|
-
#LibXS.xs_recvmsg @socket, message.address, flags
|
340
|
-
__recvmsg__(@socket, message.address, flags)
|
353
|
+
def recvmsg message, flag = 0
|
354
|
+
__recvmsg__(@socket, message.address, flag)
|
341
355
|
end
|
342
356
|
|
343
357
|
# Helper method to make a new #Message instance and convert its payload
|
344
358
|
# to a string.
|
345
359
|
#
|
346
|
-
#
|
360
|
+
# @param string
|
361
|
+
# @param flag
|
362
|
+
# One of @0 (default)@ and @XS::NonBlocking@
|
347
363
|
#
|
348
|
-
#
|
349
|
-
#
|
350
|
-
#
|
351
|
-
#
|
364
|
+
# @return 0 when the message was successfully dequeued
|
365
|
+
# @return -1 under two conditions
|
366
|
+
# 1. The message could not be dequeued
|
367
|
+
# 2. When +flag+ is set with XS::NonBlocking and the socket returned EAGAIN
|
352
368
|
#
|
353
369
|
# With a -1 return code, the user must check XS.errno to determine the
|
354
370
|
# cause.
|
355
371
|
#
|
356
372
|
# The application code is responsible for handling the +message+ object lifecycle
|
357
373
|
# when #recv returns an error code.
|
358
|
-
|
359
|
-
def recv_string string, flags = 0
|
374
|
+
def recv_string string, flag = 0
|
360
375
|
message = @receiver_klass.new
|
361
|
-
rc = recvmsg message,
|
376
|
+
rc = recvmsg message, flag
|
362
377
|
string.replace(message.copy_out_string) if Util.resultcode_ok?(rc)
|
363
378
|
message.close
|
364
379
|
rc
|
@@ -366,9 +381,13 @@ module XS
|
|
366
381
|
|
367
382
|
# Receive a multipart message as a list of strings.
|
368
383
|
#
|
369
|
-
#
|
370
|
-
#
|
384
|
+
# @param [Array] list
|
385
|
+
# @param flag
|
386
|
+
# One of @0 (default)@ and @XS::NonBlocking@. Any other flag will be
|
387
|
+
# removed.
|
371
388
|
#
|
389
|
+
# @return 0 if successful
|
390
|
+
# @return -1 if unsuccessful
|
372
391
|
def recv_strings list, flag = 0
|
373
392
|
array = []
|
374
393
|
rc = recvmsgs array, flag
|
@@ -386,9 +405,13 @@ module XS
|
|
386
405
|
# Receive a multipart message as an array of objects
|
387
406
|
# (by default these are instances of Message).
|
388
407
|
#
|
389
|
-
#
|
390
|
-
#
|
408
|
+
# @param [Array] list
|
409
|
+
# @param flag
|
410
|
+
# One of @0 (default)@ and @XS::NonBlocking@. Any other flag will be
|
411
|
+
# removed.
|
391
412
|
#
|
413
|
+
# @return 0 if successful
|
414
|
+
# @return -1 if unsuccessful
|
392
415
|
def recvmsgs list, flag = 0
|
393
416
|
flag = NonBlocking if dontwait?(flag)
|
394
417
|
|
@@ -424,6 +447,13 @@ module XS
|
|
424
447
|
# a +list+ for receiving the message body parts and a +routing_envelope+
|
425
448
|
# for receiving the message parts comprising the 0mq routing information.
|
426
449
|
#
|
450
|
+
# @param [Array] list
|
451
|
+
# @param routing_envelope
|
452
|
+
# @param flag
|
453
|
+
# One of @0 (default)@ and @XS::NonBlocking@
|
454
|
+
#
|
455
|
+
# @return 0 if successful
|
456
|
+
# @return -1 if unsuccessful
|
427
457
|
def recv_multipart list, routing_envelope, flag = 0
|
428
458
|
parts = []
|
429
459
|
rc = recvmsgs parts, flag
|
@@ -446,6 +476,12 @@ module XS
|
|
446
476
|
|
447
477
|
private
|
448
478
|
|
479
|
+
# Gets socket option
|
480
|
+
#
|
481
|
+
# @param name
|
482
|
+
# @param array
|
483
|
+
#
|
484
|
+
# @return option number
|
449
485
|
def __getsockopt__ name, array
|
450
486
|
# a small optimization so we only have to determine the option
|
451
487
|
# type a single time; gives approx 5% speedup to do it this way.
|
@@ -468,9 +504,12 @@ module XS
|
|
468
504
|
rc
|
469
505
|
end
|
470
506
|
|
471
|
-
# Calls to
|
507
|
+
# Calls to xs_getsockopt require us to pass in some pointers. We can cache and save those buffers
|
472
508
|
# for subsequent calls. This is a big perf win for calling RCVMORE which happens quite often.
|
473
509
|
# Cannot save the buffer for the IDENTITY.
|
510
|
+
#
|
511
|
+
# @param option_type
|
512
|
+
# @return cached number or string
|
474
513
|
def sockopt_buffers option_type
|
475
514
|
if 1 == option_type
|
476
515
|
# int64_t or uint64_t
|
@@ -510,9 +549,10 @@ module XS
|
|
510
549
|
end
|
511
550
|
end
|
512
551
|
|
552
|
+
# Populate socket option lookup array
|
513
553
|
def populate_option_lookup
|
514
554
|
# integer options
|
515
|
-
[EVENTS, LINGER, RECONNECT_IVL, FD, TYPE, BACKLOG].each { |option| @option_lookup[option] = 0 }
|
555
|
+
[EVENTS, LINGER, RECONNECT_IVL, FD, TYPE, BACKLOG, KEEPALIVE, IPV4ONLY].each { |option| @option_lookup[option] = 0 }
|
516
556
|
|
517
557
|
# long long options
|
518
558
|
[RCVMORE, AFFINITY].each { |option| @option_lookup[option] = 1 }
|
@@ -521,13 +561,20 @@ module XS
|
|
521
561
|
[SUBSCRIBE, UNSUBSCRIBE].each { |option| @option_lookup[option] = 2 }
|
522
562
|
end
|
523
563
|
|
564
|
+
# Initialize caches
|
524
565
|
def release_cache
|
525
566
|
@longlong_cache = nil
|
526
567
|
@int_cache = nil
|
527
568
|
end
|
528
569
|
|
529
|
-
|
530
|
-
|
570
|
+
# Convenience method to decide whether flag is DONTWAIT
|
571
|
+
#
|
572
|
+
# @param flag
|
573
|
+
#
|
574
|
+
# @return true if is DONTWAIT
|
575
|
+
# @return false if not
|
576
|
+
def dontwait?(flag)
|
577
|
+
(NonBlocking & flag) == NonBlocking
|
531
578
|
end
|
532
579
|
alias :noblock? :dontwait?
|
533
580
|
end # module CommonSocketBehavior
|
@@ -537,6 +584,7 @@ module XS
|
|
537
584
|
|
538
585
|
# Convenience method for getting the value of the socket IDENTITY.
|
539
586
|
#
|
587
|
+
# @return identity
|
540
588
|
def identity
|
541
589
|
array = []
|
542
590
|
getsockopt IDENTITY, array
|
@@ -545,6 +593,7 @@ module XS
|
|
545
593
|
|
546
594
|
# Convenience method for setting the value of the socket IDENTITY.
|
547
595
|
#
|
596
|
+
# @param value
|
548
597
|
def identity=(value)
|
549
598
|
setsockopt IDENTITY, value.to_s
|
550
599
|
end
|
@@ -552,6 +601,7 @@ module XS
|
|
552
601
|
|
553
602
|
private
|
554
603
|
|
604
|
+
# Populate option lookup array
|
555
605
|
def populate_option_lookup
|
556
606
|
super()
|
557
607
|
|
@@ -567,39 +617,28 @@ module XS
|
|
567
617
|
|
568
618
|
# Get the options set on this socket.
|
569
619
|
#
|
570
|
-
#
|
571
|
-
#
|
572
|
-
#
|
573
|
-
#
|
574
|
-
#
|
575
|
-
#
|
576
|
-
#
|
577
|
-
#
|
578
|
-
#
|
579
|
-
#
|
580
|
-
#
|
581
|
-
#
|
582
|
-
#
|
583
|
-
#
|
584
|
-
# XS::RCVBUF - integer
|
585
|
-
# XS::FD - fd in an integer
|
586
|
-
# XS::EVENTS - bitmap integer
|
587
|
-
# XS::LINGER - integer measured in milliseconds
|
588
|
-
# XS::RECONNECT_IVL - integer measured in milliseconds
|
589
|
-
# XS::BACKLOG - integer
|
590
|
-
# XS::RECOVER_IVL_MSEC - integer measured in milliseconds
|
591
|
-
#
|
592
|
-
# Returns 0 when the operation completed successfully.
|
593
|
-
# Returns -1 when this operation failed.
|
620
|
+
# @param name
|
621
|
+
# One of @XS::RCVMORE@, @XS::SNDHWM@, @XS::AFFINITY@, @XS::IDENTITY@,
|
622
|
+
# @XS::RATE@, @XS::RECOVERY_IVL@, @XS::SNDBUF@,
|
623
|
+
# @XS::RCVBUF@, @XS::FD@, @XS::EVENTS@, @XS::LINGER@,
|
624
|
+
# @XS::RECONNECT_IVL@, @XS::BACKLOG@, XS::RECONNECT_IVL_MAX@,
|
625
|
+
# @XS::RCVTIMEO@, @XS::SNDTIMEO@, @XS::IPV4ONLY@, @XS::TYPE@,
|
626
|
+
# @XS::RCVHWM@, @XS::MAXMSGSIZE@, @XS::MULTICAST_HOPS@,
|
627
|
+
# @XS::KEEPALIVE@
|
628
|
+
# @param array should be an empty array; a result of the proper type
|
629
|
+
# (numeric, string, boolean) will be inserted into
|
630
|
+
# the first position.
|
631
|
+
#
|
632
|
+
# @return 0 when the operation completed successfully
|
633
|
+
# @return -1 when this operation failed
|
594
634
|
#
|
595
635
|
# With a -1 return code, the user must check XS.errno to determine the
|
596
636
|
# cause.
|
597
637
|
#
|
598
|
-
#
|
599
|
-
#
|
600
|
-
#
|
601
|
-
#
|
602
|
-
#
|
638
|
+
# @example Retrieve send high water mark
|
639
|
+
# array = []
|
640
|
+
# rc = socket.getsockopt(XS::SNDHWM, array)
|
641
|
+
# sndhwm = array.first if XS::Util.resultcode_ok?(rc)
|
603
642
|
def getsockopt name, array
|
604
643
|
rc = __getsockopt__ name, array
|
605
644
|
|
@@ -614,14 +653,30 @@ module XS
|
|
614
653
|
|
615
654
|
private
|
616
655
|
|
617
|
-
|
618
|
-
|
656
|
+
# Queue message to send
|
657
|
+
#
|
658
|
+
# @param socket
|
659
|
+
# @param address
|
660
|
+
# @param flag
|
661
|
+
def __sendmsg__(socket, address, flag)
|
662
|
+
LibXS.xs_sendmsg(socket, address, flag)
|
619
663
|
end
|
620
664
|
|
621
|
-
|
622
|
-
|
665
|
+
# Receive message
|
666
|
+
#
|
667
|
+
# @param socket
|
668
|
+
# @param address
|
669
|
+
# @param flag
|
670
|
+
def __recvmsg__(socket, address, flag)
|
671
|
+
LibXS.xs_recvmsg(socket, address, flag)
|
623
672
|
end
|
624
673
|
|
674
|
+
# Convenience method to decide if option is integer
|
675
|
+
#
|
676
|
+
# @param name
|
677
|
+
#
|
678
|
+
# @return true if integer
|
679
|
+
# @return false if not
|
625
680
|
def int_option? name
|
626
681
|
super(name) ||
|
627
682
|
RECONNECT_IVL_MAX == name ||
|
@@ -633,6 +688,7 @@ module XS
|
|
633
688
|
RCVBUF == name
|
634
689
|
end
|
635
690
|
|
691
|
+
# Populate socket option lookup array
|
636
692
|
def populate_option_lookup
|
637
693
|
super()
|
638
694
|
|
@@ -642,15 +698,18 @@ module XS
|
|
642
698
|
|
643
699
|
# these finalizer-related methods cannot live in the CommonSocketBehavior
|
644
700
|
# module; they *must* be in the class definition directly
|
645
|
-
|
701
|
+
#
|
702
|
+
# Deletes native resources after object has been destroyed
|
646
703
|
def define_finalizer
|
647
704
|
ObjectSpace.define_finalizer(self, self.class.close(@socket))
|
648
705
|
end
|
649
706
|
|
707
|
+
# Removes all finalizers for object
|
650
708
|
def remove_finalizer
|
651
709
|
ObjectSpace.undefine_finalizer self
|
652
710
|
end
|
653
711
|
|
712
|
+
# Closes the socket
|
654
713
|
def self.close socket
|
655
714
|
Proc.new { LibXS.xs_close socket }
|
656
715
|
end
|