Add support for trying alternate server (STUN 300 error message) on TCP
BUG=3774 R=juberti@webrtc.org Review URL: https://webrtc-codereview.appspot.com/32979004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@8036 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
0ba1533fdb
commit
19e4e8d751
@ -348,6 +348,7 @@ void TurnPort::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
|
||||
|
||||
void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
|
||||
LOG_J(LS_WARNING, this) << "Connection with server failed, error=" << error;
|
||||
ASSERT(socket == socket_);
|
||||
if (!connected_) {
|
||||
OnAllocateError();
|
||||
}
|
||||
@ -645,6 +646,22 @@ void TurnPort::OnMessage(rtc::Message* message) {
|
||||
} else if (message->message_id == MSG_ALLOCATE_MISMATCH) {
|
||||
OnAllocateMismatch();
|
||||
return;
|
||||
} else if (message->message_id == MSG_TRY_ALTERNATE_SERVER) {
|
||||
if (server_address().proto == PROTO_UDP) {
|
||||
// Send another allocate request to alternate server, with the received
|
||||
// realm and nonce values.
|
||||
SendRequest(new TurnAllocateRequest(this), 0);
|
||||
} else {
|
||||
// Since it's TCP, we have to delete the connected socket and reconnect
|
||||
// with the alternate server. PrepareAddress will send stun binding once
|
||||
// the new socket is connected.
|
||||
ASSERT(server_address().proto == PROTO_TCP);
|
||||
ASSERT(!SharedSocket());
|
||||
delete socket_;
|
||||
socket_ = NULL;
|
||||
PrepareAddress();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Port::OnMessage(message);
|
||||
@ -959,15 +976,6 @@ void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
|
||||
}
|
||||
|
||||
void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
|
||||
// TODO(guoweis): Currently, we only support UDP redirect
|
||||
if (port_->server_address().proto != PROTO_UDP) {
|
||||
LOG_J(LS_WARNING, port_) << "Receiving 300 Alternate Server on non-UDP "
|
||||
<< "allocating request from ["
|
||||
<< port_->server_address().address.ToSensitiveString()
|
||||
<< "], failed as currently not supported";
|
||||
port_->OnAllocateError();
|
||||
return;
|
||||
}
|
||||
|
||||
// According to RFC 5389 section 11, there are use cases where
|
||||
// authentication of response is not possible, we're not validating
|
||||
@ -1004,9 +1012,10 @@ void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) {
|
||||
port_->set_nonce(nonce_attr->GetString());
|
||||
}
|
||||
|
||||
// Send another allocate request to alternate server,
|
||||
// with the received realm and nonce values.
|
||||
port_->SendRequest(new TurnAllocateRequest(port_), 0);
|
||||
// For TCP, we can't close the original Tcp socket during handling a 300 as
|
||||
// we're still inside that socket's event handler. Doing so will cause
|
||||
// deadlock.
|
||||
port_->thread()->Post(port_, TurnPort::MSG_TRY_ALTERNATE_SERVER);
|
||||
}
|
||||
|
||||
TurnRefreshRequest::TurnRefreshRequest(TurnPort* port)
|
||||
|
@ -152,7 +152,8 @@ class TurnPort : public Port {
|
||||
private:
|
||||
enum {
|
||||
MSG_ERROR = MSG_FIRST_AVAILABLE,
|
||||
MSG_ALLOCATE_MISMATCH
|
||||
MSG_ALLOCATE_MISMATCH,
|
||||
MSG_TRY_ALTERNATE_SERVER
|
||||
};
|
||||
|
||||
typedef std::list<TurnEntry*> EntryList;
|
||||
|
@ -47,8 +47,13 @@ static const SocketAddress kTurnUdpIntAddr("99.99.99.3",
|
||||
static const SocketAddress kTurnTcpIntAddr("99.99.99.4",
|
||||
cricket::TURN_SERVER_PORT);
|
||||
static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
|
||||
static const SocketAddress kTurnAlternateUdpIntAddr(
|
||||
"99.99.99.6", cricket::TURN_SERVER_PORT);
|
||||
static const SocketAddress kTurnAlternateIntAddr("99.99.99.6",
|
||||
cricket::TURN_SERVER_PORT);
|
||||
static const SocketAddress kTurnIntAddr("99.99.99.7",
|
||||
cricket::TURN_SERVER_PORT);
|
||||
static const SocketAddress kTurnIPv6IntAddr(
|
||||
"2400:4030:2:2c00:be30:abcd:efab:cdef",
|
||||
cricket::TURN_SERVER_PORT);
|
||||
static const SocketAddress kTurnUdpIPv6IntAddr(
|
||||
"2400:4030:1:2c00:be30:abcd:efab:cdef", cricket::TURN_SERVER_PORT);
|
||||
static const SocketAddress kTurnUdpIPv6ExtAddr(
|
||||
@ -276,6 +281,87 @@ class TurnPortTest : public testing::Test,
|
||||
this, &TurnPortTest::OnUdpPortComplete);
|
||||
}
|
||||
|
||||
void TestTurnAlternateServer(cricket::ProtocolType protocol_type) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnAlternateIntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
|
||||
turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type);
|
||||
turn_server_.AddInternalSocket(kTurnAlternateIntAddr, protocol_type);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword,
|
||||
cricket::ProtocolAddress(kTurnIntAddr, protocol_type));
|
||||
|
||||
// Retrieve the address before we run the state machine.
|
||||
const SocketAddress old_addr = turn_port_->server_address().address;
|
||||
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_ready_, kTimeout * 100);
|
||||
// Retrieve the address again, the turn port's address should be
|
||||
// changed.
|
||||
const SocketAddress new_addr = turn_port_->server_address().address;
|
||||
EXPECT_NE(old_addr, new_addr);
|
||||
ASSERT_EQ(1U, turn_port_->Candidates().size());
|
||||
EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
|
||||
turn_port_->Candidates()[0].address().ipaddr());
|
||||
EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
|
||||
}
|
||||
|
||||
void TestTurnAlternateServerV4toV6(cricket::ProtocolType protocol_type) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnIPv6IntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword,
|
||||
cricket::ProtocolAddress(kTurnIntAddr, protocol_type));
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_error_, kTimeout);
|
||||
}
|
||||
|
||||
void TestTurnAlternateServerPingPong(cricket::ProtocolType protocol_type) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnAlternateIntAddr);
|
||||
redirect_addresses.push_back(kTurnIntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
|
||||
turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type);
|
||||
turn_server_.AddInternalSocket(kTurnAlternateIntAddr, protocol_type);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword,
|
||||
cricket::ProtocolAddress(kTurnIntAddr, protocol_type));
|
||||
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_error_, kTimeout);
|
||||
ASSERT_EQ(0U, turn_port_->Candidates().size());
|
||||
rtc::SocketAddress address;
|
||||
// Verify that we have exhausted all alternate servers instead of
|
||||
// failure caused by other errors.
|
||||
EXPECT_FALSE(redirector.ShouldRedirect(address, &address));
|
||||
}
|
||||
|
||||
void TestTurnAlternateServerDetectRepetition(
|
||||
cricket::ProtocolType protocol_type) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnAlternateIntAddr);
|
||||
redirect_addresses.push_back(kTurnAlternateIntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
|
||||
turn_server_.AddInternalSocket(kTurnIntAddr, protocol_type);
|
||||
turn_server_.AddInternalSocket(kTurnAlternateIntAddr, protocol_type);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword,
|
||||
cricket::ProtocolAddress(kTurnIntAddr, protocol_type));
|
||||
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_error_, kTimeout);
|
||||
ASSERT_EQ(0U, turn_port_->Candidates().size());
|
||||
}
|
||||
|
||||
void TestTurnConnection() {
|
||||
// Create ports and prepare addresses.
|
||||
ASSERT_TRUE(turn_port_ != NULL);
|
||||
@ -529,6 +615,43 @@ TEST_F(TurnPortTest, TestTurnTcpAllocateMismatch) {
|
||||
EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress());
|
||||
}
|
||||
|
||||
// Test try-alternate-server feature.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerUDP) {
|
||||
TestTurnAlternateServer(cricket::PROTO_UDP);
|
||||
}
|
||||
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerTCP) {
|
||||
TestTurnAlternateServer(cricket::PROTO_TCP);
|
||||
}
|
||||
|
||||
// Test that we fail when we redirect to an address different from
|
||||
// current IP family.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6UDP) {
|
||||
TestTurnAlternateServerV4toV6(cricket::PROTO_UDP);
|
||||
}
|
||||
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6TCP) {
|
||||
TestTurnAlternateServerV4toV6(cricket::PROTO_TCP);
|
||||
}
|
||||
|
||||
// Test try-alternate-server catches the case of pingpong.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerPingPongUDP) {
|
||||
TestTurnAlternateServerPingPong(cricket::PROTO_UDP);
|
||||
}
|
||||
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerPingPongTCP) {
|
||||
TestTurnAlternateServerPingPong(cricket::PROTO_TCP);
|
||||
}
|
||||
|
||||
// Test try-alternate-server catch the case of repeated server.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetitionUDP) {
|
||||
TestTurnAlternateServerDetectRepetition(cricket::PROTO_UDP);
|
||||
}
|
||||
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetitionTCP) {
|
||||
TestTurnAlternateServerDetectRepetition(cricket::PROTO_TCP);
|
||||
}
|
||||
|
||||
// Do a TURN allocation and try to send a packet to it from the outside.
|
||||
// The packet should be dropped. Then, try to send a packet from TURN to the
|
||||
// outside. It should reach its destination. Finally, try again from the
|
||||
@ -563,103 +686,6 @@ TEST_F(TurnPortTest, TestTurnTlsTcpConnectionFails) {
|
||||
ASSERT_EQ(0U, turn_port_->Candidates().size());
|
||||
}
|
||||
|
||||
// Test try-alternate-server feature.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServer) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr,
|
||||
cricket::PROTO_UDP);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
|
||||
|
||||
// Retrieve the address before we run the state machine.
|
||||
const SocketAddress old_addr = turn_port_->server_address().address;
|
||||
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
|
||||
// Retrieve the address again, the turn port's address should be
|
||||
// changed.
|
||||
const SocketAddress new_addr = turn_port_->server_address().address;
|
||||
EXPECT_NE(old_addr, new_addr);
|
||||
ASSERT_EQ(1U, turn_port_->Candidates().size());
|
||||
EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
|
||||
turn_port_->Candidates()[0].address().ipaddr());
|
||||
EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
|
||||
}
|
||||
|
||||
// Test that we fail when we redirect to an address different from
|
||||
// current IP family.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnUdpIPv6IntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr,
|
||||
cricket::PROTO_UDP);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_error_, kTimeout);
|
||||
}
|
||||
|
||||
// Test that we fail to handle alternate-server response over TCP protocol.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerTcp) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
|
||||
|
||||
turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, cricket::PROTO_TCP);
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_error_, kTimeout);
|
||||
}
|
||||
|
||||
// Test try-alternate-server catches the case of pingpong.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerPingPong) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
|
||||
redirect_addresses.push_back(kTurnUdpIntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
|
||||
turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr,
|
||||
cricket::PROTO_UDP);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
|
||||
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_error_, kTimeout);
|
||||
ASSERT_EQ(0U, turn_port_->Candidates().size());
|
||||
rtc::SocketAddress address;
|
||||
// Verify that we have exhausted all alternate servers instead of
|
||||
// failure caused by other errors.
|
||||
EXPECT_FALSE(redirector.ShouldRedirect(address, &address));
|
||||
}
|
||||
|
||||
// Test try-alternate-server catch the case of repeated server.
|
||||
TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetition) {
|
||||
std::vector<rtc::SocketAddress> redirect_addresses;
|
||||
redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
|
||||
redirect_addresses.push_back(kTurnAlternateUdpIntAddr);
|
||||
|
||||
cricket::TestTurnRedirector redirector(redirect_addresses);
|
||||
|
||||
turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr,
|
||||
cricket::PROTO_UDP);
|
||||
turn_server_.set_redirect_hook(&redirector);
|
||||
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
|
||||
|
||||
turn_port_->PrepareAddress();
|
||||
EXPECT_TRUE_WAIT(turn_error_, kTimeout);
|
||||
ASSERT_EQ(0U, turn_port_->Candidates().size());
|
||||
}
|
||||
|
||||
|
||||
// Run TurnConnectionTest with one-time-use nonce feature.
|
||||
// Here server will send a 438 STALE_NONCE error message for
|
||||
// every TURN transaction.
|
||||
|
Loading…
Reference in New Issue
Block a user