Class: RaptorIO::Socket
- Inherits:
-
Object
- Object
- RaptorIO::Socket
- Extended by:
- Forwardable
- Defined in:
- lib/raptor-io/socket.rb
Overview
A basic class for specific transports to inherit from. Analogous to stdlib’s BasicSocket
Defined Under Namespace
Classes: Comm, CommChain, Error, SwitchBoard, TCP, TCPServer
Instance Attribute Summary collapse
-
#options ⇒ Hash<Symbol,Object>
Options for this socket.
Class Method Summary collapse
-
.getaddrinfo(*args) ⇒ Object
Delegates to ‘::Socket.getaddrinfo`.
-
.method_missing(meth, *args, &block) ⇒ Object
Delegate to Ruby Socket.
- .respond_to_missing?(meth, include_private = false) ⇒ Boolean
-
.select(read_array = [], write_array = [], error_array = [], timeout = nil) ⇒ Array?
Like IO.select, but smarter.
-
.translate_errors(&block) ⇒ Object
Captures Ruby exceptions and converts them to RaptorIO Errors.
Instance Method Summary collapse
- #close ⇒ Object
- #closed? ⇒ Object
-
#initialize(socket, options = {}) ⇒ Socket
constructor
A new instance of Socket.
-
#ssl? ⇒ Boolean
Whether this socket is an SSL stream.
-
#to_io ⇒ IO
Used by Kernel.select.
Constructor Details
#initialize(socket, options = {}) ⇒ Socket
Returns a new instance of Socket.
159 160 161 162 |
# File 'lib/raptor-io/socket.rb', line 159 def initialize( socket, = {} ) @socket = socket @options = end |
Instance Attribute Details
#options ⇒ Hash<Symbol,Object>
Options for this socket.
150 151 152 |
# File 'lib/raptor-io/socket.rb', line 150 def @options end |
Class Method Details
.getaddrinfo(*args) ⇒ Object
Delegates to ‘::Socket.getaddrinfo`.
121 122 123 124 125 126 127 128 |
# File 'lib/raptor-io/socket.rb', line 121 def getaddrinfo( *args ) begin ::Socket.getaddrinfo( *args ) # OSX raises SocketError. rescue ::SocketError, ::Errno::ENOENT => e raise RaptorIO::Socket::Error::CouldNotResolve.new( e.to_s ) end end |
.method_missing(meth, *args, &block) ⇒ Object
Delegate to Ruby Socket.
131 132 133 134 135 136 137 138 139 140 |
# File 'lib/raptor-io/socket.rb', line 131 def method_missing(meth, *args, &block) #$stderr.puts("Socket.method_missing(#{meth}, #{args.inspect}") if ::Socket.respond_to?(meth) translate_errors do ::Socket.__send__(meth, *args, &block) end else super end end |
.respond_to_missing?(meth, include_private = false) ⇒ Boolean
142 143 144 |
# File 'lib/raptor-io/socket.rb', line 142 def respond_to_missing?(meth, include_private=false) ::Socket.respond_to?(meth, include_private) end |
.select(read_array = [], write_array = [], error_array = [], timeout = nil) ⇒ Array?
Like IO.select, but smarter
OpenSSL does its own buffering which can result in a consumed TCP buffer, leading ‘IO.select` to think that the SSLSocket has no more data to provide, when that’s not the case, effectively making ‘IO.select` block forever, even though the SSLSocket’s buffer has not yet been consumed.
We work around this by attempting a non-blocking read of one byte on each of the ‘read_array`, and putting the byte back with `Socket#ungetc` if it worked, or running it through the the real `IO.select` if it doesn’t.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/raptor-io/socket.rb', line 41 def self.select(read_array=[], write_array=[], error_array=[], timeout=nil) read_array ||= [] write_array ||= [] error_array ||= [] readers_with_data = [] selectable_readers = read_array.dup.delete_if do |reader| begin # If this socket doesn't have a read_nonblock method, then it's # a server of some kind and we have to run it through the real # select to see if it can {TCPServer#accept accept}. next false unless reader.respond_to? :read_nonblock byte = reader.read_nonblock(1) rescue IO::WaitReadable, IO::WaitWritable # Then this thing needs to go through the real select to be able # to tell if it has data. # # Note that {IO::WaitWritable} is needed here because OpenSSL # sockets can block for writing when calling `read*` because of # session renegotiation and the like. false rescue EOFError # Then this thing has an empty read buffer and there's no more # on the wire. We mark it as having data so a subsequent # read or read_nonblock will raise EOFError appropriately. readers_with_data << reader true else # Then this thing has data already in its read buffer and we can # skip the real select for it. reader.ungetc(byte) readers_with_data << reader true end end if readers_with_data.any? if selectable_readers.any? || write_array.any? || error_array.any? #$stderr.puts(" ----- Selecting readers:") #pp selectable_readers # Then see if anything has data right now by using a 0 timeout r,w,e = IO.select(selectable_readers, write_array, error_array, 0) real = [ readers_with_data | (r || []), w || [], e || [] ] else # Then there's nothing selectable and we can just return stuff # that has buffered data real = [ readers_with_data, [], [] ] end else # Then wait the given timeout, regardless of whether the arrays # are empty real = IO.select(read_array, write_array, error_array, timeout) end #$stderr.puts '------ RaptorIO::Socket.select result ------' #pp real return real end |
.translate_errors(&block) ⇒ Object
Captures Ruby exceptions and converts them to RaptorIO Errors.
112 113 114 115 116 117 118 |
# File 'lib/raptor-io/socket.rb', line 112 def translate_errors( &block ) block.call rescue ::Errno::EPIPE, ::Errno::ECONNRESET => e raise RaptorIO::Socket::Error::BrokenPipe, e.to_s rescue ::Errno::ECONNREFUSED => e raise RaptorIO::Socket::Error::ConnectionRefused, e.to_s end |
Instance Method Details
#close ⇒ Object
168 |
# File 'lib/raptor-io/socket.rb', line 168 def_delegator :@socket, :close, :close |
#closed? ⇒ Object
165 |
# File 'lib/raptor-io/socket.rb', line 165 def_delegator :@socket, :closed?, :closed? |
#ssl? ⇒ Boolean
Whether this socket is an SSL stream.
171 172 173 |
# File 'lib/raptor-io/socket.rb', line 171 def ssl? false end |
#to_io ⇒ IO
Used by Kernel.select
155 |
# File 'lib/raptor-io/socket.rb', line 155 def_delegator :@socket, :to_io, :to_io |