summaryrefslogtreecommitdiffstats
path: root/chromium/content/renderer/p2p/ipc_socket_factory.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/renderer/p2p/ipc_socket_factory.cc')
-rw-r--r--chromium/content/renderer/p2p/ipc_socket_factory.cc220
1 files changed, 200 insertions, 20 deletions
diff --git a/chromium/content/renderer/p2p/ipc_socket_factory.cc b/chromium/content/renderer/p2p/ipc_socket_factory.cc
index 04825c35f75..43b6d163ff4 100644
--- a/chromium/content/renderer/p2p/ipc_socket_factory.cc
+++ b/chromium/content/renderer/p2p/ipc_socket_factory.cc
@@ -4,14 +4,18 @@
#include "content/renderer/p2p/ipc_socket_factory.h"
+#include <algorithm>
#include <deque>
#include "base/compiler_specific.h"
#include "base/debug/trace_event.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
-#include "content/public/renderer/p2p_socket_client_delegate.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/non_thread_safe.h"
+#include "content/renderer/media/webrtc_logging.h"
#include "content/renderer/p2p/host_address_request.h"
+#include "content/renderer/p2p/socket_client_delegate.h"
#include "content/renderer/p2p/socket_client_impl.h"
#include "content/renderer/p2p/socket_dispatcher.h"
#include "jingle/glue/utils.h"
@@ -21,6 +25,8 @@ namespace content {
namespace {
+const int kDefaultNonSetOptionValue = -1;
+
bool IsTcpClientSocket(P2PSocketType type) {
return (type == P2P_SOCKET_STUN_TCP_CLIENT) ||
(type == P2P_SOCKET_TCP_CLIENT) ||
@@ -30,6 +36,30 @@ bool IsTcpClientSocket(P2PSocketType type) {
(type == P2P_SOCKET_STUN_TLS_CLIENT);
}
+bool JingleSocketOptionToP2PSocketOption(talk_base::Socket::Option option,
+ P2PSocketOption* ipc_option) {
+ switch (option) {
+ case talk_base::Socket::OPT_RCVBUF:
+ *ipc_option = P2P_SOCKET_OPT_RCVBUF;
+ break;
+ case talk_base::Socket::OPT_SNDBUF:
+ *ipc_option = P2P_SOCKET_OPT_SNDBUF;
+ break;
+ case talk_base::Socket::OPT_DSCP:
+ *ipc_option = P2P_SOCKET_OPT_DSCP;
+ break;
+ case talk_base::Socket::OPT_DONTFRAGMENT:
+ case talk_base::Socket::OPT_NODELAY:
+ case talk_base::Socket::OPT_IPV6_V6ONLY:
+ case talk_base::Socket::OPT_RTP_SENDTIME_EXTN_ID:
+ return false; // Not supported by the chrome sockets.
+ default:
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
// TODO(miu): This needs tuning. http://crbug.com/237960
const size_t kMaximumInFlightBytes = 64 * 1024; // 64 KB
@@ -51,14 +81,14 @@ class IpcPacketSocket : public talk_base::AsyncPacketSocket,
virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE;
virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE;
virtual int Send(const void *pv, size_t cb,
- talk_base::DiffServCodePoint dscp) OVERRIDE;
+ const talk_base::PacketOptions& options) OVERRIDE;
virtual int SendTo(const void *pv, size_t cb,
const talk_base::SocketAddress& addr,
- talk_base::DiffServCodePoint dscp) OVERRIDE;
+ const talk_base::PacketOptions& options) OVERRIDE;
virtual int Close() OVERRIDE;
virtual State GetState() const OVERRIDE;
- virtual int GetOption(talk_base::Socket::Option opt, int* value) OVERRIDE;
- virtual int SetOption(talk_base::Socket::Option opt, int value) OVERRIDE;
+ virtual int GetOption(talk_base::Socket::Option option, int* value) OVERRIDE;
+ virtual int SetOption(talk_base::Socket::Option option, int value) OVERRIDE;
virtual int GetError() const OVERRIDE;
virtual void SetError(int error) OVERRIDE;
@@ -90,6 +120,9 @@ class IpcPacketSocket : public talk_base::AsyncPacketSocket,
void InitAcceptedTcp(P2PSocketClient* client,
const talk_base::SocketAddress& local_address,
const talk_base::SocketAddress& remote_address);
+
+ int DoSetOption(P2PSocketOption option, int value);
+
P2PSocketType type_;
// Message loop on which this socket was created and being used.
@@ -124,10 +157,37 @@ class IpcPacketSocket : public talk_base::AsyncPacketSocket,
// Current error code. Valid when state_ == IS_ERROR.
int error_;
+ int options_[P2P_SOCKET_OPT_MAX];
DISALLOW_COPY_AND_ASSIGN(IpcPacketSocket);
};
+// Simple wrapper around P2PAsyncAddressResolver. The main purpose of this
+// class is to send SignalDone, after OnDone callback from
+// P2PAsyncAddressResolver. Libjingle sig slots are not thread safe. In case
+// of MT sig slots clients must call disconnect. This class is to make sure
+// we destruct from the same thread on which is created.
+class AsyncAddressResolverImpl : public base::NonThreadSafe,
+ public talk_base::AsyncResolverInterface {
+ public:
+ AsyncAddressResolverImpl(P2PSocketDispatcher* dispatcher);
+ virtual ~AsyncAddressResolverImpl();
+
+ // talk_base::AsyncResolverInterface interface.
+ virtual void Start(const talk_base::SocketAddress& addr) OVERRIDE;
+ virtual bool GetResolvedAddress(
+ int family, talk_base::SocketAddress* addr) const OVERRIDE;
+ virtual int GetError() const OVERRIDE;
+ virtual void Destroy(bool wait) OVERRIDE;
+
+ private:
+ virtual void OnAddressResolved(const net::IPAddressList& addresses);
+
+ scoped_refptr<P2PAsyncAddressResolver> resolver_;
+ int port_; // Port number in |addr| from Start() method.
+ std::vector<talk_base::IPAddress> addresses_; // Resolved addresses.
+};
+
IpcPacketSocket::IpcPacketSocket()
: type_(P2P_SOCKET_UDP),
message_loop_(base::MessageLoop::current()),
@@ -136,6 +196,8 @@ IpcPacketSocket::IpcPacketSocket()
writable_signal_expected_(false),
error_(0) {
COMPILE_ASSERT(kMaximumInFlightBytes > 0, would_send_at_zero_rate);
+ std::fill_n(options_, static_cast<int> (P2P_SOCKET_OPT_MAX),
+ kDefaultNonSetOptionValue);
}
IpcPacketSocket::~IpcPacketSocket() {
@@ -178,7 +240,12 @@ bool IpcPacketSocket::Init(P2PSocketType type,
return false;
}
- client->Init(type, local_endpoint, remote_endpoint, this);
+ // We need to send both resolved and unresolved address in Init. Unresolved
+ // address will be used in case of TLS for certificate hostname matching.
+ // Certificate will be tied to domain name not to IP address.
+ P2PHostAndIPEndPoint remote_info(remote_address.hostname(), remote_endpoint);
+
+ client->Init(type, local_endpoint, remote_info, this);
return true;
}
@@ -210,14 +277,14 @@ talk_base::SocketAddress IpcPacketSocket::GetRemoteAddress() const {
}
int IpcPacketSocket::Send(const void *data, size_t data_size,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
- return SendTo(data, data_size, remote_address_, dscp);
+ return SendTo(data, data_size, remote_address_, options);
}
int IpcPacketSocket::SendTo(const void *data, size_t data_size,
const talk_base::SocketAddress& address,
- talk_base::DiffServCodePoint dscp) {
+ const talk_base::PacketOptions& options) {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
switch (state_) {
@@ -245,7 +312,14 @@ int IpcPacketSocket::SendTo(const void *data, size_t data_size,
TRACE_EVENT_SCOPE_THREAD,
"id",
client_->GetSocketID());
- writable_signal_expected_ = true;
+ if (!writable_signal_expected_) {
+ WebRtcLogMessage(base::StringPrintf(
+ "IpcPacketSocket: sending is blocked. %d packets_in_flight.",
+ static_cast<int>(in_flight_packet_sizes_.size())));
+
+ writable_signal_expected_ = true;
+ }
+
error_ = EWOULDBLOCK;
return -1;
}
@@ -263,8 +337,7 @@ int IpcPacketSocket::SendTo(const void *data, size_t data_size,
const char* data_char = reinterpret_cast<const char*>(data);
std::vector<char> data_vector(data_char, data_char + data_size);
- client_->SendWithDscp(address_chrome, data_vector,
- static_cast<net::DiffServCodePoint>(dscp));
+ client_->SendWithDscp(address_chrome, data_vector, options);
// Fake successful send. The caller ignores result anyway.
return data_size;
@@ -306,14 +379,41 @@ talk_base::AsyncPacketSocket::State IpcPacketSocket::GetState() const {
return STATE_CLOSED;
}
-int IpcPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) {
- // We don't support socket options for IPC sockets.
- return -1;
+int IpcPacketSocket::GetOption(talk_base::Socket::Option option, int* value) {
+ P2PSocketOption p2p_socket_option = P2P_SOCKET_OPT_MAX;
+ if (!JingleSocketOptionToP2PSocketOption(option, &p2p_socket_option)) {
+ // unsupported option.
+ return -1;
+ }
+
+ *value = options_[p2p_socket_option];
+ return 0;
+}
+
+int IpcPacketSocket::SetOption(talk_base::Socket::Option option, int value) {
+ DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+
+ P2PSocketOption p2p_socket_option = P2P_SOCKET_OPT_MAX;
+ if (!JingleSocketOptionToP2PSocketOption(option, &p2p_socket_option)) {
+ // Option is not supported.
+ return -1;
+ }
+
+ options_[p2p_socket_option] = value;
+
+ if (state_ == IS_OPEN) {
+ // Options will be applied when state becomes IS_OPEN in OnOpen.
+ return DoSetOption(p2p_socket_option, value);
+ }
+ return 0;
}
-int IpcPacketSocket::SetOption(talk_base::Socket::Option opt, int value) {
- // We don't support socket options for IPC sockets.
- return -1;
+int IpcPacketSocket::DoSetOption(P2PSocketOption option, int value) {
+ DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+ DCHECK_EQ(state_, IS_OPEN);
+
+ client_->SetOption(option, value);
+ return 0;
}
int IpcPacketSocket::GetError() const {
@@ -339,6 +439,12 @@ void IpcPacketSocket::OnOpen(const net::IPEndPoint& address) {
state_ = IS_OPEN;
TraceSendThrottlingState();
+ // Set all pending options if any.
+ for (int i = 0; i < P2P_SOCKET_OPT_MAX; ++i) {
+ if (options_[i] != kDefaultNonSetOptionValue)
+ DoSetOption(static_cast<P2PSocketOption> (i), options_[i]);
+ }
+
SignalAddressReady(this, local_address_);
if (IsTcpClientSocket(type_))
SignalConnect(this);
@@ -365,11 +471,17 @@ void IpcPacketSocket::OnSendComplete() {
CHECK(!in_flight_packet_sizes_.empty());
send_bytes_available_ += in_flight_packet_sizes_.front();
+
DCHECK_LE(send_bytes_available_, kMaximumInFlightBytes);
+
in_flight_packet_sizes_.pop_front();
TraceSendThrottlingState();
if (writable_signal_expected_ && send_bytes_available_ > 0) {
+ WebRtcLogMessage(base::StringPrintf(
+ "IpcPacketSocket: sending is unblocked. %d packets in flight.",
+ static_cast<int>(in_flight_packet_sizes_.size())));
+
SignalReadyToSend(this);
writable_signal_expected_ = false;
}
@@ -377,8 +489,12 @@ void IpcPacketSocket::OnSendComplete() {
void IpcPacketSocket::OnError() {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+ bool was_closed = (state_ == IS_ERROR || state_ == IS_CLOSED);
state_ = IS_ERROR;
error_ = ECONNABORTED;
+ if (!was_closed) {
+ SignalClose(this, 0);
+ }
}
void IpcPacketSocket::OnDataReceived(const net::IPEndPoint& address,
@@ -399,6 +515,69 @@ void IpcPacketSocket::OnDataReceived(const net::IPEndPoint& address,
packet_time);
}
+AsyncAddressResolverImpl::AsyncAddressResolverImpl(
+ P2PSocketDispatcher* dispatcher)
+ : resolver_(new P2PAsyncAddressResolver(dispatcher)) {
+}
+
+AsyncAddressResolverImpl::~AsyncAddressResolverImpl() {
+}
+
+void AsyncAddressResolverImpl::Start(const talk_base::SocketAddress& addr) {
+ DCHECK(CalledOnValidThread());
+ // Copy port number from |addr|. |port_| must be copied
+ // when resolved address is returned in GetResolvedAddress.
+ port_ = addr.port();
+
+ resolver_->Start(addr, base::Bind(
+ &AsyncAddressResolverImpl::OnAddressResolved,
+ base::Unretained(this)));
+}
+
+bool AsyncAddressResolverImpl::GetResolvedAddress(
+ int family, talk_base::SocketAddress* addr) const {
+ DCHECK(CalledOnValidThread());
+
+ if (addresses_.empty())
+ return false;
+
+ for (size_t i = 0; i < addresses_.size(); ++i) {
+ if (family == addresses_[i].family()) {
+ addr->SetResolvedIP(addresses_[i]);
+ addr->SetPort(port_);
+ return true;
+ }
+ }
+ return false;
+}
+
+int AsyncAddressResolverImpl::GetError() const {
+ DCHECK(CalledOnValidThread());
+ return addresses_.empty() ? -1 : 0;
+}
+
+void AsyncAddressResolverImpl::Destroy(bool wait) {
+ DCHECK(CalledOnValidThread());
+ resolver_->Cancel();
+ // Libjingle doesn't need this object any more and it's not going to delete
+ // it explicitly.
+ delete this;
+}
+
+void AsyncAddressResolverImpl::OnAddressResolved(
+ const net::IPAddressList& addresses) {
+ DCHECK(CalledOnValidThread());
+ for (size_t i = 0; i < addresses.size(); ++i) {
+ talk_base::SocketAddress socket_address;
+ if (!jingle_glue::IPEndPointToSocketAddress(
+ net::IPEndPoint(addresses[i], 0), &socket_address)) {
+ NOTREACHED();
+ }
+ addresses_.push_back(socket_address.ipaddr());
+ }
+ SignalDone(this);
+}
+
} // namespace
IpcPacketSocketFactory::IpcPacketSocketFactory(
@@ -469,8 +648,9 @@ talk_base::AsyncPacketSocket* IpcPacketSocketFactory::CreateClientTcpSocket(
talk_base::AsyncResolverInterface*
IpcPacketSocketFactory::CreateAsyncResolver() {
- NOTREACHED();
- return NULL;
+ scoped_ptr<AsyncAddressResolverImpl> resolver(
+ new AsyncAddressResolverImpl(socket_dispatcher_));
+ return resolver.release();
}
} // namespace content