ffi-rxs 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|