summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/renderer_host/p2p/socket_host.cc11
-rw-r--r--content/browser/renderer_host/p2p/socket_host.h1
-rw-r--r--content/browser/renderer_host/p2p/socket_host_tcp.cc236
-rw-r--r--content/browser/renderer_host/p2p/socket_host_tcp.h58
-rw-r--r--content/browser/renderer_host/p2p/socket_host_tcp_server.cc13
-rw-r--r--content/browser/renderer_host/p2p/socket_host_tcp_server.h8
-rw-r--r--content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc3
-rw-r--r--content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc154
-rw-r--r--content/common/p2p_sockets.h2
9 files changed, 410 insertions, 76 deletions
diff --git a/content/browser/renderer_host/p2p/socket_host.cc b/content/browser/renderer_host/p2p/socket_host.cc
index 40d173a..e3203e0 100644
--- a/content/browser/renderer_host/p2p/socket_host.cc
+++ b/content/browser/renderer_host/p2p/socket_host.cc
@@ -10,7 +10,6 @@
#include "content/browser/renderer_host/p2p/socket_host_udp.h"
namespace {
-const int kStunHeaderSize = 20;
const uint32 kStunMagicCookie = 0x2112A442;
} // namespace
@@ -79,10 +78,18 @@ P2PSocketHost* P2PSocketHost::Create(
return new P2PSocketHostUdp(message_sender, id);
case P2P_SOCKET_TCP_SERVER:
- return new P2PSocketHostTcpServer(message_sender, id);
+ return new P2PSocketHostTcpServer(
+ message_sender, id, P2P_SOCKET_TCP_CLIENT);
+
+ case P2P_SOCKET_STUN_TCP_SERVER:
+ return new P2PSocketHostTcpServer(
+ message_sender, id, P2P_SOCKET_STUN_TCP_CLIENT);
case P2P_SOCKET_TCP_CLIENT:
return new P2PSocketHostTcp(message_sender, id);
+
+ case P2P_SOCKET_STUN_TCP_CLIENT:
+ return new P2PSocketHostStunTcp(message_sender, id);
}
NOTREACHED();
diff --git a/content/browser/renderer_host/p2p/socket_host.h b/content/browser/renderer_host/p2p/socket_host.h
index 9fe985d..0283700 100644
--- a/content/browser/renderer_host/p2p/socket_host.h
+++ b/content/browser/renderer_host/p2p/socket_host.h
@@ -19,6 +19,7 @@ namespace content {
// Base class for P2P sockets.
class CONTENT_EXPORT P2PSocketHost {
public:
+ static const int kStunHeaderSize = 20;
// Creates P2PSocketHost of the specific type.
static P2PSocketHost* Create(IPC::Sender* message_sender,
int id, P2PSocketType type);
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.cc b/content/browser/renderer_host/p2p/socket_host_tcp.cc
index de62ffb..65d4c85 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -13,27 +13,33 @@
#include "net/socket/tcp_client_socket.h"
namespace {
+
+typedef uint16 PacketLength;
+const int kPacketHeaderSize = sizeof(PacketLength);
const int kReadBufferSize = 4096;
-const int kPacketHeaderSize = sizeof(uint16);
+const int kPacketLengthOffset = 2;
+const int kTurnChannelDataHeaderSize = 4;
+
} // namespace
namespace content {
-P2PSocketHostTcp::P2PSocketHostTcp(IPC::Sender* message_sender, int id)
+P2PSocketHostTcpBase::P2PSocketHostTcpBase(IPC::Sender* message_sender,
+ int id)
: P2PSocketHost(message_sender, id),
write_pending_(false),
connected_(false) {
}
-P2PSocketHostTcp::~P2PSocketHostTcp() {
+P2PSocketHostTcpBase::~P2PSocketHostTcpBase() {
if (state_ == STATE_OPEN) {
DCHECK(socket_.get());
socket_.reset();
}
}
-bool P2PSocketHostTcp::InitAccepted(const net::IPEndPoint& remote_address,
- net::StreamSocket* socket) {
+bool P2PSocketHostTcpBase::InitAccepted(const net::IPEndPoint& remote_address,
+ net::StreamSocket* socket) {
DCHECK(socket);
DCHECK_EQ(state_, STATE_UNINITIALIZED);
@@ -44,7 +50,7 @@ bool P2PSocketHostTcp::InitAccepted(const net::IPEndPoint& remote_address,
return state_ != STATE_ERROR;
}
-bool P2PSocketHostTcp::Init(const net::IPEndPoint& local_address,
+bool P2PSocketHostTcpBase::Init(const net::IPEndPoint& local_address,
const net::IPEndPoint& remote_address) {
DCHECK_EQ(state_, STATE_UNINITIALIZED);
@@ -68,7 +74,7 @@ bool P2PSocketHostTcp::Init(const net::IPEndPoint& local_address,
return state_ != STATE_ERROR;
}
-void P2PSocketHostTcp::OnError() {
+void P2PSocketHostTcpBase::OnError() {
socket_.reset();
if (state_ == STATE_UNINITIALIZED || state_ == STATE_CONNECTING ||
@@ -79,7 +85,7 @@ void P2PSocketHostTcp::OnError() {
state_ = STATE_ERROR;
}
-void P2PSocketHostTcp::OnConnected(int result) {
+void P2PSocketHostTcpBase::OnConnected(int result) {
DCHECK_EQ(state_, STATE_CONNECTING);
DCHECK_NE(result, net::ERR_IO_PENDING);
@@ -103,7 +109,7 @@ void P2PSocketHostTcp::OnConnected(int result) {
DoRead();
}
-void P2PSocketHostTcp::DoRead() {
+void P2PSocketHostTcpBase::DoRead() {
int result;
do {
if (!read_buffer_) {
@@ -124,14 +130,14 @@ void P2PSocketHostTcp::DoRead() {
} while (result > 0);
}
-void P2PSocketHostTcp::OnRead(int result) {
+void P2PSocketHostTcpBase::OnRead(int result) {
DidCompleteRead(result);
if (state_ == STATE_OPEN) {
DoRead();
}
}
-void P2PSocketHostTcp::OnPacket(std::vector<char>& data) {
+void P2PSocketHostTcpBase::OnPacket(const std::vector<char>& data) {
if (!connected_) {
P2PSocketHost::StunMessageType type;
bool stun = GetStunPacketType(&*data.begin(), data.size(), &type);
@@ -150,43 +156,8 @@ void P2PSocketHostTcp::OnPacket(std::vector<char>& data) {
message_sender_->Send(new P2PMsg_OnDataReceived(id_, remote_address_, data));
}
-void P2PSocketHostTcp::DidCompleteRead(int result) {
- DCHECK_EQ(state_, STATE_OPEN);
-
- if (result == net::ERR_IO_PENDING) {
- return;
- } else if (result < 0){
- LOG(ERROR) << "Error when reading from TCP socket: " << result;
- OnError();
- return;
- }
-
- read_buffer_->set_offset(read_buffer_->offset() + result);
- char* head = read_buffer_->StartOfBuffer(); // Purely a convenience.
- int consumed = 0;
- while (consumed + kPacketHeaderSize <= read_buffer_->offset() &&
- state_ == STATE_OPEN) {
- int packet_size = base::NetToHost16(
- *reinterpret_cast<uint16*>(head + consumed));
- if (consumed + packet_size + kPacketHeaderSize > read_buffer_->offset())
- break;
- // We've got a full packet!
- consumed += kPacketHeaderSize;
- char* cur = head + consumed;
- std::vector<char> data(cur, cur + packet_size);
- OnPacket(data);
- consumed += packet_size;
- }
- // We've consumed all complete packets from the buffer; now move any remaining
- // bytes to the head of the buffer and set offset to reflect this.
- if (consumed && consumed <= read_buffer_->offset()) {
- memmove(head, head + consumed, read_buffer_->offset() - consumed);
- read_buffer_->set_offset(read_buffer_->offset() - consumed);
- }
-}
-
-void P2PSocketHostTcp::Send(const net::IPEndPoint& to,
- const std::vector<char>& data) {
+void P2PSocketHostTcpBase::Send(const net::IPEndPoint& to,
+ const std::vector<char>& data) {
if (!socket_) {
// The Send message may be sent after the an OnError message was
// sent by hasn't been processed the renderer.
@@ -211,12 +182,11 @@ void P2PSocketHostTcp::Send(const net::IPEndPoint& to,
}
}
- int size = kPacketHeaderSize + data.size();
- scoped_refptr<net::DrainableIOBuffer> buffer =
- new net::DrainableIOBuffer(new net::IOBuffer(size), size);
- *reinterpret_cast<uint16*>(buffer->data()) = base::HostToNet16(data.size());
- memcpy(buffer->data() + kPacketHeaderSize, &data[0], data.size());
+ DoSend(to, data);
+}
+void P2PSocketHostTcpBase::WriteOrQueue(
+ scoped_refptr<net::DrainableIOBuffer>& buffer) {
if (write_buffer_) {
write_queue_.push(buffer);
return;
@@ -226,7 +196,7 @@ void P2PSocketHostTcp::Send(const net::IPEndPoint& to,
DoWrite();
}
-void P2PSocketHostTcp::DoWrite() {
+void P2PSocketHostTcpBase::DoWrite() {
while (write_buffer_ && state_ == STATE_OPEN && !write_pending_) {
int result = socket_->Write(write_buffer_, write_buffer_->BytesRemaining(),
base::Bind(&P2PSocketHostTcp::OnWritten,
@@ -235,7 +205,7 @@ void P2PSocketHostTcp::DoWrite() {
}
}
-void P2PSocketHostTcp::OnWritten(int result) {
+void P2PSocketHostTcpBase::OnWritten(int result) {
DCHECK(write_pending_);
DCHECK_NE(result, net::ERR_IO_PENDING);
@@ -244,7 +214,7 @@ void P2PSocketHostTcp::OnWritten(int result) {
DoWrite();
}
-void P2PSocketHostTcp::HandleWriteResult(int result) {
+void P2PSocketHostTcpBase::HandleWriteResult(int result) {
DCHECK(write_buffer_);
if (result >= 0) {
write_buffer_->DidConsume(result);
@@ -265,11 +235,161 @@ void P2PSocketHostTcp::HandleWriteResult(int result) {
}
}
-P2PSocketHost* P2PSocketHostTcp::AcceptIncomingTcpConnection(
+P2PSocketHost* P2PSocketHostTcpBase::AcceptIncomingTcpConnection(
const net::IPEndPoint& remote_address, int id) {
NOTREACHED();
OnError();
return NULL;
}
-} // namespace content
+void P2PSocketHostTcpBase::DidCompleteRead(int result) {
+ DCHECK_EQ(state_, STATE_OPEN);
+
+ if (result == net::ERR_IO_PENDING) {
+ return;
+ } else if (result < 0) {
+ LOG(ERROR) << "Error when reading from TCP socket: " << result;
+ OnError();
+ return;
+ }
+
+ read_buffer_->set_offset(read_buffer_->offset() + result);
+ char* head = read_buffer_->StartOfBuffer(); // Purely a convenience.
+ int pos = 0;
+ while (pos <= read_buffer_->offset() && state_ == STATE_OPEN) {
+ int consumed = ProcessInput(head + pos, read_buffer_->offset() - pos);
+ if (!consumed)
+ break;
+ pos += consumed;
+ }
+ // We've consumed all complete packets from the buffer; now move any remaining
+ // bytes to the head of the buffer and set offset to reflect this.
+ if (pos && pos <= read_buffer_->offset()) {
+ memmove(head, head + pos, read_buffer_->offset() - pos);
+ read_buffer_->set_offset(read_buffer_->offset() - pos);
+ }
+}
+
+P2PSocketHostTcp::P2PSocketHostTcp(IPC::Sender* message_sender, int id)
+ : P2PSocketHostTcpBase(message_sender, id) {
+}
+
+P2PSocketHostTcp::~P2PSocketHostTcp() {
+}
+
+int P2PSocketHostTcp::ProcessInput(char* input, int input_len) {
+ if (input_len < kPacketHeaderSize)
+ return 0;
+ int packet_size = base::NetToHost16(*reinterpret_cast<uint16*>(input));
+ if (input_len < packet_size + kPacketHeaderSize)
+ return 0;
+
+ int consumed = kPacketHeaderSize;
+ char* cur = input + consumed;
+ std::vector<char> data(cur, cur + packet_size);
+ OnPacket(data);
+ consumed += packet_size;
+ return consumed;
+}
+
+void P2PSocketHostTcp::DoSend(const net::IPEndPoint& to,
+ const std::vector<char>& data) {
+ int size = kPacketHeaderSize + data.size();
+ scoped_refptr<net::DrainableIOBuffer> buffer =
+ new net::DrainableIOBuffer(new net::IOBuffer(size), size);
+ *reinterpret_cast<uint16*>(buffer->data()) = base::HostToNet16(data.size());
+ memcpy(buffer->data() + kPacketHeaderSize, &data[0], data.size());
+
+ WriteOrQueue(buffer);
+}
+
+// P2PSocketHostStunTcp
+P2PSocketHostStunTcp::P2PSocketHostStunTcp(IPC::Sender* message_sender,
+ int id)
+ : P2PSocketHostTcpBase(message_sender, id) {
+}
+
+P2PSocketHostStunTcp::~P2PSocketHostStunTcp() {
+}
+
+int P2PSocketHostStunTcp::ProcessInput(char* input, int input_len) {
+ if (input_len < kPacketHeaderSize + kPacketLengthOffset)
+ return 0;
+
+ int pad_bytes;
+ int packet_size = GetExpectedPacketSize(
+ input, input_len, &pad_bytes);
+
+ if (input_len < packet_size + pad_bytes)
+ return 0;
+
+ // We have a complete packet. Read through it.
+ int consumed = 0;
+ char* cur = input;
+ std::vector<char> data(cur, cur + packet_size);
+ OnPacket(data);
+ consumed += packet_size;
+ consumed += pad_bytes;
+ return consumed;
+}
+
+void P2PSocketHostStunTcp::DoSend(const net::IPEndPoint& to,
+ const std::vector<char>& data) {
+ // Each packet is expected to have header (STUN/TURN ChannelData), where
+ // header contains message type and and length of message.
+ if (data.size() < kPacketHeaderSize + kPacketLengthOffset) {
+ NOTREACHED();
+ OnError();
+ return;
+ }
+
+ int pad_bytes;
+ size_t expected_len = GetExpectedPacketSize(
+ &data[0], data.size(), &pad_bytes);
+
+ // Accepts only complete STUN/TURN packets.
+ if (data.size() != expected_len) {
+ NOTREACHED();
+ OnError();
+ return;
+ }
+
+ // Add any pad bytes to the total size.
+ int size = data.size() + pad_bytes;
+
+ scoped_refptr<net::DrainableIOBuffer> buffer =
+ new net::DrainableIOBuffer(new net::IOBuffer(size), size);
+ memcpy(buffer->data(), &data[0], data.size());
+
+ if (pad_bytes) {
+ char padding[4] = {0};
+ DCHECK_LE(pad_bytes, 4);
+ memcpy(buffer->data() + data.size(), padding, pad_bytes);
+ }
+ WriteOrQueue(buffer);
+}
+
+int P2PSocketHostStunTcp::GetExpectedPacketSize(
+ const char* data, int len, int* pad_bytes) {
+ DCHECK_LE(kTurnChannelDataHeaderSize, len);
+ // Both stun and turn had length at offset 2.
+ int packet_size = base::NetToHost16(*reinterpret_cast<const uint16*>(
+ data + kPacketLengthOffset));
+
+ // Get packet type (STUN or TURN).
+ uint16 msg_type = base::NetToHost16(*reinterpret_cast<const uint16*>(data));
+
+ *pad_bytes = 0;
+ // Add heder length to packet length.
+ if ((msg_type & 0xC000) == 0) {
+ packet_size += kStunHeaderSize;
+ } else {
+ packet_size += kTurnChannelDataHeaderSize;
+ // Calculate any padding if present.
+ if (packet_size % 4)
+ *pad_bytes = 4 - packet_size % 4;
+ }
+ return packet_size;
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.h b/content/browser/renderer_host/p2p/socket_host_tcp.h
index 4fa3fae..1b6ec9a 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp.h
+++ b/content/browser/renderer_host/p2p/socket_host_tcp.h
@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_H_
#define CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_H_
+#include <queue>
#include <vector>
#include "base/compiler_specific.h"
@@ -24,10 +25,10 @@ class StreamSocket;
namespace content {
-class CONTENT_EXPORT P2PSocketHostTcp : public P2PSocketHost {
+class CONTENT_EXPORT P2PSocketHostTcpBase : public P2PSocketHost {
public:
- P2PSocketHostTcp(IPC::Sender* message_sender, int id);
- virtual ~P2PSocketHostTcp();
+ P2PSocketHostTcpBase(IPC::Sender* message_sender, int id);
+ virtual ~P2PSocketHostTcpBase();
bool InitAccepted(const net::IPEndPoint& remote_address,
net::StreamSocket* socket);
@@ -40,15 +41,23 @@ class CONTENT_EXPORT P2PSocketHostTcp : public P2PSocketHost {
virtual P2PSocketHost* AcceptIncomingTcpConnection(
const net::IPEndPoint& remote_address, int id) OVERRIDE;
+ protected:
+ // Derived classes will provide the implementation.
+ virtual int ProcessInput(char* input, int input_len) = 0;
+ virtual void DoSend(const net::IPEndPoint& to,
+ const std::vector<char>& data) = 0;
+
+ void WriteOrQueue(scoped_refptr<net::DrainableIOBuffer>& buffer);
+ void OnPacket(const std::vector<char>& data);
+ void OnError();
+
private:
friend class P2PSocketHostTcpTest;
friend class P2PSocketHostTcpServerTest;
+ friend class P2PSocketHostStunTcpTest;
- void OnError();
-
- void DoRead();
void DidCompleteRead(int result);
- void OnPacket(std::vector<char>& data);
+ void DoRead();
void DoWrite();
void HandleWriteResult(int result);
@@ -62,16 +71,49 @@ class CONTENT_EXPORT P2PSocketHostTcp : public P2PSocketHost {
scoped_ptr<net::StreamSocket> socket_;
scoped_refptr<net::GrowableIOBuffer> read_buffer_;
-
std::queue<scoped_refptr<net::DrainableIOBuffer> > write_queue_;
scoped_refptr<net::DrainableIOBuffer> write_buffer_;
+
bool write_pending_;
bool connected_;
+ DISALLOW_COPY_AND_ASSIGN(P2PSocketHostTcpBase);
+};
+
+class CONTENT_EXPORT P2PSocketHostTcp : public P2PSocketHostTcpBase {
+ public:
+ P2PSocketHostTcp(IPC::Sender* message_sender, int id);
+ virtual ~P2PSocketHostTcp();
+
+ protected:
+ virtual int ProcessInput(char* input, int input_len) OVERRIDE;
+ virtual void DoSend(const net::IPEndPoint& to,
+ const std::vector<char>& data) OVERRIDE;
+ private:
DISALLOW_COPY_AND_ASSIGN(P2PSocketHostTcp);
};
+// P2PSocketHostStunTcp class provides the framing of STUN messages when used
+// with TURN. These messages will not have length at front of the packet and
+// are padded to multiple of 4 bytes.
+// Formatting of messages is defined in RFC5766.
+class CONTENT_EXPORT P2PSocketHostStunTcp : public P2PSocketHostTcpBase {
+ public:
+ P2PSocketHostStunTcp(IPC::Sender* message_sender, int id);
+ virtual ~P2PSocketHostStunTcp();
+
+ protected:
+ virtual int ProcessInput(char* input, int input_len) OVERRIDE;
+ virtual void DoSend(const net::IPEndPoint& to,
+ const std::vector<char>& data) OVERRIDE;
+ private:
+ int GetExpectedPacketSize(const char* data, int len, int* pad_bytes);
+
+ DISALLOW_COPY_AND_ASSIGN(P2PSocketHostStunTcp);
+};
+
+
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_P2P_SOCKET_HOST_TCP_H_
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_server.cc b/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
index 113eb4d..a55c86b 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
@@ -21,8 +21,9 @@ const int kListenBacklog = 5;
namespace content {
P2PSocketHostTcpServer::P2PSocketHostTcpServer(
- IPC::Sender* message_sender, int id)
+ IPC::Sender* message_sender, int id, P2PSocketType client_type)
: P2PSocketHost(message_sender, id),
+ client_type_(client_type),
socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())),
accept_callback_(
base::Bind(&P2PSocketHostTcpServer::OnAccepted,
@@ -127,11 +128,15 @@ P2PSocketHost* P2PSocketHostTcpServer::AcceptIncomingTcpConnection(
net::StreamSocket* socket = it->second;
accepted_sockets_.erase(it);
- scoped_ptr<P2PSocketHostTcp> result(
- new P2PSocketHostTcp(message_sender_, id));
+
+ scoped_ptr<P2PSocketHostTcpBase> result;
+ if (client_type_ == P2P_SOCKET_TCP_CLIENT) {
+ result.reset(new P2PSocketHostTcp(message_sender_, id));
+ } else {
+ result.reset(new P2PSocketHostStunTcp(message_sender_, id));
+ }
if (!result->InitAccepted(remote_address, socket))
return NULL;
-
return result.release();
}
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_server.h b/content/browser/renderer_host/p2p/socket_host_tcp_server.h
index cd1ad17..2c50249 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_server.h
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_server.h
@@ -26,7 +26,10 @@ namespace content {
class CONTENT_EXPORT P2PSocketHostTcpServer : public P2PSocketHost {
public:
- P2PSocketHostTcpServer(IPC::Sender* message_sender, int id);
+ typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
+
+ P2PSocketHostTcpServer(IPC::Sender* message_sender, int id,
+ P2PSocketType client_type);
virtual ~P2PSocketHostTcpServer();
// P2PSocketHost overrides.
@@ -40,8 +43,6 @@ class CONTENT_EXPORT P2PSocketHostTcpServer : public P2PSocketHost {
private:
friend class P2PSocketHostTcpServerTest;
- typedef std::map<net::IPEndPoint, net::StreamSocket*> AcceptedSocketsMap;
-
void OnError();
void DoAccept();
@@ -50,6 +51,7 @@ class CONTENT_EXPORT P2PSocketHostTcpServer : public P2PSocketHost {
// Callback for Accept().
void OnAccepted(int result);
+ const P2PSocketType client_type_;
scoped_ptr<net::ServerSocket> socket_;
net::IPEndPoint local_address_;
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc b/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
index 71634df..6bca738 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
@@ -93,7 +93,8 @@ class P2PSocketHostTcpServerTest : public testing::Test {
protected:
virtual void SetUp() OVERRIDE {
socket_ = new FakeServerSocket();
- socket_host_.reset(new P2PSocketHostTcpServer(&sender_, 0));
+ socket_host_.reset(new P2PSocketHostTcpServer(
+ &sender_, 0, P2P_SOCKET_TCP_CLIENT));
socket_host_->socket_.reset(socket_);
EXPECT_CALL(sender_, Send(
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc b/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
index cc46b2b..b352c9f 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_unittest.cc
@@ -59,6 +59,46 @@ class P2PSocketHostTcpTest : public testing::Test {
net::IPEndPoint dest2_;
};
+class P2PSocketHostStunTcpTest : public testing::Test {
+ protected:
+ virtual void SetUp() OVERRIDE {
+ EXPECT_CALL(sender_, Send(
+ MatchMessage(static_cast<uint32>(P2PMsg_OnSocketCreated::ID))))
+ .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
+
+ socket_host_.reset(new P2PSocketHostStunTcp(&sender_, 0));
+ socket_ = new FakeSocket(&sent_data_);
+ socket_->SetLocalAddress(ParseAddress(kTestLocalIpAddress, kTestPort1));
+ socket_host_->socket_.reset(socket_);
+
+ dest_ = ParseAddress(kTestIpAddress1, kTestPort1);
+
+ local_address_ = ParseAddress(kTestLocalIpAddress, kTestPort1);
+
+ socket_host_->remote_address_ = dest_;
+ socket_host_->state_ = P2PSocketHost::STATE_CONNECTING;
+ socket_host_->OnConnected(net::OK);
+ }
+
+ std::string IntToSize(int size) {
+ std::string result;
+ uint16 size16 = base::HostToNet16(size);
+ result.resize(sizeof(size16));
+ memcpy(&result[0], &size16, sizeof(size16));
+ return result;
+ }
+
+ std::string sent_data_;
+ FakeSocket* socket_; // Owned by |socket_host_|.
+ scoped_ptr<P2PSocketHostStunTcp> socket_host_;
+ MockIPCSender sender_;
+
+ net::IPEndPoint local_address_;
+
+ net::IPEndPoint dest_;
+ net::IPEndPoint dest2_;
+};
+
// Verify that we can send STUN message and that they are formatted
// properly.
TEST_F(P2PSocketHostTcpTest, SendStunNoAuth) {
@@ -211,4 +251,118 @@ TEST_F(P2PSocketHostTcpTest, AsyncWrites) {
EXPECT_EQ(expected_data, sent_data_);
}
+// Verify that we can send STUN message and that they are formatted
+// properly.
+TEST_F(P2PSocketHostStunTcpTest, SendStunNoAuth) {
+ EXPECT_CALL(sender_, Send(
+ MatchMessage(static_cast<uint32>(P2PMsg_OnSendComplete::ID))))
+ .Times(3)
+ .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
+
+ std::vector<char> packet1;
+ CreateStunRequest(&packet1);
+ socket_host_->Send(dest_, packet1);
+
+ std::vector<char> packet2;
+ CreateStunResponse(&packet2);
+ socket_host_->Send(dest_, packet2);
+
+ std::vector<char> packet3;
+ CreateStunError(&packet3);
+ socket_host_->Send(dest_, packet3);
+
+ std::string expected_data;
+ expected_data.append(packet1.begin(), packet1.end());
+ expected_data.append(packet2.begin(), packet2.end());
+ expected_data.append(packet3.begin(), packet3.end());
+
+ EXPECT_EQ(expected_data, sent_data_);
+}
+
+// Verify that we can receive STUN messages from the socket, and that
+// the messages are parsed properly.
+TEST_F(P2PSocketHostStunTcpTest, ReceiveStun) {
+ EXPECT_CALL(sender_, Send(
+ MatchMessage(static_cast<uint32>(P2PMsg_OnSendComplete::ID))))
+ .Times(3)
+ .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
+
+ std::vector<char> packet1;
+ CreateStunRequest(&packet1);
+ socket_host_->Send(dest_, packet1);
+
+ std::vector<char> packet2;
+ CreateStunResponse(&packet2);
+ socket_host_->Send(dest_, packet2);
+
+ std::vector<char> packet3;
+ CreateStunError(&packet3);
+ socket_host_->Send(dest_, packet3);
+
+ std::string received_data;
+ received_data.append(packet1.begin(), packet1.end());
+ received_data.append(packet2.begin(), packet2.end());
+ received_data.append(packet3.begin(), packet3.end());
+
+ EXPECT_CALL(sender_, Send(MatchPacketMessage(packet1)))
+ .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
+ EXPECT_CALL(sender_, Send(MatchPacketMessage(packet2)))
+ .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
+ EXPECT_CALL(sender_, Send(MatchPacketMessage(packet3)))
+ .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
+
+ size_t pos = 0;
+ size_t step_sizes[] = {3, 2, 1};
+ size_t step = 0;
+ while (pos < received_data.size()) {
+ size_t step_size = std::min(step_sizes[step], received_data.size() - pos);
+ socket_->AppendInputData(&received_data[pos], step_size);
+ pos += step_size;
+ if (++step >= arraysize(step_sizes))
+ step = 0;
+ }
+}
+
+// Verify that we can't send data before we've received STUN response
+// from the other side.
+TEST_F(P2PSocketHostStunTcpTest, SendDataNoAuth) {
+ EXPECT_CALL(sender_, Send(
+ MatchMessage(static_cast<uint32>(P2PMsg_OnError::ID))))
+ .WillOnce(DoAll(DeleteArg<0>(), Return(true)));
+
+ std::vector<char> packet;
+ CreateRandomPacket(&packet);
+ socket_host_->Send(dest_, packet);
+
+ EXPECT_EQ(0U, sent_data_.size());
+}
+
+// Verify that asynchronous writes are handled correctly.
+TEST_F(P2PSocketHostStunTcpTest, AsyncWrites) {
+ MessageLoop message_loop;
+
+ socket_->set_async_write(true);
+
+ EXPECT_CALL(sender_, Send(
+ MatchMessage(static_cast<uint32>(P2PMsg_OnSendComplete::ID))))
+ .Times(2)
+ .WillRepeatedly(DoAll(DeleteArg<0>(), Return(true)));
+
+ std::vector<char> packet1;
+ CreateStunRequest(&packet1);
+ socket_host_->Send(dest_, packet1);
+
+ std::vector<char> packet2;
+ CreateStunResponse(&packet2);
+ socket_host_->Send(dest_, packet2);
+
+ message_loop.RunUntilIdle();
+
+ std::string expected_data;
+ expected_data.append(packet1.begin(), packet1.end());
+ expected_data.append(packet2.begin(), packet2.end());
+
+ EXPECT_EQ(expected_data, sent_data_);
+}
+
} // namespace content
diff --git a/content/common/p2p_sockets.h b/content/common/p2p_sockets.h
index f24d2ac..b8de0d7 100644
--- a/content/common/p2p_sockets.h
+++ b/content/common/p2p_sockets.h
@@ -14,7 +14,9 @@ namespace content {
enum P2PSocketType {
P2P_SOCKET_UDP,
P2P_SOCKET_TCP_SERVER,
+ P2P_SOCKET_STUN_TCP_SERVER,
P2P_SOCKET_TCP_CLIENT,
+ P2P_SOCKET_STUN_TCP_CLIENT,
};
} // namespace content