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
This commit is contained in:
pthatcher@webrtc.org 2015-01-10 00:47:02 +00:00
parent 2693a54614
commit 0ba1533fdb
23 changed files with 398 additions and 227 deletions

View File

@ -9,6 +9,7 @@ Christophe Dumez <ch.dumez@samsung.com>
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 @@ Rafael Lopez Diez <rafalopezdiez@gmail.com>
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>

View File

@ -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;

View File

@ -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_; }

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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
};

View File

@ -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<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;

View File

@ -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() {

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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<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 @@ 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.

View File

@ -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.

View File

@ -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()) {

View File

@ -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 {

View File

@ -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)

View File

@ -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<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 @@ 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;

View File

@ -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<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 @@ class TurnRedirectInterface {
// 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 @@ 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<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 @@ 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::AsyncPacketSocket*,
@ -183,6 +263,8 @@ class TurnServer : public sigslot::has_slots<> {
rtc::SocketAddress external_addr_;
AllocationMap allocations_;
friend class TurnServerAllocation;
};
} // namespace cricket

View File

@ -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);

View File

@ -371,7 +371,8 @@ StunPort* ConnectivityChecker::CreateStunPort(
0,
username,
password,
config->stun_servers);
config->stun_servers,
std::string());
}
RelayPort* ConnectivityChecker::CreateRelayPort(

View File

@ -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.

View File

@ -56,7 +56,8 @@ class FakePortAllocatorSession : public PortAllocatorSession {
0,
0,
username(),
password()));
password(),
std::string()));
AddPort(port_.get());
}
++port_config_count_;