Class: Net::TTI::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/net/tti/connection.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Connection

Returns a new instance of Connection.



23
24
25
26
27
# File 'lib/net/tti/connection.rb', line 23

def initialize(opts={})
  Net::TTI.logger.debug("Creating new TNS Connection")
  @tns_connection = Net::TNS::Connection.new(opts)
  @conn_params = ConnectionParameters.new()
end

Instance Attribute Details

#conn_paramsObject (readonly)

Returns the value of attribute conn_params.



21
22
23
# File 'lib/net/tti/connection.rb', line 21

def conn_params
  @conn_params
end

Instance Method Details

#connect(opts = {}) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/net/tti/connection.rb', line 29

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.platform )
  dt_nego_response_raw = send_and_receive( dt_nego_request )

  return nil
end

#disconnectObject



48
49
50
# File 'lib/net/tti/connection.rb', line 48

def disconnect()
  @tns_connection.disconnect
end

#get_error_messageObject



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/net/tti/connection.rb', line 127

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) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/net/tti/connection.rb', line 73

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::TNSException.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_packet.num_bytes > 2000
        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) ⇒ Object



52
53
54
55
# File 'lib/net/tti/connection.rb', line 52

def send_and_receive( tti_message )
  send_tti_message(tti_message)
  receive_tti_message()
end

#send_tti_message(tti_message) ⇒ Object

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



59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/net/tti/connection.rb', line 59

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 = Net::TNS::DataPacket.max_data_length
  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