diff --git a/AUTHORS b/AUTHORS index abe78142d..c5b7f7207 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,6 +9,7 @@ Christophe Dumez Colin Plumb Eric Rescorla, RTFM Inc. Giji Gangadharan +Graham Yoakum James H. Brown Jie Mao Luke Weber @@ -21,6 +22,7 @@ Rafael Lopez Diez Ralph Giles Robert Nagy Ron Rivest +Ryan Yoakum Sarah Thompson Saul Kravitz Silviu Caragea diff --git a/webrtc/libjingle/session/session_unittest.cc b/webrtc/libjingle/session/session_unittest.cc index c2ff1a791..e1168db26 100644 --- a/webrtc/libjingle/session/session_unittest.cc +++ b/webrtc/libjingle/session/session_unittest.cc @@ -598,7 +598,8 @@ class TestPortAllocatorSession : public cricket::PortAllocatorSession { ports_[i] = cricket::UDPPort::Create( rtc::Thread::Current(), &socket_factory_, &network_, address_.ipaddr(), GetPort(index), GetPort(index), - GetUsername(index), GetPassword(index)); + GetUsername(index), GetPassword(index), + std::string()); AddPort(ports_[i]); } running_ = true; diff --git a/webrtc/p2p/base/port.h b/webrtc/p2p/base/port.h index b78c2c554..4a5c89985 100644 --- a/webrtc/p2p/base/port.h +++ b/webrtc/p2p/base/port.h @@ -262,7 +262,7 @@ class Port : public PortInterface, public rtc::MessageHandler, // Debugging description of this port virtual std::string ToString() const; - rtc::IPAddress& ip() { return ip_; } + const rtc::IPAddress& ip() const { return ip_; } uint16 min_port() { return min_port_; } uint16 max_port() { return max_port_; } diff --git a/webrtc/p2p/base/port_unittest.cc b/webrtc/p2p/base/port_unittest.cc index f09db284b..26e46a699 100644 --- a/webrtc/p2p/base/port_unittest.cc +++ b/webrtc/p2p/base/port_unittest.cc @@ -207,7 +207,7 @@ class TestChannel : public sigslot::has_slots<> { // Takes ownership of |p1| (but not |p2|). TestChannel(Port* p1, Port* p2) : ice_mode_(ICEMODE_FULL), src_(p1), dst_(p2), complete_count_(0), - conn_(NULL), remote_request_(), nominated_(false) { + conn_(NULL), remote_request_(), nominated_(false) { src_->SignalPortComplete.connect( this, &TestChannel::OnPortComplete); src_->SignalUnknownAddress.connect(this, &TestChannel::OnUnknownAddress); @@ -413,7 +413,8 @@ class PortTest : public testing::Test, public sigslot::has_slots<> { UDPPort* CreateUdpPort(const SocketAddress& addr, PacketSocketFactory* socket_factory) { UDPPort* port = UDPPort::Create(main_, socket_factory, &network_, - addr.ipaddr(), 0, 0, username_, password_); + addr.ipaddr(), 0, 0, username_, password_, + std::string()); port->SetIceProtocolType(ice_protocol_); return port; } @@ -436,7 +437,8 @@ class PortTest : public testing::Test, public sigslot::has_slots<> { stun_servers.insert(kStunAddr); StunPort* port = StunPort::Create(main_, factory, &network_, addr.ipaddr(), 0, 0, - username_, password_, stun_servers); + username_, password_, stun_servers, + std::string()); port->SetIceProtocolType(ice_protocol_); return port; } @@ -461,8 +463,9 @@ class PortTest : public testing::Test, public sigslot::has_slots<> { TurnPort* port = TurnPort::Create(main_, socket_factory, &network_, addr.ipaddr(), 0, 0, username_, password_, ProtocolAddress( - server_addr, PROTO_UDP), - kRelayCredentials, 0); + server_addr, PROTO_UDP), + kRelayCredentials, 0, + std::string()); port->SetIceProtocolType(ice_protocol_); return port; } diff --git a/webrtc/p2p/base/portallocator.h b/webrtc/p2p/base/portallocator.h index 65aab44c6..1a3735b16 100644 --- a/webrtc/p2p/base/portallocator.h +++ b/webrtc/p2p/base/portallocator.h @@ -167,6 +167,10 @@ class PortAllocator : public sigslot::has_slots<> { return true; } + // Gets/Sets the Origin value used for WebRTC STUN requests. + const std::string& origin() const { return origin_; } + void set_origin(const std::string& origin) { origin_ = origin; } + protected: virtual PortAllocatorSession* CreateSessionInternal( const std::string& content_name, @@ -185,6 +189,7 @@ class PortAllocator : public sigslot::has_slots<> { SessionMuxerMap muxers_; bool allow_tcp_listen_; uint32 candidate_filter_; + std::string origin_; }; } // namespace cricket diff --git a/webrtc/p2p/base/stun.cc b/webrtc/p2p/base/stun.cc index 60367fa10..866621f75 100644 --- a/webrtc/p2p/base/stun.cc +++ b/webrtc/p2p/base/stun.cc @@ -387,6 +387,7 @@ StunAttributeValueType StunMessage::GetAttributeValueType(int type) const { case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING; case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS; case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32; + case STUN_ATTR_ORIGIN: return STUN_VALUE_BYTE_STRING; case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32; default: return STUN_VALUE_UNKNOWN; } diff --git a/webrtc/p2p/base/stun.h b/webrtc/p2p/base/stun.h index 0f600dbf7..4bf654788 100644 --- a/webrtc/p2p/base/stun.h +++ b/webrtc/p2p/base/stun.h @@ -48,6 +48,7 @@ enum StunAttributeType { STUN_ATTR_SOFTWARE = 0x8022, // ByteString STUN_ATTR_ALTERNATE_SERVER = 0x8023, // Address STUN_ATTR_FINGERPRINT = 0x8028, // UInt32 + STUN_ATTR_ORIGIN = 0x802F, // ByteString STUN_ATTR_RETRANSMIT_COUNT = 0xFF00 // UInt32 }; diff --git a/webrtc/p2p/base/stun_unittest.cc b/webrtc/p2p/base/stun_unittest.cc index 396beb6af..9d5779d7d 100644 --- a/webrtc/p2p/base/stun_unittest.cc +++ b/webrtc/p2p/base/stun_unittest.cc @@ -191,6 +191,20 @@ static const unsigned char kStunMessageWithErrorAttribute[] = { 0x69, 0x7a, 0x65, 0x64 }; +static const unsigned char kStunMessageWithOriginAttribute[] = { + 0x00, 0x01, 0x00, 0x18, // message header (binding request), length 24 + 0x21, 0x12, 0xA4, 0x42, // magic cookie + 0x29, 0x1f, 0xcd, 0x7c, // transaction id + 0xba, 0x58, 0xab, 0xd7, + 0xf2, 0x41, 0x01, 0x00, + 0x80, 0x2f, 0x00, 0x12, // origin attribute (length 18) + 0x68, 0x74, 0x74, 0x70, // http://example.com + 0x3A, 0x2F, 0x2F, 0x65, + 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x00, 0x00, +}; + // Sample messages with an invalid length Field // The actual length in bytes of the invalid messages (including STUN header) @@ -472,6 +486,7 @@ const in_addr kIPv4TestAddress1 = { { 0x0ac, 0x017, 0x044, 0x0e6 } }; const char kTestUserName1[] = "abcdefgh"; const char kTestUserName2[] = "abc"; const char kTestErrorReason[] = "Unauthorized"; +const char kTestOrigin[] = "http://example.com"; const int kTestErrorClass = 4; const int kTestErrorNumber = 1; const int kTestErrorCode = 401; @@ -1020,6 +1035,16 @@ TEST_F(StunTest, ReadMessageWithAnUnknownAttribute) { EXPECT_EQ(kTestUserName2, username->GetString()); } +TEST_F(StunTest, ReadMessageWithOriginAttribute) { + StunMessage msg; + size_t size = ReadStunMessage(&msg, kStunMessageWithOriginAttribute); + CheckStunHeader(msg, STUN_BINDING_REQUEST, size); + const StunByteStringAttribute* origin = + msg.GetByteString(STUN_ATTR_ORIGIN); + ASSERT_TRUE(origin != NULL); + EXPECT_EQ(kTestOrigin, origin->GetString()); +} + TEST_F(StunTest, WriteMessageWithAnErrorCodeAttribute) { StunMessage msg; size_t size = sizeof(kStunMessageWithErrorAttribute); @@ -1066,6 +1091,25 @@ TEST_F(StunTest, WriteMessageWithAUInt16ListAttribute) { memcmp(out.Data(), kStunMessageWithUInt16ListAttribute, size - 2)); } +TEST_F(StunTest, WriteMessageWithOriginAttribute) { + StunMessage msg; + size_t size = sizeof(kStunMessageWithOriginAttribute); + + msg.SetType(STUN_BINDING_REQUEST); + msg.SetTransactionID( + std::string(reinterpret_cast(kTestTransactionId1), + kStunTransactionIdLength)); + StunByteStringAttribute* origin = + new StunByteStringAttribute(STUN_ATTR_ORIGIN, kTestOrigin); + EXPECT_TRUE(msg.AddAttribute(origin)); + + rtc::ByteBuffer out; + EXPECT_TRUE(msg.Write(&out)); + ASSERT_EQ(size, out.Length()); + // Check everything up to the padding + ASSERT_EQ(0, memcmp(out.Data(), kStunMessageWithOriginAttribute, size - 2)); +} + // Test that we fail to read messages with invalid lengths. void CheckFailureToRead(const unsigned char* testcase, size_t length) { StunMessage msg; diff --git a/webrtc/p2p/base/stunport.cc b/webrtc/p2p/base/stunport.cc index 5ef9e9eac..fe125ec2b 100644 --- a/webrtc/p2p/base/stunport.cc +++ b/webrtc/p2p/base/stunport.cc @@ -163,7 +163,8 @@ UDPPort::UDPPort(rtc::Thread* thread, rtc::Network* network, rtc::AsyncPacketSocket* socket, const std::string& username, - const std::string& password) + const std::string& password, + const std::string& origin) : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(), username, password), requests_(thread), @@ -171,6 +172,7 @@ UDPPort::UDPPort(rtc::Thread* thread, error_(0), ready_(false), stun_keepalive_delay_(KEEPALIVE_DELAY) { + requests_.set_origin(origin); } UDPPort::UDPPort(rtc::Thread* thread, @@ -180,7 +182,8 @@ UDPPort::UDPPort(rtc::Thread* thread, uint16 min_port, uint16 max_port, const std::string& username, - const std::string& password) + const std::string& password, + const std::string& origin) : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port, username, password), requests_(thread), @@ -188,6 +191,7 @@ UDPPort::UDPPort(rtc::Thread* thread, error_(0), ready_(false), stun_keepalive_delay_(KEEPALIVE_DELAY) { + requests_.set_origin(origin); } bool UDPPort::Init() { diff --git a/webrtc/p2p/base/stunport.h b/webrtc/p2p/base/stunport.h index 9ca60462e..d840a9712 100644 --- a/webrtc/p2p/base/stunport.h +++ b/webrtc/p2p/base/stunport.h @@ -33,9 +33,10 @@ class UDPPort : public Port { rtc::Network* network, rtc::AsyncPacketSocket* socket, const std::string& username, - const std::string& password) { - UDPPort* port = - new UDPPort(thread, factory, network, socket, username, password); + const std::string& password, + const std::string& origin) { + UDPPort* port = new UDPPort(thread, factory, network, socket, + username, password, origin); if (!port->Init()) { delete port; port = NULL; @@ -50,15 +51,18 @@ class UDPPort : public Port { uint16 min_port, uint16 max_port, const std::string& username, - const std::string& password) { - UDPPort* port = new UDPPort(thread, factory, network, ip, min_port, - max_port, username, password); + const std::string& password, + const std::string& origin) { + UDPPort* port = new UDPPort(thread, factory, network, + ip, min_port, max_port, + username, password, origin); if (!port->Init()) { delete port; port = NULL; } return port; } + virtual ~UDPPort(); rtc::SocketAddress GetLocalAddress() const { @@ -105,14 +109,16 @@ class UDPPort : public Port { uint16 min_port, uint16 max_port, const std::string& username, - const std::string& password); + const std::string& password, + const std::string& origin); UDPPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, rtc::Network* network, rtc::AsyncPacketSocket* socket, const std::string& username, - const std::string& password); + const std::string& password, + const std::string& origin); bool Init(); @@ -208,9 +214,12 @@ class StunPort : public UDPPort { uint16 min_port, uint16 max_port, const std::string& username, const std::string& password, - const ServerAddresses& servers) { - StunPort* port = new StunPort(thread, factory, network, ip, min_port, - max_port, username, password, servers); + const ServerAddresses& servers, + const std::string& origin) { + StunPort* port = new StunPort(thread, factory, network, + ip, min_port, max_port, + username, password, servers, + origin); if (!port->Init()) { delete port; port = NULL; @@ -233,9 +242,10 @@ class StunPort : public UDPPort { uint16 max_port, const std::string& username, const std::string& password, - const ServerAddresses& servers) + const ServerAddresses& servers, + const std::string& origin) : UDPPort(thread, factory, network, ip, min_port, max_port, username, - password) { + password, origin) { // UDPPort will set these to local udp, updating these to STUN. set_type(STUN_PORT_TYPE); set_server_addresses(servers); diff --git a/webrtc/p2p/base/stunport_unittest.cc b/webrtc/p2p/base/stunport_unittest.cc index 81b680863..8b6e81b6d 100644 --- a/webrtc/p2p/base/stunport_unittest.cc +++ b/webrtc/p2p/base/stunport_unittest.cc @@ -65,7 +65,7 @@ class StunPortTest : public testing::Test, stun_port_.reset(cricket::StunPort::Create( rtc::Thread::Current(), &socket_factory_, &network_, kLocalAddr.ipaddr(), 0, 0, rtc::CreateRandomString(16), - rtc::CreateRandomString(22), stun_servers)); + rtc::CreateRandomString(22), stun_servers, std::string())); stun_port_->set_stun_keepalive_delay(stun_keepalive_delay_); stun_port_->SignalPortComplete.connect(this, &StunPortTest::OnPortComplete); @@ -81,7 +81,8 @@ class StunPortTest : public testing::Test, stun_port_.reset(cricket::UDPPort::Create( rtc::Thread::Current(), &socket_factory_, &network_, socket_.get(), - rtc::CreateRandomString(16), rtc::CreateRandomString(22))); + rtc::CreateRandomString(16), rtc::CreateRandomString(22), + std::string())); ASSERT_TRUE(stun_port_ != NULL); ServerAddresses stun_servers; stun_servers.insert(server_addr); diff --git a/webrtc/p2p/base/stunrequest.cc b/webrtc/p2p/base/stunrequest.cc index 65eb027f4..a6f4c1536 100644 --- a/webrtc/p2p/base/stunrequest.cc +++ b/webrtc/p2p/base/stunrequest.cc @@ -41,6 +41,7 @@ void StunRequestManager::Send(StunRequest* request) { void StunRequestManager::SendDelayed(StunRequest* request, int delay) { request->set_manager(this); ASSERT(requests_.find(request->id()) == requests_.end()); + request->set_origin(origin_); request->Construct(); requests_[request->id()] = request; thread_->PostDelayed(delay, request, MSG_STUN_SEND, NULL); @@ -138,6 +139,10 @@ StunRequest::~StunRequest() { void StunRequest::Construct() { if (msg_->type() == 0) { + if (!origin_.empty()) { + msg_->AddAttribute(new StunByteStringAttribute(STUN_ATTR_ORIGIN, + origin_)); + } Prepare(msg_); ASSERT(msg_->type() != 0); } diff --git a/webrtc/p2p/base/stunrequest.h b/webrtc/p2p/base/stunrequest.h index 5fefc2ff9..6a4bdc097 100644 --- a/webrtc/p2p/base/stunrequest.h +++ b/webrtc/p2p/base/stunrequest.h @@ -24,7 +24,7 @@ class StunRequest; // Manages a set of STUN requests, sending and resending until we receive a // response or determine that the request has timed out. class StunRequestManager { -public: + public: StunRequestManager(rtc::Thread* thread); ~StunRequestManager(); @@ -46,14 +46,18 @@ public: bool empty() { return requests_.empty(); } + // Set the Origin header for outgoing stun messages. + void set_origin(const std::string& origin) { origin_ = origin; } + // Raised when there are bytes to be sent. sigslot::signal3 SignalSendPacket; -private: + private: typedef std::map RequestMap; rtc::Thread* thread_; RequestMap requests_; + std::string origin_; friend class StunRequest; }; @@ -61,7 +65,7 @@ private: // Represents an individual request to be sent. The STUN message can either be // constructed beforehand or built on demand. class StunRequest : public rtc::MessageHandler { -public: + public: StunRequest(); StunRequest(StunMessage* request); virtual ~StunRequest(); @@ -75,6 +79,10 @@ public: // Returns the transaction ID of this request. const std::string& id() { return msg_->transaction_id(); } + // the origin value + const std::string& origin() const { return origin_; } + void set_origin(const std::string& origin) { origin_ = origin; } + // Returns the STUN type of the request message. int type(); @@ -84,9 +92,10 @@ public: // Time elapsed since last send (in ms) uint32 Elapsed() const; -protected: + protected: int count_; bool timeout_; + std::string origin_; // Fills in a request object to be sent. Note that request's transaction ID // will already be set and cannot be changed. @@ -98,7 +107,7 @@ protected: virtual void OnTimeout() {} virtual int GetNextDelay(); -private: + private: void set_manager(StunRequestManager* manager); // Handles messages for sending and timeout. diff --git a/webrtc/p2p/base/testturnserver.h b/webrtc/p2p/base/testturnserver.h index 19f73e7f8..7be35e534 100644 --- a/webrtc/p2p/base/testturnserver.h +++ b/webrtc/p2p/base/testturnserver.h @@ -87,6 +87,19 @@ class TestTurnServer : public TurnAuthInterface { } } + // Finds the first allocation in the server allocation map with a source + // ip and port matching the socket address provided. + TurnServerAllocation* FindAllocation(const rtc::SocketAddress& src) { + const TurnServer::AllocationMap& map = server_.allocations(); + for (TurnServer::AllocationMap::const_iterator it = map.begin(); + it != map.end(); ++it) { + if (src == it->first.src()) { + return it->second; + } + } + return NULL; + } + private: // For this test server, succeed if the password is the same as the username. // Obviously, do not use this in a production environment. diff --git a/webrtc/p2p/base/turnport.cc b/webrtc/p2p/base/turnport.cc index 8994aa895..2ea3ff445 100644 --- a/webrtc/p2p/base/turnport.cc +++ b/webrtc/p2p/base/turnport.cc @@ -164,7 +164,8 @@ TurnPort::TurnPort(rtc::Thread* thread, const std::string& password, const ProtocolAddress& server_address, const RelayCredentials& credentials, - int server_priority) + int server_priority, + const std::string& origin) : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(), username, password), server_address_(server_address), @@ -178,6 +179,7 @@ TurnPort::TurnPort(rtc::Thread* thread, server_priority_(server_priority), allocate_mismatch_retries_(0) { request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); + request_manager_.set_origin(origin); } TurnPort::TurnPort(rtc::Thread* thread, @@ -190,7 +192,8 @@ TurnPort::TurnPort(rtc::Thread* thread, const std::string& password, const ProtocolAddress& server_address, const RelayCredentials& credentials, - int server_priority) + int server_priority, + const std::string& origin) : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port, username, password), server_address_(server_address), @@ -204,6 +207,7 @@ TurnPort::TurnPort(rtc::Thread* thread, server_priority_(server_priority), allocate_mismatch_retries_(0) { request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); + request_manager_.set_origin(origin); } TurnPort::~TurnPort() { @@ -219,6 +223,10 @@ TurnPort::~TurnPort() { } } +rtc::SocketAddress TurnPort::GetLocalAddress() const { + return socket_ ? socket_->GetLocalAddress() : rtc::SocketAddress(); +} + void TurnPort::PrepareAddress() { if (credentials_.username.empty() || credentials_.password.empty()) { diff --git a/webrtc/p2p/base/turnport.h b/webrtc/p2p/base/turnport.h index 4ed77a0c1..3d3dad39e 100644 --- a/webrtc/p2p/base/turnport.h +++ b/webrtc/p2p/base/turnport.h @@ -41,9 +41,10 @@ class TurnPort : public Port { const std::string& password, // ice password. const ProtocolAddress& server_address, const RelayCredentials& credentials, - int server_priority) { + int server_priority, + const std::string& origin) { return new TurnPort(thread, factory, network, socket, username, password, - server_address, credentials, server_priority); + server_address, credentials, server_priority, origin); } static TurnPort* Create(rtc::Thread* thread, @@ -56,15 +57,18 @@ class TurnPort : public Port { const std::string& password, // ice password. const ProtocolAddress& server_address, const RelayCredentials& credentials, - int server_priority) { + int server_priority, + const std::string& origin) { return new TurnPort(thread, factory, network, ip, min_port, max_port, username, password, server_address, credentials, - server_priority); + server_priority, origin); } virtual ~TurnPort(); const ProtocolAddress& server_address() const { return server_address_; } + // Returns an empty address if the local address has not been assigned. + rtc::SocketAddress GetLocalAddress() const; bool connected() const { return connected_; } const RelayCredentials& credentials() const { return credentials_; } @@ -129,7 +133,8 @@ class TurnPort : public Port { const std::string& password, const ProtocolAddress& server_address, const RelayCredentials& credentials, - int server_priority); + int server_priority, + const std::string& origin); TurnPort(rtc::Thread* thread, rtc::PacketSocketFactory* factory, @@ -141,7 +146,8 @@ class TurnPort : public Port { const std::string& password, const ProtocolAddress& server_address, const RelayCredentials& credentials, - int server_priority); + int server_priority, + const std::string& origin); private: enum { diff --git a/webrtc/p2p/base/turnport_unittest.cc b/webrtc/p2p/base/turnport_unittest.cc index 748ed9d20..e871acab2 100644 --- a/webrtc/p2p/base/turnport_unittest.cc +++ b/webrtc/p2p/base/turnport_unittest.cc @@ -60,6 +60,7 @@ static const char kIcePwd1[] = "TESTICEPWD00000000000001"; static const char kIcePwd2[] = "TESTICEPWD00000000000002"; static const char kTurnUsername[] = "test"; static const char kTurnPassword[] = "test"; +static const char kTestOrigin[] = "http://example.com"; static const unsigned int kTimeout = 1000; static const cricket::ProtocolAddress kTurnUdpProtoAddr( @@ -193,7 +194,30 @@ class TurnPortTest : public testing::Test, turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_, local_address.ipaddr(), 0, 0, kIceUfrag1, kIcePwd1, - server_address, credentials, 0)); + server_address, credentials, 0, + std::string())); + // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be + // in Hybrid mode. Protocol type is necessary to send correct type STUN ping + // messages. + // This TURN port will be the controlling. + turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); + turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING); + ConnectSignals(); + } + + // Should be identical to CreateTurnPort but specifies an origin value + // when creating the instance of TurnPort. + void CreateTurnPortWithOrigin(const rtc::SocketAddress& local_address, + const std::string& username, + const std::string& password, + const cricket::ProtocolAddress& server_address, + const std::string& origin) { + cricket::RelayCredentials credentials(username, password); + turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_, + local_address.ipaddr(), 0, 0, + kIceUfrag1, kIcePwd1, + server_address, credentials, 0, + origin)); // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be // in Hybrid mode. Protocol type is necessary to send correct type STUN ping // messages. @@ -219,7 +243,7 @@ class TurnPortTest : public testing::Test, cricket::RelayCredentials credentials(username, password); turn_port_.reset(cricket::TurnPort::Create( main_, &socket_factory_, &network_, socket_.get(), - kIceUfrag1, kIcePwd1, server_address, credentials, 0)); + kIceUfrag1, kIcePwd1, server_address, credentials, 0, std::string())); // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be // in Hybrid mode. Protocol type is necessary to send correct type STUN ping // messages. @@ -242,7 +266,8 @@ class TurnPortTest : public testing::Test, void CreateUdpPort() { udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_, kLocalAddr2.ipaddr(), 0, 0, - kIceUfrag2, kIcePwd2)); + kIceUfrag2, kIcePwd2, + std::string())); // Set protocol type to RFC5245, as turn port is also in same mode. // UDP port will be controlled. udp_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); @@ -685,6 +710,17 @@ TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) { EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); } +TEST_F(TurnPortTest, TestOriginHeader) { + CreateTurnPortWithOrigin(kLocalAddr1, kTurnUsername, kTurnPassword, + kTurnUdpProtoAddr, kTestOrigin); + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + ASSERT_GT(turn_server_.server()->allocations().size(), 0U); + SocketAddress local_address = turn_port_->GetLocalAddress(); + ASSERT_TRUE(turn_server_.FindAllocation(local_address) != NULL); + EXPECT_EQ(kTestOrigin, turn_server_.FindAllocation(local_address)->origin()); +} + // This test verifies any FD's are not leaked after TurnPort is destroyed. // https://code.google.com/p/webrtc/issues/detail?id=2651 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) diff --git a/webrtc/p2p/base/turnserver.cc b/webrtc/p2p/base/turnserver.cc index 8605e98da..7d82d55c5 100644 --- a/webrtc/p2p/base/turnserver.cc +++ b/webrtc/p2p/base/turnserver.cc @@ -45,88 +45,15 @@ inline bool IsTurnChannelData(uint16 msg_type) { return ((msg_type & 0xC000) == 0x4000); } -// IDs used for posted messages for TurnServer::Allocation. +// IDs used for posted messages for TurnServerAllocation. enum { MSG_ALLOCATION_TIMEOUT, }; -// Encapsulates a TURN allocation. -// The object is created when an allocation request is received, and then -// handles TURN messages (via HandleTurnMessage) and channel data messages -// (via HandleChannelData) for this allocation when received by the server. -// The object self-deletes and informs the server if its lifetime timer expires. -class TurnServer::Allocation : public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - Allocation(TurnServer* server_, - rtc::Thread* thread, const Connection& conn, - rtc::AsyncPacketSocket* server_socket, - const std::string& key); - virtual ~Allocation(); - - Connection* conn() { return &conn_; } - const std::string& key() const { return key_; } - const std::string& transaction_id() const { return transaction_id_; } - const std::string& username() const { return username_; } - const std::string& last_nonce() const { return last_nonce_; } - void set_last_nonce(const std::string& nonce) { last_nonce_ = nonce; } - - std::string ToString() const; - - void HandleTurnMessage(const TurnMessage* msg); - void HandleChannelData(const char* data, size_t size); - - sigslot::signal1 SignalDestroyed; - - private: - typedef std::list PermissionList; - typedef std::list ChannelList; - - void HandleAllocateRequest(const TurnMessage* msg); - void HandleRefreshRequest(const TurnMessage* msg); - void HandleSendIndication(const TurnMessage* msg); - void HandleCreatePermissionRequest(const TurnMessage* msg); - void HandleChannelBindRequest(const TurnMessage* msg); - - void OnExternalPacket(rtc::AsyncPacketSocket* socket, - const char* data, size_t size, - const rtc::SocketAddress& addr, - const rtc::PacketTime& packet_time); - - static int ComputeLifetime(const TurnMessage* msg); - bool HasPermission(const rtc::IPAddress& addr); - void AddPermission(const rtc::IPAddress& addr); - Permission* FindPermission(const rtc::IPAddress& addr) const; - Channel* FindChannel(int channel_id) const; - Channel* FindChannel(const rtc::SocketAddress& addr) const; - - void SendResponse(TurnMessage* msg); - void SendBadRequestResponse(const TurnMessage* req); - void SendErrorResponse(const TurnMessage* req, int code, - const std::string& reason); - void SendExternal(const void* data, size_t size, - const rtc::SocketAddress& peer); - - void OnPermissionDestroyed(Permission* perm); - void OnChannelDestroyed(Channel* channel); - virtual void OnMessage(rtc::Message* msg); - - TurnServer* server_; - rtc::Thread* thread_; - Connection conn_; - rtc::scoped_ptr external_socket_; - std::string key_; - std::string transaction_id_; - std::string username_; - std::string last_nonce_; - PermissionList perms_; - ChannelList channels_; -}; - // Encapsulates a TURN permission. // The object is created when a create permission request is received by an // allocation, and self-deletes when its lifetime timer expires. -class TurnServer::Permission : public rtc::MessageHandler { +class TurnServerAllocation::Permission : public rtc::MessageHandler { public: Permission(rtc::Thread* thread, const rtc::IPAddress& peer); ~Permission(); @@ -146,7 +73,7 @@ class TurnServer::Permission : public rtc::MessageHandler { // Encapsulates a TURN channel binding. // The object is created when a channel bind request is received by an // allocation, and self-deletes when its lifetime timer expires. -class TurnServer::Channel : public rtc::MessageHandler { +class TurnServerAllocation::Channel : public rtc::MessageHandler { public: Channel(rtc::Thread* thread, int id, const rtc::SocketAddress& peer); @@ -187,6 +114,7 @@ static bool InitErrorResponse(const StunMessage* req, int code, return true; } + TurnServer::TurnServer(rtc::Thread* thread) : thread_(thread), nonce_key_(rtc::CreateRandomString(kNonceKeySize)), @@ -271,21 +199,21 @@ void TurnServer::OnInternalPacket(rtc::AsyncPacketSocket* socket, } InternalSocketMap::iterator iter = server_sockets_.find(socket); ASSERT(iter != server_sockets_.end()); - Connection conn(addr, iter->second, socket); + TurnServerConnection conn(addr, iter->second, socket); uint16 msg_type = rtc::GetBE16(data); if (!IsTurnChannelData(msg_type)) { // This is a STUN message. HandleStunMessage(&conn, data, size); } else { // This is a channel message; let the allocation handle it. - Allocation* allocation = FindAllocation(&conn); + TurnServerAllocation* allocation = FindAllocation(&conn); if (allocation) { allocation->HandleChannelData(data, size); } } } -void TurnServer::HandleStunMessage(Connection* conn, const char* data, +void TurnServer::HandleStunMessage(TurnServerConnection* conn, const char* data, size_t size) { TurnMessage msg; rtc::ByteBuffer buf(data, size); @@ -311,7 +239,7 @@ void TurnServer::HandleStunMessage(Connection* conn, const char* data, // Look up the key that we'll use to validate the M-I. If we have an // existing allocation, the key will already be cached. - Allocation* allocation = FindAllocation(conn); + TurnServerAllocation* allocation = FindAllocation(conn); std::string key; if (!allocation) { GetKey(&msg, &key); @@ -359,7 +287,7 @@ bool TurnServer::GetKey(const StunMessage* msg, std::string* key) { return (auth_hook_ != NULL && auth_hook_->GetKey(username, realm_, key)); } -bool TurnServer::CheckAuthorization(Connection* conn, +bool TurnServer::CheckAuthorization(TurnServerConnection* conn, const StunMessage* msg, const char* data, size_t size, const std::string& key) { @@ -404,7 +332,7 @@ bool TurnServer::CheckAuthorization(Connection* conn, } // Fail if one-time-use nonce feature is enabled. - Allocation* allocation = FindAllocation(conn); + TurnServerAllocation* allocation = FindAllocation(conn); if (enable_otu_nonce_ && allocation && allocation->last_nonce() == nonce_attr->GetString()) { SendErrorResponseWithRealmAndNonce(conn, msg, STUN_ERROR_STALE_NONCE, @@ -419,7 +347,7 @@ bool TurnServer::CheckAuthorization(Connection* conn, return true; } -void TurnServer::HandleBindingRequest(Connection* conn, +void TurnServer::HandleBindingRequest(TurnServerConnection* conn, const StunMessage* req) { StunMessage response; InitResponse(req, &response); @@ -433,7 +361,7 @@ void TurnServer::HandleBindingRequest(Connection* conn, SendStun(conn, &response); } -void TurnServer::HandleAllocateRequest(Connection* conn, +void TurnServer::HandleAllocateRequest(TurnServerConnection* conn, const TurnMessage* msg, const std::string& key) { // Check the parameters in the request. @@ -455,7 +383,7 @@ void TurnServer::HandleAllocateRequest(Connection* conn, // Create the allocation and let it send the success response. // If the actual socket allocation fails, send an internal error. - Allocation* alloc = CreateAllocation(conn, proto, key); + TurnServerAllocation* alloc = CreateAllocation(conn, proto, key); if (alloc) { alloc->HandleTurnMessage(msg); } else { @@ -499,14 +427,14 @@ bool TurnServer::ValidateNonce(const std::string& nonce) const { return rtc::TimeSince(then) < kNonceTimeout; } -TurnServer::Allocation* TurnServer::FindAllocation(Connection* conn) { +TurnServerAllocation* TurnServer::FindAllocation(TurnServerConnection* conn) { AllocationMap::const_iterator it = allocations_.find(*conn); return (it != allocations_.end()) ? it->second : NULL; } -TurnServer::Allocation* TurnServer::CreateAllocation(Connection* conn, - int proto, - const std::string& key) { +TurnServerAllocation* TurnServer::CreateAllocation(TurnServerConnection* conn, + int proto, + const std::string& key) { rtc::AsyncPacketSocket* external_socket = (external_socket_factory_) ? external_socket_factory_->CreateUdpSocket(external_addr_, 0, 0) : NULL; if (!external_socket) { @@ -514,14 +442,14 @@ TurnServer::Allocation* TurnServer::CreateAllocation(Connection* conn, } // The Allocation takes ownership of the socket. - Allocation* allocation = new Allocation(this, + TurnServerAllocation* allocation = new TurnServerAllocation(this, thread_, *conn, external_socket, key); allocation->SignalDestroyed.connect(this, &TurnServer::OnAllocationDestroyed); allocations_[*conn] = allocation; return allocation; } -void TurnServer::SendErrorResponse(Connection* conn, +void TurnServer::SendErrorResponse(TurnServerConnection* conn, const StunMessage* req, int code, const std::string& reason) { TurnMessage resp; @@ -532,7 +460,7 @@ void TurnServer::SendErrorResponse(Connection* conn, } void TurnServer::SendErrorResponseWithRealmAndNonce( - Connection* conn, const StunMessage* msg, + TurnServerConnection* conn, const StunMessage* msg, int code, const std::string& reason) { TurnMessage resp; InitErrorResponse(msg, code, reason, &resp); @@ -544,7 +472,7 @@ void TurnServer::SendErrorResponseWithRealmAndNonce( } void TurnServer::SendErrorResponseWithAlternateServer( - Connection* conn, const StunMessage* msg, + TurnServerConnection* conn, const StunMessage* msg, const rtc::SocketAddress& addr) { TurnMessage resp; InitErrorResponse(msg, STUN_ERROR_TRY_ALTERNATE, @@ -554,7 +482,7 @@ void TurnServer::SendErrorResponseWithAlternateServer( SendStun(conn, &resp); } -void TurnServer::SendStun(Connection* conn, StunMessage* msg) { +void TurnServer::SendStun(TurnServerConnection* conn, StunMessage* msg) { rtc::ByteBuffer buf; // Add a SOFTWARE attribute if one is set. if (!software_.empty()) { @@ -565,13 +493,13 @@ void TurnServer::SendStun(Connection* conn, StunMessage* msg) { Send(conn, buf); } -void TurnServer::Send(Connection* conn, +void TurnServer::Send(TurnServerConnection* conn, const rtc::ByteBuffer& buf) { rtc::PacketOptions options; conn->socket()->SendTo(buf.Data(), buf.Length(), conn->src(), options); } -void TurnServer::OnAllocationDestroyed(Allocation* allocation) { +void TurnServer::OnAllocationDestroyed(TurnServerAllocation* allocation) { // Removing the internal socket if the connection is not udp. rtc::AsyncPacketSocket* socket = allocation->conn()->socket(); InternalSocketMap::iterator iter = server_sockets_.find(socket); @@ -598,24 +526,24 @@ void TurnServer::DestroyInternalSocket(rtc::AsyncPacketSocket* socket) { } } -TurnServer::Connection::Connection(const rtc::SocketAddress& src, - ProtocolType proto, - rtc::AsyncPacketSocket* socket) +TurnServerConnection::TurnServerConnection(const rtc::SocketAddress& src, + ProtocolType proto, + rtc::AsyncPacketSocket* socket) : src_(src), dst_(socket->GetRemoteAddress()), proto_(proto), socket_(socket) { } -bool TurnServer::Connection::operator==(const Connection& c) const { +bool TurnServerConnection::operator==(const TurnServerConnection& c) const { return src_ == c.src_ && dst_ == c.dst_ && proto_ == c.proto_; } -bool TurnServer::Connection::operator<(const Connection& c) const { +bool TurnServerConnection::operator<(const TurnServerConnection& c) const { return src_ < c.src_ || dst_ < c.dst_ || proto_ < c.proto_; } -std::string TurnServer::Connection::ToString() const { +std::string TurnServerConnection::ToString() const { const char* const kProtos[] = { "unknown", "udp", "tcp", "ssltcp" }; @@ -624,21 +552,21 @@ std::string TurnServer::Connection::ToString() const { return ost.str(); } -TurnServer::Allocation::Allocation(TurnServer* server, - rtc::Thread* thread, - const Connection& conn, - rtc::AsyncPacketSocket* socket, - const std::string& key) +TurnServerAllocation::TurnServerAllocation(TurnServer* server, + rtc::Thread* thread, + const TurnServerConnection& conn, + rtc::AsyncPacketSocket* socket, + const std::string& key) : server_(server), thread_(thread), conn_(conn), external_socket_(socket), key_(key) { external_socket_->SignalReadPacket.connect( - this, &TurnServer::Allocation::OnExternalPacket); + this, &TurnServerAllocation::OnExternalPacket); } -TurnServer::Allocation::~Allocation() { +TurnServerAllocation::~TurnServerAllocation() { for (ChannelList::iterator it = channels_.begin(); it != channels_.end(); ++it) { delete *it; @@ -651,13 +579,13 @@ TurnServer::Allocation::~Allocation() { LOG_J(LS_INFO, this) << "Allocation destroyed"; } -std::string TurnServer::Allocation::ToString() const { +std::string TurnServerAllocation::ToString() const { std::ostringstream ost; ost << "Alloc[" << conn_.ToString() << "]"; return ost.str(); } -void TurnServer::Allocation::HandleTurnMessage(const TurnMessage* msg) { +void TurnServerAllocation::HandleTurnMessage(const TurnMessage* msg) { ASSERT(msg != NULL); switch (msg->type()) { case STUN_ALLOCATE_REQUEST: @@ -682,13 +610,18 @@ void TurnServer::Allocation::HandleTurnMessage(const TurnMessage* msg) { } } -void TurnServer::Allocation::HandleAllocateRequest(const TurnMessage* msg) { +void TurnServerAllocation::HandleAllocateRequest(const TurnMessage* msg) { // Copy the important info from the allocate request. transaction_id_ = msg->transaction_id(); const StunByteStringAttribute* username_attr = msg->GetByteString(STUN_ATTR_USERNAME); ASSERT(username_attr != NULL); username_ = username_attr->GetString(); + const StunByteStringAttribute* origin_attr = + msg->GetByteString(STUN_ATTR_ORIGIN); + if (origin_attr) { + origin_ = origin_attr->GetString(); + } // Figure out the lifetime and start the allocation timer. int lifetime_secs = ComputeLifetime(msg); @@ -714,7 +647,7 @@ void TurnServer::Allocation::HandleAllocateRequest(const TurnMessage* msg) { SendResponse(&response); } -void TurnServer::Allocation::HandleRefreshRequest(const TurnMessage* msg) { +void TurnServerAllocation::HandleRefreshRequest(const TurnMessage* msg) { // Figure out the new lifetime. int lifetime_secs = ComputeLifetime(msg); @@ -735,7 +668,7 @@ void TurnServer::Allocation::HandleRefreshRequest(const TurnMessage* msg) { SendResponse(&response); } -void TurnServer::Allocation::HandleSendIndication(const TurnMessage* msg) { +void TurnServerAllocation::HandleSendIndication(const TurnMessage* msg) { // Check mandatory attributes. const StunByteStringAttribute* data_attr = msg->GetByteString(STUN_ATTR_DATA); const StunAddressAttribute* peer_attr = @@ -755,7 +688,7 @@ void TurnServer::Allocation::HandleSendIndication(const TurnMessage* msg) { } } -void TurnServer::Allocation::HandleCreatePermissionRequest( +void TurnServerAllocation::HandleCreatePermissionRequest( const TurnMessage* msg) { // Check mandatory attributes. const StunAddressAttribute* peer_attr = @@ -777,7 +710,7 @@ void TurnServer::Allocation::HandleCreatePermissionRequest( SendResponse(&response); } -void TurnServer::Allocation::HandleChannelBindRequest(const TurnMessage* msg) { +void TurnServerAllocation::HandleChannelBindRequest(const TurnMessage* msg) { // Check mandatory attributes. const StunUInt32Attribute* channel_attr = msg->GetUInt32(STUN_ATTR_CHANNEL_NUMBER); @@ -808,7 +741,7 @@ void TurnServer::Allocation::HandleChannelBindRequest(const TurnMessage* msg) { if (!channel1) { channel1 = new Channel(thread_, channel_id, peer_attr->GetAddress()); channel1->SignalDestroyed.connect(this, - &TurnServer::Allocation::OnChannelDestroyed); + &TurnServerAllocation::OnChannelDestroyed); channels_.push_back(channel1); } else { channel1->Refresh(); @@ -826,7 +759,7 @@ void TurnServer::Allocation::HandleChannelBindRequest(const TurnMessage* msg) { SendResponse(&response); } -void TurnServer::Allocation::HandleChannelData(const char* data, size_t size) { +void TurnServerAllocation::HandleChannelData(const char* data, size_t size) { // Extract the channel number from the data. uint16 channel_id = rtc::GetBE16(data); Channel* channel = FindChannel(channel_id); @@ -840,7 +773,7 @@ void TurnServer::Allocation::HandleChannelData(const char* data, size_t size) { } } -void TurnServer::Allocation::OnExternalPacket( +void TurnServerAllocation::OnExternalPacket( rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& addr, @@ -871,7 +804,7 @@ void TurnServer::Allocation::OnExternalPacket( } } -int TurnServer::Allocation::ComputeLifetime(const TurnMessage* msg) { +int TurnServerAllocation::ComputeLifetime(const TurnMessage* msg) { // Return the smaller of our default lifetime and the requested lifetime. uint32 lifetime = kDefaultAllocationTimeout / 1000; // convert to seconds const StunUInt32Attribute* lifetime_attr = msg->GetUInt32(STUN_ATTR_LIFETIME); @@ -881,23 +814,23 @@ int TurnServer::Allocation::ComputeLifetime(const TurnMessage* msg) { return lifetime; } -bool TurnServer::Allocation::HasPermission(const rtc::IPAddress& addr) { +bool TurnServerAllocation::HasPermission(const rtc::IPAddress& addr) { return (FindPermission(addr) != NULL); } -void TurnServer::Allocation::AddPermission(const rtc::IPAddress& addr) { +void TurnServerAllocation::AddPermission(const rtc::IPAddress& addr) { Permission* perm = FindPermission(addr); if (!perm) { perm = new Permission(thread_, addr); perm->SignalDestroyed.connect( - this, &TurnServer::Allocation::OnPermissionDestroyed); + this, &TurnServerAllocation::OnPermissionDestroyed); perms_.push_back(perm); } else { perm->Refresh(); } } -TurnServer::Permission* TurnServer::Allocation::FindPermission( +TurnServerAllocation::Permission* TurnServerAllocation::FindPermission( const rtc::IPAddress& addr) const { for (PermissionList::const_iterator it = perms_.begin(); it != perms_.end(); ++it) { @@ -907,7 +840,8 @@ TurnServer::Permission* TurnServer::Allocation::FindPermission( return NULL; } -TurnServer::Channel* TurnServer::Allocation::FindChannel(int channel_id) const { +TurnServerAllocation::Channel* TurnServerAllocation::FindChannel( + int channel_id) const { for (ChannelList::const_iterator it = channels_.begin(); it != channels_.end(); ++it) { if ((*it)->id() == channel_id) @@ -916,7 +850,7 @@ TurnServer::Channel* TurnServer::Allocation::FindChannel(int channel_id) const { return NULL; } -TurnServer::Channel* TurnServer::Allocation::FindChannel( +TurnServerAllocation::Channel* TurnServerAllocation::FindChannel( const rtc::SocketAddress& addr) const { for (ChannelList::const_iterator it = channels_.begin(); it != channels_.end(); ++it) { @@ -926,83 +860,83 @@ TurnServer::Channel* TurnServer::Allocation::FindChannel( return NULL; } -void TurnServer::Allocation::SendResponse(TurnMessage* msg) { +void TurnServerAllocation::SendResponse(TurnMessage* msg) { // Success responses always have M-I. msg->AddMessageIntegrity(key_); server_->SendStun(&conn_, msg); } -void TurnServer::Allocation::SendBadRequestResponse(const TurnMessage* req) { +void TurnServerAllocation::SendBadRequestResponse(const TurnMessage* req) { SendErrorResponse(req, STUN_ERROR_BAD_REQUEST, STUN_ERROR_REASON_BAD_REQUEST); } -void TurnServer::Allocation::SendErrorResponse(const TurnMessage* req, int code, +void TurnServerAllocation::SendErrorResponse(const TurnMessage* req, int code, const std::string& reason) { server_->SendErrorResponse(&conn_, req, code, reason); } -void TurnServer::Allocation::SendExternal(const void* data, size_t size, +void TurnServerAllocation::SendExternal(const void* data, size_t size, const rtc::SocketAddress& peer) { rtc::PacketOptions options; external_socket_->SendTo(data, size, peer, options); } -void TurnServer::Allocation::OnMessage(rtc::Message* msg) { +void TurnServerAllocation::OnMessage(rtc::Message* msg) { ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); SignalDestroyed(this); delete this; } -void TurnServer::Allocation::OnPermissionDestroyed(Permission* perm) { +void TurnServerAllocation::OnPermissionDestroyed(Permission* perm) { PermissionList::iterator it = std::find(perms_.begin(), perms_.end(), perm); ASSERT(it != perms_.end()); perms_.erase(it); } -void TurnServer::Allocation::OnChannelDestroyed(Channel* channel) { +void TurnServerAllocation::OnChannelDestroyed(Channel* channel) { ChannelList::iterator it = std::find(channels_.begin(), channels_.end(), channel); ASSERT(it != channels_.end()); channels_.erase(it); } -TurnServer::Permission::Permission(rtc::Thread* thread, +TurnServerAllocation::Permission::Permission(rtc::Thread* thread, const rtc::IPAddress& peer) : thread_(thread), peer_(peer) { Refresh(); } -TurnServer::Permission::~Permission() { +TurnServerAllocation::Permission::~Permission() { thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); } -void TurnServer::Permission::Refresh() { +void TurnServerAllocation::Permission::Refresh() { thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); thread_->PostDelayed(kPermissionTimeout, this, MSG_ALLOCATION_TIMEOUT); } -void TurnServer::Permission::OnMessage(rtc::Message* msg) { +void TurnServerAllocation::Permission::OnMessage(rtc::Message* msg) { ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); SignalDestroyed(this); delete this; } -TurnServer::Channel::Channel(rtc::Thread* thread, int id, +TurnServerAllocation::Channel::Channel(rtc::Thread* thread, int id, const rtc::SocketAddress& peer) : thread_(thread), id_(id), peer_(peer) { Refresh(); } -TurnServer::Channel::~Channel() { +TurnServerAllocation::Channel::~Channel() { thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); } -void TurnServer::Channel::Refresh() { +void TurnServerAllocation::Channel::Refresh() { thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); thread_->PostDelayed(kChannelTimeout, this, MSG_ALLOCATION_TIMEOUT); } -void TurnServer::Channel::OnMessage(rtc::Message* msg) { +void TurnServerAllocation::Channel::OnMessage(rtc::Message* msg) { ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); SignalDestroyed(this); delete this; diff --git a/webrtc/p2p/base/turnserver.h b/webrtc/p2p/base/turnserver.h index 670b61804..d3bd77a86 100644 --- a/webrtc/p2p/base/turnserver.h +++ b/webrtc/p2p/base/turnserver.h @@ -32,10 +32,109 @@ namespace cricket { class StunMessage; class TurnMessage; +class TurnServer; // The default server port for TURN, as specified in RFC5766. const int TURN_SERVER_PORT = 3478; +// Encapsulates the client's connection to the server. +class TurnServerConnection { + public: + TurnServerConnection() : proto_(PROTO_UDP), socket_(NULL) {} + TurnServerConnection(const rtc::SocketAddress& src, + ProtocolType proto, + rtc::AsyncPacketSocket* socket); + const rtc::SocketAddress& src() const { return src_; } + rtc::AsyncPacketSocket* socket() { return socket_; } + bool operator==(const TurnServerConnection& t) const; + bool operator<(const TurnServerConnection& t) const; + std::string ToString() const; + + private: + rtc::SocketAddress src_; + rtc::SocketAddress dst_; + cricket::ProtocolType proto_; + rtc::AsyncPacketSocket* socket_; +}; + +// Encapsulates a TURN allocation. +// The object is created when an allocation request is received, and then +// handles TURN messages (via HandleTurnMessage) and channel data messages +// (via HandleChannelData) for this allocation when received by the server. +// The object self-deletes and informs the server if its lifetime timer expires. +class TurnServerAllocation : public rtc::MessageHandler, + public sigslot::has_slots<> { + public: + TurnServerAllocation(TurnServer* server_, + rtc::Thread* thread, + const TurnServerConnection& conn, + rtc::AsyncPacketSocket* server_socket, + const std::string& key); + virtual ~TurnServerAllocation(); + + TurnServerConnection* conn() { return &conn_; } + const std::string& key() const { return key_; } + const std::string& transaction_id() const { return transaction_id_; } + const std::string& username() const { return username_; } + const std::string& origin() const { return origin_; } + const std::string& last_nonce() const { return last_nonce_; } + void set_last_nonce(const std::string& nonce) { last_nonce_ = nonce; } + + std::string ToString() const; + + void HandleTurnMessage(const TurnMessage* msg); + void HandleChannelData(const char* data, size_t size); + + sigslot::signal1 SignalDestroyed; + + private: + class Channel; + class Permission; + typedef std::list PermissionList; + typedef std::list ChannelList; + + void HandleAllocateRequest(const TurnMessage* msg); + void HandleRefreshRequest(const TurnMessage* msg); + void HandleSendIndication(const TurnMessage* msg); + void HandleCreatePermissionRequest(const TurnMessage* msg); + void HandleChannelBindRequest(const TurnMessage* msg); + + void OnExternalPacket(rtc::AsyncPacketSocket* socket, + const char* data, size_t size, + const rtc::SocketAddress& addr, + const rtc::PacketTime& packet_time); + + static int ComputeLifetime(const TurnMessage* msg); + bool HasPermission(const rtc::IPAddress& addr); + void AddPermission(const rtc::IPAddress& addr); + Permission* FindPermission(const rtc::IPAddress& addr) const; + Channel* FindChannel(int channel_id) const; + Channel* FindChannel(const rtc::SocketAddress& addr) const; + + void SendResponse(TurnMessage* msg); + void SendBadRequestResponse(const TurnMessage* req); + void SendErrorResponse(const TurnMessage* req, int code, + const std::string& reason); + void SendExternal(const void* data, size_t size, + const rtc::SocketAddress& peer); + + void OnPermissionDestroyed(Permission* perm); + void OnChannelDestroyed(Channel* channel); + virtual void OnMessage(rtc::Message* msg); + + TurnServer* server_; + rtc::Thread* thread_; + TurnServerConnection conn_; + rtc::scoped_ptr external_socket_; + std::string key_; + std::string transaction_id_; + std::string username_; + std::string origin_; + std::string last_nonce_; + PermissionList perms_; + ChannelList channels_; +}; + // An interface through which the MD5 credential hash can be retrieved. class TurnAuthInterface { public: @@ -60,6 +159,8 @@ class TurnRedirectInterface { // Not yet wired up: TCP support. class TurnServer : public sigslot::has_slots<> { public: + typedef std::map AllocationMap; + explicit TurnServer(rtc::Thread* thread); ~TurnServer(); @@ -71,6 +172,8 @@ class TurnServer : public sigslot::has_slots<> { const std::string& software() const { return software_; } void set_software(const std::string& software) { software_ = software; } + const AllocationMap& allocations() const { return allocations_; } + // Sets the authentication callback; does not take ownership. void set_auth_hook(TurnAuthInterface* auth_hook) { auth_hook_ = auth_hook; } @@ -93,30 +196,6 @@ class TurnServer : public sigslot::has_slots<> { const rtc::SocketAddress& address); private: - // Encapsulates the client's connection to the server. - class Connection { - public: - Connection() : proto_(PROTO_UDP), socket_(NULL) {} - Connection(const rtc::SocketAddress& src, - ProtocolType proto, - rtc::AsyncPacketSocket* socket); - const rtc::SocketAddress& src() const { return src_; } - rtc::AsyncPacketSocket* socket() { return socket_; } - bool operator==(const Connection& t) const; - bool operator<(const Connection& t) const; - std::string ToString() const; - - private: - rtc::SocketAddress src_; - rtc::SocketAddress dst_; - cricket::ProtocolType proto_; - rtc::AsyncPacketSocket* socket_; - }; - class Allocation; - class Permission; - class Channel; - typedef std::map AllocationMap; - void OnInternalPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& address, const rtc::PacketTime& packet_time); @@ -127,38 +206,39 @@ class TurnServer : public sigslot::has_slots<> { void AcceptConnection(rtc::AsyncSocket* server_socket); void OnInternalSocketClose(rtc::AsyncPacketSocket* socket, int err); - void HandleStunMessage(Connection* conn, const char* data, size_t size); - void HandleBindingRequest(Connection* conn, const StunMessage* msg); - void HandleAllocateRequest(Connection* conn, const TurnMessage* msg, + void HandleStunMessage( + TurnServerConnection* conn, const char* data, size_t size); + void HandleBindingRequest(TurnServerConnection* conn, const StunMessage* msg); + void HandleAllocateRequest(TurnServerConnection* conn, const TurnMessage* msg, const std::string& key); bool GetKey(const StunMessage* msg, std::string* key); - bool CheckAuthorization(Connection* conn, const StunMessage* msg, + bool CheckAuthorization(TurnServerConnection* conn, const StunMessage* msg, const char* data, size_t size, const std::string& key); std::string GenerateNonce() const; bool ValidateNonce(const std::string& nonce) const; - Allocation* FindAllocation(Connection* conn); - Allocation* CreateAllocation(Connection* conn, int proto, - const std::string& key); + TurnServerAllocation* FindAllocation(TurnServerConnection* conn); + TurnServerAllocation* CreateAllocation( + TurnServerConnection* conn, int proto, const std::string& key); - void SendErrorResponse(Connection* conn, const StunMessage* req, + void SendErrorResponse(TurnServerConnection* conn, const StunMessage* req, int code, const std::string& reason); - void SendErrorResponseWithRealmAndNonce(Connection* conn, + void SendErrorResponseWithRealmAndNonce(TurnServerConnection* conn, const StunMessage* req, int code, const std::string& reason); - void SendErrorResponseWithAlternateServer(Connection* conn, + void SendErrorResponseWithAlternateServer(TurnServerConnection* conn, const StunMessage* req, const rtc::SocketAddress& addr); - void SendStun(Connection* conn, StunMessage* msg); - void Send(Connection* conn, const rtc::ByteBuffer& buf); + void SendStun(TurnServerConnection* conn, StunMessage* msg); + void Send(TurnServerConnection* conn, const rtc::ByteBuffer& buf); - void OnAllocationDestroyed(Allocation* allocation); + void OnAllocationDestroyed(TurnServerAllocation* allocation); void DestroyInternalSocket(rtc::AsyncPacketSocket* socket); typedef std::map { rtc::SocketAddress external_addr_; AllocationMap allocations_; + + friend class TurnServerAllocation; }; } // namespace cricket diff --git a/webrtc/p2p/client/basicportallocator.cc b/webrtc/p2p/client/basicportallocator.cc index 5013a5756..a763791aa 100644 --- a/webrtc/p2p/client/basicportallocator.cc +++ b/webrtc/p2p/client/basicportallocator.cc @@ -889,14 +889,16 @@ void AllocationSequence::CreateUDPPorts() { port = UDPPort::Create(session_->network_thread(), session_->socket_factory(), network_, udp_socket_.get(), - session_->username(), session_->password()); + session_->username(), session_->password(), + session_->allocator()->origin()); } else { port = UDPPort::Create(session_->network_thread(), session_->socket_factory(), network_, ip_, session_->allocator()->min_port(), session_->allocator()->max_port(), - session_->username(), session_->password()); + session_->username(), session_->password(), + session_->allocator()->origin()); } if (port) { @@ -973,7 +975,8 @@ void AllocationSequence::CreateStunPorts() { session_->allocator()->min_port(), session_->allocator()->max_port(), session_->username(), session_->password(), - config_->StunServers()); + config_->StunServers(), + session_->allocator()->origin()); if (port) { session_->AddAllocatedPort(port, this, true); // Since StunPort is not created using shared socket, |port| will not be @@ -1055,8 +1058,8 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) { session_->socket_factory(), network_, udp_socket_.get(), session_->username(), session_->password(), - *relay_port, config.credentials, config.priority); - + *relay_port, config.credentials, config.priority, + session_->allocator()->origin()); turn_ports_.push_back(port); // Listen to the port destroyed signal, to allow AllocationSequence to // remove entrt from it's map. @@ -1069,7 +1072,8 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) { session_->allocator()->max_port(), session_->username(), session_->password(), - *relay_port, config.credentials, config.priority); + *relay_port, config.credentials, config.priority, + session_->allocator()->origin()); } ASSERT(port != NULL); session_->AddAllocatedPort(port, this, true); diff --git a/webrtc/p2p/client/connectivitychecker.cc b/webrtc/p2p/client/connectivitychecker.cc index 07c9d8b0d..1c3fc0eda 100644 --- a/webrtc/p2p/client/connectivitychecker.cc +++ b/webrtc/p2p/client/connectivitychecker.cc @@ -371,7 +371,8 @@ StunPort* ConnectivityChecker::CreateStunPort( 0, username, password, - config->stun_servers); + config->stun_servers, + std::string()); } RelayPort* ConnectivityChecker::CreateRelayPort( diff --git a/webrtc/p2p/client/connectivitychecker_unittest.cc b/webrtc/p2p/client/connectivitychecker_unittest.cc index 838dc8864..4b0566f58 100644 --- a/webrtc/p2p/client/connectivitychecker_unittest.cc +++ b/webrtc/p2p/client/connectivitychecker_unittest.cc @@ -75,7 +75,7 @@ class FakeStunPort : public StunPort { const std::string& username, const std::string& password, const ServerAddresses& server_addr) : StunPort(thread, factory, network, ip, min_port, max_port, - username, password, server_addr) { + username, password, server_addr, std::string()) { } // Just set external address and signal that we are done. diff --git a/webrtc/p2p/client/fakeportallocator.h b/webrtc/p2p/client/fakeportallocator.h index 73dae3afc..e26583454 100644 --- a/webrtc/p2p/client/fakeportallocator.h +++ b/webrtc/p2p/client/fakeportallocator.h @@ -56,7 +56,8 @@ class FakePortAllocatorSession : public PortAllocatorSession { 0, 0, username(), - password())); + password(), + std::string())); AddPort(port_.get()); } ++port_config_count_;