lib/arachni/reactor/connection.rb in arachni-reactor-0.1.0.beta5 vs lib/arachni/reactor/connection.rb in arachni-reactor-0.1.0

- old
+ new

@@ -5,20 +5,19 @@ web site for more information on licensing and terms of use. =end require_relative 'connection/error' -require_relative 'connection/peer_info' require_relative 'connection/callbacks' +require_relative 'connection/peer_info' require_relative 'connection/tls' module Arachni class Reactor # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com> class Connection - include PeerInfo include Callbacks # Maximum amount of data to be written or read at a time. # # We set this to the same max block size as the OpenSSL buffers because more @@ -174,10 +173,96 @@ on_close reason close_without_callback nil end + # Accepts a new client connection. + # + # @return [Connection, nil] + # New connection or `nil` if the socket isn't ready to accept new + # connections yet. + # + # @private + def accept + return if !(accepted = socket_accept) + + connection = @server_handler.call + connection.configure socket: accepted, role: :server + @reactor.attach connection + connection + end + + # @param [Socket] socket + # Ruby `Socket` associated with this connection. + # @param [Symbol] role + # `:server` or `:client`. + # @param [Block] server_handler + # Block that generates a handler as specified in {Reactor#listen}. + # + # @private + def configure( options = {} ) + @socket = options[:socket] + @role = options[:role] + @host = options[:host] + @port = options[:port] + @server_handler = options[:server_handler] + + # If we're a server without a handler then we're an accepted connection. + if unix? || role == :server + @connected = true + on_connect + end + + nil + end + + def connected? + !!@connected + end + + # @private + def _connect + return true if unix? || connected? + + begin + Error.translate do + socket.connect_nonblock( Socket.sockaddr_in( @port, @host ) ) + end + # Already connected. :) + rescue Errno::EISCONN + end + + @connected = true + on_connect + + true + rescue IO::WaitReadable, IO::WaitWritable, Errno::EINPROGRESS + rescue Error => e + close e + end + + # @note If this is a server {#listener?} it will delegate to {#accept}. + # @note If this is a normal socket it will read {BLOCK_SIZE} amount of data. + # and pass it to {#on_read}. + # + # Processes a `read` event for this connection. + # + # @private + def _read + return _connect if !listener? && !connected? + return accept if listener? + + Error.translate do + on_read @socket.read_nonblock( BLOCK_SIZE ) + end + + # Not ready to read or write yet, we'll catch it on future Reactor ticks. + rescue IO::WaitReadable, IO::WaitWritable + rescue Error => e + close e + end + # @note Will call {#on_write} every time any of the buffer is consumed, # can be multiple times when performing partial writes. # @note Will call {#on_flush} once all of the buffer has been consumed. # # Processes a `write` event for this connection. @@ -188,16 +273,18 @@ # @return [Integer] # Amount of the buffer consumed. # # @private def _write + return _connect if !connected? + chunk = write_buffer.slice( 0, BLOCK_SIZE ) total_written = 0 begin Error.translate do - # Send out the buffer, **all** of it, or at least try to. + # Send out the chunk, **all** of it, or at least try to. loop do total_written += written = @socket.write_nonblock( chunk ) write_buffer.slice!( 0, written ) # Call #on_write every time any of the buffer is consumed. @@ -218,63 +305,9 @@ end total_written rescue Error => e close e - end - - # @note If this is a server {#listener?} it will delegate to {#accept}. - # @note If this is a normal socket it will read {BLOCK_SIZE} amount of data. - # and pass it to {#on_read}. - # - # Processes a `read` event for this connection. - # - # @private - def _read - return accept if listener? - - Error.translate do - on_read @socket.read_nonblock( BLOCK_SIZE ) - end - - # Not ready to read or write yet, we'll catch it on future Reactor ticks. - rescue IO::WaitReadable, IO::WaitWritable - rescue Error => e - close e - end - - # Accepts a new client connection. - # - # @return [Connection, nil] - # New connection or `nil` if the socket isn't ready to accept new - # connections yet. - # - # @private - def accept - return if !(accepted = socket_accept) - - connection = @server_handler.call - connection.configure accepted, :server - @reactor.attach connection - connection - end - - # @param [Socket] socket - # Ruby `Socket` associated with this connection. - # @param [Symbol] role - # `:server` or `:client`. - # @param [Block] server_handler - # Block that generates a handler as specified in {Reactor#listen}. - # - # @private - def configure( socket, role, server_handler = nil ) - @socket = socket - @role = role - @server_handler = server_handler - - on_connect - - nil end private def write_buffer