Class: StunClient::RFC3489Client
- Inherits:
-
GenericClient
- Object
- GenericClient
- StunClient::RFC3489Client
- Defined in:
- lib/stun-client/rfc3489/client.rb
Overview
A STUN client which can send and receive RFC3489 messages. It does not support shared secret messages.
Personal note: I would have liked to implement this, but I have not found a STUN server that supports it.
Instance Method Summary collapse
-
#query(parameters = {}) ⇒ Hash
Make a STUN Binding Request.
Methods inherited from GenericClient
#initialize, #parse_mapped_address, #receive_message, #send_binary, #try_sending, #validate_and_get_change
Constructor Details
This class inherits a constructor from StunClient::GenericClient
Instance Method Details
#query(parameters = {}) ⇒ Hash
Make a STUN Binding Request.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 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 |
# File 'lib/stun-client/rfc3489/client.rb', line 31 def query parameters = {} txid = StunClient::Utilities.generate_txid(128) change_port, change_ip = validate_and_get_change parameters request = RFC3489Message::StunMessage.new request[:message_type] = 0x0001 # binding request request[:transaction_id] = txid request[:message_length] = request.to_binary_s.length - 20 if change_port == 1 || change_ip == 1 cr = RFC3489Message::ChangeRequest.new cr[:change_ip] = change_ip cr[:change_port] = change_port attr = RFC3489Message::Attribute.new attr[:attribute_type] = 0x0003 attr[:attribute_length] = cr.to_binary_s.length attr[:attribute_value] = cr request[:message_length] += attr.to_binary_s.length request[:attributes] << attr end if parameters.has_key?(:response_port) && parameters[:response_port] && parameters.has_key?(:response_ip) && parameters[:response_ip] raise 'Response Port must be a Integer' if ! parameters[:response_port].is_a? Integer raise 'Response IP must be a String' if ! parameters[:response_ip].is_a? String family = parameters[:response_ip].include?(':') ? 2 : 1 begin ip = IPAddr.new(parameters[:response_ip]).hton rescue IPAddr::InvalidAddressError raise ArgumentError, 'Invalid IP' end ra = RFC3489Message::MappedAddress.new ra[:family] = family ra[:address] = ip ra[:port] = parameters[:response_port] attr = RFC3489Message::Attribute.new attr[:attribute_type] = 0x0002 attr[:attribute_length] = ra.to_binary_s.length attr[:attribute_value] = ra request[:message_length] += attr.to_binary_s.length request[:attributes] << attr end new_interval = ->(old_interval) { (old_interval < 1.6 ? old_interval * 2 : old_interval ) } response = send_binary parameters, request.to_binary_s, new_interval, 9, 0.1 msg = RFC3489Message::StunMessage.read response[0] res = {} res[:response] = msg if msg[:transaction_id] != txid expected = StunClient::Utilities.sanitize_string txid actual = StunClient::Utilities.sanitize_string msg[:transaction_id] # rubocop:disable Layout/TrailingWhitespace raise InvalidTransactionId, "Server responsed with invalid transaction id. Expected: #{expected}, Actual: #{actual}" # rubocop:enable Layout/TrailingWhitespace end case RFC3489Message::StunMessage::MESSAGE_TYPES[msg[:message_type]] when :binding_response res.merge! parse_attributes(msg[:attributes]) when :bindung_error_response res.merge! parse_attributes(msg[:attributes]) msg = 'Server returns an unknown error' if res[:error] if res[:error][:unknown_attributes] msg += ": Unknown attributes: #{res[:error][:unknown_attributes]}" end if res[:error][:class] = StunClient::Utilities.sanitize_string res[:error][:message] msg += ": #{res[:error][:class]}#{res[:error][:number]}#{}" end else msg += '.' end raise BindungErrorResponse, msg else raise UnableToInterpretResponse, 'Server responsed with unknown message type' end return res end |