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.



33
34
35
36
37
# 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

Instance Attribute Details

#conn_paramsObject (readonly)

Returns the value of attribute conn_params.



31
32
33
# File 'lib/net/tti/connection.rb', line 31

def conn_params
  @conn_params
end

Instance Method Details

#connect(opts = {}) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 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

#disconnectObject



58
59
60
# File 'lib/net/tti/connection.rb', line 58

def disconnect()
  @tns_connection.disconnect
end

#get_error_messageObject



137
138
139
140
141
142
143
144
145
146
147
148
149
# 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) ⇒ Object



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
126
127
128
129
130
131
132
133
134
135
# 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) ⇒ Object



62
63
64
65
# 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) ⇒ Object

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



69
70
71
72
73
74
75
76
77
78
79
80
81
# 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