| /* |
| * libjingle |
| * Copyright 2004 Google Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <string> |
| |
| #include "talk/base/bytebuffer.h" |
| #include "talk/base/gunit.h" |
| #include "talk/base/logging.h" |
| #include "talk/base/scoped_ptr.h" |
| #include "talk/base/socketaddress.h" |
| #include "talk/p2p/base/stun.h" |
| |
| namespace cricket { |
| |
| class StunTest : public ::testing::Test { |
| protected: |
| void CheckStunHeader(const StunMessage& msg, StunMessageType expected_type, |
| size_t expected_length) { |
| ASSERT_EQ(expected_type, msg.type()); |
| ASSERT_EQ(expected_length, msg.length()); |
| } |
| |
| void CheckStunTransactionID(const StunMessage& msg, |
| const unsigned char* expectedID, size_t length) { |
| ASSERT_EQ(0, std::memcmp(msg.transaction_id().c_str(), |
| expectedID, length)); |
| } |
| |
| void CheckStunAddressAttribute(const StunAddressAttribute* addr, |
| StunAddressFamily expected_family, |
| int expected_port, |
| talk_base::IPAddress expected_address) { |
| ASSERT_EQ(expected_family, addr->family()); |
| ASSERT_EQ(expected_port, addr->port()); |
| |
| if (addr->family() == STUN_ADDRESS_IPV4) { |
| in_addr v4_address = expected_address.ipv4_address(); |
| in_addr stun_address = addr->ipaddr().ipv4_address(); |
| ASSERT_EQ(0, std::memcmp(&v4_address, &stun_address, |
| sizeof(stun_address))); |
| } else if (addr->family() == STUN_ADDRESS_IPV6) { |
| in6_addr v6_address = expected_address.ipv6_address(); |
| in6_addr stun_address = addr->ipaddr().ipv6_address(); |
| ASSERT_EQ(0, std::memcmp(&v6_address, &stun_address, |
| sizeof(stun_address))); |
| } else { |
| ASSERT_TRUE(addr->family() == STUN_ADDRESS_IPV6 || |
| addr->family() == STUN_ADDRESS_IPV4); |
| } |
| } |
| |
| size_t ReadStunMessageTestCase(StunMessage* msg, |
| const unsigned char* testcase, |
| size_t size) { |
| const char* input = reinterpret_cast<const char*>(testcase); |
| talk_base::ByteBuffer buf(input, size); |
| if (msg->Read(&buf)) { |
| // Returns the size the stun message should report itself as being |
| return (size - 20); |
| } else { |
| return 0; |
| } |
| } |
| }; |
| |
| |
| // Sample STUN packets with various attributes |
| // Gathered by wiresharking pjproject's pjnath test programs |
| // pjproject available at www.pjsip.org |
| |
| static const unsigned char kStunMessageWithIPv6MappedAddress[] = { |
| 0x00, 0x01, 0x00, 0x18, // message header |
| 0x21, 0x12, 0xa4, 0x42, // transaction id |
| 0x29, 0x1f, 0xcd, 0x7c, |
| 0xba, 0x58, 0xab, 0xd7, |
| 0xf2, 0x41, 0x01, 0x00, |
| 0x00, 0x01, 0x00, 0x14, // Address type (mapped), length |
| 0x00, 0x02, 0xb8, 0x81, // family (IPv6), port |
| 0x24, 0x01, 0xfa, 0x00, // an IPv6 address |
| 0x00, 0x04, 0x10, 0x00, |
| 0xbe, 0x30, 0x5b, 0xff, |
| 0xfe, 0xe5, 0x00, 0xc3 |
| }; |
| |
| static const unsigned char kStunMessageWithIPv4MappedAddress[] = { |
| 0x01, 0x01, 0x00, 0x0c, // binding response, length 12 |
| 0x21, 0x12, 0xa4, 0x42, // magic cookie |
| 0x29, 0x1f, 0xcd, 0x7c, // transaction ID |
| 0xba, 0x58, 0xab, 0xd7, |
| 0xf2, 0x41, 0x01, 0x00, |
| 0x00, 0x01, 0x00, 0x08, // Mapped, 8 byte length |
| 0x00, 0x01, 0x9d, 0xfc, // AF_INET, unxor-ed port |
| 0xac, 0x17, 0x44, 0xe6 // IPv4 address |
| }; |
| |
| // Test XOR-mapped IP addresses: |
| static const unsigned char kStunMessageWithIPv6XorMappedAddress[] = { |
| 0x01, 0x01, 0x00, 0x18, // message header (binding response) |
| 0x21, 0x12, 0xa4, 0x42, // magic cookie (rfc5389) |
| 0xe3, 0xa9, 0x46, 0xe1, // transaction ID |
| 0x7c, 0x00, 0xc2, 0x62, |
| 0x54, 0x08, 0x01, 0x00, |
| 0x00, 0x20, 0x00, 0x14, // Address Type (XOR), length |
| 0x00, 0x02, 0xcb, 0x5b, // family, XOR-ed port |
| 0x05, 0x13, 0x5e, 0x42, // XOR-ed IPv6 address |
| 0xe3, 0xad, 0x56, 0xe1, |
| 0xc2, 0x30, 0x99, 0x9d, |
| 0xaa, 0xed, 0x01, 0xc3 |
| }; |
| |
| static const unsigned char kStunMessageWithIPv4XorMappedAddress[] = { |
| 0x01, 0x01, 0x00, 0x0c, // message header (binding response) |
| 0x21, 0x12, 0xa4, 0x42, // magic cookie |
| 0x29, 0x1f, 0xcd, 0x7c, // transaction ID |
| 0xba, 0x58, 0xab, 0xd7, |
| 0xf2, 0x41, 0x01, 0x00, |
| 0x00, 0x20, 0x00, 0x08, // address type (xor), length |
| 0x00, 0x01, 0xfc, 0xb5, // family (AF_INET), XOR-ed port |
| 0x8d, 0x05, 0xe0, 0xa4 // IPv4 address |
| }; |
| |
| // ByteString Attribute (username) |
| static const unsigned char kStunMessageWithByteStringAttribute[] = { |
| 0x00, 0x01, 0x00, 0x0c, |
| 0x21, 0x12, 0xa4, 0x42, |
| 0xe3, 0xa9, 0x46, 0xe1, |
| 0x7c, 0x00, 0xc2, 0x62, |
| 0x54, 0x08, 0x01, 0x00, |
| 0x00, 0x06, 0x00, 0x08, // username attribute (length 8) |
| 0x61, 0x62, 0x63, 0x64, // abcdefgh |
| 0x65, 0x66, 0x67, 0x68 |
| }; |
| |
| // Message with an unknown but comprehensible optional attribute. |
| // Parsing should succeed despite this unknown attribute. |
| static const unsigned char kStunMessageWithUnknownAttribute[] = { |
| 0x00, 0x01, 0x00, 0x14, |
| 0x21, 0x12, 0xa4, 0x42, |
| 0xe3, 0xa9, 0x46, 0xe1, |
| 0x7c, 0x00, 0xc2, 0x62, |
| 0x54, 0x08, 0x01, 0x00, |
| 0x00, 0xaa, 0x00, 0x07, // Unknown attribute, length 7 (needs padding!) |
| 0x61, 0x62, 0x63, 0x64, // abcdefg + padding |
| 0x65, 0x66, 0x67, 0x00, |
| 0x00, 0x0d, 0x00, 0x04, // Followed by a known attribute we can |
| 0x00, 0x00, 0x00, 0x0b // check for. |
| }; |
| |
| // ByteString Attribute (username) with padding byte |
| static const unsigned char kStunMessageWithPaddedByteStringAttribute[] = { |
| 0x00, 0x01, 0x00, 0x08, |
| 0x21, 0x12, 0xa4, 0x42, |
| 0xe3, 0xa9, 0x46, 0xe1, |
| 0x7c, 0x00, 0xc2, 0x62, |
| 0x54, 0x08, 0x01, 0x00, |
| 0x00, 0x06, 0x00, 0x03, // username attribute (length 3) |
| 0x61, 0x62, 0x63, 0xcc // abc |
| }; |
| |
| // Message with an Unknown Attributes (uint16 list) attribute. |
| static const unsigned char kStunMessageWithUInt16ListAttribute[] = { |
| 0x00, 0x01, 0x00, 0x0c, |
| 0x21, 0x12, 0xa4, 0x42, |
| 0xe3, 0xa9, 0x46, 0xe1, |
| 0x7c, 0x00, 0xc2, 0x62, |
| 0x54, 0x08, 0x01, 0x00, |
| 0x00, 0x0a, 0x00, 0x06, // username attribute (length 6) |
| 0x00, 0x01, 0x10, 0x00, // three attributes plus padding |
| 0xAB, 0xCU, 0xBE, 0xEF |
| }; |
| |
| // Error response message (unauthorized) |
| static const unsigned char kStunMessageWithErrorAttribute[] = { |
| 0x01, 0x13, 0x00, 0x14, |
| 0x21, 0x12, 0xa4, 0x42, |
| 0x29, 0x1f, 0xcd, 0x7c, |
| 0xba, 0x58, 0xab, 0xd7, |
| 0xf2, 0x41, 0x01, 0x00, |
| 0x00, 0x09, 0x00, 0x10, |
| 0x00, 0x00, 0x04, 0x01, |
| 0x55, 0x6e, 0x61, 0x75, |
| 0x74, 0x68, 0x6f, 0x72, |
| 0x69, 0x7a, 0x65, 0x64 |
| }; |
| |
| // Message with an address attribute with an unknown address family, |
| // and a byte string attribute. Check that we quit reading after the |
| // bogus address family and don't read the username attribute. |
| static const unsigned char kStunMessageWithInvalidAddressFamily[] = { |
| 0x01, 0x01, 0x00, 0x18, // binding response, length 24 |
| 0x21, 0x12, 0xa4, 0x42, // magic cookie |
| 0x29, 0x1f, 0xcd, 0x7c, // transaction ID |
| 0xba, 0x58, 0xab, 0xd7, |
| 0xf2, 0x41, 0x01, 0x00, |
| 0x00, 0x01, 0x00, 0x08, // Mapped address, 4 byte length |
| 0x00, 0x09, 0xfe, 0xed, // Bogus address family (port unimportant). |
| 0xac, 0x17, 0x44, 0xe6, // Should be skipped. |
| 0x00, 0x06, 0x00, 0x08, // Username attribute (length 8) |
| 0x61, 0x62, 0x63, 0x64, // abcdefgh |
| 0x65, 0x66, 0x67, 0x68 |
| }; |
| |
| // Message with an address attribute with an invalid address length. |
| // Should fail to be read. |
| static const unsigned char kStunMessageWithInvalidAddressLength[] = { |
| 0x01, 0x01, 0x00, 0x18, // binding response, length 24 |
| 0x21, 0x12, 0xa4, 0x42, // magic cookie |
| 0x29, 0x1f, 0xcd, 0x7c, // transaction ID |
| 0xba, 0x58, 0xab, 0xd7, |
| 0xf2, 0x41, 0x01, 0x00, |
| 0x00, 0x01, 0x00, 0x0c, // Mapped address, 12 byte length |
| 0x00, 0x01, 0xfe, 0xed, // Claims to be AF_INET. |
| 0xac, 0x17, 0x44, 0xe6, |
| 0x00, 0x06, 0x00, 0x08 |
| }; |
| |
| // Sample messages with an invalid length Field |
| |
| // The actual length in bytes of the invalid messages (including STUN header) |
| static const int kRealLengthOfInvalidLengthTestCases = 32; |
| |
| static const unsigned char kStunMessageWithZeroLength[] = { |
| 0x00, 0x01, 0x00, 0x00, // length of 0 (last 2 bytes) |
| 0x21, 0x12, 0xA4, 0x42, // magic cookie |
| '0', '1', '2', '3', // transaction id |
| '4', '5', '6', '7', |
| '8', '9', 'a', 'b', |
| 0x00, 0x20, 0x00, 0x08, // xor mapped address |
| 0x00, 0x01, 0x21, 0x1F, |
| 0x21, 0x12, 0xA4, 0x53, |
| }; |
| |
| static const unsigned char kStunMessageWithExcessLength[] = { |
| 0x00, 0x01, 0x00, 0x55, // length of 85 |
| 0x21, 0x12, 0xA4, 0x42, // magic cookie |
| '0', '1', '2', '3', // transaction id |
| '4', '5', '6', '7', |
| '8', '9', 'a', 'b', |
| 0x00, 0x20, 0x00, 0x08, // xor mapped address |
| 0x00, 0x01, 0x21, 0x1F, |
| 0x21, 0x12, 0xA4, 0x53, |
| }; |
| |
| static const unsigned char kStunMessageWithSmallLength[] = { |
| 0x00, 0x01, 0x00, 0x03, // length of 3 |
| 0x21, 0x12, 0xA4, 0x42, // magic cookie |
| '0', '1', '2', '3', // transaction id |
| '4', '5', '6', '7', |
| '8', '9', 'a', 'b', |
| 0x00, 0x20, 0x00, 0x08, // xor mapped address |
| 0x00, 0x01, 0x21, 0x1F, |
| 0x21, 0x12, 0xA4, 0x53, |
| }; |
| |
| // Legacy STUN tests. |
| // Included for completeness, but it's not recommended to change these. |
| static const unsigned char kStunMessageWithManyAttributes[] = { |
| 0x00, 0x01, 0x00, 136, // message header |
| 0x21, 0x12, 0xA4, 0x42, // magic cookie |
| '0', '1', '2', '3', // transaction id |
| '4', '5', '6', '7', |
| '8', '9', 'a', 'b', |
| 0x00, 0x01, 0x00, 8, // mapped address |
| 0x00, 0x01, 0x00, 13, |
| 0x00, 0x00, 0x00, 17, |
| 0x00, 0x06, 0x00, 12, // username |
| 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', |
| 0x00, 0x08, 0x00, 20, // message integrity |
| 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', |
| 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', |
| 0x00, 0x09, 0x00, 12, // error code |
| 0x00, 0x00, 2, 10, |
| 'f', 'o', 'o', ' ', 'b', 'a', 'r', '!', |
| 0x00, 0x0a, 0x00, 4, // unknown attributes |
| 0x00, 0x01, 0x00, 0x02, |
| 0x00, 0x0d, 0x00, 4, // lifetime |
| 0x00, 0x00, 0x00, 11, |
| 0x00, 0x0f, 0x00, 4, // magic cookie |
| 0x72, 0xc6, 0x4b, 0xc6, |
| 0x00, 0x10, 0x00, 4, // bandwidth |
| 0x00, 0x00, 0x00, 6, |
| 0x00, 0x11, 0x00, 8, // destination address |
| 0x00, 0x01, 0x00, 13, |
| 0x00, 0x00, 0x00, 17, |
| 0x00, 0x12, 0x00, 8, // source address 2 |
| 0x00, 0x01, 0x00, 13, |
| 0x00, 0x00, 0x00, 17, |
| 0x00, 0x13, 0x00, 7, // data |
| 'a', 'b', 'c', 'd', 'e', 'f', 'g', 0 // DATA must be padded per rfc5766. |
| }; |
| |
| // RTCP packet, for testing we correctly ignore non stun packet types. |
| // V=2, P=false, RC=0, Type=200, Len=6, Sender-SSRC=85, etc |
| static const unsigned char kRtcpPacket[] = { |
| 0x80, 0xc8, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, |
| 0xce, 0xa5, 0x18, 0x3a, 0x39, 0xcc, 0x7d, 0x09, |
| 0x23, 0xed, 0x19, 0x07, 0x00, 0x00, 0x01, 0x56, |
| 0x00, 0x03, 0x73, 0x50, |
| }; |
| |
| // A transaction ID without the 'magic cookie' portion |
| // pjnat's test programs use this transaction ID a lot. |
| const unsigned char kTestTransactionId1[] = { 0x029, 0x01f, 0x0cd, 0x07c, |
| 0x0ba, 0x058, 0x0ab, 0x0d7, |
| 0x0f2, 0x041, 0x001, 0x000 }; |
| |
| // They use this one sometimes too. |
| const unsigned char kTestTransactionId2[] = { 0x0e3, 0x0a9, 0x046, 0x0e1, |
| 0x07c, 0x000, 0x0c2, 0x062, |
| 0x054, 0x008, 0x001, 0x000 }; |
| |
| const in6_addr kIPv6TestAddress1 = { { { 0x24, 0x01, 0xfa, 0x00, |
| 0x00, 0x04, 0x10, 0x00, |
| 0xbe, 0x30, 0x5b, 0xff, |
| 0xfe, 0xe5, 0x00, 0xc3 } } }; |
| const in6_addr kIPv6TestAddress2 = { { { 0x24, 0x01, 0xfa, 0x00, |
| 0x00, 0x04, 0x10, 0x12, |
| 0x06, 0x0c, 0xce, 0xff, |
| 0xfe, 0x1f, 0x61, 0xa4 } } }; |
| |
| // This is kIPv6TestAddress1 xor-ed with kTestTransactionID2. |
| const in6_addr kIPv6XoredTestAddress = { { { 0x05, 0x13, 0x5e, 0x42, |
| 0xe3, 0xad, 0x56, 0xe1, |
| 0xc2, 0x30, 0x99, 0x9d, |
| 0xaa, 0xed, 0x01, 0xc3 } } }; |
| |
| #ifdef POSIX |
| const in_addr kIPv4TestAddress1 = { 0xe64417ac }; |
| // This is kIPv4TestAddress xored with the STUN magic cookie. |
| const in_addr kIPv4XoredTestAddress = { 0x8d05e0a4 }; |
| #elif defined WIN32 |
| // Windows in_addr has a union with a uchar[] array first. |
| const in_addr kIPv4XoredTestAddress = { { 0x8d, 0x05, 0xe0, 0xa4 } }; |
| const in_addr kIPv4TestAddress1 = { { 0x0ac, 0x017, 0x044, 0x0e6 } }; |
| #endif |
| const char kTestUserName1[] = "abcdefgh"; |
| const char kTestUserName2[] = "abc"; |
| const char kTestErrorReason[] = "Unauthorized"; |
| const int kTestErrorClass = 4; |
| const int kTestErrorNumber = 1; |
| |
| const int kTestMessagePort1 = 59977; |
| const int kTestMessagePort2 = 47233; |
| const int kTestMessagePort3 = 56743; |
| const int kTestMessagePort4 = 40444; |
| |
| #define ReadStunMessage(X, Y) ReadStunMessageTestCase(X, Y, sizeof(Y)); |
| |
| TEST_F(StunTest, ReadMessageWithIPv4AddressAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4MappedAddress); |
| CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| |
| const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); |
| talk_base::IPAddress test_address(kIPv4TestAddress1); |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, |
| kTestMessagePort4, test_address); |
| } |
| |
| TEST_F(StunTest, ReadMessageWithIPv4XorAddressAttribute) { |
| StunMessage msg; |
| StunMessage msg2; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4XorMappedAddress); |
| CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| |
| const StunAddressAttribute* addr = |
| msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); |
| talk_base::IPAddress test_address(kIPv4TestAddress1); |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, |
| kTestMessagePort3, test_address); |
| } |
| |
| TEST_F(StunTest, ReadMessageWithIPv6AddressAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress); |
| CheckStunHeader(msg, STUN_BINDING_REQUEST, size); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| |
| talk_base::IPAddress test_address(kIPv6TestAddress1); |
| |
| const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, |
| kTestMessagePort2, test_address); |
| } |
| |
| TEST_F(StunTest, ReadMessageWithInvalidAddressAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6MappedAddress); |
| CheckStunHeader(msg, STUN_BINDING_REQUEST, size); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| |
| talk_base::IPAddress test_address(kIPv6TestAddress1); |
| |
| const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, |
| kTestMessagePort2, test_address); |
| } |
| |
| TEST_F(StunTest, ReadMessageWithIPv6XorAddressAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6XorMappedAddress); |
| |
| talk_base::IPAddress test_address(kIPv6TestAddress1); |
| |
| CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); |
| CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); |
| |
| const StunAddressAttribute* addr = |
| msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, |
| kTestMessagePort1, test_address); |
| } |
| |
| TEST_F(StunTest, SetIPv6XorAddressAttributeOwner) { |
| StunMessage msg; |
| StunMessage msg2; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithIPv6XorMappedAddress); |
| |
| talk_base::IPAddress test_address(kIPv6TestAddress1); |
| |
| CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); |
| CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); |
| |
| const StunAddressAttribute* addr = |
| msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, |
| kTestMessagePort1, test_address); |
| |
| // Owner with a different transaction ID. |
| msg2.SetTransactionID("ABCDABCDABCD"); |
| StunXorAddressAttribute addr2(STUN_ATTR_XOR_MAPPED_ADDRESS, 20); |
| addr2.SetIP(addr->ipaddr()); |
| addr2.SetPort(addr->port()); |
| addr2.SetOwner(&msg2); |
| // The internal IP address shouldn't change. |
| ASSERT_EQ(addr2.ipaddr(), addr->ipaddr()); |
| |
| talk_base::ByteBuffer correct_buf; |
| talk_base::ByteBuffer wrong_buf; |
| addr->Write(&correct_buf); |
| addr2.Write(&wrong_buf); |
| // But when written out, the buffers should look different. |
| ASSERT_NE(0, std::memcmp(correct_buf.Data(), |
| wrong_buf.Data(), |
| wrong_buf.Length())); |
| // And when reading a known good value, the address should be wrong |
| addr2.Read(&correct_buf); |
| ASSERT_NE(addr->ipaddr(), addr2.ipaddr()); |
| addr2.SetIP(addr->ipaddr()); |
| addr2.SetPort(addr->port()); |
| // Try writing with no owner at all. Should write 4 bytes (1 byte reserved, |
| // 2 bytes port, 1 byte address family, 0 bytes address). This is an invalid |
| // but well-formed address attribute. |
| addr2.SetOwner(NULL); |
| ASSERT_EQ(addr2.ipaddr(), addr->ipaddr()); |
| wrong_buf.Shift(wrong_buf.Length()); |
| addr2.Write(&wrong_buf); |
| ASSERT_EQ(4U, wrong_buf.Length()); |
| ASSERT_NE(wrong_buf.Length(), correct_buf.Length()); |
| ASSERT_NE(0, std::memcmp(correct_buf.Data(), |
| wrong_buf.Data(), |
| wrong_buf.Length())); |
| } |
| |
| TEST_F(StunTest, SetIPv4XorAddressAttributeOwner) { |
| // Unlike the IPv6XorAddressAttributeOwner test, IPv4 XOR address attributes |
| // should _not_ be affected by a change in owner. IPv4 XOR address uses the |
| // magic cookie value which is fixed. |
| StunMessage msg; |
| StunMessage msg2; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithIPv4XorMappedAddress); |
| |
| talk_base::IPAddress test_address(kIPv4TestAddress1); |
| |
| CheckStunHeader(msg, STUN_BINDING_RESPONSE, size); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| |
| const StunAddressAttribute* addr = |
| msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, |
| kTestMessagePort3, test_address); |
| |
| // Owner with a different transaction ID. |
| msg2.SetTransactionID("ABCDABCDABCD"); |
| StunXorAddressAttribute addr2(STUN_ATTR_XOR_MAPPED_ADDRESS, 20); |
| addr2.SetIP(addr->ipaddr()); |
| addr2.SetPort(addr->port()); |
| addr2.SetOwner(&msg2); |
| // The internal IP address shouldn't change. |
| ASSERT_EQ(addr2.ipaddr(), addr->ipaddr()); |
| |
| talk_base::ByteBuffer correct_buf; |
| talk_base::ByteBuffer wrong_buf; |
| addr->Write(&correct_buf); |
| addr2.Write(&wrong_buf); |
| // The same address data should be written. |
| ASSERT_EQ(0, std::memcmp(correct_buf.Data(), |
| wrong_buf.Data(), |
| wrong_buf.Length())); |
| // And an attribute should be able to un-XOR an address belonging to a message |
| // with a different transaction ID. |
| addr2.Read(&correct_buf); |
| ASSERT_EQ(addr->ipaddr(), addr2.ipaddr()); |
| |
| // However, no owner is still an error. Write 4 bytes and a 0 length address. |
| addr2.SetOwner(NULL); |
| ASSERT_EQ(addr2.ipaddr(), addr->ipaddr()); |
| wrong_buf.Shift(wrong_buf.Length()); |
| addr2.Write(&wrong_buf); |
| ASSERT_NE(wrong_buf.Length(), correct_buf.Length()); |
| ASSERT_NE(0, std::memcmp(correct_buf.Data(), |
| wrong_buf.Data(), |
| wrong_buf.Length())); |
| } |
| |
| TEST_F(StunTest, CreateIPv6AddressAttribute) { |
| talk_base::IPAddress test_ip(kIPv6TestAddress2); |
| |
| StunAddressAttribute* addr = |
| StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); |
| talk_base::SocketAddress test_addr(test_ip, kTestMessagePort2); |
| addr->SetAddress(test_addr); |
| |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV6, |
| kTestMessagePort2, test_ip); |
| delete addr; |
| } |
| |
| TEST_F(StunTest, CreateIPv4AddressAttribute) { |
| struct in_addr test_in_addr; |
| test_in_addr.s_addr = 0xBEB0B0BE; |
| talk_base::IPAddress test_ip(test_in_addr); |
| |
| StunAddressAttribute* addr = |
| StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); |
| talk_base::SocketAddress test_addr(test_ip, kTestMessagePort2); |
| addr->SetAddress(test_addr); |
| |
| CheckStunAddressAttribute(addr, STUN_ADDRESS_IPV4, |
| kTestMessagePort2, test_ip); |
| delete addr; |
| } |
| |
| TEST_F(StunTest, WriteMessageWithIPv6AddressAttribute) { |
| StunMessage msg; |
| size_t size = sizeof(kStunMessageWithIPv6MappedAddress); |
| |
| talk_base::IPAddress test_ip(kIPv6TestAddress1); |
| |
| msg.SetType(STUN_BINDING_REQUEST); |
| msg.SetTransactionID( |
| std::string(reinterpret_cast<const char*>(kTestTransactionId1), |
| kStunTransactionIdLength)); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| |
| StunAddressAttribute* addr = |
| StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); |
| talk_base::SocketAddress test_addr(test_ip, kTestMessagePort2); |
| addr->SetAddress(test_addr); |
| msg.AddAttribute(addr); |
| |
| CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20)); |
| |
| talk_base::ByteBuffer out; |
| msg.Write(&out); |
| ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv6MappedAddress)); |
| int len1 = out.Length(); |
| std::string bytes; |
| out.ReadString(&bytes, len1); |
| ASSERT_EQ(0, std::memcmp(bytes.c_str(), |
| kStunMessageWithIPv6MappedAddress, |
| len1)); |
| } |
| |
| TEST_F(StunTest, WriteMessageWithIPv4AddressAttribute) { |
| StunMessage msg; |
| size_t size = sizeof(kStunMessageWithIPv4MappedAddress); |
| |
| talk_base::IPAddress test_ip(kIPv4TestAddress1); |
| |
| msg.SetType(STUN_BINDING_RESPONSE); |
| msg.SetTransactionID( |
| std::string(reinterpret_cast<const char*>(kTestTransactionId1), |
| kStunTransactionIdLength)); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| |
| StunAddressAttribute* addr = |
| StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); |
| talk_base::SocketAddress test_addr(test_ip, kTestMessagePort4); |
| addr->SetAddress(test_addr); |
| msg.AddAttribute(addr); |
| |
| CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20)); |
| |
| talk_base::ByteBuffer out; |
| msg.Write(&out); |
| ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv4MappedAddress)); |
| int len1 = out.Length(); |
| std::string bytes; |
| out.ReadString(&bytes, len1); |
| ASSERT_EQ(0, std::memcmp(bytes.c_str(), |
| kStunMessageWithIPv4MappedAddress, |
| len1)); |
| } |
| |
| TEST_F(StunTest, WriteMessageWithIPv6XorAddressAttribute) { |
| StunMessage msg; |
| size_t size = sizeof(kStunMessageWithIPv6XorMappedAddress); |
| |
| talk_base::IPAddress test_ip(kIPv6TestAddress1); |
| |
| msg.SetType(STUN_BINDING_RESPONSE); |
| msg.SetTransactionID( |
| std::string(reinterpret_cast<const char*>(kTestTransactionId2), |
| kStunTransactionIdLength)); |
| CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); |
| |
| StunAddressAttribute* addr = |
| StunAttribute::CreateAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); |
| talk_base::SocketAddress test_addr(test_ip, kTestMessagePort1); |
| addr->SetAddress(test_addr); |
| msg.AddAttribute(addr); |
| |
| CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20)); |
| |
| talk_base::ByteBuffer out; |
| msg.Write(&out); |
| ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv6XorMappedAddress)); |
| int len1 = out.Length(); |
| std::string bytes; |
| out.ReadString(&bytes, len1); |
| ASSERT_EQ(0, std::memcmp(bytes.c_str(), |
| kStunMessageWithIPv6XorMappedAddress, |
| len1)); |
| } |
| |
| TEST_F(StunTest, WriteMessageWithIPv4XoreAddressAttribute) { |
| StunMessage msg; |
| size_t size = sizeof(kStunMessageWithIPv4XorMappedAddress); |
| |
| talk_base::IPAddress test_ip(kIPv4TestAddress1); |
| |
| msg.SetType(STUN_BINDING_RESPONSE); |
| msg.SetTransactionID( |
| std::string(reinterpret_cast<const char*>(kTestTransactionId1), |
| kStunTransactionIdLength)); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| |
| StunAddressAttribute* addr = |
| StunAttribute::CreateAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); |
| talk_base::SocketAddress test_addr(test_ip, kTestMessagePort3); |
| addr->SetAddress(test_addr); |
| msg.AddAttribute(addr); |
| |
| CheckStunHeader(msg, STUN_BINDING_RESPONSE, (size - 20)); |
| |
| talk_base::ByteBuffer out; |
| msg.Write(&out); |
| ASSERT_EQ(out.Length(), sizeof(kStunMessageWithIPv4XorMappedAddress)); |
| int len1 = out.Length(); |
| std::string bytes; |
| out.ReadString(&bytes, len1); |
| ASSERT_EQ(0, std::memcmp(bytes.c_str(), |
| kStunMessageWithIPv4XorMappedAddress, |
| len1)); |
| } |
| |
| TEST_F(StunTest, ReadByteStringAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithByteStringAttribute); |
| |
| CheckStunHeader(msg, STUN_BINDING_REQUEST, size); |
| CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); |
| const StunByteStringAttribute* username = |
| msg.GetByteString(STUN_ATTR_USERNAME); |
| ASSERT_EQ(0, std::memcmp(kTestUserName1, username->bytes(), |
| username->length())); |
| } |
| |
| TEST_F(StunTest, ReadPaddedByteStringAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, |
| kStunMessageWithPaddedByteStringAttribute); |
| ASSERT_NE(0U, size); |
| CheckStunHeader(msg, STUN_BINDING_REQUEST, size); |
| CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); |
| const StunByteStringAttribute* username = |
| msg.GetByteString(STUN_ATTR_USERNAME); |
| ASSERT_EQ(0, std::memcmp(kTestUserName2, username->bytes(), |
| username->length())); |
| } |
| |
| TEST_F(StunTest, ReadErrorCodeAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithErrorAttribute); |
| |
| CheckStunHeader(msg, STUN_ALLOCATE_ERROR_RESPONSE, size); |
| CheckStunTransactionID(msg, kTestTransactionId1, kStunTransactionIdLength); |
| const StunErrorCodeAttribute* errorcode = msg.GetErrorCode(); |
| ASSERT_EQ(kTestErrorClass, errorcode->error_class()); |
| ASSERT_EQ(kTestErrorNumber, errorcode->number()); |
| std::string reason = errorcode->reason(); |
| ASSERT_EQ(0, strcmp(reason.c_str(), kTestErrorReason)); |
| } |
| |
| TEST_F(StunTest, ReadMessageWithAnUnknownAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithUnknownAttribute); |
| CheckStunHeader(msg, STUN_BINDING_REQUEST, size); |
| |
| // Parsing should have succeeded and there should be a lifetime attribute |
| const StunUInt32Attribute* uval = msg.GetUInt32(STUN_ATTR_LIFETIME); |
| EXPECT_TRUE(uval != NULL); |
| if (uval != NULL) { |
| EXPECT_EQ(11U, uval->value()); |
| } |
| } |
| |
| TEST_F(StunTest, ReadMessageWithAUInt16ListAttribute) { |
| StunMessage msg; |
| size_t size = ReadStunMessage(&msg, kStunMessageWithUInt16ListAttribute); |
| CheckStunHeader(msg, STUN_BINDING_REQUEST, size); |
| const StunUInt16ListAttribute* types = msg.GetUnknownAttributes(); |
| EXPECT_EQ(3U, types->Size()); |
| EXPECT_EQ(0x1U, types->GetType(0)); |
| EXPECT_EQ(0x1000U, types->GetType(1)); |
| EXPECT_EQ(0xAB0CU, types->GetType(2)); |
| } |
| |
| TEST_F(StunTest, WriteMessageWithAUInt16ListAttribute) { |
| StunMessage msg; |
| size_t size = sizeof(kStunMessageWithUInt16ListAttribute); |
| |
| msg.SetType(STUN_BINDING_REQUEST); |
| msg.SetTransactionID( |
| std::string(reinterpret_cast<const char*>(kTestTransactionId2), |
| kStunTransactionIdLength)); |
| CheckStunTransactionID(msg, kTestTransactionId2, kStunTransactionIdLength); |
| StunUInt16ListAttribute* list = StunAttribute::CreateUnknownAttributes(); |
| list->AddType(0x1U); |
| list->AddType(0x1000U); |
| list->AddType(0xAB0CU); |
| msg.AddAttribute(list); |
| CheckStunHeader(msg, STUN_BINDING_REQUEST, (size - 20)); |
| |
| talk_base::ByteBuffer out; |
| msg.Write(&out); |
| ASSERT_EQ(size, out.Length()); |
| // Check everything up to the padding. |
| ASSERT_EQ(0, std::memcmp(out.Data(), kStunMessageWithUInt16ListAttribute, |
| size - 2)); |
| } |
| |
| void CheckFailureToRead(const unsigned char* testcase, size_t length) { |
| StunMessage msg; |
| const char* input = reinterpret_cast<const char*>(testcase); |
| talk_base::ByteBuffer buf(input, length); |
| ASSERT_FALSE(msg.Read(&buf)); |
| } |
| |
| TEST_F(StunTest, FailToReadInvalidMessages) { |
| CheckFailureToRead(kStunMessageWithZeroLength, |
| kRealLengthOfInvalidLengthTestCases); |
| CheckFailureToRead(kStunMessageWithSmallLength, |
| kRealLengthOfInvalidLengthTestCases); |
| CheckFailureToRead(kStunMessageWithExcessLength, |
| kRealLengthOfInvalidLengthTestCases); |
| } |
| |
| #undef ReadStunMessage |
| |
| // Test that we don't care what order we set the parts of an address |
| TEST_F(StunTest, CreateAddressInArbitraryOrder) { |
| StunAddressAttribute* addr = |
| StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); |
| // Port first |
| addr->SetPort(kTestMessagePort1); |
| addr->SetIP(talk_base::IPAddress(kIPv4TestAddress1)); |
| ASSERT_EQ(kTestMessagePort1, addr->port()); |
| ASSERT_EQ(talk_base::IPAddress(kIPv4TestAddress1), addr->ipaddr()); |
| |
| StunAddressAttribute* addr2 = |
| StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); |
| // IP first |
| addr2->SetIP(talk_base::IPAddress(kIPv4TestAddress1)); |
| addr2->SetPort(kTestMessagePort2); |
| ASSERT_EQ(kTestMessagePort2, addr2->port()); |
| ASSERT_EQ(talk_base::IPAddress(kIPv4TestAddress1), addr2->ipaddr()); |
| |
| delete addr; |
| delete addr2; |
| } |
| |
| // Legacy test bodies |
| static void DoTest(const char* input, size_t size, const char* transaction_id) { |
| StunMessage msg, msg2; |
| in_addr legacy_in_addr; |
| legacy_in_addr.s_addr = htonl(17U); |
| talk_base::IPAddress legacy_ip(legacy_in_addr); |
| |
| talk_base::ByteBuffer buf(input, size); |
| EXPECT_TRUE(msg.Read(&buf)); |
| |
| EXPECT_EQ(STUN_BINDING_REQUEST, msg.type()); |
| EXPECT_EQ(size - 20, msg.length()); |
| EXPECT_EQ(transaction_id, msg.transaction_id()); |
| |
| msg2.SetType(STUN_BINDING_REQUEST); |
| msg2.SetTransactionID(transaction_id); |
| |
| const StunAddressAttribute* addr = msg.GetAddress(STUN_ATTR_MAPPED_ADDRESS); |
| ASSERT_TRUE(addr != NULL); |
| EXPECT_EQ(1, addr->family()); |
| EXPECT_EQ(13, addr->port()); |
| EXPECT_EQ(legacy_ip, addr->ipaddr()); |
| |
| StunAddressAttribute* addr2 = |
| StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); |
| addr2->SetPort(13); |
| addr2->SetIP(legacy_ip); |
| msg2.AddAttribute(addr2); |
| |
| const StunByteStringAttribute* bytes = msg.GetByteString(STUN_ATTR_USERNAME); |
| ASSERT_TRUE(bytes != NULL); |
| EXPECT_EQ(12, bytes->length()); |
| EXPECT_EQ(0, std::memcmp(bytes->bytes(), "abcdefghijkl", bytes->length())); |
| |
| StunByteStringAttribute* bytes2 = |
| StunAttribute::CreateByteString(STUN_ATTR_USERNAME); |
| bytes2->CopyBytes("abcdefghijkl"); |
| msg2.AddAttribute(bytes2); |
| |
| bytes = msg.GetByteString(STUN_ATTR_MESSAGE_INTEGRITY); |
| ASSERT_TRUE(bytes != NULL); |
| EXPECT_EQ(20, bytes->length()); |
| EXPECT_EQ(0, std::memcmp(bytes->bytes(), |
| "abcdefghijklmnopqrst", |
| bytes->length())); |
| |
| bytes2 = StunAttribute::CreateByteString(STUN_ATTR_MESSAGE_INTEGRITY); |
| bytes2->CopyBytes("abcdefghijklmnopqrst"); |
| msg2.AddAttribute(bytes2); |
| |
| const StunErrorCodeAttribute* ecode = msg.GetErrorCode(); |
| ASSERT_TRUE(ecode != NULL); |
| EXPECT_EQ(2, ecode->error_class()); |
| EXPECT_EQ(10, ecode->number()); |
| EXPECT_EQ("foo bar!", ecode->reason()); |
| |
| StunErrorCodeAttribute* ecode2 = StunAttribute::CreateErrorCode(); |
| ecode2->SetErrorClass(2); |
| ecode2->SetNumber(10); |
| ecode2->SetReason("foo bar!"); |
| msg2.AddAttribute(ecode2); |
| |
| const StunUInt16ListAttribute* unknown = msg.GetUnknownAttributes(); |
| ASSERT_TRUE(unknown != NULL); |
| EXPECT_EQ(2U, unknown->Size()); |
| EXPECT_EQ(1U, unknown->GetType(0)); |
| EXPECT_EQ(2U, unknown->GetType(1)); |
| |
| StunUInt16ListAttribute* unknown2 = StunAttribute::CreateUnknownAttributes(); |
| unknown2->AddType(1); |
| unknown2->AddType(2); |
| msg2.AddAttribute(unknown2); |
| |
| const StunUInt32Attribute* uval = msg.GetUInt32(STUN_ATTR_LIFETIME); |
| ASSERT_TRUE(uval != NULL); |
| EXPECT_EQ(11U, uval->value()); |
| |
| StunUInt32Attribute* uval2 = StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME); |
| uval2->SetValue(11); |
| msg2.AddAttribute(uval2); |
| |
| bytes = msg.GetByteString(STUN_ATTR_MAGIC_COOKIE); |
| ASSERT_TRUE(bytes != NULL); |
| EXPECT_EQ(4, bytes->length()); |
| EXPECT_EQ(0, std::memcmp(bytes->bytes(), TURN_MAGIC_COOKIE_VALUE, |
| sizeof(TURN_MAGIC_COOKIE_VALUE))); |
| |
| bytes2 = StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE); |
| bytes2->CopyBytes(reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE), |
| sizeof(TURN_MAGIC_COOKIE_VALUE)); |
| msg2.AddAttribute(bytes2); |
| |
| uval = msg.GetUInt32(STUN_ATTR_BANDWIDTH); |
| ASSERT_TRUE(uval != NULL); |
| EXPECT_EQ(6U, uval->value()); |
| |
| uval2 = StunAttribute::CreateUInt32(STUN_ATTR_BANDWIDTH); |
| uval2->SetValue(6); |
| msg2.AddAttribute(uval2); |
| |
| addr = msg.GetAddress(STUN_ATTR_DESTINATION_ADDRESS); |
| ASSERT_TRUE(addr != NULL); |
| EXPECT_EQ(1, addr->family()); |
| EXPECT_EQ(13, addr->port()); |
| EXPECT_EQ(legacy_ip, addr->ipaddr()); |
| |
| addr2 = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); |
| addr2->SetPort(13); |
| addr2->SetIP(legacy_ip); |
| msg2.AddAttribute(addr2); |
| |
| addr = msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2); |
| ASSERT_TRUE(addr != NULL); |
| EXPECT_EQ(1, addr->family()); |
| EXPECT_EQ(13, addr->port()); |
| EXPECT_EQ(legacy_ip, addr->ipaddr()); |
| |
| addr2 = StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2); |
| addr2->SetPort(13); |
| addr2->SetIP(legacy_ip); |
| msg2.AddAttribute(addr2); |
| |
| bytes = msg.GetByteString(STUN_ATTR_DATA); |
| ASSERT_TRUE(bytes != NULL); |
| EXPECT_EQ(7, bytes->length()); |
| EXPECT_EQ(0, std::memcmp(bytes->bytes(), "abcdefg", bytes->length())); |
| |
| bytes2 = StunAttribute::CreateByteString(STUN_ATTR_DATA); |
| bytes2->CopyBytes("abcdefg"); |
| msg2.AddAttribute(bytes2); |
| |
| talk_base::ByteBuffer out; |
| msg.Write(&out); |
| EXPECT_EQ(size, out.Length()); |
| size_t len1 = out.Length(); |
| std::string outstring; |
| out.ReadString(&outstring, len1); |
| EXPECT_EQ(0, std::memcmp(outstring.c_str(), input, len1)); |
| |
| talk_base::ByteBuffer out2; |
| msg2.Write(&out2); |
| EXPECT_EQ(size, out2.Length()); |
| size_t len2 = out2.Length(); |
| std::string outstring2; |
| out2.ReadString(&outstring2, len2); |
| EXPECT_EQ(0, std::memcmp(outstring2.c_str(), input, len2)); |
| } |
| |
| TEST_F(StunTest, TestStunPacket) { |
| DoTest(reinterpret_cast<const char*>(kStunMessageWithManyAttributes), |
| sizeof(kStunMessageWithManyAttributes), |
| "0123456789ab"); |
| } |
| |
| TEST_F(StunTest, TestRejectsRtcpPacket) { |
| StunMessage msg; |
| |
| talk_base::ByteBuffer buf( |
| reinterpret_cast<const char*>(kRtcpPacket), sizeof(kRtcpPacket)); |
| EXPECT_FALSE(msg.Read(&buf)); |
| } |
| |
| TEST_F(StunTest, TestLegacyPacket) { |
| // The RFC3489 packet in this test is the same as |
| // kStunMessageWithManyAttributes, but with a different value where the |
| // magic cookie was. |
| talk_base::scoped_array<char> |
| rfc3489_packet(new char[sizeof(kStunMessageWithManyAttributes)]); |
| memcpy(rfc3489_packet.get(), kStunMessageWithManyAttributes, |
| sizeof(kStunMessageWithManyAttributes)); |
| // Overwrites the magic cookie here. |
| memcpy(&rfc3489_packet[4], &kStunMessageWithManyAttributes[8], 4); |
| |
| DoTest(reinterpret_cast<const char*>(rfc3489_packet.get()), |
| sizeof(kStunMessageWithManyAttributes), "01230123456789ab"); |
| } |
| |
| } // namespace cricket |