class Lumberjack::Beats::Server

Constants

SOCKET_TIMEOUT

Attributes

port[R]

Public Class Methods

new(options={}) click to toggle source

Create a new Lumberjack server.

  • options is a hash. Valid options are:

  • :port - the port to listen on

  • :address - the host/address to bind to

  • :ssl_certificate - the path to the ssl cert to use

  • :ssl_key - the path to the ssl key to use

  • :ssl_key_passphrase - the key passphrase (optional)

# File lib/lumberjack/beats/server.rb, line 25
def initialize(options={})
  @options = {
    :port => 0,
    :address => "0.0.0.0",
    :ssl => true,
    :ssl_certificate => nil,
    :ssl_key => nil,
    :ssl_key_passphrase => nil,
    :ssl_version => nil,
    :ssl_ciphers => nil,
  }.merge(options)

  if @options[:ssl]
    [:ssl_certificate, :ssl_key].each do |k|
      if @options[k].nil?
        raise "You must specify #{k} in Lumberjack::Server.new(...)"
      end
    end
  end

  @server = TCPServer.new(@options[:address], @options[:port])

  @close = Concurrent::AtomicBoolean.new

  # Query the port in case the port number is '0'
  # TCPServer#addr == [ address_family, port, address, address ]
  @port = @server.addr[1]

  if @options[:ssl]
    # load SSL certificate
    @ssl = OpenSSL::SSL::SSLContext.new
    if @options[:ssl_version]
      @ssl.ssl_version = @options[:ssl_version]
    end
    if @options[:ssl_ciphers]
      @ssl.ciphers = @options[:ssl_ciphers]
    end
    @ssl.cert = OpenSSL::X509::Certificate.new(File.read(@options[:ssl_certificate]))
    @ssl.key = OpenSSL::PKey::RSA.new(File.read(@options[:ssl_key]),
      @options[:ssl_key_passphrase])
  end
end

Public Instance Methods

accept(&block) click to toggle source
# File lib/lumberjack/beats/server.rb, line 87
def accept(&block)
  begin
    socket = @server.accept_nonblock
    # update the socket with a SSL layer
    socket = accept_ssl(socket) if ssl?

    if block_given?
      block.call(socket, self)
    else
      return Connection.new(socket, self)
    end
  rescue OpenSSL::SSL::SSLError, IOError, EOFError, Errno::EBADF
    socket.close rescue nil
    retry unless closed?
  rescue IO::WaitReadable, Errno::EAGAIN # Resource not ready yet, so lets try again
    begin
      IO.select([@server], nil, nil, SOCKET_TIMEOUT)
      retry unless closed?
    rescue IOError, Errno::EBADF => e # we currently closing
      raise e unless closed?
    end
  end
end
accept_ssl(tcp_socket) click to toggle source
# File lib/lumberjack/beats/server.rb, line 111
def accept_ssl(tcp_socket)
  ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, @ssl)
  ssl_socket.sync_close

  begin
    ssl_socket.accept_nonblock

    return ssl_socket
  rescue IO::WaitReadable # handshake
    IO.select([ssl_socket], nil, nil, SOCKET_TIMEOUT)
    retry unless closed?
  rescue IO::WaitWritable # handshake
    IO.select(nil, [ssl_socket], nil, SOCKET_TIMEOUT)
    retry unless closed?
  end
end
close() click to toggle source
# File lib/lumberjack/beats/server.rb, line 132
def close
  @close.make_true
  @server.close unless @server.closed?
end
closed?() click to toggle source
# File lib/lumberjack/beats/server.rb, line 128
def closed?
  @close.value
end
run(&block) click to toggle source
# File lib/lumberjack/beats/server.rb, line 68
def run(&block)
  while !closed?
    connection = accept

    # Some exception may occur in the accept loop
    # we will try again in the next iteration
    # unless the server is closing
    next unless connection

    Thread.new(connection) do |connection|
      connection.run(&block)
    end
  end
end
ssl?() click to toggle source
# File lib/lumberjack/beats/server.rb, line 83
def ssl?
  @ssl
end