Added support for an Origin header in STUN messages.
For WebRTC there are instances where it may be desirable to provide
information to the STUN/TURN server about the website that initiated
a peer connection. This modification allows an origin string to be
included in the MediaConstraints object provided by the browser, which
is then passed as a STUN header in communications with the server.
A separate change will be submitted to the Chromium project that
uses and is dependent on this change, implementing IETF draft
http://tools.ietf.org/html/draft-johnston-tram-stun-origin-02
Originally a patch from skobalt@gmail.com.
(https://webrtc-codereview.appspot.com/12839005/edit)
R=juberti@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/41409004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8035 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/AUTHORS b/AUTHORS
index abe7814..c5b7f72 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -9,6 +9,7 @@
Colin Plumb
Eric Rescorla, RTFM Inc.
Giji Gangadharan <giji.g@samsung.com>
+Graham Yoakum <gyoakum@skobalt.com>
James H. Brown <jbrown@burgoyne.com>
Jie Mao <maojie0924@gmail.com>
Luke Weber
@@ -21,6 +22,7 @@
Ralph Giles <giles@ghostscript.com>
Robert Nagy
Ron Rivest
+Ryan Yoakum <ryoakum@skobalt.com>
Sarah Thompson <sarah@telergy.com>
Saul Kravitz <Saul.Kravitz@celera.com>
Silviu Caragea <silviu.cpp@gmail.com>
diff --git a/webrtc/libjingle/session/session_unittest.cc b/webrtc/libjingle/session/session_unittest.cc
index c2ff1a7..e1168db 100644
--- a/webrtc/libjingle/session/session_unittest.cc
+++ b/webrtc/libjingle/session/session_unittest.cc
@@ -598,7 +598,8 @@
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 b78c2c5..4a5c899 100644
--- a/webrtc/p2p/base/port.h
+++ b/webrtc/p2p/base/port.h
@@ -262,7 +262,7 @@
// 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 f09db28..26e46a6 100644
--- a/webrtc/p2p/base/port_unittest.cc
+++ b/webrtc/p2p/base/port_unittest.cc
@@ -207,7 +207,7 @@
// 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 @@
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 @@
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 @@
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 65aab44..1a3735b 100644
--- a/webrtc/p2p/base/portallocator.h
+++ b/webrtc/p2p/base/portallocator.h
@@ -167,6 +167,10 @@
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 @@
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 60367fa..866621f 100644
--- a/webrtc/p2p/base/stun.cc
+++ b/webrtc/p2p/base/stun.cc
@@ -387,6 +387,7 @@
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 0f600db..4bf6547 100644
--- a/webrtc/p2p/base/stun.h
+++ b/webrtc/p2p/base/stun.h
@@ -48,6 +48,7 @@
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 396beb6..9d5779d7 100644
--- a/webrtc/p2p/base/stun_unittest.cc
+++ b/webrtc/p2p/base/stun_unittest.cc
@@ -191,6 +191,20 @@
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 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 @@
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 @@
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<const char*>(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 5ef9e9e..fe125ec 100644
--- a/webrtc/p2p/base/stunport.cc
+++ b/webrtc/p2p/base/stunport.cc
@@ -163,7 +163,8 @@
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 @@
error_(0),
ready_(false),
stun_keepalive_delay_(KEEPALIVE_DELAY) {
+ requests_.set_origin(origin);
}
UDPPort::UDPPort(rtc::Thread* thread,
@@ -180,7 +182,8 @@
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 @@
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 9ca6046..d840a97 100644
--- a/webrtc/p2p/base/stunport.h
+++ b/webrtc/p2p/base/stunport.h
@@ -33,9 +33,10 @@
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 @@
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 @@
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 @@
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 @@
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 81b6808..8b6e81b 100644
--- a/webrtc/p2p/base/stunport_unittest.cc
+++ b/webrtc/p2p/base/stunport_unittest.cc
@@ -65,7 +65,7 @@
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 @@
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 65eb027..a6f4c15 100644
--- a/webrtc/p2p/base/stunrequest.cc
+++ b/webrtc/p2p/base/stunrequest.cc
@@ -41,6 +41,7 @@
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 @@
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 5fefc2f..6a4bdc0 100644
--- a/webrtc/p2p/base/stunrequest.h
+++ b/webrtc/p2p/base/stunrequest.h
@@ -24,7 +24,7 @@
// 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 @@
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<const void*, size_t, StunRequest*> SignalSendPacket;
-private:
+ private:
typedef std::map<std::string, StunRequest*> RequestMap;
rtc::Thread* thread_;
RequestMap requests_;
+ std::string origin_;
friend class StunRequest;
};
@@ -61,7 +65,7 @@
// 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 @@
// 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 @@
// 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 @@
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 19f73e7..7be35e5 100644
--- a/webrtc/p2p/base/testturnserver.h
+++ b/webrtc/p2p/base/testturnserver.h
@@ -87,6 +87,19 @@
}
}
+ // 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 8994aa8..2ea3ff4 100644
--- a/webrtc/p2p/base/turnport.cc
+++ b/webrtc/p2p/base/turnport.cc
@@ -164,7 +164,8 @@
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 @@
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 @@
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 @@
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 @@
}
}
+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 4ed77a0..3d3dad3 100644
--- a/webrtc/p2p/base/turnport.h
+++ b/webrtc/p2p/base/turnport.h
@@ -41,9 +41,10 @@
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 @@
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 @@
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 @@
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 748ed9d..e871aca 100644
--- a/webrtc/p2p/base/turnport_unittest.cc
+++ b/webrtc/p2p/base/turnport_unittest.cc
@@ -60,6 +60,7 @@
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 @@
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 @@
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 @@
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 @@
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 8605e98..7d82d55 100644
--- a/webrtc/p2p/base/turnserver.cc
+++ b/webrtc/p2p/base/turnserver.cc
@@ -45,88 +45,15 @@
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<Allocation*> SignalDestroyed;
-
- private:
- typedef std::list<Permission*> PermissionList;
- typedef std::list<Channel*> 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<rtc::AsyncPacketSocket> 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 @@
// 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 @@
return true;
}
+
TurnServer::TurnServer(rtc::Thread* thread)
: thread_(thread),
nonce_key_(rtc::CreateRandomString(kNonceKeySize)),
@@ -271,21 +199,21 @@
}
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 @@
// 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 @@
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 @@
}
// 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 @@
return true;
}
-void TurnServer::HandleBindingRequest(Connection* conn,
+void TurnServer::HandleBindingRequest(TurnServerConnection* conn,
const StunMessage* req) {
StunMessage response;
InitResponse(req, &response);
@@ -433,7 +361,7 @@
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 @@
// 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 @@
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 @@
}
// 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::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::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 @@
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 @@
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 @@
}
}
-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 @@
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 @@
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::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 @@
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 @@
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::HandleCreatePermissionRequest(
+void TurnServerAllocation::HandleCreatePermissionRequest(
const TurnMessage* msg) {
// Check mandatory attributes.
const StunAddressAttribute* peer_attr =
@@ -777,7 +710,7 @@
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 @@
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 @@
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::OnExternalPacket(
+void TurnServerAllocation::OnExternalPacket(
rtc::AsyncPacketSocket* socket,
const char* data, size_t size,
const rtc::SocketAddress& addr,
@@ -871,7 +804,7 @@
}
}
-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 @@
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 @@
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 @@
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 @@
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 670b618..d3bd77a 100644
--- a/webrtc/p2p/base/turnserver.h
+++ b/webrtc/p2p/base/turnserver.h
@@ -32,10 +32,109 @@
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<TurnServerAllocation*> SignalDestroyed;
+
+ private:
+ class Channel;
+ class Permission;
+ typedef std::list<Permission*> PermissionList;
+ typedef std::list<Channel*> 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<rtc::AsyncPacketSocket> 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 @@
// Not yet wired up: TCP support.
class TurnServer : public sigslot::has_slots<> {
public:
+ typedef std::map<TurnServerConnection, TurnServerAllocation*> AllocationMap;
+
explicit TurnServer(rtc::Thread* thread);
~TurnServer();
@@ -71,6 +172,8 @@
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 @@
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<Connection, Allocation*> 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 @@
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::AsyncPacketSocket*,
@@ -183,6 +263,8 @@
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 5013a57..a763791 100644
--- a/webrtc/p2p/client/basicportallocator.cc
+++ b/webrtc/p2p/client/basicportallocator.cc
@@ -889,14 +889,16 @@
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 @@
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 @@
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 @@
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 07c9d8b..1c3fc0e 100644
--- a/webrtc/p2p/client/connectivitychecker.cc
+++ b/webrtc/p2p/client/connectivitychecker.cc
@@ -371,7 +371,8 @@
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 838dc88..4b0566f 100644
--- a/webrtc/p2p/client/connectivitychecker_unittest.cc
+++ b/webrtc/p2p/client/connectivitychecker_unittest.cc
@@ -75,7 +75,7 @@
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 73dae3a..e265834 100644
--- a/webrtc/p2p/client/fakeportallocator.h
+++ b/webrtc/p2p/client/fakeportallocator.h
@@ -56,7 +56,8 @@
0,
0,
username(),
- password()));
+ password(),
+ std::string()));
AddPort(port_.get());
}
++port_config_count_;