summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorronghuawu@chromium.org <ronghuawu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-06 23:49:14 +0000
committerronghuawu@chromium.org <ronghuawu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-06 23:49:14 +0000
commit5dd5d9bd3ed34a49e679caf58689ae6e6c5ff75a (patch)
tree078c3f7d6b140c8b7460b21a1363d55fa6de7172
parent34202de532cd22eb74871b78bc60ff32b268dbf6 (diff)
downloadchromium_src-5dd5d9bd3ed34a49e679caf58689ae6e6c5ff75a.zip
chromium_src-5dd5d9bd3ed34a49e679caf58689ae6e6c5ff75a.tar.gz
chromium_src-5dd5d9bd3ed34a49e679caf58689ae6e6c5ff75a.tar.bz2
Adding TCP packet support for STUN/TURN packets.
The frame of these packets is different from ICE TCP. These packets doesn't carry the length of the packet at the head. Length will be present in packet it self at offset 2. This has been reviewed and tried here: https://codereview.chromium.org/14882003/ TBR=mallinath@chromium.org, sergeyu@chromium.org Review URL: https://codereview.chromium.org/14580006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@198565 0039d316-1c4b-4281-b951-d872f2087c98
-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