Add ICU message format support
[chromium-blink-merge.git] / content / browser / renderer_host / p2p / socket_dispatcher_host.cc
blob724294f085e04b45794059feebbfe84ee47f783f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
7 #include "base/bind.h"
8 #include "base/stl_util.h"
9 #include "content/browser/renderer_host/p2p/socket_host.h"
10 #include "content/common/p2p_messages.h"
11 #include "content/public/browser/resource_context.h"
12 #include "net/base/address_list.h"
13 #include "net/base/completion_callback.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/sys_addrinfo.h"
16 #include "net/dns/single_request_host_resolver.h"
17 #include "net/log/net_log.h"
18 #include "net/url_request/url_request_context_getter.h"
20 using content::BrowserMessageFilter;
21 using content::BrowserThread;
23 namespace content {
25 const size_t kMaximumPacketSize = 32768;
27 class P2PSocketDispatcherHost::DnsRequest {
28 public:
29 typedef base::Callback<void(const net::IPAddressList&)> DoneCallback;
31 DnsRequest(int32 request_id, net::HostResolver* host_resolver)
32 : request_id_(request_id),
33 resolver_(host_resolver) {
36 void Resolve(const std::string& host_name,
37 const DoneCallback& done_callback) {
38 DCHECK(!done_callback.is_null());
40 host_name_ = host_name;
41 done_callback_ = done_callback;
43 // Return an error if it's an empty string.
44 if (host_name_.empty()) {
45 net::IPAddressList address_list;
46 done_callback_.Run(address_list);
47 return;
50 // Add period at the end to make sure that we only resolve
51 // fully-qualified names.
52 if (host_name_.at(host_name_.size() - 1) != '.')
53 host_name_ = host_name_ + '.';
55 net::HostResolver::RequestInfo info(net::HostPortPair(host_name_, 0));
56 int result = resolver_.Resolve(
57 info,
58 net::DEFAULT_PRIORITY,
59 &addresses_,
60 base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone,
61 base::Unretained(this)),
62 net::BoundNetLog());
63 if (result != net::ERR_IO_PENDING)
64 OnDone(result);
67 int32 request_id() { return request_id_; }
69 private:
70 void OnDone(int result) {
71 net::IPAddressList list;
72 if (result != net::OK) {
73 LOG(ERROR) << "Failed to resolve address for " << host_name_
74 << ", errorcode: " << result;
75 done_callback_.Run(list);
76 return;
79 DCHECK(!addresses_.empty());
80 for (net::AddressList::iterator iter = addresses_.begin();
81 iter != addresses_.end(); ++iter) {
82 list.push_back(iter->address());
84 done_callback_.Run(list);
87 int32 request_id_;
88 net::AddressList addresses_;
90 std::string host_name_;
91 net::SingleRequestHostResolver resolver_;
93 DoneCallback done_callback_;
96 P2PSocketDispatcherHost::P2PSocketDispatcherHost(
97 content::ResourceContext* resource_context,
98 net::URLRequestContextGetter* url_context)
99 : BrowserMessageFilter(P2PMsgStart),
100 resource_context_(resource_context),
101 url_context_(url_context),
102 monitoring_networks_(false),
103 dump_incoming_rtp_packet_(false),
104 dump_outgoing_rtp_packet_(false) {
107 void P2PSocketDispatcherHost::OnChannelClosing() {
108 // Since the IPC sender is gone, close pending connections.
109 STLDeleteContainerPairSecondPointers(sockets_.begin(), sockets_.end());
110 sockets_.clear();
112 STLDeleteContainerPointers(dns_requests_.begin(), dns_requests_.end());
113 dns_requests_.clear();
115 if (monitoring_networks_) {
116 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
117 monitoring_networks_ = false;
121 void P2PSocketDispatcherHost::OnDestruct() const {
122 BrowserThread::DeleteOnIOThread::Destruct(this);
125 bool P2PSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
126 bool handled = true;
127 IPC_BEGIN_MESSAGE_MAP(P2PSocketDispatcherHost, message)
128 IPC_MESSAGE_HANDLER(P2PHostMsg_StartNetworkNotifications,
129 OnStartNetworkNotifications)
130 IPC_MESSAGE_HANDLER(P2PHostMsg_StopNetworkNotifications,
131 OnStopNetworkNotifications)
132 IPC_MESSAGE_HANDLER(P2PHostMsg_GetHostAddress, OnGetHostAddress)
133 IPC_MESSAGE_HANDLER(P2PHostMsg_CreateSocket, OnCreateSocket)
134 IPC_MESSAGE_HANDLER(P2PHostMsg_AcceptIncomingTcpConnection,
135 OnAcceptIncomingTcpConnection)
136 IPC_MESSAGE_HANDLER(P2PHostMsg_Send, OnSend)
137 IPC_MESSAGE_HANDLER(P2PHostMsg_SetOption, OnSetOption)
138 IPC_MESSAGE_HANDLER(P2PHostMsg_DestroySocket, OnDestroySocket)
139 IPC_MESSAGE_UNHANDLED(handled = false)
140 IPC_END_MESSAGE_MAP()
141 return handled;
144 void P2PSocketDispatcherHost::OnIPAddressChanged() {
145 // Notify the renderer about changes to list of network interfaces.
146 BrowserThread::PostTask(
147 BrowserThread::FILE, FROM_HERE, base::Bind(
148 &P2PSocketDispatcherHost::DoGetNetworkList, this));
151 void P2PSocketDispatcherHost::StartRtpDump(
152 bool incoming,
153 bool outgoing,
154 const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback) {
155 DCHECK_CURRENTLY_ON(BrowserThread::IO);
157 if ((!dump_incoming_rtp_packet_ && incoming) ||
158 (!dump_outgoing_rtp_packet_ && outgoing)) {
159 if (incoming)
160 dump_incoming_rtp_packet_ = true;
162 if (outgoing)
163 dump_outgoing_rtp_packet_ = true;
165 packet_callback_ = packet_callback;
166 for (SocketsMap::iterator it = sockets_.begin(); it != sockets_.end(); ++it)
167 it->second->StartRtpDump(incoming, outgoing, packet_callback);
171 void P2PSocketDispatcherHost::StopRtpDumpOnUIThread(bool incoming,
172 bool outgoing) {
173 DCHECK_CURRENTLY_ON(BrowserThread::UI);
174 BrowserThread::PostTask(
175 BrowserThread::IO,
176 FROM_HERE,
177 base::Bind(&P2PSocketDispatcherHost::StopRtpDumpOnIOThread,
178 this,
179 incoming,
180 outgoing));
183 P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {
184 DCHECK(sockets_.empty());
185 DCHECK(dns_requests_.empty());
187 if (monitoring_networks_)
188 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
191 P2PSocketHost* P2PSocketDispatcherHost::LookupSocket(int socket_id) {
192 SocketsMap::iterator it = sockets_.find(socket_id);
193 return (it == sockets_.end()) ? NULL : it->second;
196 void P2PSocketDispatcherHost::OnStartNetworkNotifications() {
197 if (!monitoring_networks_) {
198 net::NetworkChangeNotifier::AddIPAddressObserver(this);
199 monitoring_networks_ = true;
202 BrowserThread::PostTask(
203 BrowserThread::FILE, FROM_HERE, base::Bind(
204 &P2PSocketDispatcherHost::DoGetNetworkList, this));
207 void P2PSocketDispatcherHost::OnStopNetworkNotifications() {
208 if (monitoring_networks_) {
209 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
210 monitoring_networks_ = false;
214 void P2PSocketDispatcherHost::OnGetHostAddress(const std::string& host_name,
215 int32 request_id) {
216 DnsRequest* request = new DnsRequest(request_id,
217 resource_context_->GetHostResolver());
218 dns_requests_.insert(request);
219 request->Resolve(host_name, base::Bind(
220 &P2PSocketDispatcherHost::OnAddressResolved,
221 base::Unretained(this), request));
224 void P2PSocketDispatcherHost::OnCreateSocket(
225 P2PSocketType type, int socket_id,
226 const net::IPEndPoint& local_address,
227 const P2PHostAndIPEndPoint& remote_address) {
228 if (LookupSocket(socket_id)) {
229 LOG(ERROR) << "Received P2PHostMsg_CreateSocket for socket "
230 "that already exists.";
231 return;
234 scoped_ptr<P2PSocketHost> socket(P2PSocketHost::Create(
235 this, socket_id, type, url_context_.get(), &throttler_));
237 if (!socket) {
238 Send(new P2PMsg_OnError(socket_id));
239 return;
242 if (socket->Init(local_address, remote_address)) {
243 sockets_[socket_id] = socket.release();
245 if (dump_incoming_rtp_packet_ || dump_outgoing_rtp_packet_) {
246 sockets_[socket_id]->StartRtpDump(dump_incoming_rtp_packet_,
247 dump_outgoing_rtp_packet_,
248 packet_callback_);
253 void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
254 int listen_socket_id, const net::IPEndPoint& remote_address,
255 int connected_socket_id) {
256 P2PSocketHost* socket = LookupSocket(listen_socket_id);
257 if (!socket) {
258 LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
259 "for invalid listen_socket_id.";
260 return;
262 if (LookupSocket(connected_socket_id) != NULL) {
263 LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
264 "for duplicated connected_socket_id.";
265 return;
268 P2PSocketHost* accepted_connection =
269 socket->AcceptIncomingTcpConnection(remote_address, connected_socket_id);
270 if (accepted_connection) {
271 sockets_[connected_socket_id] = accepted_connection;
275 void P2PSocketDispatcherHost::OnSend(int socket_id,
276 const net::IPEndPoint& socket_address,
277 const std::vector<char>& data,
278 const rtc::PacketOptions& options,
279 uint64 packet_id) {
280 P2PSocketHost* socket = LookupSocket(socket_id);
281 if (!socket) {
282 LOG(ERROR) << "Received P2PHostMsg_Send for invalid socket_id.";
283 return;
286 if (data.size() > kMaximumPacketSize) {
287 LOG(ERROR) << "Received P2PHostMsg_Send with a packet that is too big: "
288 << data.size();
289 Send(new P2PMsg_OnError(socket_id));
290 delete socket;
291 sockets_.erase(socket_id);
292 return;
295 socket->Send(socket_address, data, options, packet_id);
298 void P2PSocketDispatcherHost::OnSetOption(int socket_id,
299 P2PSocketOption option,
300 int value) {
301 P2PSocketHost* socket = LookupSocket(socket_id);
302 if (!socket) {
303 LOG(ERROR) << "Received P2PHostMsg_SetOption for invalid socket_id.";
304 return;
307 socket->SetOption(option, value);
310 void P2PSocketDispatcherHost::OnDestroySocket(int socket_id) {
311 SocketsMap::iterator it = sockets_.find(socket_id);
312 if (it != sockets_.end()) {
313 delete it->second;
314 sockets_.erase(it);
315 } else {
316 LOG(ERROR) << "Received P2PHostMsg_DestroySocket for invalid socket_id.";
320 void P2PSocketDispatcherHost::DoGetNetworkList() {
321 net::NetworkInterfaceList list;
322 net::GetNetworkList(&list, net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES);
323 BrowserThread::PostTask(
324 BrowserThread::IO, FROM_HERE, base::Bind(
325 &P2PSocketDispatcherHost::SendNetworkList, this, list));
328 void P2PSocketDispatcherHost::SendNetworkList(
329 const net::NetworkInterfaceList& list) {
330 Send(new P2PMsg_NetworkListChanged(list));
333 void P2PSocketDispatcherHost::OnAddressResolved(
334 DnsRequest* request,
335 const net::IPAddressList& addresses) {
336 Send(new P2PMsg_GetHostAddressResult(request->request_id(), addresses));
338 dns_requests_.erase(request);
339 delete request;
342 void P2PSocketDispatcherHost::StopRtpDumpOnIOThread(bool incoming,
343 bool outgoing) {
344 if ((dump_incoming_rtp_packet_ && incoming) ||
345 (dump_outgoing_rtp_packet_ && outgoing)) {
346 if (incoming)
347 dump_incoming_rtp_packet_ = false;
349 if (outgoing)
350 dump_outgoing_rtp_packet_ = false;
352 if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_)
353 packet_callback_.Reset();
355 for (SocketsMap::iterator it = sockets_.begin(); it != sockets_.end(); ++it)
356 it->second->StopRtpDump(incoming, outgoing);
360 } // namespace content