class Net::TTI::Connection

Attributes

conn_params[R]

Public Class Methods

new(opts={}) click to toggle source
# File lib/net/tti/connection.rb, line 33
def initialize(opts={})
  Net::TTI.logger.debug("Creating new TNS Connection")
  @tns_connection = Net::TNS::Connection.new(opts)
  @conn_params = ConnectionParameters.new()
end

Public Instance Methods

connect(opts={}) click to toggle source
# File lib/net/tti/connection.rb, line 39
def connect(opts={})
  Net::TTI.logger.debug("Connection#connect called")
  @tns_connection.connect(opts)
  @conn_params.tns_version = @tns_connection.tns_protocol_version

  Net::TTI.logger.debug("Sending protocol negotiation request")
  proto_nego_request = ProtocolNegotiationRequest.create_request()
  proto_nego_response_raw = send_and_receive( proto_nego_request )

  proto_nego_response = ProtocolNegotiationResponse.read( proto_nego_response_raw )
  proto_nego_response.populate_connection_parameters( @conn_params )

  Net::TTI.logger.debug("Sending data type negotiation request")
  dt_nego_request = DataTypeNegotiationRequest.create_request( @conn_params )
  dt_nego_response_raw = send_and_receive( dt_nego_request )

  return nil
end
disconnect() click to toggle source
# File lib/net/tti/connection.rb, line 58
def disconnect()
  @tns_connection.disconnect
end
get_error_message() click to toggle source
# File lib/net/tti/connection.rb, line 137
def get_error_message
  error_request = Net::TNS::MarkerPacket.create_request()
  @tns_connection.send_tns_packet( error_request )

  raw_response = receive_tti_message(true)
  response = Message.from_data_string(raw_response)

  unless response.is_a?(ErrorMessage)
    raise Exceptions::ProtocolException.new( "Received #{response.class} instead of error message" )
  end

  return response.message
end
receive_tti_message( waiting_for_error_message = false, max_message_length=10_000 ) click to toggle source
# File lib/net/tti/connection.rb, line 83
def receive_tti_message( waiting_for_error_message = false, max_message_length=10_000 )
  # This is structured as a loop in order to handle messages (e.g. Markers)
  # that need to be handled without returning to the caller. To keep a malicious
  # server from making us loop continuously, we set an arbitrary limit of
  # 10 loops without a "real" message before we throw an exception.
  receive_count = 0
  while ( true )
    receive_count += 1
    if ( receive_count >= 3 )
      raise Exceptions::ProtocolException.new( "Maximum receive attempts exceeded - too many Markers received." )
    end

    Net::TTI.logger.debug("Attempting to receive packet (try ##{receive_count})")
    case tns_packet = @tns_connection.receive_tns_packet()
    when Net::TNS::DataPacket
      message_data = tns_packet.data
      # If this is a long packet, the data may have hit the max length and
      # carried into an additional packet. We wouldn't need to do this if
      # we could fully parse every message (or at least know lengths to
      # read). I'm looking at you, DataTypeNegotiationResponse.
      if @tns_connection.tns_protocol_version <= 313 && tns_packet.num_bytes > 1900
        begin
          max_message_length -= message_data.length
          message_data += receive_tti_message(waiting_for_error_message, max_message_length)
        rescue Net::TNS::Exceptions::ReceiveTimeoutExceeded
          Net::TTI.logger.debug("Hit receive timeout trying to read another Data packet")
        end
      end

      return message_data

    # We received an error notification
    when Net::TNS::MarkerPacket
      Net::TTI.logger.info("Received MarkerPacket")
      # TNS Markers seem to come in pairs. If we've already got one and sent
      # the request for the error message, we'll ignore subsequent markers
      # until we get the error message.
      unless waiting_for_error_message
        error_message = get_error_message()
        raise Exceptions::ErrorMessageReceived.new( error_message )
      end

    # We received something else
    else
      Net::TTI.logger.warn("Received #{tns_packet.class} instead of Data")
      if waiting_for_error_message
        raise Exceptions::ProtocolException.new( "Invalid response while waiting for error message - got #{tns_packet.class}" )
      else
        raise Exceptions::ProtocolException.new( "Received #{tns_packet.class} instead of TNS data packet (for TTI)" )
      end
    end
  end
end
send_and_receive( tti_message ) click to toggle source
# File lib/net/tti/connection.rb, line 62
def send_and_receive( tti_message )
  send_tti_message(tti_message)
  receive_tti_message()
end
send_tti_message( tti_message ) click to toggle source

Sends a TTI message. This function takes a TTI payload, embeds it in one or more TNS Data packets and sends those packets.

# File lib/net/tti/connection.rb, line 69
def send_tti_message( tti_message )
  raw_message = tti_message.to_binary_s
  Net::TTI.logger.debug( "Connection#send_tti_message called with #{raw_message.length}-byte #{tti_message.class} message" )

  # Split the message into multiple packets if necessary
  max_data = @tns_connection.tns_sdu - 12 # 12 = 10 (HEADER) + 2 (FLAGS)
  raw_message.scan(/.{1,#{max_data}}/m).each do |raw_message_part|
    tns_packet = Net::TNS::DataPacket.new()
    tns_packet.data = raw_message_part
    Net::TTI.logger.debug( "Sending data packet (#{tns_packet.num_bytes} bytes total)" )
    @tns_connection.send_tns_packet( tns_packet )
  end
end