ffi-rxs 1.0.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.
- data/.gitignore +7 -0
- data/AUTHORS.txt +21 -0
- data/Gemfile +3 -0
- data/README.rdoc +86 -0
- data/Rakefile +6 -0
- data/ext/README +5 -0
- data/ffi-rxs.gemspec +25 -0
- data/lib/ffi-rxs/constants.rb +104 -0
- data/lib/ffi-rxs/constants.rb~ +100 -0
- data/lib/ffi-rxs/context.rb +153 -0
- data/lib/ffi-rxs/context.rb~ +155 -0
- data/lib/ffi-rxs/device.rb~ +28 -0
- data/lib/ffi-rxs/exceptions.rb +47 -0
- data/lib/ffi-rxs/exceptions.rb~ +47 -0
- data/lib/ffi-rxs/libc.rb +19 -0
- data/lib/ffi-rxs/libc.rb~ +19 -0
- data/lib/ffi-rxs/libxs.rb +156 -0
- data/lib/ffi-rxs/libxs.rb~ +156 -0
- data/lib/ffi-rxs/message.rb +282 -0
- data/lib/ffi-rxs/message.rb~ +282 -0
- data/lib/ffi-rxs/poll.rb +212 -0
- data/lib/ffi-rxs/poll.rb~ +212 -0
- data/lib/ffi-rxs/poll_items.rb +120 -0
- data/lib/ffi-rxs/poll_items.rb~ +120 -0
- data/lib/ffi-rxs/socket.rb +659 -0
- data/lib/ffi-rxs/socket.rb~ +659 -0
- data/lib/ffi-rxs/util.rb +105 -0
- data/lib/ffi-rxs/util.rb~ +105 -0
- data/lib/ffi-rxs/version.rb +3 -0
- data/lib/ffi-rxs/version.rb~ +3 -0
- data/lib/ffi-rxs.rb +74 -0
- data/spec/context_spec.rb +138 -0
- data/spec/message_spec.rb +128 -0
- data/spec/multipart_spec.rb +108 -0
- data/spec/nonblocking_recv_spec.rb +309 -0
- data/spec/poll_spec.rb +168 -0
- data/spec/pushpull_spec.rb +113 -0
- data/spec/reqrep_spec.rb +66 -0
- data/spec/socket_spec.rb +496 -0
- data/spec/spec_helper.rb +57 -0
- metadata +126 -0
data/spec/socket_spec.rb
ADDED
@@ -0,0 +1,496 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
3
|
+
|
4
|
+
module XS
|
5
|
+
|
6
|
+
|
7
|
+
describe Socket do
|
8
|
+
|
9
|
+
socket_types = [XS::REQ, XS::REP, XS::DEALER, XS::ROUTER, XS::PUB, XS::SUB, XS::PUSH, XS::PULL, XS::PAIR, XS::XPUB, XS::XSUB]
|
10
|
+
|
11
|
+
context "when initializing" do
|
12
|
+
before(:all) { @ctx = Context.new }
|
13
|
+
after(:all) { @ctx.terminate }
|
14
|
+
|
15
|
+
|
16
|
+
it "should raise an error for a nil context" do
|
17
|
+
lambda { Socket.new(FFI::Pointer.new(0), XS::REQ) }.should raise_exception(XS::ContextError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "works with a Context#pointer as the context_ptr" do
|
21
|
+
lambda do
|
22
|
+
s = Socket.new(@ctx.pointer, XS::REQ)
|
23
|
+
s.close
|
24
|
+
end.should_not raise_exception(XS::ContextError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "works with a Context instance as the context_ptr" do
|
28
|
+
lambda do
|
29
|
+
s = Socket.new(@ctx, XS::SUB)
|
30
|
+
s.close
|
31
|
+
end.should_not raise_exception(XS::ContextError)
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
socket_types.each do |socket_type|
|
36
|
+
|
37
|
+
it "should not raise an error for a [#{XS::SocketTypeNameMap[socket_type]}] socket type" do
|
38
|
+
sock = nil
|
39
|
+
lambda { sock = Socket.new(@ctx.pointer, socket_type) }.should_not raise_error
|
40
|
+
sock.close
|
41
|
+
end
|
42
|
+
end # each socket_type
|
43
|
+
|
44
|
+
it "should set the :socket accessor to the raw socket allocated by libxs" do
|
45
|
+
socket = mock('socket')
|
46
|
+
socket.stub!(:null? => false)
|
47
|
+
LibXS.should_receive(:xs_socket).and_return(socket)
|
48
|
+
|
49
|
+
sock = Socket.new(@ctx.pointer, XS::REQ)
|
50
|
+
sock.socket.should == socket
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should define a finalizer on this object" do
|
54
|
+
ObjectSpace.should_receive(:define_finalizer).at_least(1)
|
55
|
+
sock = Socket.new(@ctx.pointer, XS::REQ)
|
56
|
+
sock.close
|
57
|
+
end
|
58
|
+
end # context initializing
|
59
|
+
|
60
|
+
|
61
|
+
context "calling close" do
|
62
|
+
before(:all) { @ctx = Context.new }
|
63
|
+
after(:all) { @ctx.terminate }
|
64
|
+
|
65
|
+
it "should call LibXS.close only once" do
|
66
|
+
sock = Socket.new @ctx.pointer, XS::REQ
|
67
|
+
raw_socket = sock.socket
|
68
|
+
|
69
|
+
LibXS.should_receive(:close).with(raw_socket)
|
70
|
+
sock.close
|
71
|
+
sock.close
|
72
|
+
LibXS.close raw_socket # *really close it otherwise the context will block indefinitely
|
73
|
+
end
|
74
|
+
end # context calling close
|
75
|
+
|
76
|
+
|
77
|
+
context "identity=" do
|
78
|
+
before(:all) { @ctx = Context.new }
|
79
|
+
after(:all) { @ctx.terminate }
|
80
|
+
|
81
|
+
it "fails to set identity for identities in excess of 255 bytes" do
|
82
|
+
sock = Socket.new @ctx.pointer, XS::REQ
|
83
|
+
|
84
|
+
sock.identity = ('a' * 256)
|
85
|
+
sock.identity.should == ''
|
86
|
+
sock.close
|
87
|
+
end
|
88
|
+
|
89
|
+
it "fails to set identity for identities of length 0" do
|
90
|
+
sock = Socket.new @ctx.pointer, XS::REQ
|
91
|
+
|
92
|
+
sock.identity = ''
|
93
|
+
sock.identity.should == ''
|
94
|
+
sock.close
|
95
|
+
end
|
96
|
+
|
97
|
+
it "sets the identity for identities of 1 byte" do
|
98
|
+
sock = Socket.new @ctx.pointer, XS::REQ
|
99
|
+
|
100
|
+
sock.identity = 'a'
|
101
|
+
sock.identity.should == 'a'
|
102
|
+
sock.close
|
103
|
+
end
|
104
|
+
|
105
|
+
it "set the identity identities of 255 bytes" do
|
106
|
+
sock = Socket.new @ctx.pointer, XS::REQ
|
107
|
+
|
108
|
+
sock.identity = ('a' * 255)
|
109
|
+
sock.identity.should == ('a' * 255)
|
110
|
+
sock.close
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should convert numeric identities to strings" do
|
114
|
+
sock = Socket.new @ctx.pointer, XS::REQ
|
115
|
+
|
116
|
+
sock.identity = 7
|
117
|
+
sock.identity.should == '7'
|
118
|
+
sock.close
|
119
|
+
end
|
120
|
+
end # context identity=
|
121
|
+
|
122
|
+
|
123
|
+
socket_types.each do |socket_type|
|
124
|
+
|
125
|
+
context "#setsockopt for a #{XS::SocketTypeNameMap[socket_type]} socket" do
|
126
|
+
before(:all) { @ctx = Context.new }
|
127
|
+
after(:all) { @ctx.terminate }
|
128
|
+
|
129
|
+
let(:socket) do
|
130
|
+
Socket.new @ctx.pointer, socket_type
|
131
|
+
end
|
132
|
+
|
133
|
+
after(:each) do
|
134
|
+
socket.close
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
context "using option XS::IDENTITY" do
|
139
|
+
it "should set the identity given any string under 255 characters" do
|
140
|
+
length = 4
|
141
|
+
(1..255).each do |length|
|
142
|
+
identity = 'a' * length
|
143
|
+
socket.setsockopt XS::IDENTITY, identity
|
144
|
+
|
145
|
+
array = []
|
146
|
+
rc = socket.getsockopt(XS::IDENTITY, array)
|
147
|
+
rc.should == 0
|
148
|
+
array[0].should == identity
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
it "returns -1 given a string 256 characters or longer" do
|
153
|
+
identity = 'a' * 256
|
154
|
+
array = []
|
155
|
+
rc = socket.setsockopt(XS::IDENTITY, identity)
|
156
|
+
rc.should == -1
|
157
|
+
end
|
158
|
+
end # context using option XS::IDENTITY
|
159
|
+
|
160
|
+
|
161
|
+
context "using option XS::SUBSCRIBE" do
|
162
|
+
if XS::SUB == socket_type
|
163
|
+
it "returns 0 for a SUB socket" do
|
164
|
+
rc = socket.setsockopt(XS::SUBSCRIBE, "topic.string")
|
165
|
+
rc.should == 0
|
166
|
+
end
|
167
|
+
else
|
168
|
+
it "returns -1 for non-SUB sockets" do
|
169
|
+
rc = socket.setsockopt(XS::SUBSCRIBE, "topic.string")
|
170
|
+
rc.should == -1
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end # context using option XS::SUBSCRIBE
|
174
|
+
|
175
|
+
|
176
|
+
context "using option XS::UNSUBSCRIBE" do
|
177
|
+
if XS::SUB == socket_type
|
178
|
+
it "returns 0 given a topic string that was previously subscribed" do
|
179
|
+
socket.setsockopt XS::SUBSCRIBE, "topic.string"
|
180
|
+
rc = socket.setsockopt(XS::UNSUBSCRIBE, "topic.string")
|
181
|
+
rc.should == 0
|
182
|
+
end
|
183
|
+
|
184
|
+
else
|
185
|
+
it "returns -1 for non-SUB sockets" do
|
186
|
+
rc = socket.setsockopt(XS::UNSUBSCRIBE, "topic.string")
|
187
|
+
rc.should == -1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end # context using option XS::UNSUBSCRIBE
|
191
|
+
|
192
|
+
|
193
|
+
context "using option XS::AFFINITY" do
|
194
|
+
it "should set the affinity value given a positive value" do
|
195
|
+
affinity = 3
|
196
|
+
socket.setsockopt XS::AFFINITY, affinity
|
197
|
+
array = []
|
198
|
+
rc = socket.getsockopt(XS::AFFINITY, array)
|
199
|
+
rc.should == 0
|
200
|
+
array[0].should == affinity
|
201
|
+
end
|
202
|
+
end # context using option XS::AFFINITY
|
203
|
+
|
204
|
+
|
205
|
+
context "using option XS::RATE" do
|
206
|
+
it "should set the multicast send rate given a positive value" do
|
207
|
+
rate = 200
|
208
|
+
socket.setsockopt XS::RATE, rate
|
209
|
+
array = []
|
210
|
+
rc = socket.getsockopt(XS::RATE, array)
|
211
|
+
rc.should == 0
|
212
|
+
array[0].should == rate
|
213
|
+
end
|
214
|
+
|
215
|
+
it "returns -1 given a negative value" do
|
216
|
+
rate = -200
|
217
|
+
rc = socket.setsockopt XS::RATE, rate
|
218
|
+
rc.should == -1
|
219
|
+
end
|
220
|
+
end # context using option XS::RATE
|
221
|
+
|
222
|
+
|
223
|
+
context "using option XS::RECOVERY_IVL" do
|
224
|
+
it "should set the multicast recovery buffer measured in seconds given a positive value" do
|
225
|
+
rate = 200
|
226
|
+
socket.setsockopt XS::RECOVERY_IVL, rate
|
227
|
+
array = []
|
228
|
+
rc = socket.getsockopt(XS::RECOVERY_IVL, array)
|
229
|
+
rc.should == 0
|
230
|
+
array[0].should == rate
|
231
|
+
end
|
232
|
+
|
233
|
+
it "returns -1 given a negative value" do
|
234
|
+
rate = -200
|
235
|
+
rc = socket.setsockopt XS::RECOVERY_IVL, rate
|
236
|
+
rc.should == -1
|
237
|
+
end
|
238
|
+
end # context using option XS::RECOVERY_IVL
|
239
|
+
|
240
|
+
|
241
|
+
context "using option XS::SNDBUF" do
|
242
|
+
it "should set the OS send buffer given a positive value" do
|
243
|
+
size = 100
|
244
|
+
socket.setsockopt XS::SNDBUF, size
|
245
|
+
array = []
|
246
|
+
rc = socket.getsockopt(XS::SNDBUF, array)
|
247
|
+
rc.should == 0
|
248
|
+
array[0].should == size
|
249
|
+
end
|
250
|
+
end # context using option XS::SNDBUF
|
251
|
+
|
252
|
+
|
253
|
+
context "using option XS::RCVBUF" do
|
254
|
+
it "should set the OS receive buffer given a positive value" do
|
255
|
+
size = 100
|
256
|
+
socket.setsockopt XS::RCVBUF, size
|
257
|
+
array = []
|
258
|
+
rc = socket.getsockopt(XS::RCVBUF, array)
|
259
|
+
rc.should == 0
|
260
|
+
array[0].should == size
|
261
|
+
end
|
262
|
+
end # context using option XS::RCVBUF
|
263
|
+
|
264
|
+
|
265
|
+
context "using option XS::LINGER" do
|
266
|
+
it "should set the socket message linger option measured in milliseconds given a positive value" do
|
267
|
+
value = 200
|
268
|
+
socket.setsockopt XS::LINGER, value
|
269
|
+
array = []
|
270
|
+
rc = socket.getsockopt(XS::LINGER, array)
|
271
|
+
rc.should == 0
|
272
|
+
array[0].should == value
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should set the socket message linger option to 0 for dropping packets" do
|
276
|
+
value = 0
|
277
|
+
socket.setsockopt XS::LINGER, value
|
278
|
+
array = []
|
279
|
+
rc = socket.getsockopt(XS::LINGER, array)
|
280
|
+
rc.should == 0
|
281
|
+
array[0].should == value
|
282
|
+
end
|
283
|
+
|
284
|
+
if (defined?(XS::XSUB) && XS::XSUB == socket_type) or
|
285
|
+
(defined?(XS::SUB) && XS::SUB == socket_type)
|
286
|
+
it "should default to a value of 0" do
|
287
|
+
value = 0
|
288
|
+
array = []
|
289
|
+
rc = socket.getsockopt(XS::LINGER, array)
|
290
|
+
rc.should == 0
|
291
|
+
array[0].should == value
|
292
|
+
end
|
293
|
+
else
|
294
|
+
it "should default to a value of -1" do
|
295
|
+
value = -1
|
296
|
+
array = []
|
297
|
+
rc = socket.getsockopt(XS::LINGER, array)
|
298
|
+
rc.should == 0
|
299
|
+
array[0].should == value
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end # context using option XS::LINGER
|
303
|
+
|
304
|
+
|
305
|
+
context "using option XS::RECONNECT_IVL" do
|
306
|
+
it "should set the time interval for reconnecting disconnected sockets measured in milliseconds given a positive value" do
|
307
|
+
value = 200
|
308
|
+
socket.setsockopt XS::RECONNECT_IVL, value
|
309
|
+
array = []
|
310
|
+
rc = socket.getsockopt(XS::RECONNECT_IVL, array)
|
311
|
+
rc.should == 0
|
312
|
+
array[0].should == value
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should default to a value of 100" do
|
316
|
+
value = 100
|
317
|
+
array = []
|
318
|
+
rc = socket.getsockopt(XS::RECONNECT_IVL, array)
|
319
|
+
rc.should == 0
|
320
|
+
array[0].should == value
|
321
|
+
end
|
322
|
+
end # context using option XS::RECONNECT_IVL
|
323
|
+
|
324
|
+
|
325
|
+
context "using option XS::BACKLOG" do
|
326
|
+
it "should set the maximum number of pending socket connections given a positive value" do
|
327
|
+
value = 200
|
328
|
+
socket.setsockopt XS::BACKLOG, value
|
329
|
+
array = []
|
330
|
+
rc = socket.getsockopt(XS::BACKLOG, array)
|
331
|
+
rc.should == 0
|
332
|
+
array[0].should == value
|
333
|
+
end
|
334
|
+
|
335
|
+
it "should default to a value of 100" do
|
336
|
+
value = 100
|
337
|
+
array = []
|
338
|
+
rc = socket.getsockopt(XS::BACKLOG, array)
|
339
|
+
rc.should == 0
|
340
|
+
array[0].should == value
|
341
|
+
end
|
342
|
+
end # context using option XS::BACKLOG
|
343
|
+
end # context #setsockopt
|
344
|
+
|
345
|
+
|
346
|
+
context "#getsockopt for a #{XS::SocketTypeNameMap[socket_type]} socket" do
|
347
|
+
before(:all) { @ctx = Context.new }
|
348
|
+
after(:all) { @ctx.terminate }
|
349
|
+
|
350
|
+
let(:socket) do
|
351
|
+
Socket.new @ctx.pointer, socket_type
|
352
|
+
end
|
353
|
+
|
354
|
+
after(:each) do
|
355
|
+
socket.close
|
356
|
+
end
|
357
|
+
|
358
|
+
if RUBY_PLATFORM =~ /linux|darwin/
|
359
|
+
# this spec doesn't work on Windows; hints welcome
|
360
|
+
|
361
|
+
context "using option XS::FD" do
|
362
|
+
it "should return an FD as a positive integer" do
|
363
|
+
array = []
|
364
|
+
rc = socket.getsockopt(XS::FD, array)
|
365
|
+
rc.should == 0
|
366
|
+
array[0].should be_a(Fixnum)
|
367
|
+
end
|
368
|
+
|
369
|
+
it "returns a valid FD that is accepted by the system poll() function" do
|
370
|
+
# Use FFI to wrap the C library function +poll+ so that we can execute it
|
371
|
+
# on the 0mq file descriptor. If it returns 0, then it succeeded and the FD
|
372
|
+
# is valid!
|
373
|
+
module LibSocket
|
374
|
+
extend FFI::Library
|
375
|
+
# figures out the correct libc for each platform including Windows
|
376
|
+
library = ffi_lib(FFI::Library::LIBC).first
|
377
|
+
|
378
|
+
find_type(:nfds_t) rescue typedef(:uint32, :nfds_t)
|
379
|
+
|
380
|
+
attach_function :poll, [:pointer, :nfds_t, :int], :int
|
381
|
+
|
382
|
+
class PollFD < FFI::Struct
|
383
|
+
layout :fd, :int,
|
384
|
+
:events, :short,
|
385
|
+
:revents, :short
|
386
|
+
end
|
387
|
+
end # module LibSocket
|
388
|
+
|
389
|
+
array = []
|
390
|
+
rc = socket.getsockopt(XS::FD, array)
|
391
|
+
rc.should be_zero
|
392
|
+
fd = array[0]
|
393
|
+
|
394
|
+
# setup the BSD poll_fd struct
|
395
|
+
pollfd = LibSocket::PollFD.new
|
396
|
+
pollfd[:fd] = fd
|
397
|
+
pollfd[:events] = 0
|
398
|
+
pollfd[:revents] = 0
|
399
|
+
|
400
|
+
rc = LibSocket.poll(pollfd, 1, 0)
|
401
|
+
rc.should be_zero
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
end # posix platform
|
406
|
+
|
407
|
+
context "using option XS::EVENTS" do
|
408
|
+
it "should return a mask of events as a Fixnum" do
|
409
|
+
array = []
|
410
|
+
rc = socket.getsockopt(XS::EVENTS, array)
|
411
|
+
rc.should == 0
|
412
|
+
array[0].should be_a(Fixnum)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
context "using option XS::TYPE" do
|
417
|
+
it "should return the socket type" do
|
418
|
+
array = []
|
419
|
+
rc = socket.getsockopt(XS::TYPE, array)
|
420
|
+
rc.should == 0
|
421
|
+
array[0].should == socket_type
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end # context #getsockopt
|
425
|
+
|
426
|
+
end # each socket_type
|
427
|
+
|
428
|
+
|
429
|
+
describe "Mapping socket EVENTS to POLLIN and POLLOUT" do
|
430
|
+
include APIHelper
|
431
|
+
|
432
|
+
shared_examples_for "pubsub sockets where" do
|
433
|
+
it "SUB socket that received a message always has POLLIN set" do
|
434
|
+
events = []
|
435
|
+
rc = @sub.getsockopt(XS::EVENTS, events)
|
436
|
+
rc.should == 0
|
437
|
+
events[0].should == XS::POLLIN
|
438
|
+
end
|
439
|
+
|
440
|
+
it "PUB socket always has POLLOUT set" do
|
441
|
+
events = []
|
442
|
+
rc = @pub.getsockopt(XS::EVENTS, events)
|
443
|
+
rc.should == 0
|
444
|
+
events[0].should == XS::POLLOUT
|
445
|
+
end
|
446
|
+
|
447
|
+
it "PUB socket never has POLLIN set" do
|
448
|
+
events = []
|
449
|
+
rc = @pub.getsockopt(XS::EVENTS, events)
|
450
|
+
rc.should == 0
|
451
|
+
events[0].should_not == XS::POLLIN
|
452
|
+
end
|
453
|
+
|
454
|
+
it "SUB socket never has POLLOUT set" do
|
455
|
+
events = []
|
456
|
+
rc = @sub.getsockopt(XS::EVENTS, events)
|
457
|
+
rc.should == 0
|
458
|
+
events[0].should_not == XS::POLLOUT
|
459
|
+
end
|
460
|
+
end # shared example for pubsub
|
461
|
+
|
462
|
+
|
463
|
+
context "when SUB connects and PUB binds" do
|
464
|
+
|
465
|
+
before(:each) do
|
466
|
+
@ctx = Context.new
|
467
|
+
|
468
|
+
@sub = @ctx.socket XS::SUB
|
469
|
+
rc = @sub.setsockopt XS::SUBSCRIBE, ''
|
470
|
+
|
471
|
+
@pub = @ctx.socket XS::PUB
|
472
|
+
port = bind_to_random_tcp_port(@pub)
|
473
|
+
rc = @sub.connect "tcp://127.0.0.1:#{port}"
|
474
|
+
sleep 0.5
|
475
|
+
|
476
|
+
rc = @pub.send_string('test')
|
477
|
+
sleep 0.2
|
478
|
+
end
|
479
|
+
|
480
|
+
it_behaves_like "pubsub sockets where"
|
481
|
+
end # context SUB binds PUB connects
|
482
|
+
|
483
|
+
|
484
|
+
after(:each) do
|
485
|
+
@sub.close
|
486
|
+
@pub.close
|
487
|
+
# must call close on *every* socket before calling terminate otherwise it blocks indefinitely
|
488
|
+
@ctx.terminate
|
489
|
+
end
|
490
|
+
|
491
|
+
end # describe 'events mapping to pollin and pollout'
|
492
|
+
|
493
|
+
end # describe Socket
|
494
|
+
|
495
|
+
|
496
|
+
end # module XS
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Execute 'rake spec' from the main directory to run all specs.
|
2
|
+
|
3
|
+
require File.expand_path(
|
4
|
+
File.join(File.dirname(__FILE__), %w[.. lib ffi-rxs]))
|
5
|
+
|
6
|
+
Thread.abort_on_exception = true
|
7
|
+
|
8
|
+
module APIHelper
|
9
|
+
def stub_libxs
|
10
|
+
@err_str_mock = mock("error string")
|
11
|
+
|
12
|
+
LibXS.stub!(
|
13
|
+
:xs_init => 0,
|
14
|
+
:xs_errno => 0,
|
15
|
+
:xs_sterror => @err_str_mock
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
# generate a random port between 10_000 and 65534
|
20
|
+
def random_port
|
21
|
+
rand(55534) + 10_000
|
22
|
+
end
|
23
|
+
|
24
|
+
def bind_to_random_tcp_port socket, max_tries = 500
|
25
|
+
tries = 0
|
26
|
+
rc = -1
|
27
|
+
|
28
|
+
while !XS::Util.resultcode_ok?(rc) && tries < max_tries
|
29
|
+
tries += 1
|
30
|
+
random = random_port
|
31
|
+
rc = socket.bind(local_transport_string(random))
|
32
|
+
end
|
33
|
+
|
34
|
+
random
|
35
|
+
end
|
36
|
+
|
37
|
+
def connect_to_random_tcp_port socket, max_tries = 500
|
38
|
+
tries = 0
|
39
|
+
rc = -1
|
40
|
+
|
41
|
+
while !XS::Util.resultcode_ok?(rc) && tries < max_tries
|
42
|
+
tries += 1
|
43
|
+
random = random_port
|
44
|
+
rc = socket.connect(local_transport_string(random))
|
45
|
+
end
|
46
|
+
|
47
|
+
random
|
48
|
+
end
|
49
|
+
|
50
|
+
def local_transport_string(port)
|
51
|
+
"tcp://127.0.0.1:#{port}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def assert_ok(rc)
|
55
|
+
raise "Failed with rc [#{rc}] and errno [#{XS::Util.errno}], msg [#{XS::Util.error_string}]! #{caller(0)}" unless rc >= 0
|
56
|
+
end
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ffi-rxs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris Duncan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ffi
|
16
|
+
requirement: &83395810 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *83395810
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &83413290 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.6'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *83413290
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &83412730 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *83412730
|
47
|
+
description: ! 'This gem wraps the Crossroads I/O networking library using the ruby
|
48
|
+
FFI (foreign
|
49
|
+
|
50
|
+
function interface). It''s a pure ruby wrapper so this gem can be loaded
|
51
|
+
|
52
|
+
and run by any ruby runtime that supports FFI. That''s all of them:
|
53
|
+
|
54
|
+
MRI 1.9.x, Rubinius and JRuby.'
|
55
|
+
email:
|
56
|
+
- celldee@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- .gitignore
|
62
|
+
- AUTHORS.txt
|
63
|
+
- Gemfile
|
64
|
+
- README.rdoc
|
65
|
+
- Rakefile
|
66
|
+
- ext/README
|
67
|
+
- ffi-rxs.gemspec
|
68
|
+
- lib/ffi-rxs.rb
|
69
|
+
- lib/ffi-rxs/constants.rb
|
70
|
+
- lib/ffi-rxs/constants.rb~
|
71
|
+
- lib/ffi-rxs/context.rb
|
72
|
+
- lib/ffi-rxs/context.rb~
|
73
|
+
- lib/ffi-rxs/device.rb~
|
74
|
+
- lib/ffi-rxs/exceptions.rb
|
75
|
+
- lib/ffi-rxs/exceptions.rb~
|
76
|
+
- lib/ffi-rxs/libc.rb
|
77
|
+
- lib/ffi-rxs/libc.rb~
|
78
|
+
- lib/ffi-rxs/libxs.rb
|
79
|
+
- lib/ffi-rxs/libxs.rb~
|
80
|
+
- lib/ffi-rxs/message.rb
|
81
|
+
- lib/ffi-rxs/message.rb~
|
82
|
+
- lib/ffi-rxs/poll.rb
|
83
|
+
- lib/ffi-rxs/poll.rb~
|
84
|
+
- lib/ffi-rxs/poll_items.rb
|
85
|
+
- lib/ffi-rxs/poll_items.rb~
|
86
|
+
- lib/ffi-rxs/socket.rb
|
87
|
+
- lib/ffi-rxs/socket.rb~
|
88
|
+
- lib/ffi-rxs/util.rb
|
89
|
+
- lib/ffi-rxs/util.rb~
|
90
|
+
- lib/ffi-rxs/version.rb
|
91
|
+
- lib/ffi-rxs/version.rb~
|
92
|
+
- spec/context_spec.rb
|
93
|
+
- spec/message_spec.rb
|
94
|
+
- spec/multipart_spec.rb
|
95
|
+
- spec/nonblocking_recv_spec.rb
|
96
|
+
- spec/poll_spec.rb
|
97
|
+
- spec/pushpull_spec.rb
|
98
|
+
- spec/reqrep_spec.rb
|
99
|
+
- spec/socket_spec.rb
|
100
|
+
- spec/spec_helper.rb
|
101
|
+
homepage: http://github.com/celldee/ffi-rxs
|
102
|
+
licenses: []
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 1.8.6
|
122
|
+
signing_key:
|
123
|
+
specification_version: 3
|
124
|
+
summary: This gem wraps the Crossroads I/O networking library using Ruby FFI (foreign
|
125
|
+
function interface).
|
126
|
+
test_files: []
|