class Connection

The connection class maintains a socket connection with a reactor and handles all events dispatched by the reactor.

Attributes

addr[R]
host[R]
inbuffer[RW]
initdone[R]
outbuffer[RW]
pstack[R]
server[R]
sockio[R]

Public Class Methods

new(server, sock) click to toggle source

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

Public Instance Methods

handle_close() click to toggle source

#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() click to toggle source

#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() click to toggle source

#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() click to toggle source

#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() click to toggle source

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
query(attrib) click to toggle source
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(msg) click to toggle source

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
set(attrib, val) click to toggle source
+attrib,val+
  • 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
set_initdone() click to toggle source

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(msg) click to toggle source

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:

:quit
  • This symbol message from the client is a request to

    close the Connection.  It is handled here.
String
  • 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