The connection class maintains a socket connection with a reactor and handles all events dispatched by the reactor.
Create a new connection object
server
The reactor this connection is associated with.
sock
The socket for this connection.
returns
A connection object.
# File lib/network/connection.rb, line 34 def initialize(server, sock) super(server, sock) case @server.service_io when :lineio @sockio = LineIO.new(@sock) when :packetio @sockio = PacketIO.new(@sock) else @sockio = SockIO.new(@sock) end @inbuffer = "" # buffer lines waiting to be processed @outbuffer = "" # buffer lines waiting to be output if @server.service_filters.include? :telnetfilter @initdone = false # keeps silent until we're done with negotiations else @initdone = true end @pstack = ProtocolStack.new(self) end
#handle_close is called to when an close event occurs for this session.
# File lib/network/connection.rb, line 131 def handle_close @connected = false publish(:disconnected) unsubscribe_all log.info "(#{self.object_id}) Connection '#{@host}(#{@addr})' closing" @server.unregister(self) # @sock.shutdown # odd errors thrown with this @sock.close rescue Exception log.error "(#{self.object_id}) Connection#handle_close closing" log.error $! end
#handle_input is called to order a connection to process any input waiting on its socket. Input is parsed into lines based on the occurance of the CRLF terminator and pushed into a buffer which is a list of lines. The buffer expands dynamically as input is processed. Input that has yet to see a CRLF terminator is left in the connection's inbuffer.
# File lib/network/connection.rb, line 75 def handle_input buf = @sockio.read raise(EOFError) if !buf || buf.empty? buf = @pstack.filter_call(:filter_in,buf) if @server.service_io == :packetio || @server.service_type == :client publish(buf) else @inbuffer << buf if @initdone # Just let buffer fill until we indicate we're done # negotiating. Set by calling initdone from TelnetFilter while p = @inbuffer.index("\n") ln = @inbuffer.slice!(0..p).chop publish(ln) end end end rescue EOFError, Errno::ECONNRESET, Errno::ECONNABORTED @closing = true publish(:disconnected) unsubscribe_all log.info "(#{self.object_id}) Connection '#{@host}(#{@addr})' disconnecting" log.error $! rescue Exception @closing = true publish(:disconnected) unsubscribe_all log.error "(#{self.object_id}) Connection#handle_input disconnecting" log.error $! end
#handle_oob is called when an out of band data event occurs for this session.
# File lib/network/connection.rb, line 146 def handle_oob buf = @sockio.read_urgent log.debug "(#{self.object_id}) Connection urgent data received - '#{buf[0]}'" @pstack.set(:urgent, true) buf = @pstack.filter_call(:filter_in,buf) rescue Exception log.error "(#{self.object_id}) Connection#handle_oob" log.error $! end
#handle_output is called to order a connection to process any output waiting on its socket.
# File lib/network/connection.rb, line 108 def handle_output @outbuffer = @pstack.filter_call(:filter_out,@outbuffer) done = @sockio.write(@outbuffer) @outbuffer = "" if done @write_blocked = false else @write_blocked = true end rescue EOFError, Errno::ECONNABORTED, Errno::ECONNRESET @closing = true publish(:disconnected) unsubscribe_all log.info "(#{self.object_id}) Connection '#{@host}(#{@addr})' disconnecting" rescue Exception @closing = true publish(:disconnected) unsubscribe_all log.error "(#{self.object_id}) Connection#handle_output disconnecting" log.error $! end
init is called before using the connection.
returns
true is connection is properly initialized
# File lib/network/connection.rb, line 56 def init @host, @addr = @sock.peeraddr.slice(2..3) @connected = true @server.register(self) log.info "(#{self.object_id}) New Connection on '#{@host}(#{@addr})'" @pstack.filter_call(:init,nil) true rescue Exception log.error "(#{self.object_id}) Connection#init" log.error $! false end
attrib
A Symbol not handled here is assumed to be a query and
its handling is delegated to the ProtocolStack, the result of which is a pair immediately sent back to as a message to the client. <pre> client -> us :echo us -> ProtocolStack query(:echo) ProtocolStack -> us [:echo, true] us -> client [:echo, true] </pre>
# File lib/network/connection.rb, line 216 def query(attrib) @pstack.query(attrib) end
sendmsg places a message on the Connection’s output buffer.
msg
The message, a reference to a buffer
# File lib/network/connection.rb, line 237 def sendmsg(msg) @outbuffer << msg @write_blocked = true # change status to write_blocked end
An Array not handled here is assumed to be a set command and
its handling is delegated to the ProtocolStack. <pre> client -> us [:color, true] us -> ProtocolStack set(:color, true) </pre>
# File lib/network/connection.rb, line 230 def set(attrib, val) @pstack.set(attrib, val) end
This is called from TelnetFilter when we are done with negotiations. The event :initdone wakens observer to begin user activity
# File lib/network/connection.rb, line 158 def set_initdone @initdone = true publish(:initdone) end
Update will be called when the object the connection is observing wants to notify us of a change in state or new message. When a new connection is accepted in acceptor that connection is passed to the observer of the acceptor which allows the client to attach an observer to the connection and make the connection an observer of that object. We need to keep both sides interest in each other limited to a narrow but flexible interface to prevent tight coupling.
This supports the following:
This symbol message from the client is a request to
close the Connection. It is handled here.
A String is assumed to be output and placed in our @outbuffer.
# File lib/network/connection.rb, line 178 def update(msg) case msg when :quit handle_output @closing = true when :reconnecting unsubscribe_all log.info "(#{self.object_id}) Connection '#{@host}(#{@addr})' closing for reconnection" @server.unregister(self) # @sock.shutdown # odd errors thrown with this @sock.close when String sendmsg(msg) else log.error "(#{self.object_id}) Connection#update - unknown message '#{@msg.inspect}'" end rescue # We squash and print out all exceptions here. There is no reason to # throw these back at out subscribers. log.error $! end