ffi-rxs 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+
6
+ *.rbc
7
+ .redcar/
data/AUTHORS.txt ADDED
@@ -0,0 +1,21 @@
1
+ Chuck Remes, github: chuckremes
2
+
3
+ Andrew Cholakian, github: andrewvc
4
+
5
+ Ar Vicco, github: arvicco
6
+
7
+ Ben Mabey, github: bmabey
8
+
9
+ Julien Ammous, github: schmurfy
10
+
11
+ Zachary Belzer, github: zbelzer
12
+
13
+ Cory Forsyth, github: bantic
14
+
15
+ Stefan Kaes, github: skaes
16
+
17
+ Dmitry Ustalov, github: eveel
18
+
19
+ Patrik Sundberg, github: sundbp
20
+
21
+ Chris Duncan, github: celldee
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,86 @@
1
+ ffi-rxs
2
+ by Chris Duncan
3
+
4
+ == DESCRIPTION:
5
+
6
+ This gem wraps the Crossroads I/O networking library using the Ruby FFI (foreign
7
+ function interface). It's a pure Ruby wrapper so this gem can be loaded
8
+ and run by any Ruby runtime that supports FFI. That's all of them:
9
+ MRI 1.9.x, Rubinius and JRuby.
10
+
11
+ Crossroads I/O is a fork of ZeroMQ. This gem is a re-working of the ffi-rzmq gem
12
+ created by Chuck Remes to provide bindings for the Crossroads I/O libxs C library
13
+ instead of the ZeroMQ libzmq library. The gem auto-configures itself to expose
14
+ the API conforming to the loaded C library.
15
+
16
+ == FEATURES/PROBLEMS:
17
+
18
+ This gem needs to be tested in the wild. Please kick its tyres and give it a
19
+ good thrashing. It is inevitable that bugs will be discovered, so please open
20
+ issues for them here or fork this project, fix them, and send me a pull
21
+ request.
22
+
23
+ The 'ffi' gem has dropped support for MRI 1.8.x. Since this project relies
24
+ on that gem to load and run this code, then this project does not support
25
+ MRI 1.8.x. I recommend JRuby for the best performance and stability.
26
+
27
+ == REQUIREMENTS:
28
+
29
+ * Crossroads I/O version 1.0.0 or later.
30
+
31
+ The Crossroads I/O library must be installed on your system in a well-known location
32
+ like /usr/local/lib. This is the default for new Crossroads I/O installs.
33
+
34
+ Future releases may include the library as a C extension built at
35
+ time of installation.
36
+
37
+ * ffi (>= 1.0.0)
38
+
39
+ Do *not* run this gem under MRI with an old 'ffi' gem. It will crash randomly and
40
+ you will be sad.
41
+
42
+ == INSTALL:
43
+
44
+ A full gem has been released to Rubygems.org as of release 1.0.0.
45
+ Make sure the Crossroads I/O library is already installed on your system.
46
+
47
+ % gem install ffi-rxs # should grab the latest release
48
+
49
+
50
+ To build from git master:
51
+
52
+ % git clone git://github.com/celldee/ffi-rxs
53
+ % cd ffi-rxs
54
+ % gem build ffi-rxs.gemspec
55
+ % gem install ffi-rxs-*.gem
56
+
57
+
58
+ NOTE for Windows users!
59
+ In order for this gem to find the libxs.dll, it *must* be on the Windows PATH. Google
60
+ for "modify windows path" for instructions on how to do that if you are unfamiliar with
61
+ that activity.
62
+
63
+ == LICENSE:
64
+
65
+ (The MIT License)
66
+
67
+ Copyright (c) 2011 - 2012 Chuck Remes, Chris Duncan and contributors
68
+
69
+ Permission is hereby granted, free of charge, to any person obtaining
70
+ a copy of this software and associated documentation files (the
71
+ 'Software'), to deal in the Software without restriction, including
72
+ without limitation the rights to use, copy, modify, merge, publish,
73
+ distribute, sublicense, and/or sell copies of the Software, and to
74
+ permit persons to whom the Software is furnished to do so, subject to
75
+ the following conditions:
76
+
77
+ The above copyright notice and this permission notice shall be
78
+ included in all copies or substantial portions of the Software.
79
+
80
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
81
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
82
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
83
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
84
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
85
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
86
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
data/ext/README ADDED
@@ -0,0 +1,5 @@
1
+ To avoid loading a system-wide Crossroads I/O library, place
2
+ the C libraries here. This lets you run your Ruby
3
+ code with a Crossroads C library build that is different
4
+ from the system-wide one. This can be handy for
5
+ rolling upgrades or testing.
data/ffi-rxs.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "ffi-rxs/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "ffi-rxs"
7
+ s.version = XS::VERSION
8
+ s.authors = ["Chris Duncan"]
9
+ s.email = ["celldee@gmail.com"]
10
+ s.homepage = "http://github.com/celldee/ffi-rxs"
11
+ s.summary = %q{This gem wraps the Crossroads I/O networking library using Ruby FFI (foreign function interface).}
12
+ s.description = %q{This gem wraps the Crossroads I/O networking library using the ruby FFI (foreign
13
+ function interface). It's a pure ruby wrapper so this gem can be loaded
14
+ and run by any ruby runtime that supports FFI. That's all of them:
15
+ MRI 1.9.x, Rubinius and JRuby.}
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency "ffi"
23
+ s.add_development_dependency "rspec", ["~> 2.6"]
24
+ s.add_development_dependency "rake"
25
+ end
@@ -0,0 +1,104 @@
1
+ module XS
2
+ # Set up all of the constants
3
+
4
+ # Context options
5
+ MAX_SOCKETS = 1
6
+ IO_THREADS = 2
7
+
8
+ # Socket types
9
+ PAIR = 0
10
+ PUB = 1
11
+ SUB = 2
12
+ REQ = 3
13
+ REP = 4
14
+ XREQ = 5
15
+ XREP = 6
16
+ PULL = 7
17
+ PUSH = 8
18
+ XPUB = 9
19
+ XSUB = 10
20
+ DEALER = XREQ
21
+ ROUTER = XREP
22
+
23
+ SocketTypeNameMap = {
24
+ PAIR => "PAIR",
25
+ PUB => "PUB",
26
+ SUB => "SUB",
27
+ REQ => "REQ",
28
+ REP => "REP",
29
+ PULL => "PULL",
30
+ PUSH => "PUSH",
31
+ XREQ => "XREQ",
32
+ XREP => "XREP",
33
+ ROUTER => "ROUTER",
34
+ DEALER => "DEALER",
35
+ XPUB => "XPUB",
36
+ XSUB => "XSUB"
37
+ }
38
+
39
+ # Socket options
40
+ AFFINITY = 4
41
+ IDENTITY = 5
42
+ SUBSCRIBE = 6
43
+ UNSUBSCRIBE = 7
44
+ RATE = 8
45
+ RECOVERY_IVL = 9
46
+ SNDBUF = 11
47
+ RCVBUF = 12
48
+ RCVMORE = 13
49
+ FD = 14
50
+ EVENTS = 15
51
+ TYPE = 16
52
+ LINGER = 17
53
+ RECONNECT_IVL = 18
54
+ BACKLOG = 19
55
+ RECONNECT_IVL_MAX = 21
56
+ MAXMSGSIZE = 22
57
+ SNDHWM = 23
58
+ RCVHWM = 24
59
+ MULTICAST_HOPS = 25
60
+ RCVTIMEO = 27
61
+ SNDTIMEO = 28
62
+
63
+ # Send/recv options
64
+ DONTWAIT = 1
65
+ SNDMORE = 2
66
+ SNDLABEL = 4
67
+ NonBlocking = DONTWAIT
68
+
69
+ # I/O multiplexing
70
+
71
+ POLL = 1
72
+ POLLIN = 1
73
+ POLLOUT = 2
74
+ POLLERR = 4
75
+
76
+ # Socket errors
77
+ EAGAIN = Errno::EAGAIN::Errno
78
+ EFAULT = Errno::EFAULT::Errno
79
+ EINVAL = Errno::EINVAL::Errno
80
+ EMFILE = Errno::EMFILE::Errno
81
+ ENOMEM = Errno::ENOMEM::Errno
82
+ ENODEV = Errno::ENODEV::Errno
83
+
84
+ # XS errors
85
+ HAUSNUMERO = 156384712
86
+ EMTHREAD = (HAUSNUMERO + 50)
87
+ EFSM = (HAUSNUMERO + 51)
88
+ ENOCOMPATPROTO = (HAUSNUMERO + 52)
89
+ ETERM = (HAUSNUMERO + 53)
90
+
91
+ # Rescue unknown constants and use the Crossroads defined values
92
+ # Usually only happens on Windows though some don't resolve on
93
+ # OSX too (ENOTSUP)
94
+ ENOTSUP = Errno::ENOTSUP::Errno rescue (HAUSNUMERO + 1)
95
+ EPROTONOSUPPORT = Errno::EPROTONOSUPPORT::Errno rescue (HAUSNUMERO + 2)
96
+ ENOBUFS = Errno::ENOBUFS::Errno rescue (HAUSNUMERO + 3)
97
+ ENETDOWN = Errno::ENETDOWN::Errno rescue (HAUSNUMERO + 4)
98
+ EADDRINUSE = Errno::EADDRINUSE::Errno rescue (HAUSNUMERO + 5)
99
+ EADDRNOTAVAIL = Errno::EADDRNOTAVAIL::Errno rescue (HAUSNUMERO + 6)
100
+ ECONNREFUSED = Errno::ECONNREFUSED::Errno rescue (HAUSNUMERO + 7)
101
+ EINPROGRESS = Errno::EINPROGRESS::Errno rescue (HAUSNUMERO + 8)
102
+ ENOTSOCK = Errno::ENOTSOCK::Errno rescue (HAUSNUMERO + 9)
103
+ EINTR = Errno::EINTR::Errno rescue (HAUSNUMERO + 10)
104
+ end # module XS
@@ -0,0 +1,100 @@
1
+ module XS
2
+ # Set up all of the constants
3
+
4
+ # Socket types
5
+ PAIR = 0
6
+ PUB = 1
7
+ SUB = 2
8
+ REQ = 3
9
+ REP = 4
10
+ XREQ = 5
11
+ XREP = 6
12
+ PULL = 7
13
+ PUSH = 8
14
+ XPUB = 9
15
+ XSUB = 10
16
+ DEALER = XREQ
17
+ ROUTER = XREP
18
+
19
+ SocketTypeNameMap = {
20
+ PAIR => "PAIR",
21
+ PUB => "PUB",
22
+ SUB => "SUB",
23
+ REQ => "REQ",
24
+ REP => "REP",
25
+ PULL => "PULL",
26
+ PUSH => "PUSH",
27
+ XREQ => "XREQ",
28
+ XREP => "XREP",
29
+ ROUTER => "ROUTER",
30
+ DEALER => "DEALER",
31
+ XPUB => "XPUB",
32
+ XSUB => "XSUB"
33
+ }
34
+
35
+ # Socket options
36
+ AFFINITY = 4
37
+ IDENTITY = 5
38
+ SUBSCRIBE = 6
39
+ UNSUBSCRIBE = 7
40
+ RATE = 8
41
+ RECOVERY_IVL = 9
42
+ SNDBUF = 11
43
+ RCVBUF = 12
44
+ RCVMORE = 13
45
+ FD = 14
46
+ EVENTS = 15
47
+ TYPE = 16
48
+ LINGER = 17
49
+ RECONNECT_IVL = 18
50
+ BACKLOG = 19
51
+ RECONNECT_IVL_MAX = 21
52
+ MAXMSGSIZE = 22
53
+ SNDHWM = 23
54
+ RCVHWM = 24
55
+ MULTICAST_HOPS = 25
56
+ RCVTIMEO = 27
57
+ SNDTIMEO = 28
58
+
59
+ # Send/recv options
60
+ DONTWAIT = 1
61
+ SNDMORE = 2
62
+ SNDLABEL = 4
63
+ NonBlocking = DONTWAIT
64
+
65
+ # I/O multiplexing
66
+
67
+ POLL = 1
68
+ POLLIN = 1
69
+ POLLOUT = 2
70
+ POLLERR = 4
71
+
72
+ # Socket errors
73
+ EAGAIN = Errno::EAGAIN::Errno
74
+ EFAULT = Errno::EFAULT::Errno
75
+ EINVAL = Errno::EINVAL::Errno
76
+ EMFILE = Errno::EMFILE::Errno
77
+ ENOMEM = Errno::ENOMEM::Errno
78
+ ENODEV = Errno::ENODEV::Errno
79
+
80
+ # XS errors
81
+ HAUSNUMERO = 156384712
82
+ EMTHREAD = (HAUSNUMERO + 50)
83
+ EFSM = (HAUSNUMERO + 51)
84
+ ENOCOMPATPROTO = (HAUSNUMERO + 52)
85
+ ETERM = (HAUSNUMERO + 53)
86
+
87
+ # Rescue unknown constants and use the Crossroads defined values
88
+ # Usually only happens on Windows though some don't resolve on
89
+ # OSX too (ENOTSUP)
90
+ ENOTSUP = Errno::ENOTSUP::Errno rescue (HAUSNUMERO + 1)
91
+ EPROTONOSUPPORT = Errno::EPROTONOSUPPORT::Errno rescue (HAUSNUMERO + 2)
92
+ ENOBUFS = Errno::ENOBUFS::Errno rescue (HAUSNUMERO + 3)
93
+ ENETDOWN = Errno::ENETDOWN::Errno rescue (HAUSNUMERO + 4)
94
+ EADDRINUSE = Errno::EADDRINUSE::Errno rescue (HAUSNUMERO + 5)
95
+ EADDRNOTAVAIL = Errno::EADDRNOTAVAIL::Errno rescue (HAUSNUMERO + 6)
96
+ ECONNREFUSED = Errno::ECONNREFUSED::Errno rescue (HAUSNUMERO + 7)
97
+ EINPROGRESS = Errno::EINPROGRESS::Errno rescue (HAUSNUMERO + 8)
98
+ ENOTSOCK = Errno::ENOTSOCK::Errno rescue (HAUSNUMERO + 9)
99
+ EINTR = Errno::EINTR::Errno rescue (HAUSNUMERO + 10)
100
+ end # module XS
@@ -0,0 +1,153 @@
1
+
2
+ module XS
3
+
4
+
5
+ # Recommended to use the default for +io_threads+
6
+ # since most programs will not saturate I/O.
7
+ #
8
+ # The rule of thumb is to make +io_threads+ equal to the number
9
+ # gigabits per second that the application will produce.
10
+ #
11
+ # The +io_threads+ number specifies the size of the thread pool
12
+ # allocated by 0mq for processing incoming/outgoing messages.
13
+ #
14
+ # Returns a context object when allocation succeeds. It's necessary
15
+ # for passing to the
16
+ # #Socket constructor when allocating new sockets. All sockets
17
+ # live within a context.
18
+ #
19
+ # Also, Sockets should *only* be accessed from the thread where they
20
+ # were first created. Do *not* pass sockets between threads; pass
21
+ # in the context and allocate a new socket per thread. If you must
22
+ # use threads, then make sure to execute a full memory barrier (e.g.
23
+ # mutex) as you pass a socket from one thread to the next.
24
+ #
25
+ # To connect sockets between contexts, use +inproc+ or +ipc+
26
+ # transport and set up a Crossroads socket between them. This is also the
27
+ # recommended technique for allowing sockets to communicate between
28
+ # threads.
29
+ #
30
+ # context = XS::Context.create
31
+ # if context
32
+ # socket = context.socket(XS::REQ)
33
+ # if socket
34
+ # ...
35
+ # else
36
+ # STDERR.puts "Socket allocation failed"
37
+ # end
38
+ # else
39
+ # STDERR.puts "Context allocation failed"
40
+ # end
41
+ #
42
+ #
43
+ class Context
44
+ include XS::Util
45
+
46
+ attr_reader :context, :pointer
47
+
48
+ def self.create
49
+ new() rescue nil
50
+ end
51
+
52
+ # Use the factory method Context#create to make contexts.
53
+ #
54
+ def initialize
55
+ @sockets = []
56
+ @context = LibXS.xs_init()
57
+ @pointer = @context
58
+ error_check 'xs_init', (@context.nil? || @context.null?) ? -1 : 0
59
+
60
+ define_finalizer
61
+ end
62
+
63
+ # Set options on this context.
64
+ #
65
+ # Context options take effect only if set with setctxopt() prior to
66
+ # creating the first socket in a given context with socket().
67
+ #
68
+ # Valid +name+ values that take a numeric +value+ are:
69
+ # XS::IO_THREADS
70
+ # XS::MAX_SOCKETS
71
+ #
72
+ # Returns 0 when the operation completed successfully.
73
+ # Returns -1 when this operation failed.
74
+ #
75
+ # With a -1 return code, the user must check XS.errno to determine the
76
+ # cause.
77
+ #
78
+ # rc = context.setctxopt(XS::IO_THREADS, 10)
79
+ # XS::Util.resultcode_ok?(rc) ? puts("succeeded") : puts("failed")
80
+ #
81
+ def setctxopt name, value, length = nil
82
+ length = 4
83
+ pointer = LibC.malloc length
84
+ pointer.write_int value
85
+
86
+ rc = LibXS.xs_setctxopt @context, name, pointer, length
87
+ LibC.free(pointer) unless pointer.nil? || pointer.null?
88
+ rc
89
+ end
90
+
91
+ # Call to release the context and any remaining data associated
92
+ # with past sockets. This will close any sockets that remain
93
+ # open; further calls to those sockets will return -1 to indicate
94
+ # the operation failed.
95
+ #
96
+ # Returns 0 for success, -1 for failure.
97
+ #
98
+ def terminate
99
+ unless @context.nil? || @context.null?
100
+ remove_finalizer
101
+ rc = LibXS.xs_term @context
102
+ @context = nil
103
+ @sockets = nil
104
+ rc
105
+ else
106
+ 0
107
+ end
108
+ end
109
+
110
+ # Short-cut to allocate a socket for a specific context.
111
+ #
112
+ # Takes several +type+ values:
113
+ # #XS::REQ
114
+ # #XS::REP
115
+ # #XS::PUB
116
+ # #XS::SUB
117
+ # #XS::PAIR
118
+ # #XS::PULL
119
+ # #XS::PUSH
120
+ # #XS::DEALER
121
+ # #XS::ROUTER
122
+ #
123
+ # Returns a #XS::Socket when the allocation succeeds, nil
124
+ # if it fails.
125
+ #
126
+ def socket type
127
+ sock = nil
128
+ begin
129
+ sock = Socket.new @context, type
130
+ rescue ContextError => e
131
+ sock = nil
132
+ end
133
+
134
+ sock
135
+ end
136
+
137
+
138
+ private
139
+
140
+ def define_finalizer
141
+ ObjectSpace.define_finalizer(self, self.class.close(@context))
142
+ end
143
+
144
+ def remove_finalizer
145
+ ObjectSpace.undefine_finalizer self
146
+ end
147
+
148
+ def self.close context
149
+ Proc.new { LibXS.xs_term context unless context.null? }
150
+ end
151
+ end
152
+
153
+ end # module XS
@@ -0,0 +1,155 @@
1
+
2
+ module XS
3
+
4
+
5
+ # Recommended to use the default for +io_threads+
6
+ # since most programs will not saturate I/O.
7
+ #
8
+ # The rule of thumb is to make +io_threads+ equal to the number
9
+ # gigabits per second that the application will produce.
10
+ #
11
+ # The +io_threads+ number specifies the size of the thread pool
12
+ # allocated by 0mq for processing incoming/outgoing messages.
13
+ #
14
+ # Returns a context object when allocation succeeds. It's necessary
15
+ # for passing to the
16
+ # #Socket constructor when allocating new sockets. All sockets
17
+ # live within a context.
18
+ #
19
+ # Also, Sockets should *only* be accessed from the thread where they
20
+ # were first created. Do *not* pass sockets between threads; pass
21
+ # in the context and allocate a new socket per thread. If you must
22
+ # use threads, then make sure to execute a full memory barrier (e.g.
23
+ # mutex) as you pass a socket from one thread to the next.
24
+ #
25
+ # To connect sockets between contexts, use +inproc+ or +ipc+
26
+ # transport and set up a Crossroads socket between them. This is also the
27
+ # recommended technique for allowing sockets to communicate between
28
+ # threads.
29
+ #
30
+ # context = XS::Context.create
31
+ # if context
32
+ # socket = context.socket(XS::REQ)
33
+ # if socket
34
+ # ...
35
+ # else
36
+ # STDERR.puts "Socket allocation failed"
37
+ # end
38
+ # else
39
+ # STDERR.puts "Context allocation failed"
40
+ # end
41
+ #
42
+ #
43
+ class Context
44
+ include XS::Util
45
+
46
+ attr_reader :context, :pointer
47
+
48
+ def self.create
49
+ new() rescue nil
50
+ end
51
+
52
+ # Use the factory method Context#create to make contexts.
53
+ #
54
+ def initialize
55
+ @sockets = []
56
+ @context = LibXS.xs_init()
57
+ @pointer = @context
58
+ error_check 'xs_init', (@context.nil? || @context.null?) ? -1 : 0
59
+
60
+ define_finalizer
61
+ end
62
+
63
+ # Set options on this context.
64
+ #
65
+ # Context options take effect only if set with setctxopt() prior to
66
+ # creating the first socket in a given context with socket().
67
+ #
68
+ # Valid +name+ values that take a numeric +value+ are:
69
+ # XS::IO_THREADS
70
+ # XS::MAX_SOCKETS
71
+ #
72
+ # Returns 0 when the operation completed successfully.
73
+ # Returns -1 when this operation failed.
74
+ #
75
+ # With a -1 return code, the user must check XS.errno to determine the
76
+ # cause.
77
+ #
78
+ # rc = context.setctxopt(XS::IO_THREADS, 10)
79
+ # XS::Util.resultcode_ok?(rc) ? puts("succeeded") : puts("failed")
80
+ #
81
+ def setctxopt name, value, length = nil
82
+ #if (name == XS::IO_THREADS) || (name == XS::MAX_SOCKETS)
83
+ length = 4
84
+ pointer = LibC.malloc length
85
+ pointer.write_int value
86
+ #end
87
+
88
+ rc = LibXS.xs_setctxopt @context, name, pointer, length
89
+ LibC.free(pointer) unless pointer.nil? || pointer.null?
90
+ rc
91
+ end
92
+
93
+ # Call to release the context and any remaining data associated
94
+ # with past sockets. This will close any sockets that remain
95
+ # open; further calls to those sockets will return -1 to indicate
96
+ # the operation failed.
97
+ #
98
+ # Returns 0 for success, -1 for failure.
99
+ #
100
+ def terminate
101
+ unless @context.nil? || @context.null?
102
+ remove_finalizer
103
+ rc = LibXS.xs_term @context
104
+ @context = nil
105
+ @sockets = nil
106
+ rc
107
+ else
108
+ 0
109
+ end
110
+ end
111
+
112
+ # Short-cut to allocate a socket for a specific context.
113
+ #
114
+ # Takes several +type+ values:
115
+ # #XS::REQ
116
+ # #XS::REP
117
+ # #XS::PUB
118
+ # #XS::SUB
119
+ # #XS::PAIR
120
+ # #XS::PULL
121
+ # #XS::PUSH
122
+ # #XS::DEALER
123
+ # #XS::ROUTER
124
+ #
125
+ # Returns a #XS::Socket when the allocation succeeds, nil
126
+ # if it fails.
127
+ #
128
+ def socket type
129
+ sock = nil
130
+ begin
131
+ sock = Socket.new @context, type
132
+ rescue ContextError => e
133
+ sock = nil
134
+ end
135
+
136
+ sock
137
+ end
138
+
139
+
140
+ private
141
+
142
+ def define_finalizer
143
+ ObjectSpace.define_finalizer(self, self.class.close(@context))
144
+ end
145
+
146
+ def remove_finalizer
147
+ ObjectSpace.undefine_finalizer self
148
+ end
149
+
150
+ def self.close context
151
+ Proc.new { LibXS.xs_term context unless context.null? }
152
+ end
153
+ end
154
+
155
+ end # module XS
@@ -0,0 +1,28 @@
1
+ module ZMQ
2
+ if LibZMQ.version2?
3
+ class Device
4
+ attr_reader :device
5
+
6
+ def self.create(device_type, frontend, backend)
7
+ dev = nil
8
+ begin
9
+ dev = new device_type, frontend, backend
10
+ rescue ArgumentError
11
+ dev = nil
12
+ end
13
+
14
+ dev
15
+ end
16
+
17
+ def initialize(device_type,frontend,backend)
18
+ [["frontend", frontend],["backend", backend]].each do |name,socket|
19
+ unless socket.is_a?(ZMQ::Socket)
20
+ raise ArgumentError, "Expected a ZMQ::Socket, not a #{socket.class} as the #{name}"
21
+ end
22
+ end
23
+
24
+ LibZMQ.zmq_device(device_type, frontend.socket, backend.socket)
25
+ end
26
+ end
27
+ end
28
+ end