class CrapServer::ConnectionHandler

Public Class Methods

new(sockets) click to toggle source
# File lib/crap_server/connection_handler.rb, line 4
def initialize(sockets)
  @sockets = sockets
  @sockets.each do |io|
    add_to_read io
  end
end

Public Instance Methods

add_read_buffer(io, string) click to toggle source
# File lib/crap_server/connection_handler.rb, line 65
def add_read_buffer(io, string)
  @rbuffer ||= {}
  @rbuffer[io.fileno] ||= ''
  @rbuffer[io.fileno] << string
end
add_to_read(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 40
def add_to_read(io)
  @to_read ||= {}
  @to_read[io.fileno] = io
end
add_to_write(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 11
def add_to_write(io)
  @to_write ||= {}
  @to_write[io.fileno] = io
end
address(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 50
def address(io)
  @address ||= {}
  @address[io.fileno]
end
buffer(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 26
def buffer(io)
  @buffer ||= {}
  @buffer[io.fileno]
end
close(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 81
def close(io)
  remove_to_read io
  remove_to_write io
  @closeaw ||= {}
  @closeaw.delete io.fileno
  io.close
end
close_after_write(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 76
def close_after_write(io)
  @closeaw ||= {}
  @closeaw[io.fileno]
end
handle(&block) click to toggle source
# File lib/crap_server/connection_handler.rb, line 89
def handle(&block)
  # The main loop. Listening IPv4 and IPv6 connections
  accept_loop do |data, remote_socket, address_info|
    instance = CrapServer::ConnectionInstance.new
    instance.socket = remote_socket
    instance.config = config
    instance.address = address_info
    instance.handler = self
    instance.run data, &block
  end
end
read_buffer(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 60
def read_buffer(io)
  @rbuffer ||= {}
  @rbuffer[io.fileno]
end
remove_to_read(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 45
def remove_to_read(io)
  @to_read.delete io.fileno
  @address.delete io.fileno
end
remove_to_write(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 20
def remove_to_write(io)
  @buffer ||= {}
  @to_write.delete io.fileno
  @buffer.delete io.fileno
end
set_address(io, addrs) click to toggle source
# File lib/crap_server/connection_handler.rb, line 55
def set_address(io, addrs)
  @address ||= {}
  @address[io.fileno] = addrs
end
set_buffer(io, string) click to toggle source
# File lib/crap_server/connection_handler.rb, line 31
def set_buffer(io, string)
  @buffer ||= {}
  @buffer[io.fileno] = string
end
set_close_after_write(io) click to toggle source
# File lib/crap_server/connection_handler.rb, line 71
def set_close_after_write(io)
  @closeaw ||= {}
  @closeaw[io.fileno] = true
end
to_read() click to toggle source
# File lib/crap_server/connection_handler.rb, line 36
def to_read
  (@to_read ||= {}).values
end
to_write() click to toggle source
# File lib/crap_server/connection_handler.rb, line 16
def to_write
  (@to_write ||= {}).values
end

Protected Instance Methods

accept_connection(socket) click to toggle source
# File lib/crap_server/connection_handler.rb, line 156
def accept_connection(socket)
  begin
    io, addr = socket.accept_nonblock
    set_address io, addr
    set_close_after_write io if config.auto_close_connection
    # Disabling Nagle's algorithm. Is fucking slow :P
    io.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
    # We add him to the read queue
    add_to_read io
  rescue Errno::EINPROGRESS, IO::EAGAINWaitReadable
  end
end
accept_loop(&block) click to toggle source

Evented loop (Reactor pattern)

# File lib/crap_server/connection_handler.rb, line 104
def accept_loop(&block)
  loop {
    @readables,  @writables = IO.select(to_read, to_write)

    process_readables &block
    process_writables
  }
end
config() click to toggle source
# File lib/crap_server/connection_handler.rb, line 178
def config
  CrapServer::Application.send(:config)
end
logger() click to toggle source
# File lib/crap_server/connection_handler.rb, line 182
def logger
  CrapServer::Application.send(:logger)
end
process_readables(&block) click to toggle source
# File lib/crap_server/connection_handler.rb, line 115
def process_readables(&block)
  @readables.each do |socket|
    if @sockets.include? socket
      accept_connection socket
    else
      begin
        read_and_process_data socket, &block
      rescue Errno::EAGAIN
      rescue EOFError
        remove_to_read socket
      end
    end
  end
end
process_writables() click to toggle source
# File lib/crap_server/connection_handler.rb, line 130
def process_writables
  @writables.each do |socket|
    begin
      string = buffer socket
      bytes = socket.write_nonblock string
      string.slice! 0, bytes
      if string.empty?
        # If we don't have more data to send to the client
        if close_after_write socket
          close socket
        else
          remove_to_write socket
        end
      else
        set_buffer socket, string
        remove_to_read socket
      end
    # If the client close the connection, we remove is from read and from write
    rescue Errno::ECONNRESET, Errno::EPIPE
      if close_after_write socket
        close socket
      end
    end
  end
end
read_and_process_data(socket, &block) click to toggle source
# File lib/crap_server/connection_handler.rb, line 169
def read_and_process_data(socket, &block)
  _, data = socket, socket.read_nonblock(config.read_buffer_size)
  block.call data, socket, address(socket)
  # We close the connection if we auto_close_connection is true and the user didn't write in the buffer.
  if config.auto_close_connection && buffer(socket).nil?
    close socket
  end
end