Delete gturn support

Delete enum RelayType and classes RelayPort and RelayServer.

See also PSA: https://groups.google.com/forum/?#!msg/discuss-webrtc/0ROpUXpw3Gs/eikIN-eEBwAJROpUXpw3Gs/eikIN-eEBwAJ

Bug: webrtc:10998
Change-Id: I1eab760dc73df9156cd1224cf99ad4a4c12ed882
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/154522
Reviewed-by: Justin Uberti <juberti@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Commit-Queue: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29677}
This commit is contained in:
Niels Möller 2019-11-04 08:49:12 +01:00 committed by Commit Bot
parent 9dda1b3a48
commit 191e38fb47
19 changed files with 52 additions and 3145 deletions

View File

@ -47,7 +47,6 @@ group("examples") {
if (is_linux || is_win) {
deps += [
":peerconnection_server",
":relayserver",
":stunserver",
":turnserver",
]
@ -740,19 +739,6 @@ if (is_linux || is_win) {
"//third_party/abseil-cpp/absl/flags:usage",
]
}
rtc_executable("relayserver") {
testonly = true
sources = [
"relayserver/relayserver_main.cc",
]
deps = [
"../p2p:p2p_server_utils",
"../p2p:rtc_p2p",
"../pc:rtc_pc",
"../rtc_base",
"../rtc_base:rtc_base_approved",
]
}
rtc_executable("turnserver") {
testonly = true
sources = [

View File

@ -1,66 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <iostream> // NOLINT
#include <memory>
#include "p2p/base/relay_server.h"
#include "rtc_base/async_udp_socket.h"
#include "rtc_base/socket_address.h"
#include "rtc_base/socket_server.h"
#include "rtc_base/thread.h"
int main(int argc, char** argv) {
if (argc != 3) {
std::cerr << "usage: relayserver internal-address external-address"
<< std::endl;
return 1;
}
rtc::SocketAddress int_addr;
if (!int_addr.FromString(argv[1])) {
std::cerr << "Unable to parse IP address: " << argv[1];
return 1;
}
rtc::SocketAddress ext_addr;
if (!ext_addr.FromString(argv[2])) {
std::cerr << "Unable to parse IP address: " << argv[2];
return 1;
}
rtc::Thread* pthMain = rtc::Thread::Current();
std::unique_ptr<rtc::AsyncUDPSocket> int_socket(
rtc::AsyncUDPSocket::Create(pthMain->socketserver(), int_addr));
if (!int_socket) {
std::cerr << "Failed to create a UDP socket bound at" << int_addr.ToString()
<< std::endl;
return 1;
}
std::unique_ptr<rtc::AsyncUDPSocket> ext_socket(
rtc::AsyncUDPSocket::Create(pthMain->socketserver(), ext_addr));
if (!ext_socket) {
std::cerr << "Failed to create a UDP socket bound at" << ext_addr.ToString()
<< std::endl;
return 1;
}
cricket::RelayServer server(pthMain);
server.AddInternalSocket(int_socket.get());
server.AddExternalSocket(ext_socket.get());
std::cout << "Listening internally at " << int_addr.ToString() << std::endl;
std::cout << "Listening externally at " << ext_addr.ToString() << std::endl;
pthMain->Run();
return 0;
}

View File

@ -70,8 +70,6 @@ rtc_library("rtc_p2p") {
"base/pseudo_tcp.h",
"base/regathering_controller.cc",
"base/regathering_controller.h",
"base/relay_port.cc",
"base/relay_port.h",
"base/stun_port.cc",
"base/stun_port.h",
"base/stun_request.cc",
@ -160,7 +158,6 @@ if (rtc_include_tests) {
"base/fake_packet_transport.h",
"base/mock_async_resolver.h",
"base/mock_ice_transport.h",
"base/test_relay_server.h",
"base/test_stun_server.cc",
"base/test_stun_server.h",
"base/test_turn_customizer.h",
@ -200,8 +197,6 @@ if (rtc_include_tests) {
"base/port_unittest.cc",
"base/pseudo_tcp_unittest.cc",
"base/regathering_controller_unittest.cc",
"base/relay_port_unittest.cc",
"base/relay_server_unittest.cc",
"base/stun_port_unittest.cc",
"base/stun_request_unittest.cc",
"base/stun_server_unittest.cc",
@ -244,8 +239,6 @@ if (rtc_include_tests) {
rtc_library("p2p_server_utils") {
testonly = true
sources = [
"base/relay_server.cc",
"base/relay_server.h",
"base/stun_server.cc",
"base/stun_server.h",
"base/turn_server.cc",

View File

@ -19,7 +19,6 @@
#include "p2p/base/ice_transport_internal.h"
#include "p2p/base/mock_async_resolver.h"
#include "p2p/base/packet_transport_internal.h"
#include "p2p/base/test_relay_server.h"
#include "p2p/base/test_stun_server.h"
#include "p2p/base/test_turn_server.h"
#include "p2p/client/basic_port_allocator.h"
@ -156,7 +155,7 @@ cricket::BasicPortAllocator* CreateBasicPortAllocator(
const cricket::ServerAddresses& stun_servers,
const rtc::SocketAddress& turn_server_udp,
const rtc::SocketAddress& turn_server_tcp) {
cricket::RelayServerConfig turn_server(cricket::RELAY_TURN);
cricket::RelayServerConfig turn_server;
turn_server.credentials = kRelayCredentials;
if (!turn_server_udp.IsNil()) {
turn_server.ports.push_back(
@ -2578,7 +2577,7 @@ TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControllingSide) {
TEST_F(P2PTransportChannelMultihomedTest, TestFailoverWithManyConnections) {
rtc::ScopedFakeClock clock;
test_turn_server()->AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP);
RelayServerConfig turn_server(RELAY_TURN);
RelayServerConfig turn_server;
turn_server.credentials = kRelayCredentials;
turn_server.ports.push_back(ProtocolAddress(kTurnTcpIntAddr, PROTO_TCP));
GetAllocator(0)->AddTurnServer(turn_server);
@ -4757,7 +4756,7 @@ TEST_F(P2PTransportChannelMostLikelyToWorkFirstTest,
TEST_F(P2PTransportChannelMostLikelyToWorkFirstTest, TestTcpTurn) {
// Add a Tcp Turn server.
turn_server()->AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP);
RelayServerConfig config(RELAY_TURN);
RelayServerConfig config;
config.credentials = kRelayCredentials;
config.ports.push_back(ProtocolAddress(kTurnTcpIntAddr, PROTO_TCP));
allocator()->AddTurnServer(config);

View File

@ -57,11 +57,6 @@ extern const char TCPTYPE_ACTIVE_STR[];
extern const char TCPTYPE_PASSIVE_STR[];
extern const char TCPTYPE_SIMOPEN_STR[];
enum RelayType {
RELAY_GTURN, // Legacy google relay service.
RELAY_TURN // Standard (TURN) relay service.
};
enum IcePriorityValue {
ICE_TYPE_PREFERENCE_RELAY_TLS = 0,
ICE_TYPE_PREFERENCE_RELAY_TCP = 1,

View File

@ -20,13 +20,13 @@
namespace cricket {
RelayServerConfig::RelayServerConfig(RelayType type) : type(type) {}
RelayServerConfig::RelayServerConfig() {}
RelayServerConfig::RelayServerConfig(const rtc::SocketAddress& address,
const std::string& username,
const std::string& password,
ProtocolType proto)
: type(RELAY_TURN), credentials(username, password) {
: credentials(username, password) {
ports.push_back(ProtocolAddress(address, proto));
}

View File

@ -149,7 +149,7 @@ struct RelayCredentials {
typedef std::vector<ProtocolAddress> PortList;
// TODO(deadbeef): Rename to TurnServerConfig.
struct RTC_EXPORT RelayServerConfig {
explicit RelayServerConfig(RelayType type);
RelayServerConfig();
RelayServerConfig(const rtc::SocketAddress& address,
const std::string& username,
const std::string& password,
@ -170,12 +170,11 @@ struct RTC_EXPORT RelayServerConfig {
~RelayServerConfig();
bool operator==(const RelayServerConfig& o) const {
return type == o.type && ports == o.ports && credentials == o.credentials &&
return ports == o.ports && credentials == o.credentials &&
priority == o.priority;
}
bool operator!=(const RelayServerConfig& o) const { return !(*this == o); }
RelayType type;
PortList ports;
RelayCredentials credentials;
int priority = 0;

View File

@ -27,12 +27,10 @@
#include "p2p/base/p2p_constants.h"
#include "p2p/base/port_allocator.h"
#include "p2p/base/port_interface.h"
#include "p2p/base/relay_port.h"
#include "p2p/base/stun.h"
#include "p2p/base/stun_port.h"
#include "p2p/base/stun_server.h"
#include "p2p/base/tcp_port.h"
#include "p2p/base/test_relay_server.h"
#include "p2p/base/test_stun_server.h"
#include "p2p/base/test_turn_server.h"
#include "p2p/base/transport_description.h"
@ -90,12 +88,6 @@ const SocketAddress kLocalAddr2("192.168.1.3", 0);
const SocketAddress kNatAddr1("77.77.77.77", rtc::NAT_SERVER_UDP_PORT);
const SocketAddress kNatAddr2("88.88.88.88", rtc::NAT_SERVER_UDP_PORT);
const SocketAddress kStunAddr("99.99.99.1", STUN_SERVER_PORT);
const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000);
const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001);
const SocketAddress kRelayTcpIntAddr("99.99.99.2", 5002);
const SocketAddress kRelayTcpExtAddr("99.99.99.3", 5003);
const SocketAddress kRelaySslTcpIntAddr("99.99.99.2", 5004);
const SocketAddress kRelaySslTcpExtAddr("99.99.99.3", 5005);
const SocketAddress kTurnUdpIntAddr("99.99.99.4", STUN_SERVER_PORT);
const SocketAddress kTurnTcpIntAddr("99.99.99.4", 5010);
const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
@ -112,8 +104,6 @@ constexpr int kTiebreaker2 = 22222;
const char* data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
constexpr int kGturnUserNameLength = 16;
Candidate GetCandidate(Port* port) {
RTC_DCHECK_GE(port->Candidates().size(), 1);
return port->Candidates()[0];
@ -410,13 +400,6 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> {
nat_socket_factory2_(&nat_factory2_),
stun_server_(TestStunServer::Create(&main_, kStunAddr)),
turn_server_(&main_, kTurnUdpIntAddr, kTurnUdpExtAddr),
relay_server_(&main_,
kRelayUdpIntAddr,
kRelayUdpExtAddr,
kRelayTcpIntAddr,
kRelayTcpExtAddr,
kRelaySslTcpIntAddr,
kRelaySslTcpExtAddr),
username_(rtc::CreateRandomString(ICE_UFRAG_LENGTH)),
password_(rtc::CreateRandomString(ICE_PWD_LENGTH)),
role_conflict_(false),
@ -441,13 +424,13 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> {
ntype == NAT_OPEN_CONE, true, ntype != NAT_SYMMETRIC,
true);
}
void TestLocalToRelay(RelayType rtype, ProtocolType proto) {
void TestLocalToRelay(ProtocolType proto) {
auto port1 = CreateUdpPort(kLocalAddr1);
port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
auto port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_UDP);
auto port2 = CreateRelayPort(kLocalAddr2, proto, PROTO_UDP);
port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
TestConnectivity("udp", std::move(port1), RelayName(rtype, proto),
std::move(port2), rtype == RELAY_GTURN, true, true, true);
TestConnectivity("udp", std::move(port1), RelayName(proto),
std::move(port2), false, true, true, true);
}
void TestStunToLocal(NATType ntype) {
nat_server1_ = CreateNatServer(kNatAddr1, ntype);
@ -470,15 +453,15 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> {
ntype1 != NAT_SYMMETRIC, ntype2 != NAT_SYMMETRIC,
ntype1 + ntype2 < (NAT_PORT_RESTRICTED + NAT_SYMMETRIC));
}
void TestStunToRelay(NATType ntype, RelayType rtype, ProtocolType proto) {
void TestStunToRelay(NATType ntype, ProtocolType proto) {
nat_server1_ = CreateNatServer(kNatAddr1, ntype);
auto port1 = CreateStunPort(kLocalAddr1, &nat_socket_factory1_);
port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
auto port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_UDP);
auto port2 = CreateRelayPort(kLocalAddr2, proto, PROTO_UDP);
port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
TestConnectivity(StunName(ntype), std::move(port1), RelayName(rtype, proto),
std::move(port2), rtype == RELAY_GTURN,
ntype != NAT_SYMMETRIC, true, true);
TestConnectivity(StunName(ntype), std::move(port1), RelayName(proto),
std::move(port2), false, ntype != NAT_SYMMETRIC, true,
true);
}
void TestTcpToTcp() {
auto port1 = CreateTcpPort(kLocalAddr1);
@ -488,21 +471,21 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> {
TestConnectivity("tcp", std::move(port1), "tcp", std::move(port2), true,
false, true, true);
}
void TestTcpToRelay(RelayType rtype, ProtocolType proto) {
void TestTcpToRelay(ProtocolType proto) {
auto port1 = CreateTcpPort(kLocalAddr1);
port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
auto port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_TCP);
auto port2 = CreateRelayPort(kLocalAddr2, proto, PROTO_TCP);
port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
TestConnectivity("tcp", std::move(port1), RelayName(rtype, proto),
std::move(port2), rtype == RELAY_GTURN, false, true, true);
TestConnectivity("tcp", std::move(port1), RelayName(proto),
std::move(port2), false, false, true, true);
}
void TestSslTcpToRelay(RelayType rtype, ProtocolType proto) {
void TestSslTcpToRelay(ProtocolType proto) {
auto port1 = CreateTcpPort(kLocalAddr1);
port1->SetIceRole(cricket::ICEROLE_CONTROLLING);
auto port2 = CreateRelayPort(kLocalAddr2, rtype, proto, PROTO_SSLTCP);
auto port2 = CreateRelayPort(kLocalAddr2, proto, PROTO_SSLTCP);
port2->SetIceRole(cricket::ICEROLE_CONTROLLED);
TestConnectivity("ssltcp", std::move(port1), RelayName(rtype, proto),
std::move(port2), rtype == RELAY_GTURN, false, true, true);
TestConnectivity("ssltcp", std::move(port1), RelayName(proto),
std::move(port2), false, false, true, true);
}
rtc::Network* MakeNetwork(const SocketAddress& addr) {
@ -538,14 +521,9 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> {
absl::nullopt);
}
std::unique_ptr<Port> CreateRelayPort(const SocketAddress& addr,
RelayType rtype,
ProtocolType int_proto,
ProtocolType ext_proto) {
if (rtype == RELAY_TURN) {
return CreateTurnPort(addr, &socket_factory_, int_proto, ext_proto);
} else {
return CreateGturnPort(addr, int_proto, ext_proto);
}
return CreateTurnPort(addr, &socket_factory_, int_proto, ext_proto);
}
std::unique_ptr<TurnPort> CreateTurnPort(const SocketAddress& addr,
PacketSocketFactory* socket_factory,
@ -567,24 +545,6 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> {
ProtocolAddress(server_addr, int_proto),
kRelayCredentials, 0, "", {}, {}, nullptr, nullptr);
}
std::unique_ptr<RelayPort> CreateGturnPort(const SocketAddress& addr,
ProtocolType int_proto,
ProtocolType ext_proto) {
std::unique_ptr<RelayPort> port = CreateGturnPort(addr);
SocketAddress addrs[] = {kRelayUdpIntAddr, kRelayTcpIntAddr,
kRelaySslTcpIntAddr};
port->AddServerAddress(ProtocolAddress(addrs[int_proto], int_proto));
return port;
}
std::unique_ptr<RelayPort> CreateGturnPort(const SocketAddress& addr) {
// TODO(pthatcher): Remove GTURN.
// Generate a username with length of 16 for Gturn only.
std::string username = rtc::CreateRandomString(kGturnUserNameLength);
return RelayPort::Create(&main_, &socket_factory_, MakeNetwork(addr), 0, 0,
username, password_);
// TODO(?): Add an external address for ext_proto, so that the
// other side can connect to this port using a non-UDP protocol.
}
std::unique_ptr<rtc::NATServer> CreateNatServer(const SocketAddress& addr,
rtc::NATType type) {
return std::make_unique<rtc::NATServer>(type, ss_.get(), addr, addr,
@ -604,33 +564,18 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> {
return "stun(?)";
}
}
static const char* RelayName(RelayType type, ProtocolType proto) {
if (type == RELAY_TURN) {
switch (proto) {
case PROTO_UDP:
return "turn(udp)";
case PROTO_TCP:
return "turn(tcp)";
case PROTO_SSLTCP:
return "turn(ssltcp)";
case PROTO_TLS:
return "turn(tls)";
default:
return "turn(?)";
}
} else {
switch (proto) {
case PROTO_UDP:
return "gturn(udp)";
case PROTO_TCP:
return "gturn(tcp)";
case PROTO_SSLTCP:
return "gturn(ssltcp)";
case PROTO_TLS:
return "gturn(tls)";
default:
return "gturn(?)";
}
static const char* RelayName(ProtocolType proto) {
switch (proto) {
case PROTO_UDP:
return "turn(udp)";
case PROTO_TCP:
return "turn(tcp)";
case PROTO_SSLTCP:
return "turn(ssltcp)";
case PROTO_TLS:
return "turn(tls)";
default:
return "turn(?)";
}
}
@ -856,7 +801,6 @@ class PortTest : public ::testing::Test, public sigslot::has_slots<> {
rtc::BasicPacketSocketFactory nat_socket_factory2_;
std::unique_ptr<TestStunServer> stun_server_;
TestTurnServer turn_server_;
TestRelayServer relay_server_;
std::string username_;
std::string password_;
bool role_conflict_;
@ -1120,19 +1064,7 @@ TEST_F(PortTest, TestLocalToSymNat) {
// Flaky: https://code.google.com/p/webrtc/issues/detail?id=3316.
TEST_F(PortTest, DISABLED_TestLocalToTurn) {
TestLocalToRelay(RELAY_TURN, PROTO_UDP);
}
TEST_F(PortTest, TestLocalToGturn) {
TestLocalToRelay(RELAY_GTURN, PROTO_UDP);
}
TEST_F(PortTest, TestLocalToTcpGturn) {
TestLocalToRelay(RELAY_GTURN, PROTO_TCP);
}
TEST_F(PortTest, TestLocalToSslTcpGturn) {
TestLocalToRelay(RELAY_GTURN, PROTO_SSLTCP);
TestLocalToRelay(PROTO_UDP);
}
// Cone NAT -> XXXX
@ -1157,15 +1089,7 @@ TEST_F(PortTest, TestConeNatToSymNat) {
}
TEST_F(PortTest, TestConeNatToTurn) {
TestStunToRelay(NAT_OPEN_CONE, RELAY_TURN, PROTO_UDP);
}
TEST_F(PortTest, TestConeNatToGturn) {
TestStunToRelay(NAT_OPEN_CONE, RELAY_GTURN, PROTO_UDP);
}
TEST_F(PortTest, TestConeNatToTcpGturn) {
TestStunToRelay(NAT_OPEN_CONE, RELAY_GTURN, PROTO_TCP);
TestStunToRelay(NAT_OPEN_CONE, PROTO_UDP);
}
// Address-restricted NAT -> XXXX
@ -1190,15 +1114,7 @@ TEST_F(PortTest, TestARNatToSymNat) {
}
TEST_F(PortTest, TestARNatToTurn) {
TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_TURN, PROTO_UDP);
}
TEST_F(PortTest, TestARNatToGturn) {
TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_GTURN, PROTO_UDP);
}
TEST_F(PortTest, TestARNATNatToTcpGturn) {
TestStunToRelay(NAT_ADDR_RESTRICTED, RELAY_GTURN, PROTO_TCP);
TestStunToRelay(NAT_ADDR_RESTRICTED, PROTO_UDP);
}
// Port-restricted NAT -> XXXX
@ -1224,15 +1140,7 @@ TEST_F(PortTest, TestPRNatToSymNat) {
}
TEST_F(PortTest, TestPRNatToTurn) {
TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_TURN, PROTO_UDP);
}
TEST_F(PortTest, TestPRNatToGturn) {
TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_GTURN, PROTO_UDP);
}
TEST_F(PortTest, TestPRNatToTcpGturn) {
TestStunToRelay(NAT_PORT_RESTRICTED, RELAY_GTURN, PROTO_TCP);
TestStunToRelay(NAT_PORT_RESTRICTED, PROTO_UDP);
}
// Symmetric NAT -> XXXX
@ -1259,15 +1167,7 @@ TEST_F(PortTest, TestSymNatToSymNat) {
}
TEST_F(PortTest, TestSymNatToTurn) {
TestStunToRelay(NAT_SYMMETRIC, RELAY_TURN, PROTO_UDP);
}
TEST_F(PortTest, TestSymNatToGturn) {
TestStunToRelay(NAT_SYMMETRIC, RELAY_GTURN, PROTO_UDP);
}
TEST_F(PortTest, TestSymNatToTcpGturn) {
TestStunToRelay(NAT_SYMMETRIC, RELAY_GTURN, PROTO_TCP);
TestStunToRelay(NAT_SYMMETRIC, PROTO_UDP);
}
// Outbound TCP -> XXXX
@ -2394,16 +2294,6 @@ TEST_F(PortTest, TestCandidateFoundation) {
stunport->Candidates()[0].foundation());
EXPECT_NE(udpport2->Candidates()[0].foundation(),
stunport->Candidates()[0].foundation());
// Verify GTURN candidate foundation.
auto relayport = CreateGturnPort(kLocalAddr1);
relayport->AddServerAddress(
cricket::ProtocolAddress(kRelayUdpIntAddr, cricket::PROTO_UDP));
relayport->PrepareAddress();
ASSERT_EQ_WAIT(1U, relayport->Candidates().size(), kDefaultTimeout);
EXPECT_NE(udpport1->Candidates()[0].foundation(),
relayport->Candidates()[0].foundation());
EXPECT_NE(udpport2->Candidates()[0].foundation(),
relayport->Candidates()[0].foundation());
// Verifying TURN candidate foundation.
auto turnport1 =
CreateTurnPort(kLocalAddr1, nat_socket_factory1(), PROTO_UDP, PROTO_UDP);
@ -2465,16 +2355,6 @@ TEST_F(PortTest, TestCandidateRelatedAddress) {
// Check STUN candidate related address.
EXPECT_EQ(stunport->Candidates()[0].related_address(),
stunport->GetLocalAddress());
// Verifying the related address for the GTURN candidates.
// NOTE: In case of GTURN related address will be equal to the mapped
// address, but address(mapped) will not be XOR.
auto relayport = CreateGturnPort(kLocalAddr1);
relayport->AddServerAddress(
cricket::ProtocolAddress(kRelayUdpIntAddr, cricket::PROTO_UDP));
relayport->PrepareAddress();
ASSERT_EQ_WAIT(1U, relayport->Candidates().size(), kDefaultTimeout);
// For Gturn related address is set to "0.0.0.0:0"
EXPECT_EQ(rtc::SocketAddress(), relayport->Candidates()[0].related_address());
// Verifying the related address for TURN candidate.
// For TURN related address must be equal to the mapped address.
auto turnport =

View File

@ -63,7 +63,7 @@ class RegatheringControllerTest : public ::testing::Test,
void InitializeAndGatherOnce() {
cricket::ServerAddresses stun_servers;
stun_servers.insert(kStunAddr);
cricket::RelayServerConfig turn_server(cricket::RELAY_TURN);
cricket::RelayServerConfig turn_server;
turn_server.credentials = kRelayCredentials;
turn_server.ports.push_back(
cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP));

View File

@ -1,860 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "p2p/base/relay_port.h"
#include <errno.h>
#include <string.h>
#include <algorithm>
#include "p2p/base/connection.h"
#include "p2p/base/stun.h"
#include "p2p/base/stun_request.h"
#include "rtc_base/async_packet_socket.h"
#include "rtc_base/byte_buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/dscp.h"
#include "rtc_base/location.h"
#include "rtc_base/logging.h"
#include "rtc_base/message_handler.h"
#include "rtc_base/message_queue.h"
#include "rtc_base/net_helper.h"
#include "rtc_base/proxy_info.h"
#include "rtc_base/time_utils.h"
namespace cricket {
static const int kMessageConnectTimeout = 1;
static const int kKeepAliveDelay = 10 * 60 * 1000;
static const int kRetryTimeout = 50 * 1000; // ICE says 50 secs
// How long to wait for a socket to connect to remote host in milliseconds
// before trying another connection.
static const int kSoftConnectTimeoutMs = 3 * 1000;
// Handles a connection to one address/port/protocol combination for a
// particular RelayEntry.
class RelayConnection : public sigslot::has_slots<> {
public:
RelayConnection(const ProtocolAddress* protocol_address,
rtc::AsyncPacketSocket* socket,
rtc::Thread* thread);
~RelayConnection() override;
rtc::AsyncPacketSocket* socket() const { return socket_; }
const ProtocolAddress* protocol_address() { return protocol_address_; }
rtc::SocketAddress GetAddress() const { return protocol_address_->address; }
ProtocolType GetProtocol() const { return protocol_address_->proto; }
int SetSocketOption(rtc::Socket::Option opt, int value);
// Validates a response to a STUN allocate request.
bool CheckResponse(StunMessage* msg);
// Sends data to the relay server.
int Send(const void* pv, size_t cb, const rtc::PacketOptions& options);
// Sends a STUN allocate request message to the relay server.
void SendAllocateRequest(RelayEntry* entry, int delay);
// Return the latest error generated by the socket.
int GetError() { return socket_->GetError(); }
// Called on behalf of a StunRequest to write data to the socket. This is
// already STUN intended for the server, so no wrapping is necessary.
void OnSendPacket(const void* data, size_t size, StunRequest* req);
private:
rtc::AsyncPacketSocket* socket_;
const ProtocolAddress* protocol_address_;
StunRequestManager* request_manager_;
rtc::DiffServCodePoint dscp_;
};
// Manages a number of connections to the relayserver, one for each
// available protocol. We aim to use each connection for only a
// specific destination address so that we can avoid wrapping every
// packet in a STUN send / data indication.
class RelayEntry : public rtc::MessageHandler, public sigslot::has_slots<> {
public:
RelayEntry(RelayPort* port, const rtc::SocketAddress& ext_addr);
~RelayEntry() override;
RelayPort* port() { return port_; }
const rtc::SocketAddress& address() const { return ext_addr_; }
void set_address(const rtc::SocketAddress& addr) { ext_addr_ = addr; }
bool connected() const { return connected_; }
bool locked() const { return locked_; }
// Returns the last error on the socket of this entry.
int GetError();
// Returns the most preferred connection of the given
// ones. Connections are rated based on protocol in the order of:
// UDP, TCP and SSLTCP, where UDP is the most preferred protocol
static RelayConnection* GetBestConnection(RelayConnection* conn1,
RelayConnection* conn2);
// Sends the STUN requests to the server to initiate this connection.
void Connect();
// Called when this entry becomes connected. The address given is the one
// exposed to the outside world on the relay server.
void OnConnect(const rtc::SocketAddress& mapped_addr,
RelayConnection* socket);
// Sends a packet to the given destination address using the socket of this
// entry. This will wrap the packet in STUN if necessary.
int SendTo(const void* data,
size_t size,
const rtc::SocketAddress& addr,
const rtc::PacketOptions& options);
// Schedules a keep-alive allocate request.
void ScheduleKeepAlive();
void SetServerIndex(size_t sindex) { server_index_ = sindex; }
// Sets this option on the socket of each connection.
int SetSocketOption(rtc::Socket::Option opt, int value);
size_t ServerIndex() const { return server_index_; }
// Try a different server address
void HandleConnectFailure(rtc::AsyncPacketSocket* socket);
// Implementation of the MessageHandler Interface.
void OnMessage(rtc::Message* pmsg) override;
private:
RelayPort* port_;
rtc::SocketAddress ext_addr_;
size_t server_index_;
bool connected_;
bool locked_;
RelayConnection* current_connection_;
// Called when a TCP connection is established or fails
void OnSocketConnect(rtc::AsyncPacketSocket* socket);
void OnSocketClose(rtc::AsyncPacketSocket* socket, int error);
// Called when a packet is received on this socket.
void OnReadPacket(rtc::AsyncPacketSocket* socket,
const char* data,
size_t size,
const rtc::SocketAddress& remote_addr,
const int64_t& packet_time_us);
void OnSentPacket(rtc::AsyncPacketSocket* socket,
const rtc::SentPacket& sent_packet);
// Called when the socket is currently able to send.
void OnReadyToSend(rtc::AsyncPacketSocket* socket);
// Sends the given data on the socket to the server with no wrapping. This
// returns the number of bytes written or -1 if an error occurred.
int SendPacket(const void* data,
size_t size,
const rtc::PacketOptions& options);
};
// Handles an allocate request for a particular RelayEntry.
class AllocateRequest : public StunRequest {
public:
AllocateRequest(RelayEntry* entry, RelayConnection* connection);
~AllocateRequest() override = default;
void Prepare(StunMessage* request) override;
void OnSent() override;
int resend_delay() override;
void OnResponse(StunMessage* response) override;
void OnErrorResponse(StunMessage* response) override;
void OnTimeout() override;
private:
RelayEntry* entry_;
RelayConnection* connection_;
int64_t start_time_;
};
RelayPort::RelayPort(rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
rtc::Network* network,
uint16_t min_port,
uint16_t max_port,
const std::string& username,
const std::string& password)
: Port(thread,
RELAY_PORT_TYPE,
factory,
network,
min_port,
max_port,
username,
password),
ready_(false),
error_(0) {
entries_.push_back(new RelayEntry(this, rtc::SocketAddress()));
// TODO(?): set local preference value for TCP based candidates.
}
RelayPort::~RelayPort() {
for (size_t i = 0; i < entries_.size(); ++i)
delete entries_[i];
thread()->Clear(this);
}
void RelayPort::AddServerAddress(const ProtocolAddress& addr) {
// Since HTTP proxies usually only allow 443,
// let's up the priority on PROTO_SSLTCP
if (addr.proto == PROTO_SSLTCP && (proxy().type == rtc::PROXY_HTTPS ||
proxy().type == rtc::PROXY_UNKNOWN)) {
server_addr_.push_front(addr);
} else {
server_addr_.push_back(addr);
}
}
void RelayPort::AddExternalAddress(const ProtocolAddress& addr) {
std::string proto_name = ProtoToString(addr.proto);
for (std::vector<ProtocolAddress>::iterator it = external_addr_.begin();
it != external_addr_.end(); ++it) {
if ((it->address == addr.address) && (it->proto == addr.proto)) {
RTC_LOG(INFO) << "Redundant relay address: " << proto_name << " @ "
<< addr.address.ToSensitiveString();
return;
}
}
external_addr_.push_back(addr);
}
void RelayPort::SetReady() {
if (!ready_) {
std::vector<ProtocolAddress>::iterator iter;
for (iter = external_addr_.begin(); iter != external_addr_.end(); ++iter) {
std::string proto_name = ProtoToString(iter->proto);
// In case of Gturn, related address is set to null socket address.
// This is due to as mapped address stun attribute is used for allocated
// address.
AddAddress(iter->address, iter->address, rtc::SocketAddress(), proto_name,
proto_name, "", RELAY_PORT_TYPE, ICE_TYPE_PREFERENCE_RELAY_UDP,
0, "", false);
}
ready_ = true;
SignalPortComplete(this);
}
}
const ProtocolAddress* RelayPort::ServerAddress(size_t index) const {
if (index < server_addr_.size())
return &server_addr_[index];
return NULL;
}
bool RelayPort::HasMagicCookie(const char* data, size_t size) {
if (size < 24 + sizeof(TURN_MAGIC_COOKIE_VALUE)) {
return false;
} else {
return memcmp(data + 24, TURN_MAGIC_COOKIE_VALUE,
sizeof(TURN_MAGIC_COOKIE_VALUE)) == 0;
}
}
void RelayPort::PrepareAddress() {
// We initiate a connect on the first entry. If this completes, it will fill
// in the server address as the address of this port.
RTC_DCHECK(entries_.size() == 1);
entries_[0]->Connect();
ready_ = false;
}
Connection* RelayPort::CreateConnection(const Candidate& address,
CandidateOrigin origin) {
// We only create conns to non-udp sockets if they are incoming on this port
if ((address.protocol() != UDP_PROTOCOL_NAME) &&
(origin != ORIGIN_THIS_PORT)) {
return 0;
}
// We don't support loopback on relays
if (address.type() == Type()) {
return 0;
}
if (!IsCompatibleAddress(address.address())) {
return 0;
}
size_t index = 0;
for (size_t i = 0; i < Candidates().size(); ++i) {
const Candidate& local = Candidates()[i];
if (local.protocol() == address.protocol()) {
index = i;
break;
}
}
Connection* conn = new ProxyConnection(this, index, address);
AddOrReplaceConnection(conn);
return conn;
}
int RelayPort::SendTo(const void* data,
size_t size,
const rtc::SocketAddress& addr,
const rtc::PacketOptions& options,
bool payload) {
// Try to find an entry for this specific address. Note that the first entry
// created was not given an address initially, so it can be set to the first
// address that comes along.
RelayEntry* entry = 0;
for (size_t i = 0; i < entries_.size(); ++i) {
if (entries_[i]->address().IsNil() && payload) {
entry = entries_[i];
entry->set_address(addr);
break;
} else if (entries_[i]->address() == addr) {
entry = entries_[i];
break;
}
}
// If we did not find one, then we make a new one. This will not be useable
// until it becomes connected, however.
if (!entry && payload) {
entry = new RelayEntry(this, addr);
if (!entries_.empty()) {
entry->SetServerIndex(entries_[0]->ServerIndex());
}
entry->Connect();
entries_.push_back(entry);
}
// If the entry is connected, then we can send on it (though wrapping may
// still be necessary). Otherwise, we can't yet use this connection, so we
// default to the first one.
if (!entry || !entry->connected()) {
RTC_DCHECK(!entries_.empty());
entry = entries_[0];
if (!entry->connected()) {
error_ = ENOTCONN;
return SOCKET_ERROR;
}
}
// Send the actual contents to the server using the usual mechanism.
rtc::PacketOptions modified_options(options);
CopyPortInformationToPacketInfo(&modified_options.info_signaled_after_sent);
int sent = entry->SendTo(data, size, addr, modified_options);
if (sent <= 0) {
RTC_DCHECK(sent < 0);
error_ = entry->GetError();
return SOCKET_ERROR;
}
// The caller of the function is expecting the number of user data bytes,
// rather than the size of the packet.
return static_cast<int>(size);
}
int RelayPort::SetOption(rtc::Socket::Option opt, int value) {
int result = 0;
for (size_t i = 0; i < entries_.size(); ++i) {
if (entries_[i]->SetSocketOption(opt, value) < 0) {
result = -1;
error_ = entries_[i]->GetError();
}
}
options_.push_back(OptionValue(opt, value));
return result;
}
int RelayPort::GetOption(rtc::Socket::Option opt, int* value) {
std::vector<OptionValue>::iterator it;
for (it = options_.begin(); it < options_.end(); ++it) {
if (it->first == opt) {
*value = it->second;
return 0;
}
}
return SOCKET_ERROR;
}
int RelayPort::GetError() {
return error_;
}
bool RelayPort::SupportsProtocol(const std::string& protocol) const {
// Relay port may create both TCP and UDP connections.
return true;
}
ProtocolType RelayPort::GetProtocol() const {
// We shouldn't be using RelayPort, but we need to provide an implementation
// here.
return PROTO_UDP;
}
void RelayPort::OnReadPacket(const char* data,
size_t size,
const rtc::SocketAddress& remote_addr,
ProtocolType proto,
int64_t packet_time_us) {
if (Connection* conn = GetConnection(remote_addr)) {
conn->OnReadPacket(data, size, packet_time_us);
} else {
Port::OnReadPacket(data, size, remote_addr, proto);
}
}
RelayConnection::RelayConnection(const ProtocolAddress* protocol_address,
rtc::AsyncPacketSocket* socket,
rtc::Thread* thread)
: socket_(socket),
protocol_address_(protocol_address),
dscp_(rtc::DSCP_NO_CHANGE) {
request_manager_ = new StunRequestManager(thread);
request_manager_->SignalSendPacket.connect(this,
&RelayConnection::OnSendPacket);
}
RelayConnection::~RelayConnection() {
delete request_manager_;
delete socket_;
}
int RelayConnection::SetSocketOption(rtc::Socket::Option opt, int value) {
if (opt == rtc::Socket::OPT_DSCP) {
dscp_ = static_cast<rtc::DiffServCodePoint>(value);
}
if (socket_) {
return socket_->SetOption(opt, value);
}
return 0;
}
bool RelayConnection::CheckResponse(StunMessage* msg) {
return request_manager_->CheckResponse(msg);
}
void RelayConnection::OnSendPacket(const void* data,
size_t size,
StunRequest* req) {
rtc::PacketOptions options(dscp_);
int sent = socket_->SendTo(data, size, GetAddress(), options);
if (sent <= 0) {
RTC_LOG(LS_VERBOSE) << "OnSendPacket: failed sending to "
<< GetAddress().ToSensitiveString()
<< strerror(socket_->GetError());
RTC_DCHECK(sent < 0);
}
}
int RelayConnection::Send(const void* pv,
size_t cb,
const rtc::PacketOptions& options) {
return socket_->SendTo(pv, cb, GetAddress(), options);
}
void RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) {
request_manager_->SendDelayed(new AllocateRequest(entry, this), delay);
}
RelayEntry::RelayEntry(RelayPort* port, const rtc::SocketAddress& ext_addr)
: port_(port),
ext_addr_(ext_addr),
server_index_(0),
connected_(false),
locked_(false),
current_connection_(NULL) {}
RelayEntry::~RelayEntry() {
// Remove all RelayConnections and dispose sockets.
delete current_connection_;
current_connection_ = NULL;
}
void RelayEntry::Connect() {
// If we're already connected, return.
if (connected_)
return;
// If we've exhausted all options, bail out.
const ProtocolAddress* ra = port()->ServerAddress(server_index_);
if (!ra) {
RTC_LOG(LS_WARNING) << "No more relay addresses left to try";
return;
}
// Remove any previous connection.
if (current_connection_) {
port()->thread()->Dispose(current_connection_);
current_connection_ = NULL;
}
// Try to set up our new socket.
RTC_LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto)
<< " @ " << ra->address.ToSensitiveString();
rtc::AsyncPacketSocket* socket = NULL;
if (ra->proto == PROTO_UDP) {
// UDP sockets are simple.
socket = port_->socket_factory()->CreateUdpSocket(
rtc::SocketAddress(port_->Network()->GetBestIP(), 0), port_->min_port(),
port_->max_port());
} else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) {
int opts = (ra->proto == PROTO_SSLTCP)
? rtc::PacketSocketFactory::OPT_TLS_FAKE
: 0;
rtc::PacketSocketTcpOptions tcp_opts;
tcp_opts.opts = opts;
socket = port_->socket_factory()->CreateClientTcpSocket(
rtc::SocketAddress(port_->Network()->GetBestIP(), 0), ra->address,
port_->proxy(), port_->user_agent(), tcp_opts);
} else {
RTC_LOG(LS_WARNING) << "Unknown protocol: " << ra->proto;
}
// If we failed to get a socket, move on to the next protocol.
if (!socket) {
RTC_LOG(LS_WARNING) << "Socket creation failed";
port()->thread()->Post(RTC_FROM_HERE, this, kMessageConnectTimeout);
return;
}
// Otherwise, create the new connection and configure any socket options.
socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket);
socket->SignalSentPacket.connect(this, &RelayEntry::OnSentPacket);
socket->SignalReadyToSend.connect(this, &RelayEntry::OnReadyToSend);
current_connection_ = new RelayConnection(ra, socket, port()->thread());
for (size_t i = 0; i < port_->options().size(); ++i) {
current_connection_->SetSocketOption(port_->options()[i].first,
port_->options()[i].second);
}
// If we're trying UDP, start binding requests.
// If we're trying TCP, wait for connection with a fixed timeout.
if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
socket->SignalClose.connect(this, &RelayEntry::OnSocketClose);
socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
port()->thread()->PostDelayed(RTC_FROM_HERE, kSoftConnectTimeoutMs, this,
kMessageConnectTimeout);
} else {
current_connection_->SendAllocateRequest(this, 0);
}
}
int RelayEntry::GetError() {
if (current_connection_ != NULL) {
return current_connection_->GetError();
}
return 0;
}
RelayConnection* RelayEntry::GetBestConnection(RelayConnection* conn1,
RelayConnection* conn2) {
return conn1->GetProtocol() <= conn2->GetProtocol() ? conn1 : conn2;
}
void RelayEntry::OnConnect(const rtc::SocketAddress& mapped_addr,
RelayConnection* connection) {
// We are connected, notify our parent.
ProtocolType proto = PROTO_UDP;
RTC_LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto) << " @ "
<< mapped_addr.ToSensitiveString();
connected_ = true;
port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto));
port_->SetReady();
}
int RelayEntry::SendTo(const void* data,
size_t size,
const rtc::SocketAddress& addr,
const rtc::PacketOptions& options) {
// If this connection is locked to the address given, then we can send the
// packet with no wrapper.
if (locked_ && (ext_addr_ == addr))
return SendPacket(data, size, options);
// Otherwise, we must wrap the given data in a STUN SEND request so that we
// can communicate the destination address to the server.
//
// Note that we do not use a StunRequest here. This is because there is
// likely no reason to resend this packet. If it is late, we just drop it.
// The next send to this address will try again.
RelayMessage request;
request.SetType(STUN_SEND_REQUEST);
auto magic_cookie_attr =
StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
magic_cookie_attr->CopyBytes(TURN_MAGIC_COOKIE_VALUE,
sizeof(TURN_MAGIC_COOKIE_VALUE));
request.AddAttribute(std::move(magic_cookie_attr));
auto username_attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
username_attr->CopyBytes(port_->username_fragment().c_str(),
port_->username_fragment().size());
request.AddAttribute(std::move(username_attr));
auto addr_attr = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
addr_attr->SetIP(addr.ipaddr());
addr_attr->SetPort(addr.port());
request.AddAttribute(std::move(addr_attr));
// Attempt to lock
if (ext_addr_ == addr) {
auto options_attr = StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS);
options_attr->SetValue(0x1);
request.AddAttribute(std::move(options_attr));
}
auto data_attr = StunAttribute::CreateByteString(STUN_ATTR_DATA);
data_attr->CopyBytes(data, size);
request.AddAttribute(std::move(data_attr));
// TODO(?): compute the HMAC.
rtc::ByteBufferWriter buf;
request.Write(&buf);
return SendPacket(buf.Data(), buf.Length(), options);
}
void RelayEntry::ScheduleKeepAlive() {
if (current_connection_) {
current_connection_->SendAllocateRequest(this, kKeepAliveDelay);
}
}
int RelayEntry::SetSocketOption(rtc::Socket::Option opt, int value) {
// Set the option on all available sockets.
int socket_error = 0;
if (current_connection_) {
socket_error = current_connection_->SetSocketOption(opt, value);
}
return socket_error;
}
void RelayEntry::HandleConnectFailure(rtc::AsyncPacketSocket* socket) {
// Make sure it's the current connection that has failed, it might
// be an old socked that has not yet been disposed.
if (!socket ||
(current_connection_ && socket == current_connection_->socket())) {
if (current_connection_)
port()->SignalConnectFailure(current_connection_->protocol_address());
// Try to connect to the next server address.
server_index_ += 1;
Connect();
}
}
void RelayEntry::OnMessage(rtc::Message* pmsg) {
RTC_DCHECK(pmsg->message_id == kMessageConnectTimeout);
if (current_connection_) {
const ProtocolAddress* ra = current_connection_->protocol_address();
RTC_LOG(LS_WARNING) << "Relay " << ra->proto << " connection to "
<< ra->address.ToSensitiveString() << " timed out";
// Currently we connect to each server address in sequence. If we
// have more addresses to try, treat this is an error and move on to
// the next address, otherwise give this connection more time and
// await the real timeout.
//
// TODO(?): Connect to servers in parallel to speed up connect time
// and to avoid giving up too early.
port_->SignalSoftTimeout(ra);
HandleConnectFailure(current_connection_->socket());
} else {
HandleConnectFailure(NULL);
}
}
void RelayEntry::OnSocketConnect(rtc::AsyncPacketSocket* socket) {
RTC_LOG(INFO) << "relay tcp connected to "
<< socket->GetRemoteAddress().ToSensitiveString();
if (current_connection_ != NULL) {
current_connection_->SendAllocateRequest(this, 0);
}
}
void RelayEntry::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) {
RTC_LOG_ERR_EX(LERROR, error) << "Relay connection failed: socket closed";
HandleConnectFailure(socket);
}
void RelayEntry::OnReadPacket(rtc::AsyncPacketSocket* socket,
const char* data,
size_t size,
const rtc::SocketAddress& remote_addr,
const int64_t& packet_time_us) {
// RTC_DCHECK(remote_addr == port_->server_addr());
// TODO(?): are we worried about this?
if (current_connection_ == NULL || socket != current_connection_->socket()) {
// This packet comes from an unknown address.
RTC_LOG(WARNING) << "Dropping packet: unknown address";
return;
}
// If the magic cookie is not present, then this is an unwrapped packet sent
// by the server, The actual remote address is the one we recorded.
if (!port_->HasMagicCookie(data, size)) {
if (locked_) {
port_->OnReadPacket(data, size, ext_addr_, PROTO_UDP, packet_time_us);
} else {
RTC_LOG(WARNING) << "Dropping packet: entry not locked";
}
return;
}
rtc::ByteBufferReader buf(data, size);
RelayMessage msg;
if (!msg.Read(&buf)) {
RTC_LOG(INFO) << "Incoming packet was not STUN";
return;
}
// The incoming packet should be a STUN ALLOCATE response, SEND response, or
// DATA indication.
if (current_connection_->CheckResponse(&msg)) {
return;
} else if (msg.type() == STUN_SEND_RESPONSE) {
if (const StunUInt32Attribute* options_attr =
msg.GetUInt32(STUN_ATTR_OPTIONS)) {
if (options_attr->value() & 0x1) {
locked_ = true;
}
}
return;
} else if (msg.type() != STUN_DATA_INDICATION) {
RTC_LOG(INFO) << "Received BAD stun type from server: " << msg.type();
return;
}
// This must be a data indication.
const StunAddressAttribute* addr_attr =
msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
if (!addr_attr) {
RTC_LOG(INFO) << "Data indication has no source address";
return;
} else if (addr_attr->family() != 1) {
RTC_LOG(INFO) << "Source address has bad family";
return;
}
rtc::SocketAddress remote_addr2(addr_attr->ipaddr(), addr_attr->port());
const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
if (!data_attr) {
RTC_LOG(INFO) << "Data indication has no data";
return;
}
// Process the actual data and remote address in the normal manner.
port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2,
PROTO_UDP, packet_time_us);
}
void RelayEntry::OnSentPacket(rtc::AsyncPacketSocket* socket,
const rtc::SentPacket& sent_packet) {
port_->OnSentPacket(socket, sent_packet);
}
void RelayEntry::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
if (connected()) {
port_->OnReadyToSend();
}
}
int RelayEntry::SendPacket(const void* data,
size_t size,
const rtc::PacketOptions& options) {
int sent = 0;
if (current_connection_) {
// We are connected, no need to send packets anywere else than to
// the current connection.
sent = current_connection_->Send(data, size, options);
}
return sent;
}
AllocateRequest::AllocateRequest(RelayEntry* entry, RelayConnection* connection)
: StunRequest(new RelayMessage()), entry_(entry), connection_(connection) {
start_time_ = rtc::TimeMillis();
}
void AllocateRequest::Prepare(StunMessage* request) {
request->SetType(STUN_ALLOCATE_REQUEST);
auto username_attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
username_attr->CopyBytes(entry_->port()->username_fragment().c_str(),
entry_->port()->username_fragment().size());
request->AddAttribute(std::move(username_attr));
}
void AllocateRequest::OnSent() {
count_ += 1;
if (count_ == 5)
timeout_ = true;
}
int AllocateRequest::resend_delay() {
if (count_ == 0) {
return 0;
}
return 100 * std::max(1 << (count_ - 1), 2);
}
void AllocateRequest::OnResponse(StunMessage* response) {
const StunAddressAttribute* addr_attr =
response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
if (!addr_attr) {
RTC_LOG(INFO) << "Allocate response missing mapped address.";
} else if (addr_attr->family() != 1) {
RTC_LOG(INFO) << "Mapped address has bad family";
} else {
rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
entry_->OnConnect(addr, connection_);
}
// We will do a keep-alive regardless of whether this request suceeds.
// This should have almost no impact on network usage.
entry_->ScheduleKeepAlive();
}
void AllocateRequest::OnErrorResponse(StunMessage* response) {
const StunErrorCodeAttribute* attr = response->GetErrorCode();
if (!attr) {
RTC_LOG(LS_ERROR) << "Missing allocate response error code.";
} else {
RTC_LOG(INFO) << "Allocate error response: code=" << attr->code()
<< " reason=" << attr->reason();
}
if (rtc::TimeMillis() - start_time_ <= kRetryTimeout)
entry_->ScheduleKeepAlive();
}
void AllocateRequest::OnTimeout() {
RTC_LOG(INFO) << "Allocate request timed out";
entry_->HandleConnectFailure(connection_->socket());
}
} // namespace cricket

View File

@ -1,118 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef P2P_BASE_RELAY_PORT_H_
#define P2P_BASE_RELAY_PORT_H_
#include <deque>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/memory/memory.h"
#include "p2p/base/port.h"
#include "p2p/base/stun_request.h"
namespace cricket {
class RelayEntry;
class RelayConnection;
// Communicates using an allocated port on the relay server. For each
// remote candidate that we try to send data to a RelayEntry instance
// is created. The RelayEntry will try to reach the remote destination
// by connecting to all available server addresses in a pre defined
// order with a small delay in between. When a connection is
// successful all other connection attempts are aborted.
class RelayPort : public Port {
public:
typedef std::pair<rtc::Socket::Option, int> OptionValue;
// RelayPort doesn't yet do anything fancy in the ctor.
static std::unique_ptr<RelayPort> Create(rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
rtc::Network* network,
uint16_t min_port,
uint16_t max_port,
const std::string& username,
const std::string& password) {
// Using `new` to access a non-public constructor.
return absl::WrapUnique(new RelayPort(thread, factory, network, min_port,
max_port, username, password));
}
~RelayPort() override;
void AddServerAddress(const ProtocolAddress& addr);
void AddExternalAddress(const ProtocolAddress& addr);
const std::vector<OptionValue>& options() const { return options_; }
bool HasMagicCookie(const char* data, size_t size);
void PrepareAddress() override;
Connection* CreateConnection(const Candidate& address,
CandidateOrigin origin) override;
int SetOption(rtc::Socket::Option opt, int value) override;
int GetOption(rtc::Socket::Option opt, int* value) override;
int GetError() override;
bool SupportsProtocol(const std::string& protocol) const override;
ProtocolType GetProtocol() const override;
const ProtocolAddress* ServerAddress(size_t index) const;
bool IsReady() { return ready_; }
// Used for testing.
sigslot::signal1<const ProtocolAddress*> SignalConnectFailure;
sigslot::signal1<const ProtocolAddress*> SignalSoftTimeout;
protected:
RelayPort(rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
rtc::Network*,
uint16_t min_port,
uint16_t max_port,
const std::string& username,
const std::string& password);
bool Init();
void SetReady();
int SendTo(const void* data,
size_t size,
const rtc::SocketAddress& addr,
const rtc::PacketOptions& options,
bool payload) override;
// Dispatches the given packet to the port or connection as appropriate.
void OnReadPacket(const char* data,
size_t size,
const rtc::SocketAddress& remote_addr,
ProtocolType proto,
int64_t packet_time_us);
// The OnSentPacket callback is left empty here since they are handled by
// RelayEntry.
void OnSentPacket(rtc::AsyncPacketSocket* socket,
const rtc::SentPacket& sent_packet) override {}
private:
friend class RelayEntry;
std::deque<ProtocolAddress> server_addr_;
std::vector<ProtocolAddress> external_addr_;
bool ready_;
std::vector<RelayEntry*> entries_;
std::vector<OptionValue> options_;
int error_;
};
} // namespace cricket
#endif // P2P_BASE_RELAY_PORT_H_

View File

@ -1,272 +0,0 @@
/*
* Copyright 2009 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "p2p/base/relay_port.h"
#include <map>
#include <memory>
#include "p2p/base/basic_packet_socket_factory.h"
#include "p2p/base/relay_server.h"
#include "rtc_base/gunit.h"
#include "rtc_base/helpers.h"
#include "rtc_base/logging.h"
#include "rtc_base/socket_adapters.h"
#include "rtc_base/socket_address.h"
#include "rtc_base/ssl_adapter.h"
#include "rtc_base/thread.h"
#include "rtc_base/virtual_socket_server.h"
using rtc::SocketAddress;
static const SocketAddress kLocalAddress = SocketAddress("192.168.1.2", 0);
static const SocketAddress kRelayUdpAddr = SocketAddress("99.99.99.1", 5000);
static const SocketAddress kRelayTcpAddr = SocketAddress("99.99.99.2", 5001);
static const SocketAddress kRelaySslAddr = SocketAddress("99.99.99.3", 443);
static const SocketAddress kRelayExtAddr = SocketAddress("99.99.99.3", 5002);
static const int kTimeoutMs = 1000;
static const int kMaxTimeoutMs = 5000;
// Tests connecting a RelayPort to a fake relay server
// (cricket::RelayServer) using all currently available protocols. The
// network layer is faked out by using a VirtualSocketServer for
// creating sockets. The test will monitor the current state of the
// RelayPort and created sockets by listening for signals such as,
// SignalConnectFailure, SignalConnectTimeout, SignalSocketClosed and
// SignalReadPacket.
class RelayPortTest : public ::testing::Test, public sigslot::has_slots<> {
public:
RelayPortTest()
: virtual_socket_server_(new rtc::VirtualSocketServer()),
main_(virtual_socket_server_.get()),
network_("unittest", "unittest", kLocalAddress.ipaddr(), 32),
socket_factory_(rtc::Thread::Current()),
username_(rtc::CreateRandomString(16)),
password_(rtc::CreateRandomString(16)),
relay_port_(cricket::RelayPort::Create(&main_,
&socket_factory_,
&network_,
0,
0,
username_,
password_)),
relay_server_(new cricket::RelayServer(&main_)) {
network_.AddIP(kLocalAddress.ipaddr());
}
void OnReadPacket(rtc::AsyncPacketSocket* socket,
const char* /* data */,
size_t /* size */,
const rtc::SocketAddress& /* remote_addr */,
const int64_t& /* packet_time_us */) {
received_packet_count_[socket]++;
}
void OnConnectFailure(const cricket::ProtocolAddress* addr) {
failed_connections_.push_back(*addr);
}
void OnSoftTimeout(const cricket::ProtocolAddress* addr) {
soft_timedout_connections_.push_back(*addr);
}
protected:
virtual void SetUp() {
// The relay server needs an external socket to work properly.
rtc::AsyncUDPSocket* ext_socket = CreateAsyncUdpSocket(kRelayExtAddr);
relay_server_->AddExternalSocket(ext_socket);
// Listen for failures.
relay_port_->SignalConnectFailure.connect(this,
&RelayPortTest::OnConnectFailure);
// Listen for soft timeouts.
relay_port_->SignalSoftTimeout.connect(this, &RelayPortTest::OnSoftTimeout);
}
// Udp has the highest 'goodness' value of the three different
// protocols used for connecting to the relay server. As soon as
// PrepareAddress is called, the RelayPort will start trying to
// connect to the given UDP address. As soon as a response to the
// sent STUN allocate request message has been received, the
// RelayPort will consider the connection to be complete and will
// abort any other connection attempts.
void TestConnectUdp() {
// Add a UDP socket to the relay server.
rtc::AsyncUDPSocket* internal_udp_socket =
CreateAsyncUdpSocket(kRelayUdpAddr);
rtc::AsyncSocket* server_socket = CreateServerSocket(kRelayTcpAddr);
relay_server_->AddInternalSocket(internal_udp_socket);
relay_server_->AddInternalServerSocket(server_socket, cricket::PROTO_TCP);
// Now add our relay addresses to the relay port and let it start.
relay_port_->AddServerAddress(
cricket::ProtocolAddress(kRelayUdpAddr, cricket::PROTO_UDP));
relay_port_->AddServerAddress(
cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP));
relay_port_->PrepareAddress();
// Should be connected.
EXPECT_TRUE_WAIT(relay_port_->IsReady(), kTimeoutMs);
// Make sure that we are happy with UDP, ie. not continuing with
// TCP, SSLTCP, etc.
WAIT(relay_server_->HasConnection(kRelayTcpAddr), kTimeoutMs);
// Should have only one connection.
EXPECT_EQ(1, relay_server_->GetConnectionCount());
// Should be the UDP address.
EXPECT_TRUE(relay_server_->HasConnection(kRelayUdpAddr));
}
// TCP has the second best 'goodness' value, and as soon as UDP
// connection has failed, the RelayPort will attempt to connect via
// TCP. Here we add a fake UDP address together with a real TCP
// address to simulate an UDP failure. As soon as UDP has failed the
// RelayPort will try the TCP adress and succed.
void TestConnectTcp() {
// Create a fake UDP address for relay port to simulate a failure.
cricket::ProtocolAddress fake_protocol_address =
cricket::ProtocolAddress(kRelayUdpAddr, cricket::PROTO_UDP);
// Create a server socket for the RelayServer.
rtc::AsyncSocket* server_socket = CreateServerSocket(kRelayTcpAddr);
relay_server_->AddInternalServerSocket(server_socket, cricket::PROTO_TCP);
// Add server addresses to the relay port and let it start.
relay_port_->AddServerAddress(
cricket::ProtocolAddress(fake_protocol_address));
relay_port_->AddServerAddress(
cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP));
relay_port_->PrepareAddress();
EXPECT_FALSE(relay_port_->IsReady());
// Should have timed out in 200 + 200 + 400 + 800 + 1600 ms = 3200ms.
// Add some margin of error for slow bots.
// TODO(deadbeef): Use simulated clock instead of just increasing timeouts
// to fix flaky tests.
EXPECT_TRUE_WAIT(HasFailed(&fake_protocol_address), 5000);
// Wait until relayport is ready.
EXPECT_TRUE_WAIT(relay_port_->IsReady(), kMaxTimeoutMs);
// Should have only one connection.
EXPECT_EQ(1, relay_server_->GetConnectionCount());
// Should be the TCP address.
EXPECT_TRUE(relay_server_->HasConnection(kRelayTcpAddr));
}
void TestConnectSslTcp() {
// Create a fake TCP address for relay port to simulate a failure.
// We skip UDP here since transition from UDP to TCP has been
// tested above.
cricket::ProtocolAddress fake_protocol_address =
cricket::ProtocolAddress(kRelayTcpAddr, cricket::PROTO_TCP);
// Create a ssl server socket for the RelayServer.
rtc::AsyncSocket* ssl_server_socket = CreateServerSocket(kRelaySslAddr);
relay_server_->AddInternalServerSocket(ssl_server_socket,
cricket::PROTO_SSLTCP);
// Create a tcp server socket that listens on the fake address so
// the relay port can attempt to connect to it.
std::unique_ptr<rtc::AsyncSocket> tcp_server_socket(
CreateServerSocket(kRelayTcpAddr));
// Add server addresses to the relay port and let it start.
relay_port_->AddServerAddress(fake_protocol_address);
relay_port_->AddServerAddress(
cricket::ProtocolAddress(kRelaySslAddr, cricket::PROTO_SSLTCP));
relay_port_->PrepareAddress();
EXPECT_FALSE(relay_port_->IsReady());
// Should have timed out in 3000 ms(relayport.cc, kSoftConnectTimeoutMs).
EXPECT_TRUE_WAIT_MARGIN(HasTimedOut(&fake_protocol_address), 3000, 100);
// Wait until relayport is ready.
EXPECT_TRUE_WAIT(relay_port_->IsReady(), kMaxTimeoutMs);
// Should have only one connection.
EXPECT_EQ(1, relay_server_->GetConnectionCount());
// Should be the SSLTCP address.
EXPECT_TRUE(relay_server_->HasConnection(kRelaySslAddr));
}
private:
rtc::AsyncUDPSocket* CreateAsyncUdpSocket(const SocketAddress addr) {
rtc::AsyncSocket* socket =
virtual_socket_server_->CreateAsyncSocket(AF_INET, SOCK_DGRAM);
rtc::AsyncUDPSocket* packet_socket =
rtc::AsyncUDPSocket::Create(socket, addr);
EXPECT_TRUE(packet_socket != NULL);
packet_socket->SignalReadPacket.connect(this, &RelayPortTest::OnReadPacket);
return packet_socket;
}
rtc::AsyncSocket* CreateServerSocket(const SocketAddress addr) {
rtc::AsyncSocket* socket =
virtual_socket_server_->CreateAsyncSocket(AF_INET, SOCK_STREAM);
EXPECT_GE(socket->Bind(addr), 0);
EXPECT_GE(socket->Listen(5), 0);
return socket;
}
bool HasFailed(cricket::ProtocolAddress* addr) {
for (size_t i = 0; i < failed_connections_.size(); i++) {
if (failed_connections_[i].address == addr->address &&
failed_connections_[i].proto == addr->proto) {
return true;
}
}
return false;
}
bool HasTimedOut(cricket::ProtocolAddress* addr) {
for (size_t i = 0; i < soft_timedout_connections_.size(); i++) {
if (soft_timedout_connections_[i].address == addr->address &&
soft_timedout_connections_[i].proto == addr->proto) {
return true;
}
}
return false;
}
typedef std::map<rtc::AsyncPacketSocket*, int> PacketMap;
std::unique_ptr<rtc::VirtualSocketServer> virtual_socket_server_;
rtc::AutoSocketServerThread main_;
rtc::Network network_;
rtc::BasicPacketSocketFactory socket_factory_;
std::string username_;
std::string password_;
std::unique_ptr<cricket::RelayPort> relay_port_;
std::unique_ptr<cricket::RelayServer> relay_server_;
std::vector<cricket::ProtocolAddress> failed_connections_;
std::vector<cricket::ProtocolAddress> soft_timedout_connections_;
PacketMap received_packet_count_;
};
TEST_F(RelayPortTest, ConnectUdp) {
TestConnectUdp();
}
TEST_F(RelayPortTest, ConnectTcp) {
TestConnectTcp();
}
TEST_F(RelayPortTest, ConnectSslTcp) {
TestConnectSslTcp();
}

View File

@ -1,741 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "p2p/base/relay_server.h"
#ifdef WEBRTC_POSIX
#include <errno.h>
#endif // WEBRTC_POSIX
#include <algorithm>
#include <utility>
#include "absl/algorithm/container.h"
#include "rtc_base/async_tcp_socket.h"
#include "rtc_base/checks.h"
#include "rtc_base/helpers.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/server_socket_adapters.h"
namespace cricket {
// By default, we require a ping every 90 seconds.
const int MAX_LIFETIME = 15 * 60 * 1000;
// The number of bytes in each of the usernames we use.
const uint32_t USERNAME_LENGTH = 16;
// Calls SendTo on the given socket and logs any bad results.
void Send(rtc::AsyncPacketSocket* socket,
const char* bytes,
size_t size,
const rtc::SocketAddress& addr) {
rtc::PacketOptions options;
int result = socket->SendTo(bytes, size, addr, options);
if (result < static_cast<int>(size)) {
RTC_LOG(LS_ERROR) << "SendTo wrote only " << result << " of " << size
<< " bytes";
} else if (result < 0) {
RTC_LOG_ERR(LS_ERROR) << "SendTo";
}
}
// Sends the given STUN message on the given socket.
void SendStun(const StunMessage& msg,
rtc::AsyncPacketSocket* socket,
const rtc::SocketAddress& addr) {
rtc::ByteBufferWriter buf;
msg.Write(&buf);
Send(socket, buf.Data(), buf.Length(), addr);
}
// Constructs a STUN error response and sends it on the given socket.
void SendStunError(const StunMessage& msg,
rtc::AsyncPacketSocket* socket,
const rtc::SocketAddress& remote_addr,
int error_code,
const char* error_desc,
const std::string& magic_cookie) {
RelayMessage err_msg;
err_msg.SetType(GetStunErrorResponseType(msg.type()));
err_msg.SetTransactionID(msg.transaction_id());
auto magic_cookie_attr =
StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
if (magic_cookie.size() == 0) {
magic_cookie_attr->CopyBytes(cricket::TURN_MAGIC_COOKIE_VALUE,
sizeof(cricket::TURN_MAGIC_COOKIE_VALUE));
} else {
magic_cookie_attr->CopyBytes(magic_cookie.c_str(), magic_cookie.size());
}
err_msg.AddAttribute(std::move(magic_cookie_attr));
auto err_code = StunAttribute::CreateErrorCode();
err_code->SetClass(error_code / 100);
err_code->SetNumber(error_code % 100);
err_code->SetReason(error_desc);
err_msg.AddAttribute(std::move(err_code));
SendStun(err_msg, socket, remote_addr);
}
RelayServer::RelayServer(rtc::Thread* thread)
: thread_(thread), random_(rtc::SystemTimeNanos()), log_bindings_(true) {}
RelayServer::~RelayServer() {
// Deleting the binding will cause it to be removed from the map.
while (!bindings_.empty())
delete bindings_.begin()->second;
for (size_t i = 0; i < internal_sockets_.size(); ++i)
delete internal_sockets_[i];
for (size_t i = 0; i < external_sockets_.size(); ++i)
delete external_sockets_[i];
for (size_t i = 0; i < removed_sockets_.size(); ++i)
delete removed_sockets_[i];
while (!server_sockets_.empty()) {
rtc::AsyncSocket* socket = server_sockets_.begin()->first;
server_sockets_.erase(server_sockets_.begin()->first);
delete socket;
}
}
void RelayServer::AddInternalSocket(rtc::AsyncPacketSocket* socket) {
RTC_DCHECK(!absl::c_linear_search(internal_sockets_, socket));
internal_sockets_.push_back(socket);
socket->SignalReadPacket.connect(this, &RelayServer::OnInternalPacket);
}
void RelayServer::RemoveInternalSocket(rtc::AsyncPacketSocket* socket) {
auto iter = absl::c_find(internal_sockets_, socket);
RTC_DCHECK(iter != internal_sockets_.end());
internal_sockets_.erase(iter);
removed_sockets_.push_back(socket);
socket->SignalReadPacket.disconnect(this);
}
void RelayServer::AddExternalSocket(rtc::AsyncPacketSocket* socket) {
RTC_DCHECK(!absl::c_linear_search(external_sockets_, socket));
external_sockets_.push_back(socket);
socket->SignalReadPacket.connect(this, &RelayServer::OnExternalPacket);
}
void RelayServer::RemoveExternalSocket(rtc::AsyncPacketSocket* socket) {
auto iter = absl::c_find(external_sockets_, socket);
RTC_DCHECK(iter != external_sockets_.end());
external_sockets_.erase(iter);
removed_sockets_.push_back(socket);
socket->SignalReadPacket.disconnect(this);
}
void RelayServer::AddInternalServerSocket(rtc::AsyncSocket* socket,
cricket::ProtocolType proto) {
RTC_DCHECK(server_sockets_.end() == server_sockets_.find(socket));
server_sockets_[socket] = proto;
socket->SignalReadEvent.connect(this, &RelayServer::OnReadEvent);
}
void RelayServer::RemoveInternalServerSocket(rtc::AsyncSocket* socket) {
auto iter = server_sockets_.find(socket);
RTC_DCHECK(iter != server_sockets_.end());
server_sockets_.erase(iter);
socket->SignalReadEvent.disconnect(this);
}
int RelayServer::GetConnectionCount() const {
return static_cast<int>(connections_.size());
}
rtc::SocketAddressPair RelayServer::GetConnection(int connection) const {
int i = 0;
for (const auto& entry : connections_) {
if (i == connection) {
return entry.second->addr_pair();
}
++i;
}
return rtc::SocketAddressPair();
}
bool RelayServer::HasConnection(const rtc::SocketAddress& address) const {
for (const auto& entry : connections_) {
if (entry.second->addr_pair().destination() == address) {
return true;
}
}
return false;
}
void RelayServer::OnReadEvent(rtc::AsyncSocket* socket) {
RTC_DCHECK(server_sockets_.find(socket) != server_sockets_.end());
AcceptConnection(socket);
}
void RelayServer::OnInternalPacket(rtc::AsyncPacketSocket* socket,
const char* bytes,
size_t size,
const rtc::SocketAddress& remote_addr,
const int64_t& /* packet_time_us */) {
// Get the address of the connection we just received on.
rtc::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
RTC_DCHECK(!ap.destination().IsNil());
// If this did not come from an existing connection, it should be a STUN
// allocate request.
auto piter = connections_.find(ap);
if (piter == connections_.end()) {
HandleStunAllocate(bytes, size, ap, socket);
return;
}
RelayServerConnection* int_conn = piter->second;
// Handle STUN requests to the server itself.
if (int_conn->binding()->HasMagicCookie(bytes, size)) {
HandleStun(int_conn, bytes, size);
return;
}
// Otherwise, this is a non-wrapped packet that we are to forward. Make sure
// that this connection has been locked. (Otherwise, we would not know what
// address to forward to.)
if (!int_conn->locked()) {
RTC_LOG(LS_WARNING) << "Dropping packet: connection not locked";
return;
}
// Forward this to the destination address into the connection.
RelayServerConnection* ext_conn = int_conn->binding()->GetExternalConnection(
int_conn->default_destination());
if (ext_conn && ext_conn->locked()) {
// TODO(?): Check the HMAC.
ext_conn->Send(bytes, size);
} else {
// This happens very often and is not an error.
RTC_LOG(LS_INFO) << "Dropping packet: no external connection";
}
}
void RelayServer::OnExternalPacket(rtc::AsyncPacketSocket* socket,
const char* bytes,
size_t size,
const rtc::SocketAddress& remote_addr,
const int64_t& /* packet_time_us */) {
// Get the address of the connection we just received on.
rtc::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
RTC_DCHECK(!ap.destination().IsNil());
// If this connection already exists, then forward the traffic.
auto piter = connections_.find(ap);
if (piter != connections_.end()) {
// TODO(?): Check the HMAC.
RelayServerConnection* ext_conn = piter->second;
RelayServerConnection* int_conn =
ext_conn->binding()->GetInternalConnection(
ext_conn->addr_pair().source());
RTC_DCHECK(int_conn != NULL);
int_conn->Send(bytes, size, ext_conn->addr_pair().source());
ext_conn->Lock(); // allow outgoing packets
return;
}
// The first packet should always be a STUN / TURN packet. If it isn't, then
// we should just ignore this packet.
RelayMessage msg;
rtc::ByteBufferReader buf(bytes, size);
if (!msg.Read(&buf)) {
RTC_LOG(LS_WARNING) << "Dropping packet: first packet not STUN";
return;
}
// The initial packet should have a username (which identifies the binding).
const StunByteStringAttribute* username_attr =
msg.GetByteString(STUN_ATTR_USERNAME);
if (!username_attr) {
RTC_LOG(LS_WARNING) << "Dropping packet: no username";
return;
}
uint32_t length =
std::min(static_cast<uint32_t>(username_attr->length()), USERNAME_LENGTH);
std::string username(username_attr->bytes(), length);
// TODO(?): Check the HMAC.
// The binding should already be present.
auto biter = bindings_.find(username);
if (biter == bindings_.end()) {
RTC_LOG(LS_WARNING) << "Dropping packet: no binding with username";
return;
}
// Add this authenticted connection to the binding.
RelayServerConnection* ext_conn =
new RelayServerConnection(biter->second, ap, socket);
ext_conn->binding()->AddExternalConnection(ext_conn);
AddConnection(ext_conn);
// We always know where external packets should be forwarded, so we can lock
// them from the beginning.
ext_conn->Lock();
// Send this message on the appropriate internal connection.
RelayServerConnection* int_conn = ext_conn->binding()->GetInternalConnection(
ext_conn->addr_pair().source());
RTC_DCHECK(int_conn != NULL);
int_conn->Send(bytes, size, ext_conn->addr_pair().source());
}
bool RelayServer::HandleStun(const char* bytes,
size_t size,
const rtc::SocketAddress& remote_addr,
rtc::AsyncPacketSocket* socket,
std::string* username,
StunMessage* msg) {
// Parse this into a stun message. Eat the message if this fails.
rtc::ByteBufferReader buf(bytes, size);
if (!msg->Read(&buf)) {
return false;
}
// The initial packet should have a username (which identifies the binding).
const StunByteStringAttribute* username_attr =
msg->GetByteString(STUN_ATTR_USERNAME);
if (!username_attr) {
SendStunError(*msg, socket, remote_addr, 432, "Missing Username", "");
return false;
}
// Record the username if requested.
if (username)
username->append(username_attr->bytes(), username_attr->length());
// TODO(?): Check for unknown attributes (<= 0x7fff)
return true;
}
void RelayServer::HandleStunAllocate(const char* bytes,
size_t size,
const rtc::SocketAddressPair& ap,
rtc::AsyncPacketSocket* socket) {
// Make sure this is a valid STUN request.
RelayMessage request;
std::string username;
if (!HandleStun(bytes, size, ap.source(), socket, &username, &request))
return;
// Make sure this is a an allocate request.
if (request.type() != STUN_ALLOCATE_REQUEST) {
SendStunError(request, socket, ap.source(), 600, "Operation Not Supported",
"");
return;
}
// TODO(?): Check the HMAC.
// Find or create the binding for this username.
RelayServerBinding* binding;
auto biter = bindings_.find(username);
if (biter != bindings_.end()) {
binding = biter->second;
} else {
// NOTE: In the future, bindings will be created by the bot only. This
// else-branch will then disappear.
// Compute the appropriate lifetime for this binding.
int lifetime = MAX_LIFETIME;
const StunUInt32Attribute* lifetime_attr =
request.GetUInt32(STUN_ATTR_LIFETIME);
if (lifetime_attr)
lifetime =
std::min(lifetime, static_cast<int>(lifetime_attr->value() * 1000));
binding = new RelayServerBinding(this, username, "0", lifetime);
binding->SignalTimeout.connect(this, &RelayServer::OnTimeout);
bindings_[username] = binding;
if (log_bindings_) {
RTC_LOG(LS_INFO) << "Added new binding " << username << ", "
<< bindings_.size() << " total";
}
}
// Add this connection to the binding. It starts out unlocked.
RelayServerConnection* int_conn =
new RelayServerConnection(binding, ap, socket);
binding->AddInternalConnection(int_conn);
AddConnection(int_conn);
// Now that we have a connection, this other method takes over.
HandleStunAllocate(int_conn, request);
}
void RelayServer::HandleStun(RelayServerConnection* int_conn,
const char* bytes,
size_t size) {
// Make sure this is a valid STUN request.
RelayMessage request;
std::string username;
if (!HandleStun(bytes, size, int_conn->addr_pair().source(),
int_conn->socket(), &username, &request))
return;
// Make sure the username is the one were were expecting.
if (username != int_conn->binding()->username()) {
int_conn->SendStunError(request, 430, "Stale Credentials");
return;
}
// TODO(?): Check the HMAC.
// Send this request to the appropriate handler.
if (request.type() == STUN_SEND_REQUEST)
HandleStunSend(int_conn, request);
else if (request.type() == STUN_ALLOCATE_REQUEST)
HandleStunAllocate(int_conn, request);
else
int_conn->SendStunError(request, 600, "Operation Not Supported");
}
void RelayServer::HandleStunAllocate(RelayServerConnection* int_conn,
const StunMessage& request) {
// Create a response message that includes an address with which external
// clients can communicate.
RelayMessage response;
response.SetType(STUN_ALLOCATE_RESPONSE);
response.SetTransactionID(request.transaction_id());
auto magic_cookie_attr =
StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
int_conn->binding()->magic_cookie().size());
response.AddAttribute(std::move(magic_cookie_attr));
RTC_DCHECK_GT(external_sockets_.size(), 0);
size_t index =
random_.Rand(rtc::dchecked_cast<uint32_t>(external_sockets_.size() - 1));
rtc::SocketAddress ext_addr = external_sockets_[index]->GetLocalAddress();
auto addr_attr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
addr_attr->SetIP(ext_addr.ipaddr());
addr_attr->SetPort(ext_addr.port());
response.AddAttribute(std::move(addr_attr));
auto res_lifetime_attr = StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
res_lifetime_attr->SetValue(int_conn->binding()->lifetime() / 1000);
response.AddAttribute(std::move(res_lifetime_attr));
// TODO(?): Support transport-prefs (preallocate RTCP port).
// TODO(?): Support bandwidth restrictions.
// TODO(?): Add message integrity check.
// Send a response to the caller.
int_conn->SendStun(response);
}
void RelayServer::HandleStunSend(RelayServerConnection* int_conn,
const StunMessage& request) {
const StunAddressAttribute* addr_attr =
request.GetAddress(STUN_ATTR_DESTINATION_ADDRESS);
if (!addr_attr) {
int_conn->SendStunError(request, 400, "Bad Request");
return;
}
const StunByteStringAttribute* data_attr =
request.GetByteString(STUN_ATTR_DATA);
if (!data_attr) {
int_conn->SendStunError(request, 400, "Bad Request");
return;
}
rtc::SocketAddress ext_addr(addr_attr->ipaddr(), addr_attr->port());
RelayServerConnection* ext_conn =
int_conn->binding()->GetExternalConnection(ext_addr);
if (!ext_conn) {
// Create a new connection to establish the relationship with this binding.
RTC_DCHECK(external_sockets_.size() == 1);
rtc::AsyncPacketSocket* socket = external_sockets_[0];
rtc::SocketAddressPair ap(ext_addr, socket->GetLocalAddress());
ext_conn = new RelayServerConnection(int_conn->binding(), ap, socket);
ext_conn->binding()->AddExternalConnection(ext_conn);
AddConnection(ext_conn);
}
// If this connection has pinged us, then allow outgoing traffic.
if (ext_conn->locked())
ext_conn->Send(data_attr->bytes(), data_attr->length());
const StunUInt32Attribute* options_attr =
request.GetUInt32(STUN_ATTR_OPTIONS);
if (options_attr && (options_attr->value() & 0x01)) {
int_conn->set_default_destination(ext_addr);
int_conn->Lock();
RelayMessage response;
response.SetType(STUN_SEND_RESPONSE);
response.SetTransactionID(request.transaction_id());
auto magic_cookie_attr =
StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
magic_cookie_attr->CopyBytes(int_conn->binding()->magic_cookie().c_str(),
int_conn->binding()->magic_cookie().size());
response.AddAttribute(std::move(magic_cookie_attr));
auto options2_attr =
StunAttribute::CreateUInt32(cricket::STUN_ATTR_OPTIONS);
options2_attr->SetValue(0x01);
response.AddAttribute(std::move(options2_attr));
int_conn->SendStun(response);
}
}
void RelayServer::AddConnection(RelayServerConnection* conn) {
RTC_DCHECK(connections_.find(conn->addr_pair()) == connections_.end());
connections_[conn->addr_pair()] = conn;
}
void RelayServer::RemoveConnection(RelayServerConnection* conn) {
auto iter = connections_.find(conn->addr_pair());
RTC_DCHECK(iter != connections_.end());
connections_.erase(iter);
}
void RelayServer::RemoveBinding(RelayServerBinding* binding) {
auto iter = bindings_.find(binding->username());
RTC_DCHECK(iter != bindings_.end());
bindings_.erase(iter);
if (log_bindings_) {
RTC_LOG(LS_INFO) << "Removed binding " << binding->username() << ", "
<< bindings_.size() << " remaining";
}
}
void RelayServer::OnMessage(rtc::Message* pmsg) {
static const uint32_t kMessageAcceptConnection = 1;
RTC_DCHECK(pmsg->message_id == kMessageAcceptConnection);
rtc::MessageData* data = pmsg->pdata;
rtc::AsyncSocket* socket =
static_cast<rtc::TypedMessageData<rtc::AsyncSocket*>*>(data)->data();
AcceptConnection(socket);
delete data;
}
void RelayServer::OnTimeout(RelayServerBinding* binding) {
// This call will result in all of the necessary clean-up. We can't call
// delete here, because you can't delete an object that is signaling you.
thread_->Dispose(binding);
}
void RelayServer::AcceptConnection(rtc::AsyncSocket* server_socket) {
// Check if someone is trying to connect to us.
rtc::SocketAddress accept_addr;
rtc::AsyncSocket* accepted_socket = server_socket->Accept(&accept_addr);
if (accepted_socket != NULL) {
// We had someone trying to connect, now check which protocol to
// use and create a packet socket.
RTC_DCHECK(server_sockets_[server_socket] == cricket::PROTO_TCP ||
server_sockets_[server_socket] == cricket::PROTO_SSLTCP);
if (server_sockets_[server_socket] == cricket::PROTO_SSLTCP) {
accepted_socket = new rtc::AsyncSSLServerSocket(accepted_socket);
}
rtc::AsyncTCPSocket* tcp_socket =
new rtc::AsyncTCPSocket(accepted_socket, false);
// Finally add the socket so it can start communicating with the client.
AddInternalSocket(tcp_socket);
}
}
RelayServerConnection::RelayServerConnection(
RelayServerBinding* binding,
const rtc::SocketAddressPair& addrs,
rtc::AsyncPacketSocket* socket)
: binding_(binding), addr_pair_(addrs), socket_(socket), locked_(false) {
// The creation of a new connection constitutes a use of the binding.
binding_->NoteUsed();
}
RelayServerConnection::~RelayServerConnection() {
// Remove this connection from the server's map (if it exists there).
binding_->server()->RemoveConnection(this);
}
void RelayServerConnection::Send(const char* data, size_t size) {
// Note that the binding has been used again.
binding_->NoteUsed();
cricket::Send(socket_, data, size, addr_pair_.source());
}
void RelayServerConnection::Send(const char* data,
size_t size,
const rtc::SocketAddress& from_addr) {
// If the from address is known to the client, we don't need to send it.
if (locked() && (from_addr == default_dest_)) {
Send(data, size);
return;
}
// Wrap the given data in a data-indication packet.
RelayMessage msg;
msg.SetType(STUN_DATA_INDICATION);
auto magic_cookie_attr =
StunAttribute::CreateByteString(cricket::STUN_ATTR_MAGIC_COOKIE);
magic_cookie_attr->CopyBytes(binding_->magic_cookie().c_str(),
binding_->magic_cookie().size());
msg.AddAttribute(std::move(magic_cookie_attr));
auto addr_attr = StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
addr_attr->SetIP(from_addr.ipaddr());
addr_attr->SetPort(from_addr.port());
msg.AddAttribute(std::move(addr_attr));
auto data_attr = StunAttribute::CreateByteString(STUN_ATTR_DATA);
RTC_DCHECK(size <= 65536);
data_attr->CopyBytes(data, uint16_t(size));
msg.AddAttribute(std::move(data_attr));
SendStun(msg);
}
void RelayServerConnection::SendStun(const StunMessage& msg) {
// Note that the binding has been used again.
binding_->NoteUsed();
cricket::SendStun(msg, socket_, addr_pair_.source());
}
void RelayServerConnection::SendStunError(const StunMessage& request,
int error_code,
const char* error_desc) {
// An error does not indicate use. If no legitimate use off the binding
// occurs, we want it to be cleaned up even if errors are still occuring.
cricket::SendStunError(request, socket_, addr_pair_.source(), error_code,
error_desc, binding_->magic_cookie());
}
void RelayServerConnection::Lock() {
locked_ = true;
}
void RelayServerConnection::Unlock() {
locked_ = false;
}
// IDs used for posted messages:
const uint32_t MSG_LIFETIME_TIMER = 1;
RelayServerBinding::RelayServerBinding(RelayServer* server,
const std::string& username,
const std::string& password,
int lifetime)
: server_(server),
username_(username),
password_(password),
lifetime_(lifetime) {
// For now, every connection uses the standard magic cookie value.
magic_cookie_.append(reinterpret_cast<const char*>(TURN_MAGIC_COOKIE_VALUE),
sizeof(TURN_MAGIC_COOKIE_VALUE));
// Initialize the last-used time to now.
NoteUsed();
// Set the first timeout check.
server_->thread()->PostDelayed(RTC_FROM_HERE, lifetime_, this,
MSG_LIFETIME_TIMER);
}
RelayServerBinding::~RelayServerBinding() {
// Clear the outstanding timeout check.
server_->thread()->Clear(this);
// Clean up all of the connections.
for (size_t i = 0; i < internal_connections_.size(); ++i)
delete internal_connections_[i];
for (size_t i = 0; i < external_connections_.size(); ++i)
delete external_connections_[i];
// Remove this binding from the server's map.
server_->RemoveBinding(this);
}
void RelayServerBinding::AddInternalConnection(RelayServerConnection* conn) {
internal_connections_.push_back(conn);
}
void RelayServerBinding::AddExternalConnection(RelayServerConnection* conn) {
external_connections_.push_back(conn);
}
void RelayServerBinding::NoteUsed() {
last_used_ = rtc::TimeMillis();
}
bool RelayServerBinding::HasMagicCookie(const char* bytes, size_t size) const {
if (size < 24 + magic_cookie_.size()) {
return false;
} else {
return memcmp(bytes + 24, magic_cookie_.c_str(), magic_cookie_.size()) == 0;
}
}
RelayServerConnection* RelayServerBinding::GetInternalConnection(
const rtc::SocketAddress& ext_addr) {
// Look for an internal connection that is locked to this address.
for (size_t i = 0; i < internal_connections_.size(); ++i) {
if (internal_connections_[i]->locked() &&
(ext_addr == internal_connections_[i]->default_destination()))
return internal_connections_[i];
}
// If one was not found, we send to the first connection.
RTC_DCHECK(internal_connections_.size() > 0);
return internal_connections_[0];
}
RelayServerConnection* RelayServerBinding::GetExternalConnection(
const rtc::SocketAddress& ext_addr) {
for (size_t i = 0; i < external_connections_.size(); ++i) {
if (ext_addr == external_connections_[i]->addr_pair().source())
return external_connections_[i];
}
return 0;
}
void RelayServerBinding::OnMessage(rtc::Message* pmsg) {
if (pmsg->message_id == MSG_LIFETIME_TIMER) {
RTC_DCHECK(!pmsg->pdata);
// If the lifetime timeout has been exceeded, then send a signal.
// Otherwise, just keep waiting.
if (rtc::TimeMillis() >= last_used_ + lifetime_) {
RTC_LOG(LS_INFO) << "Expiring binding " << username_;
SignalTimeout(this);
} else {
server_->thread()->PostDelayed(RTC_FROM_HERE, lifetime_, this,
MSG_LIFETIME_TIMER);
}
} else {
RTC_NOTREACHED();
}
}
} // namespace cricket

View File

@ -1,235 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef P2P_BASE_RELAY_SERVER_H_
#define P2P_BASE_RELAY_SERVER_H_
#include <map>
#include <string>
#include <vector>
#include "p2p/base/port.h"
#include "p2p/base/stun.h"
#include "rtc_base/async_udp_socket.h"
#include "rtc_base/random.h"
#include "rtc_base/socket_address_pair.h"
#include "rtc_base/thread.h"
#include "rtc_base/time_utils.h"
namespace cricket {
class RelayServerBinding;
class RelayServerConnection;
// Relays traffic between connections to the server that are "bound" together.
// All connections created with the same username/password are bound together.
class RelayServer : public rtc::MessageHandler, public sigslot::has_slots<> {
public:
// Creates a server, which will use this thread to post messages to itself.
explicit RelayServer(rtc::Thread* thread);
~RelayServer() override;
rtc::Thread* thread() { return thread_; }
// Indicates whether we will print updates of the number of bindings.
bool log_bindings() const { return log_bindings_; }
void set_log_bindings(bool log_bindings) { log_bindings_ = log_bindings; }
// Updates the set of sockets that the server uses to talk to "internal"
// clients. These are clients that do the "port allocations".
void AddInternalSocket(rtc::AsyncPacketSocket* socket);
void RemoveInternalSocket(rtc::AsyncPacketSocket* socket);
// Updates the set of sockets that the server uses to talk to "external"
// clients. These are the clients that do not do allocations. They do not
// know that these addresses represent a relay server.
void AddExternalSocket(rtc::AsyncPacketSocket* socket);
void RemoveExternalSocket(rtc::AsyncPacketSocket* socket);
// Starts listening for connections on this sockets. When someone
// tries to connect, the connection will be accepted and a new
// internal socket will be added.
void AddInternalServerSocket(rtc::AsyncSocket* socket,
cricket::ProtocolType proto);
// Removes this server socket from the list.
void RemoveInternalServerSocket(rtc::AsyncSocket* socket);
// Methods for testing and debuging.
int GetConnectionCount() const;
rtc::SocketAddressPair GetConnection(int connection) const;
bool HasConnection(const rtc::SocketAddress& address) const;
private:
rtc::Thread* thread_;
webrtc::Random random_;
bool log_bindings_;
std::vector<rtc::AsyncPacketSocket*> internal_sockets_;
std::vector<rtc::AsyncPacketSocket*> external_sockets_;
std::vector<rtc::AsyncPacketSocket*> removed_sockets_;
std::map<rtc::AsyncSocket*, cricket::ProtocolType> server_sockets_;
std::map<std::string, RelayServerBinding*> bindings_;
std::map<rtc::SocketAddressPair, RelayServerConnection*> connections_;
// Called when a packet is received by the server on one of its sockets.
void OnInternalPacket(rtc::AsyncPacketSocket* socket,
const char* bytes,
size_t size,
const rtc::SocketAddress& remote_addr,
const int64_t& packet_time_us);
void OnExternalPacket(rtc::AsyncPacketSocket* socket,
const char* bytes,
size_t size,
const rtc::SocketAddress& remote_addr,
const int64_t& packet_time_us);
void OnReadEvent(rtc::AsyncSocket* socket);
// Processes the relevant STUN request types from the client.
bool HandleStun(const char* bytes,
size_t size,
const rtc::SocketAddress& remote_addr,
rtc::AsyncPacketSocket* socket,
std::string* username,
StunMessage* msg);
void HandleStunAllocate(const char* bytes,
size_t size,
const rtc::SocketAddressPair& ap,
rtc::AsyncPacketSocket* socket);
void HandleStun(RelayServerConnection* int_conn,
const char* bytes,
size_t size);
void HandleStunAllocate(RelayServerConnection* int_conn,
const StunMessage& msg);
void HandleStunSend(RelayServerConnection* int_conn, const StunMessage& msg);
// Adds/Removes the a connection or binding.
void AddConnection(RelayServerConnection* conn);
void RemoveConnection(RelayServerConnection* conn);
void RemoveBinding(RelayServerBinding* binding);
// Handle messages in our thread.
void OnMessage(rtc::Message* pmsg) override;
// Called when the timer for checking lifetime times out.
void OnTimeout(RelayServerBinding* binding);
// Accept connections on this server socket.
void AcceptConnection(rtc::AsyncSocket* server_socket);
friend class RelayServerConnection;
friend class RelayServerBinding;
};
// Maintains information about a connection to the server. Each connection is
// part of one and only one binding.
class RelayServerConnection {
public:
RelayServerConnection(RelayServerBinding* binding,
const rtc::SocketAddressPair& addrs,
rtc::AsyncPacketSocket* socket);
~RelayServerConnection();
RelayServerBinding* binding() { return binding_; }
rtc::AsyncPacketSocket* socket() { return socket_; }
// Returns a pair where the source is the remote address and the destination
// is the local address.
const rtc::SocketAddressPair& addr_pair() { return addr_pair_; }
// Sends a packet to the connected client. If an address is provided, then
// we make sure the internal client receives it, wrapping if necessary.
void Send(const char* data, size_t size);
void Send(const char* data, size_t size, const rtc::SocketAddress& ext_addr);
// Sends a STUN message to the connected client with no wrapping.
void SendStun(const StunMessage& msg);
void SendStunError(const StunMessage& request, int code, const char* desc);
// A locked connection is one for which we know the intended destination of
// any raw packet received.
bool locked() const { return locked_; }
void Lock();
void Unlock();
// Records the address that raw packets should be forwarded to (for internal
// packets only; for external, we already know where they go).
const rtc::SocketAddress& default_destination() const {
return default_dest_;
}
void set_default_destination(const rtc::SocketAddress& addr) {
default_dest_ = addr;
}
private:
RelayServerBinding* binding_;
rtc::SocketAddressPair addr_pair_;
rtc::AsyncPacketSocket* socket_;
bool locked_;
rtc::SocketAddress default_dest_;
};
// Records a set of internal and external connections that we relay between,
// or in other words, that are "bound" together.
class RelayServerBinding : public rtc::MessageHandler {
public:
RelayServerBinding(RelayServer* server,
const std::string& username,
const std::string& password,
int lifetime);
~RelayServerBinding() override;
RelayServer* server() { return server_; }
int lifetime() { return lifetime_; }
const std::string& username() { return username_; }
const std::string& password() { return password_; }
const std::string& magic_cookie() { return magic_cookie_; }
// Adds/Removes a connection into the binding.
void AddInternalConnection(RelayServerConnection* conn);
void AddExternalConnection(RelayServerConnection* conn);
// We keep track of the use of each binding. If we detect that it was not
// used for longer than the lifetime, then we send a signal.
void NoteUsed();
sigslot::signal1<RelayServerBinding*> SignalTimeout;
// Determines whether the given packet has the magic cookie present (in the
// right place).
bool HasMagicCookie(const char* bytes, size_t size) const;
// Determines the connection to use to send packets to or from the given
// external address.
RelayServerConnection* GetInternalConnection(
const rtc::SocketAddress& ext_addr);
RelayServerConnection* GetExternalConnection(
const rtc::SocketAddress& ext_addr);
// MessageHandler:
void OnMessage(rtc::Message* pmsg) override;
private:
RelayServer* server_;
std::string username_;
std::string password_;
std::string magic_cookie_;
std::vector<RelayServerConnection*> internal_connections_;
std::vector<RelayServerConnection*> external_connections_;
int lifetime_;
int64_t last_used_;
// TODO(?): bandwidth
};
} // namespace cricket
#endif // P2P_BASE_RELAY_SERVER_H_

View File

@ -1,511 +0,0 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "p2p/base/relay_server.h"
#include <string.h>
#include <memory>
#include <string>
#include <utility>
#include "absl/memory/memory.h"
#include "rtc_base/async_udp_socket.h"
#include "rtc_base/byte_buffer.h"
#include "rtc_base/helpers.h"
#include "rtc_base/socket_address.h"
#include "rtc_base/test_client.h"
#include "rtc_base/thread.h"
#include "rtc_base/virtual_socket_server.h"
#include "test/gtest.h"
using rtc::SocketAddress;
namespace cricket {
namespace {
constexpr uint32_t LIFETIME = 4; // seconds
const SocketAddress server_int_addr("127.0.0.1", 5000);
const SocketAddress server_ext_addr("127.0.0.1", 5001);
const SocketAddress client1_addr("127.0.0.1", 6111);
const SocketAddress client2_addr("127.0.0.1", 7222);
const char* bad =
"this is a completely nonsensical message whose only "
"purpose is to make the parser go 'ack'. it doesn't "
"look anything like a normal stun message";
const char* msg1 = "spamspamspamspamspamspamspambakedbeansspam";
const char* msg2 = "Lobster Thermidor a Crevette with a mornay sauce...";
} // namespace
class RelayServerTest : public ::testing::Test {
public:
RelayServerTest()
: ss_(new rtc::VirtualSocketServer()),
thread_(ss_.get()),
username_(rtc::CreateRandomString(12)),
password_(rtc::CreateRandomString(12)) {}
protected:
virtual void SetUp() {
server_.reset(new RelayServer(rtc::Thread::Current()));
server_->AddInternalSocket(
rtc::AsyncUDPSocket::Create(ss_.get(), server_int_addr));
server_->AddExternalSocket(
rtc::AsyncUDPSocket::Create(ss_.get(), server_ext_addr));
client1_.reset(new rtc::TestClient(absl::WrapUnique(
rtc::AsyncUDPSocket::Create(ss_.get(), client1_addr))));
client2_.reset(new rtc::TestClient(absl::WrapUnique(
rtc::AsyncUDPSocket::Create(ss_.get(), client2_addr))));
}
void Allocate() {
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_ALLOCATE_REQUEST));
AddUsernameAttr(req.get(), username_);
AddLifetimeAttr(req.get(), LIFETIME);
Send1(req.get());
delete Receive1();
}
void Bind() {
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_BINDING_REQUEST));
AddUsernameAttr(req.get(), username_);
Send2(req.get());
delete Receive1();
}
void Send1(const StunMessage* msg) {
rtc::ByteBufferWriter buf;
msg->Write(&buf);
SendRaw1(buf.Data(), static_cast<int>(buf.Length()));
}
void Send2(const StunMessage* msg) {
rtc::ByteBufferWriter buf;
msg->Write(&buf);
SendRaw2(buf.Data(), static_cast<int>(buf.Length()));
}
void SendRaw1(const char* data, int len) {
return Send(client1_.get(), data, len, server_int_addr);
}
void SendRaw2(const char* data, int len) {
return Send(client2_.get(), data, len, server_ext_addr);
}
void Send(rtc::TestClient* client,
const char* data,
int len,
const SocketAddress& addr) {
client->SendTo(data, len, addr);
}
bool Receive1Fails() { return client1_.get()->CheckNoPacket(); }
bool Receive2Fails() { return client2_.get()->CheckNoPacket(); }
StunMessage* Receive1() { return Receive(client1_.get()); }
StunMessage* Receive2() { return Receive(client2_.get()); }
std::string ReceiveRaw1() { return ReceiveRaw(client1_.get()); }
std::string ReceiveRaw2() { return ReceiveRaw(client2_.get()); }
StunMessage* Receive(rtc::TestClient* client) {
StunMessage* msg = NULL;
std::unique_ptr<rtc::TestClient::Packet> packet =
client->NextPacket(rtc::TestClient::kTimeoutMs);
if (packet) {
rtc::ByteBufferWriter buf(packet->buf, packet->size);
rtc::ByteBufferReader read_buf(buf);
msg = new RelayMessage();
msg->Read(&read_buf);
}
return msg;
}
std::string ReceiveRaw(rtc::TestClient* client) {
std::string raw;
std::unique_ptr<rtc::TestClient::Packet> packet =
client->NextPacket(rtc::TestClient::kTimeoutMs);
if (packet) {
raw = std::string(packet->buf, packet->size);
}
return raw;
}
static StunMessage* CreateStunMessage(int type) {
StunMessage* msg = new RelayMessage();
msg->SetType(type);
msg->SetTransactionID(rtc::CreateRandomString(kStunTransactionIdLength));
return msg;
}
static void AddMagicCookieAttr(StunMessage* msg) {
auto attr = StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
attr->CopyBytes(TURN_MAGIC_COOKIE_VALUE, sizeof(TURN_MAGIC_COOKIE_VALUE));
msg->AddAttribute(std::move(attr));
}
static void AddUsernameAttr(StunMessage* msg, const std::string& val) {
auto attr = StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
attr->CopyBytes(val.c_str(), val.size());
msg->AddAttribute(std::move(attr));
}
static void AddLifetimeAttr(StunMessage* msg, int val) {
auto attr = StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
attr->SetValue(val);
msg->AddAttribute(std::move(attr));
}
static void AddDestinationAttr(StunMessage* msg, const SocketAddress& addr) {
auto attr = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
attr->SetIP(addr.ipaddr());
attr->SetPort(addr.port());
msg->AddAttribute(std::move(attr));
}
std::unique_ptr<rtc::VirtualSocketServer> ss_;
rtc::AutoSocketServerThread thread_;
std::unique_ptr<RelayServer> server_;
std::unique_ptr<rtc::TestClient> client1_;
std::unique_ptr<rtc::TestClient> client2_;
std::string username_;
std::string password_;
};
// Send a complete nonsense message and verify that it is eaten.
TEST_F(RelayServerTest, TestBadRequest) {
SendRaw1(bad, static_cast<int>(strlen(bad)));
ASSERT_TRUE(Receive1Fails());
}
// Send an allocate request without a username and verify it is rejected.
TEST_F(RelayServerTest, TestAllocateNoUsername) {
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_ALLOCATE_REQUEST)),
res;
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_ALLOCATE_ERROR_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunErrorCodeAttribute* err = res->GetErrorCode();
ASSERT_TRUE(err != NULL);
EXPECT_EQ(4, err->eclass());
EXPECT_EQ(32, err->number());
EXPECT_EQ("Missing Username", err->reason());
}
// Send a binding request and verify that it is rejected.
TEST_F(RelayServerTest, TestBindingRequest) {
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_BINDING_REQUEST)),
res;
AddUsernameAttr(req.get(), username_);
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunErrorCodeAttribute* err = res->GetErrorCode();
ASSERT_TRUE(err != NULL);
EXPECT_EQ(6, err->eclass());
EXPECT_EQ(0, err->number());
EXPECT_EQ("Operation Not Supported", err->reason());
}
// Send an allocate request and verify that it is accepted.
TEST_F(RelayServerTest, TestAllocate) {
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_ALLOCATE_REQUEST)),
res;
AddUsernameAttr(req.get(), username_);
AddLifetimeAttr(req.get(), LIFETIME);
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_ALLOCATE_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunAddressAttribute* mapped_addr =
res->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
ASSERT_TRUE(mapped_addr != NULL);
EXPECT_EQ(1, mapped_addr->family());
EXPECT_EQ(server_ext_addr.port(), mapped_addr->port());
EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr());
const StunUInt32Attribute* res_lifetime_attr =
res->GetUInt32(STUN_ATTR_LIFETIME);
ASSERT_TRUE(res_lifetime_attr != NULL);
EXPECT_EQ(LIFETIME, res_lifetime_attr->value());
}
// Send a second allocate request and verify that it is also accepted, though
// the lifetime should be ignored.
TEST_F(RelayServerTest, TestReallocate) {
Allocate();
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_ALLOCATE_REQUEST)),
res;
AddMagicCookieAttr(req.get());
AddUsernameAttr(req.get(), username_);
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_ALLOCATE_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunAddressAttribute* mapped_addr =
res->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
ASSERT_TRUE(mapped_addr != NULL);
EXPECT_EQ(1, mapped_addr->family());
EXPECT_EQ(server_ext_addr.port(), mapped_addr->port());
EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr());
const StunUInt32Attribute* lifetime_attr = res->GetUInt32(STUN_ATTR_LIFETIME);
ASSERT_TRUE(lifetime_attr != NULL);
EXPECT_EQ(LIFETIME, lifetime_attr->value());
}
// Send a request from another client and see that it arrives at the first
// client in the binding.
TEST_F(RelayServerTest, TestRemoteBind) {
Allocate();
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_BINDING_REQUEST)),
res;
AddUsernameAttr(req.get(), username_);
Send2(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_DATA_INDICATION, res->type());
const StunByteStringAttribute* recv_data = res->GetByteString(STUN_ATTR_DATA);
ASSERT_TRUE(recv_data != NULL);
rtc::ByteBufferReader buf(recv_data->bytes(), recv_data->length());
std::unique_ptr<StunMessage> res2(new StunMessage());
EXPECT_TRUE(res2->Read(&buf));
EXPECT_EQ(STUN_BINDING_REQUEST, res2->type());
EXPECT_EQ(req->transaction_id(), res2->transaction_id());
const StunAddressAttribute* src_addr =
res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
ASSERT_TRUE(src_addr != NULL);
EXPECT_EQ(1, src_addr->family());
EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr());
EXPECT_EQ(client2_addr.port(), src_addr->port());
EXPECT_TRUE(Receive2Fails());
}
// Send a complete nonsense message to the established connection and verify
// that it is dropped by the server.
TEST_F(RelayServerTest, TestRemoteBadRequest) {
Allocate();
Bind();
SendRaw1(bad, static_cast<int>(strlen(bad)));
EXPECT_TRUE(Receive1Fails());
EXPECT_TRUE(Receive2Fails());
}
// Send a send request without a username and verify it is rejected.
TEST_F(RelayServerTest, TestSendRequestMissingUsername) {
Allocate();
Bind();
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_SEND_REQUEST)), res;
AddMagicCookieAttr(req.get());
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunErrorCodeAttribute* err = res->GetErrorCode();
ASSERT_TRUE(err != NULL);
EXPECT_EQ(4, err->eclass());
EXPECT_EQ(32, err->number());
EXPECT_EQ("Missing Username", err->reason());
}
// Send a send request with the wrong username and verify it is rejected.
TEST_F(RelayServerTest, TestSendRequestBadUsername) {
Allocate();
Bind();
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_SEND_REQUEST)), res;
AddMagicCookieAttr(req.get());
AddUsernameAttr(req.get(), "foobarbizbaz");
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunErrorCodeAttribute* err = res->GetErrorCode();
ASSERT_TRUE(err != NULL);
EXPECT_EQ(4, err->eclass());
EXPECT_EQ(30, err->number());
EXPECT_EQ("Stale Credentials", err->reason());
}
// Send a send request without a destination address and verify that it is
// rejected.
TEST_F(RelayServerTest, TestSendRequestNoDestinationAddress) {
Allocate();
Bind();
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_SEND_REQUEST)), res;
AddMagicCookieAttr(req.get());
AddUsernameAttr(req.get(), username_);
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunErrorCodeAttribute* err = res->GetErrorCode();
ASSERT_TRUE(err != NULL);
EXPECT_EQ(4, err->eclass());
EXPECT_EQ(0, err->number());
EXPECT_EQ("Bad Request", err->reason());
}
// Send a send request without data and verify that it is rejected.
TEST_F(RelayServerTest, TestSendRequestNoData) {
Allocate();
Bind();
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_SEND_REQUEST)), res;
AddMagicCookieAttr(req.get());
AddUsernameAttr(req.get(), username_);
AddDestinationAttr(req.get(), client2_addr);
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunErrorCodeAttribute* err = res->GetErrorCode();
ASSERT_TRUE(err != NULL);
EXPECT_EQ(4, err->eclass());
EXPECT_EQ(00, err->number());
EXPECT_EQ("Bad Request", err->reason());
}
// Send a binding request after an allocate and verify that it is rejected.
TEST_F(RelayServerTest, TestSendRequestWrongType) {
Allocate();
Bind();
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_BINDING_REQUEST)),
res;
AddMagicCookieAttr(req.get());
AddUsernameAttr(req.get(), username_);
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, res->type());
EXPECT_EQ(req->transaction_id(), res->transaction_id());
const StunErrorCodeAttribute* err = res->GetErrorCode();
ASSERT_TRUE(err != NULL);
EXPECT_EQ(6, err->eclass());
EXPECT_EQ(0, err->number());
EXPECT_EQ("Operation Not Supported", err->reason());
}
// Verify that we can send traffic back and forth between the clients after a
// successful allocate and bind.
TEST_F(RelayServerTest, TestSendRaw) {
Allocate();
Bind();
for (int i = 0; i < 10; i++) {
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_SEND_REQUEST)), res;
AddMagicCookieAttr(req.get());
AddUsernameAttr(req.get(), username_);
AddDestinationAttr(req.get(), client2_addr);
auto send_data = StunAttribute::CreateByteString(STUN_ATTR_DATA);
send_data->CopyBytes(msg1);
req->AddAttribute(std::move(send_data));
Send1(req.get());
EXPECT_EQ(msg1, ReceiveRaw2());
SendRaw2(msg2, static_cast<int>(strlen(msg2)));
res.reset(Receive1());
ASSERT_TRUE(res);
EXPECT_EQ(STUN_DATA_INDICATION, res->type());
const StunAddressAttribute* src_addr =
res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
ASSERT_TRUE(src_addr != NULL);
EXPECT_EQ(1, src_addr->family());
EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr());
EXPECT_EQ(client2_addr.port(), src_addr->port());
const StunByteStringAttribute* recv_data =
res->GetByteString(STUN_ATTR_DATA);
ASSERT_TRUE(recv_data != NULL);
EXPECT_EQ(strlen(msg2), recv_data->length());
EXPECT_EQ(0, memcmp(msg2, recv_data->bytes(), recv_data->length()));
}
}
// Verify that a binding expires properly, and rejects send requests.
// Flaky, see https://code.google.com/p/webrtc/issues/detail?id=4134
TEST_F(RelayServerTest, DISABLED_TestExpiration) {
Allocate();
Bind();
// Wait twice the lifetime to make sure the server has expired the binding.
rtc::Thread::Current()->ProcessMessages((LIFETIME * 2) * 1000);
std::unique_ptr<StunMessage> req(CreateStunMessage(STUN_SEND_REQUEST)), res;
AddMagicCookieAttr(req.get());
AddUsernameAttr(req.get(), username_);
AddDestinationAttr(req.get(), client2_addr);
auto data_attr = StunAttribute::CreateByteString(STUN_ATTR_DATA);
data_attr->CopyBytes(msg1);
req->AddAttribute(std::move(data_attr));
Send1(req.get());
res.reset(Receive1());
ASSERT_TRUE(res.get() != NULL);
EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
const StunErrorCodeAttribute* err = res->GetErrorCode();
ASSERT_TRUE(err != NULL);
EXPECT_EQ(6, err->eclass());
EXPECT_EQ(0, err->number());
EXPECT_EQ("Operation Not Supported", err->reason());
// Also verify that traffic from the external client is ignored.
SendRaw2(msg2, static_cast<int>(strlen(msg2)));
EXPECT_TRUE(ReceiveRaw1().empty());
}
} // namespace cricket

View File

@ -1,101 +0,0 @@
/*
* Copyright 2008 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef P2P_BASE_TEST_RELAY_SERVER_H_
#define P2P_BASE_TEST_RELAY_SERVER_H_
#include <memory>
#include "p2p/base/relay_server.h"
#include "rtc_base/async_tcp_socket.h"
#include "rtc_base/server_socket_adapters.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread.h"
namespace cricket {
// A test relay server. Useful for unit tests.
class TestRelayServer : public sigslot::has_slots<> {
public:
TestRelayServer(rtc::Thread* thread,
const rtc::SocketAddress& udp_int_addr,
const rtc::SocketAddress& udp_ext_addr,
const rtc::SocketAddress& tcp_int_addr,
const rtc::SocketAddress& tcp_ext_addr,
const rtc::SocketAddress& ssl_int_addr,
const rtc::SocketAddress& ssl_ext_addr)
: server_(thread) {
server_.AddInternalSocket(
rtc::AsyncUDPSocket::Create(thread->socketserver(), udp_int_addr));
server_.AddExternalSocket(
rtc::AsyncUDPSocket::Create(thread->socketserver(), udp_ext_addr));
tcp_int_socket_.reset(CreateListenSocket(thread, tcp_int_addr));
tcp_ext_socket_.reset(CreateListenSocket(thread, tcp_ext_addr));
ssl_int_socket_.reset(CreateListenSocket(thread, ssl_int_addr));
ssl_ext_socket_.reset(CreateListenSocket(thread, ssl_ext_addr));
}
int GetConnectionCount() const { return server_.GetConnectionCount(); }
rtc::SocketAddressPair GetConnection(int connection) const {
return server_.GetConnection(connection);
}
bool HasConnection(const rtc::SocketAddress& address) const {
return server_.HasConnection(address);
}
private:
rtc::AsyncSocket* CreateListenSocket(rtc::Thread* thread,
const rtc::SocketAddress& addr) {
rtc::AsyncSocket* socket =
thread->socketserver()->CreateAsyncSocket(addr.family(), SOCK_STREAM);
socket->Bind(addr);
socket->Listen(5);
socket->SignalReadEvent.connect(this, &TestRelayServer::OnAccept);
return socket;
}
void OnAccept(rtc::AsyncSocket* socket) {
bool external =
(socket == tcp_ext_socket_.get() || socket == ssl_ext_socket_.get());
bool ssl =
(socket == ssl_int_socket_.get() || socket == ssl_ext_socket_.get());
rtc::AsyncSocket* raw_socket = socket->Accept(NULL);
if (raw_socket) {
rtc::AsyncTCPSocket* packet_socket = new rtc::AsyncTCPSocket(
(!ssl) ? raw_socket : new rtc::AsyncSSLServerSocket(raw_socket),
false);
if (!external) {
packet_socket->SignalClose.connect(this,
&TestRelayServer::OnInternalClose);
server_.AddInternalSocket(packet_socket);
} else {
packet_socket->SignalClose.connect(this,
&TestRelayServer::OnExternalClose);
server_.AddExternalSocket(packet_socket);
}
}
}
void OnInternalClose(rtc::AsyncPacketSocket* socket, int error) {
server_.RemoveInternalSocket(socket);
}
void OnExternalClose(rtc::AsyncPacketSocket* socket, int error) {
server_.RemoveExternalSocket(socket);
}
private:
cricket::RelayServer server_;
std::unique_ptr<rtc::AsyncSocket> tcp_int_socket_;
std::unique_ptr<rtc::AsyncSocket> tcp_ext_socket_;
std::unique_ptr<rtc::AsyncSocket> ssl_int_socket_;
std::unique_ptr<rtc::AsyncSocket> ssl_ext_socket_;
};
} // namespace cricket
#endif // P2P_BASE_TEST_RELAY_SERVER_H_

View File

@ -20,7 +20,6 @@
#include "absl/algorithm/container.h"
#include "p2p/base/basic_packet_socket_factory.h"
#include "p2p/base/port.h"
#include "p2p/base/relay_port.h"
#include "p2p/base/stun_port.h"
#include "p2p/base/tcp_port.h"
#include "p2p/base/turn_port.h"
@ -1522,42 +1521,7 @@ void AllocationSequence::CreateRelayPorts() {
}
for (RelayServerConfig& relay : config_->relays) {
if (relay.type == RELAY_GTURN) {
CreateGturnPort(relay);
} else if (relay.type == RELAY_TURN) {
CreateTurnPort(relay);
} else {
RTC_NOTREACHED();
}
}
}
void AllocationSequence::CreateGturnPort(const RelayServerConfig& config) {
// TODO(mallinath) - Rename RelayPort to GTurnPort.
std::unique_ptr<RelayPort> port = RelayPort::Create(
session_->network_thread(), session_->socket_factory(), network_,
session_->allocator()->min_port(), session_->allocator()->max_port(),
config_->username, config_->password);
if (port) {
RelayPort* port_ptr = port.release();
// Since RelayPort is not created using shared socket, |port| will not be
// added to the dequeue.
// Note: We must add the allocated port before we add addresses because
// the latter will create candidates that need name and preference
// settings. However, we also can't prepare the address (normally
// done by AddAllocatedPort) until we have these addresses. So we
// wait to do that until below.
session_->AddAllocatedPort(port_ptr, this, false);
// Add the addresses of this protocol.
PortList::const_iterator relay_port;
for (relay_port = config.ports.begin(); relay_port != config.ports.end();
++relay_port) {
port_ptr->AddServerAddress(*relay_port);
port_ptr->AddExternalAddress(*relay_port);
}
// Start fetching an address for this port.
port_ptr->PrepareAddress();
CreateTurnPort(relay);
}
}
@ -1720,7 +1684,7 @@ ServerAddresses PortConfiguration::StunServers() {
// Every UDP TURN server should also be used as a STUN server if
// use_turn_server_as_stun_server is not disabled or the stun servers are
// empty.
ServerAddresses turn_servers = GetRelayServerAddresses(RELAY_TURN, PROTO_UDP);
ServerAddresses turn_servers = GetRelayServerAddresses(PROTO_UDP);
for (const rtc::SocketAddress& turn_server : turn_servers) {
if (stun_servers.find(turn_server) == stun_servers.end()) {
stun_servers.insert(turn_server);
@ -1744,21 +1708,19 @@ bool PortConfiguration::SupportsProtocol(const RelayServerConfig& relay,
return false;
}
bool PortConfiguration::SupportsProtocol(RelayType turn_type,
ProtocolType type) const {
bool PortConfiguration::SupportsProtocol(ProtocolType type) const {
for (size_t i = 0; i < relays.size(); ++i) {
if (relays[i].type == turn_type && SupportsProtocol(relays[i], type))
if (SupportsProtocol(relays[i], type))
return true;
}
return false;
}
ServerAddresses PortConfiguration::GetRelayServerAddresses(
RelayType turn_type,
ProtocolType type) const {
ServerAddresses servers;
for (size_t i = 0; i < relays.size(); ++i) {
if (relays[i].type == turn_type && SupportsProtocol(relays[i], type)) {
if (SupportsProtocol(relays[i], type)) {
servers.insert(relays[i].ports.front().address);
}
}

View File

@ -316,11 +316,10 @@ struct RTC_EXPORT PortConfiguration : public rtc::MessageData {
// Determines whether the given relay server supports the given protocol.
bool SupportsProtocol(const RelayServerConfig& relay,
ProtocolType type) const;
bool SupportsProtocol(RelayType turn_type, ProtocolType type) const;
bool SupportsProtocol(ProtocolType type) const;
// Helper method returns the server addresses for the matching RelayType and
// Protocol type.
ServerAddresses GetRelayServerAddresses(RelayType turn_type,
ProtocolType type) const;
ServerAddresses GetRelayServerAddresses(ProtocolType type) const;
};
class UDPPort;
@ -388,7 +387,6 @@ class AllocationSequence : public rtc::MessageHandler,
void CreateTCPPorts();
void CreateStunPorts();
void CreateRelayPorts();
void CreateGturnPort(const RelayServerConfig& config);
void OnReadPacket(rtc::AsyncPacketSocket* socket,
const char* data,

View File

@ -19,7 +19,6 @@
#include "p2p/base/stun_port.h"
#include "p2p/base/stun_request.h"
#include "p2p/base/stun_server.h"
#include "p2p/base/test_relay_server.h"
#include "p2p/base/test_stun_server.h"
#include "p2p/base/test_turn_server.h"
#include "rtc_base/fake_clock.h"
@ -218,7 +217,7 @@ class BasicPortAllocatorTestBase : public ::testing::Test,
RelayServerConfig CreateTurnServers(const rtc::SocketAddress& udp_turn,
const rtc::SocketAddress& tcp_turn) {
RelayServerConfig turn_server(RELAY_TURN);
RelayServerConfig turn_server;
RelayCredentials credentials(kTurnUsername, kTurnPassword);
turn_server.credentials = credentials;
@ -1778,7 +1777,7 @@ TEST_F(BasicPortAllocatorTestWithRealClock,
AddInterface(kClientAddr);
allocator_.reset(new BasicPortAllocator(&network_manager_));
allocator_->Initialize();
RelayServerConfig turn_server(RELAY_TURN);
RelayServerConfig turn_server;
RelayCredentials credentials(kTurnUsername, kTurnPassword);
turn_server.credentials = credentials;
turn_server.ports.push_back(