class Relp::RelpServer
Public Class Methods
new(port, callback, host = '0.0.0.0' , tls_context = nil, logger = nil)
click to toggle source
# File lib/relp/server.rb, line 8 def initialize(port, callback, host = '0.0.0.0' , tls_context = nil, logger = nil) @logger = logger @logger = Logger.new(STDOUT) if logger.nil? @socket_list = Array.new @callback = callback @required_command = 'syslog' begin @server = TCPServer.new host, port if tls_context @logger.info "Starting #{self.class} with SSL enabled on %s:%i" % @server.local_address.ip_unpack @server = OpenSSL::SSL::SSLServer.new(@server, tls_context) else @logger.info "Starting #{self.class} on %s:%i" % @server.local_address.ip_unpack end rescue Errno::EADDRINUSE @logger.error "ERROR Could not start relp server: Port #{port} in use" raise Errno::EADDRINUSE end end
Public Instance Methods
ack_frame(socket, txnr)
click to toggle source
# File lib/relp/server.rb, line 76 def ack_frame(socket, txnr) frame = {:txnr => txnr, :command => 'rsp', :message => "6 200 OK\n" } frame_write(socket, frame) end
return_message(message, callback)
click to toggle source
# File lib/relp/server.rb, line 67 def return_message(message, callback) list_of_messages = message.split(/\n+/) list_of_messages.each do |msg| remove = msg.split(": ").first + ": " msg.slice! remove callback.call(msg) end end
run()
click to toggle source
# File lib/relp/server.rb, line 29 def run loop do client_socket = @server.accept Thread.start(client_socket) do |client_socket| begin @socket_list.push client_socket remote_ip = client_socket.peeraddr[3] @logger.info "New client connection coming from ip #{remote_ip}" @logger.debug "New client started with object id=#{client_socket.object_id}" connection_setup(client_socket) while Thread.current.alive? do ready = IO.select([client_socket], nil, nil, 10) if ready frame = communication_processing(client_socket) return_message(frame[:message], (@callback)) ack_frame(client_socket,frame[:txnr]) end end rescue Relp::ConnectionClosed @logger.info "Connection closed" rescue Relp::RelpProtocolError => err @logger.warn 'Relp error: ' + err.class.to_s + ' ' + err.message rescue OpenSSL::SSL::SSLError => ssl_error @logger.error "SSL Error", :exception => ssl_error rescue Exception => e @logger.debug e ensure server_close_message(client_socket) rescue nil @logger.debug "Closing client socket=#{client_socket.object_id}" @logger.info "Client from ip #{remote_ip} closed" end end end rescue Errno::EINVAL # Swallowing exception here because it results even from properly closed socket @logger.info "Socket close." end
server_close_message(socket)
click to toggle source
# File lib/relp/server.rb, line 84 def server_close_message(socket) Hash.new frame = {:txnr => 0, :command => 'close', :message => '0' } begin frame_write(socket,frame) @logger.debug 'Server close message send' socket.close @socket_list.delete socket rescue Relp::ConnectionClosed end end
server_shutdown()
click to toggle source
# File lib/relp/server.rb, line 98 def server_shutdown @socket_list.each do |client_socket| if client_socket != nil server_close_message(client_socket) end end @logger.info 'Server shutdown' @server.shutdown @server = nil end
Private Instance Methods
communication_processing(socket)
click to toggle source
# File lib/relp/server.rb, line 110 def communication_processing(socket) @logger.debug 'Communication processing' frame = frame_read(socket) if frame[:command] == 'syslog' return frame elsif frame[:command] == 'close' response_frame = create_frame(frame[:txnr], "rsp", "0") frame_write(socket,response_frame) @logger.info 'Client send close message' server_close_message(socket) raise Relp::ConnectionClosed else server_close_message(socket) raise Relp::RelpProtocolError, 'Wrong relp command' end end
connection_setup(socket)
click to toggle source
# File lib/relp/server.rb, line 127 def connection_setup(socket) @logger.debug 'Connection setup' begin read_ready = IO.select([socket], nil, nil, 10) if read_ready frame = frame_read(socket) @logger.debug 'Frame read complete, processing..' if frame[:command] == 'open' @logger.debug 'Client command open' message_informations = extract_message_information(frame[:message]) if message_informations[:relp_version].empty? @logger.warn 'Missing RELP version specification' server_close_message(socket) raise Relp::RelpProtocolError elsif @required_command != message_informations[:commands] @logger.warn 'Missing required commands - syslog' Hash.new response_frame = create_frame(frame[:txnr], 'rsp', '20 500 Missing required command ' + @required_command) frame_write(socket, response_frame) server_close_message(socket) raise Relp::InvalidCommand, 'Missing required command' else Hash.new response_frame = create_frame(frame[:txnr], 'rsp', '93 200 OK' + "\n" + 'relp_version=' +@@relp_version + "\n" + 'relp_software=' + @@relp_software + "\n" + 'commands=' + @required_command + "\n") @logger.debug 'Sending response to client' frame_write(socket, response_frame) end else server_close_message(socket) raise Relp::InvalidCommand, frame[:command] + ' expecting open command' end end rescue Relp::RelpProtocolError @logger.debug 'Timed out (no frame to read)' server_close_message(socket) end end