Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: content/renderer/p2p/ipc_socket_factory.cc

Issue 759923003: Detect situation when there is no missing send completion signal in P2PSocket implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/p2p/ipc_socket_factory.h" 5 #include "content/renderer/p2p/ipc_socket_factory.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <deque> 8 #include <list>
9 9
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/debug/trace_event.h" 11 #include "base/debug/trace_event.h"
12 #include "base/message_loop/message_loop.h" 12 #include "base/message_loop/message_loop.h"
13 #include "base/message_loop/message_loop_proxy.h" 13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/metrics/field_trial.h" 14 #include "base/metrics/field_trial.h"
15 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
16 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h" 17 #include "base/strings/stringprintf.h"
18 #include "base/threading/non_thread_safe.h" 18 #include "base/threading/non_thread_safe.h"
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 69
70 // IpcPacketSocket implements rtc::AsyncPacketSocket interface 70 // IpcPacketSocket implements rtc::AsyncPacketSocket interface
71 // using P2PSocketClient that works over IPC-channel. It must be used 71 // using P2PSocketClient that works over IPC-channel. It must be used
72 // on the thread it was created. 72 // on the thread it was created.
73 class IpcPacketSocket : public rtc::AsyncPacketSocket, 73 class IpcPacketSocket : public rtc::AsyncPacketSocket,
74 public P2PSocketClientDelegate { 74 public P2PSocketClientDelegate {
75 public: 75 public:
76 IpcPacketSocket(); 76 IpcPacketSocket();
77 ~IpcPacketSocket() override; 77 ~IpcPacketSocket() override;
78 78
79 // Struct to track information when a packet is received by this socket for
80 // send. The information tracked here will be used to match with the
81 // P2PSendPacketMetrics from the underneath system socket.
82 struct InFlightPacketRecord {
83 InFlightPacketRecord(uint64 packet_id,
84 size_t packet_size,
85 uint64 timeticks_received_by_socket)
86 : packet_id(packet_id),
87 packet_size(packet_size),
88 timeticks_received_by_socket(timeticks_received_by_socket) {}
89
90 uint64 packet_id;
91 size_t packet_size;
92 // The first time this packet shows up to this socket.
93 uint64 timeticks_received_by_socket;
Sergey Ulanov 2014/12/17 20:05:30 use base::TimeTicks type for this. Is this used an
guoweis_left_chromium 2014/12/22 21:41:47 Removed. This should been another change which tra
94 };
95
96 typedef std::list<InFlightPacketRecord> InFlightPacketList;
97
79 // Always takes ownership of client even if initialization fails. 98 // Always takes ownership of client even if initialization fails.
80 bool Init(P2PSocketType type, P2PSocketClientImpl* client, 99 bool Init(P2PSocketType type, P2PSocketClientImpl* client,
81 const rtc::SocketAddress& local_address, 100 const rtc::SocketAddress& local_address,
82 const rtc::SocketAddress& remote_address); 101 const rtc::SocketAddress& remote_address);
83 102
84 // rtc::AsyncPacketSocket interface. 103 // rtc::AsyncPacketSocket interface.
85 rtc::SocketAddress GetLocalAddress() const override; 104 rtc::SocketAddress GetLocalAddress() const override;
86 rtc::SocketAddress GetRemoteAddress() const override; 105 rtc::SocketAddress GetRemoteAddress() const override;
87 int Send(const void* pv, 106 int Send(const void* pv,
88 size_t cb, 107 size_t cb,
89 const rtc::PacketOptions& options) override; 108 const rtc::PacketOptions& options) override;
90 int SendTo(const void* pv, 109 int SendTo(const void* pv,
91 size_t cb, 110 size_t cb,
92 const rtc::SocketAddress& addr, 111 const rtc::SocketAddress& addr,
93 const rtc::PacketOptions& options) override; 112 const rtc::PacketOptions& options) override;
94 int Close() override; 113 int Close() override;
95 State GetState() const override; 114 State GetState() const override;
96 int GetOption(rtc::Socket::Option option, int* value) override; 115 int GetOption(rtc::Socket::Option option, int* value) override;
97 int SetOption(rtc::Socket::Option option, int value) override; 116 int SetOption(rtc::Socket::Option option, int value) override;
98 int GetError() const override; 117 int GetError() const override;
99 void SetError(int error) override; 118 void SetError(int error) override;
100 119
101 // P2PSocketClientDelegate implementation. 120 // P2PSocketClientDelegate implementation.
102 void OnOpen(const net::IPEndPoint& local_address, 121 void OnOpen(const net::IPEndPoint& local_address,
103 const net::IPEndPoint& remote_address) override; 122 const net::IPEndPoint& remote_address) override;
104 void OnIncomingTcpConnection(const net::IPEndPoint& address, 123 void OnIncomingTcpConnection(const net::IPEndPoint& address,
105 P2PSocketClient* client) override; 124 P2PSocketClient* client) override;
106 void OnSendComplete() override; 125 void OnSendComplete(const P2PSendPacketMetrics& send_metrics) override;
126
107 void OnError() override; 127 void OnError() override;
108 void OnDataReceived(const net::IPEndPoint& address, 128 void OnDataReceived(const net::IPEndPoint& address,
109 const std::vector<char>& data, 129 const std::vector<char>& data,
110 const base::TimeTicks& timestamp) override; 130 const base::TimeTicks& timestamp) override;
111 131
112 private: 132 private:
113 enum InternalState { 133 enum InternalState {
114 IS_UNINITIALIZED, 134 IS_UNINITIALIZED,
115 IS_OPENING, 135 IS_OPENING,
116 IS_OPEN, 136 IS_OPEN,
117 IS_CLOSED, 137 IS_CLOSED,
118 IS_ERROR, 138 IS_ERROR,
119 }; 139 };
120 140
121 // Increment the counter for consecutive bytes discarded as socket is running 141 // Increment the counter for consecutive bytes discarded as socket is running
122 // out of buffer. 142 // out of buffer.
123 void IncrementDiscardCounters(size_t bytes_discarded); 143 void IncrementDiscardCounters(size_t bytes_discarded);
124 144
125 // Update trace of send throttling internal state. This should be called 145 // Update trace of send throttling internal state. This should be called
126 // immediately after any changes to |send_bytes_available_| and/or 146 // immediately after any changes to |send_bytes_available_| and/or
127 // |in_flight_packet_sizes_|. 147 // |in_flight_packet_records_|.
128 void TraceSendThrottlingState() const; 148 void TraceSendThrottlingState() const;
129 149
130 void InitAcceptedTcp(P2PSocketClient* client, 150 void InitAcceptedTcp(P2PSocketClient* client,
131 const rtc::SocketAddress& local_address, 151 const rtc::SocketAddress& local_address,
132 const rtc::SocketAddress& remote_address); 152 const rtc::SocketAddress& remote_address);
133 153
134 int DoSetOption(P2PSocketOption option, int value); 154 int DoSetOption(P2PSocketOption option, int value);
135 155
136 // Allow a finch experiment to control the initial value of 156 // Allow a finch experiment to control the initial value of
137 // send_bytes_available_; 157 // send_bytes_available_;
138 void AdjustUdpSendBufferSize(); 158 void AdjustUdpSendBufferSize();
139 159
160 // Helper function to find the matching InFlightPacketRecord by packet_id.
161 // In normal case, it should always be the first one so the perf impact should
162 // be negligible. Return value is the iterator pointing to the matching
163 // InFlightPacketRecord. Can be InFlightPacketRecord::end() if no matching one
164 // is found.
165 InFlightPacketList::iterator FindInFlightRecord(uint64 packet_id);
166
140 P2PSocketType type_; 167 P2PSocketType type_;
141 168
142 // Message loop on which this socket was created and being used. 169 // Message loop on which this socket was created and being used.
143 base::MessageLoop* message_loop_; 170 base::MessageLoop* message_loop_;
144 171
145 // Corresponding P2P socket client. 172 // Corresponding P2P socket client.
146 scoped_refptr<P2PSocketClient> client_; 173 scoped_refptr<P2PSocketClient> client_;
147 174
148 // Local address is allocated by the browser process, and the 175 // Local address is allocated by the browser process, and the
149 // renderer side doesn't know the address until it receives OnOpen() 176 // renderer side doesn't know the address until it receives OnOpen()
150 // event from the browser. 177 // event from the browser.
151 rtc::SocketAddress local_address_; 178 rtc::SocketAddress local_address_;
152 179
153 // Remote address for client TCP connections. 180 // Remote address for client TCP connections.
154 rtc::SocketAddress remote_address_; 181 rtc::SocketAddress remote_address_;
155 182
156 // Current state of the object. 183 // Current state of the object.
157 InternalState state_; 184 InternalState state_;
158 185
159 // Track the number of bytes allowed to be sent non-blocking. This is used to 186 // Track the number of bytes allowed to be sent non-blocking. This is used to
160 // throttle the sending of packets to the browser process. For each packet 187 // throttle the sending of packets to the browser process. For each packet
161 // sent, the value is decreased. As callbacks to OnSendComplete() (as IPCs 188 // sent, the value is decreased. As callbacks to OnSendComplete() (as IPCs
162 // from the browser process) are made, the value is increased back. This 189 // from the browser process) are made, the value is increased back. This
163 // allows short bursts of high-rate sending without dropping packets, but 190 // allows short bursts of high-rate sending without dropping packets, but
164 // quickly restricts the client to a sustainable steady-state rate. 191 // quickly restricts the client to a sustainable steady-state rate.
165 size_t send_bytes_available_; 192 size_t send_bytes_available_;
166 std::deque<size_t> in_flight_packet_sizes_; 193
194 // This is a sorted linked list of all InFlightPacketRecord by its packet_id.
Sergey Ulanov 2014/12/17 20:05:30 You are not actually sorting them by packet_id. Th
guoweis_left_chromium 2014/12/22 21:41:47 Removed that comment.
195 // In normal case, the first packet should always be the one that we're going
196 // to receive the next completion signal. This list gives us a way to look for
197 // packets that we never receive its completion signal from OS.
Sergey Ulanov 2014/12/17 20:05:30 If I understand correctly the purpose of this CL i
guoweis_left_chromium 2014/12/22 21:41:47 Done.
198 InFlightPacketList in_flight_packet_records_;
167 199
168 // Set to true once EWOULDBLOCK was returned from Send(). Indicates that the 200 // Set to true once EWOULDBLOCK was returned from Send(). Indicates that the
169 // caller expects SignalWritable notification. 201 // caller expects SignalWritable notification.
170 bool writable_signal_expected_; 202 bool writable_signal_expected_;
171 203
172 // Current error code. Valid when state_ == IS_ERROR. 204 // Current error code. Valid when state_ == IS_ERROR.
173 int error_; 205 int error_;
174 int options_[P2P_SOCKET_OPT_MAX]; 206 int options_[P2P_SOCKET_OPT_MAX];
175 207
176 // Track the maximum and current consecutive bytes discarded due to not enough 208 // Track the maximum and current consecutive bytes discarded due to not enough
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 if (total_packets_ > 0) { 270 if (total_packets_ > 0) {
239 UMA_HISTOGRAM_PERCENTAGE("WebRTC.ApplicationPercentPacketsDiscarded", 271 UMA_HISTOGRAM_PERCENTAGE("WebRTC.ApplicationPercentPacketsDiscarded",
240 (packets_discarded_ * 100) / total_packets_); 272 (packets_discarded_ * 100) / total_packets_);
241 } 273 }
242 } 274 }
243 275
244 void IpcPacketSocket::TraceSendThrottlingState() const { 276 void IpcPacketSocket::TraceSendThrottlingState() const {
245 TRACE_COUNTER_ID1("p2p", "P2PSendBytesAvailable", local_address_.port(), 277 TRACE_COUNTER_ID1("p2p", "P2PSendBytesAvailable", local_address_.port(),
246 send_bytes_available_); 278 send_bytes_available_);
247 TRACE_COUNTER_ID1("p2p", "P2PSendPacketsInFlight", local_address_.port(), 279 TRACE_COUNTER_ID1("p2p", "P2PSendPacketsInFlight", local_address_.port(),
248 in_flight_packet_sizes_.size()); 280 in_flight_packet_records_.size());
249 } 281 }
250 282
251 void IpcPacketSocket::IncrementDiscardCounters(size_t bytes_discarded) { 283 void IpcPacketSocket::IncrementDiscardCounters(size_t bytes_discarded) {
252 current_discard_bytes_sequence_ += bytes_discarded; 284 current_discard_bytes_sequence_ += bytes_discarded;
253 packets_discarded_++; 285 packets_discarded_++;
254 286
255 if (current_discard_bytes_sequence_ > max_discard_bytes_sequence_) { 287 if (current_discard_bytes_sequence_ > max_discard_bytes_sequence_) {
256 max_discard_bytes_sequence_ = current_discard_bytes_sequence_; 288 max_discard_bytes_sequence_ = current_discard_bytes_sequence_;
257 } 289 }
258 } 290 }
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 return EWOULDBLOCK; 395 return EWOULDBLOCK;
364 case IS_CLOSED: 396 case IS_CLOSED:
365 return ENOTCONN; 397 return ENOTCONN;
366 case IS_ERROR: 398 case IS_ERROR:
367 return error_; 399 return error_;
368 case IS_OPEN: 400 case IS_OPEN:
369 // Continue sending the packet. 401 // Continue sending the packet.
370 break; 402 break;
371 } 403 }
372 404
405 uint64 tick_received_in_socket = base::TimeTicks::Now().ToInternalValue();
406
373 if (data_size == 0) { 407 if (data_size == 0) {
374 NOTREACHED(); 408 NOTREACHED();
375 return 0; 409 return 0;
376 } 410 }
377 411
378 total_packets_++; 412 total_packets_++;
379 413
380 if (data_size > send_bytes_available_) { 414 if (data_size > send_bytes_available_) {
381 TRACE_EVENT_INSTANT1("p2p", "MaxPendingBytesWouldBlock", 415 TRACE_EVENT_INSTANT1("p2p", "MaxPendingBytesWouldBlock",
382 TRACE_EVENT_SCOPE_THREAD, 416 TRACE_EVENT_SCOPE_THREAD,
383 "id", 417 "id",
384 client_->GetSocketID()); 418 client_->GetSocketID());
385 if (!writable_signal_expected_) { 419 if (!writable_signal_expected_) {
386 WebRtcLogMessage(base::StringPrintf( 420 WebRtcLogMessage(base::StringPrintf(
387 "IpcPacketSocket: sending is blocked. %d packets_in_flight.", 421 "IpcPacketSocket: sending is blocked. %d packets_in_flight.",
388 static_cast<int>(in_flight_packet_sizes_.size()))); 422 static_cast<int>(in_flight_packet_records_.size())));
389 423
390 writable_signal_expected_ = true; 424 writable_signal_expected_ = true;
391 } 425 }
392 426
393 error_ = EWOULDBLOCK; 427 error_ = EWOULDBLOCK;
394 IncrementDiscardCounters(data_size); 428 IncrementDiscardCounters(data_size);
395 return -1; 429 return -1;
396 } else { 430 } else {
397 current_discard_bytes_sequence_ = 0; 431 current_discard_bytes_sequence_ = 0;
398 } 432 }
399 433
400 net::IPEndPoint address_chrome; 434 net::IPEndPoint address_chrome;
401 if (!jingle_glue::SocketAddressToIPEndPoint(address, &address_chrome)) { 435 if (!jingle_glue::SocketAddressToIPEndPoint(address, &address_chrome)) {
402 DVLOG(1) << "Failed to convert remote address to IPEndPoint: address = " 436 DVLOG(1) << "Failed to convert remote address to IPEndPoint: address = "
403 << address.ToSensitiveString() << ", remote_address_ = " 437 << address.ToSensitiveString() << ", remote_address_ = "
404 << remote_address_.ToSensitiveString(); 438 << remote_address_.ToSensitiveString();
405 NOTREACHED(); 439 NOTREACHED();
406 error_ = EINVAL; 440 error_ = EINVAL;
407 return -1; 441 return -1;
408 } 442 }
409 443
410 send_bytes_available_ -= data_size; 444 send_bytes_available_ -= data_size;
411 in_flight_packet_sizes_.push_back(data_size);
412 TraceSendThrottlingState();
413 445
414 const char* data_char = reinterpret_cast<const char*>(data); 446 const char* data_char = reinterpret_cast<const char*>(data);
415 std::vector<char> data_vector(data_char, data_char + data_size); 447 std::vector<char> data_vector(data_char, data_char + data_size);
416 client_->SendWithDscp(address_chrome, data_vector, options); 448 uint64 packet_id =
449 client_->SendWithDscp(address_chrome, data_vector, options);
450
451 // Ensure packet_id is not 0. It can't be the case according to
452 // P2PSocketClientImpl::SendWithDscp().
453 DCHECK_NE(packet_id, 0uL);
454
455 // Since OnSendComplete happens on the same thread, there is no chance that
Sergey Ulanov 2014/12/17 20:05:30 nit: I don't think you really need this comment. I
guoweis_left_chromium 2014/12/22 21:41:47 Done.
456 // for the same packet, OnSendComplete is called before SendWithDscp is
457 // finished with |packet_id| back.
458 in_flight_packet_records_.push_back(
459 InFlightPacketRecord(packet_id, data_size, tick_received_in_socket));
460 TraceSendThrottlingState();
417 461
418 // Fake successful send. The caller ignores result anyway. 462 // Fake successful send. The caller ignores result anyway.
419 return data_size; 463 return data_size;
420 } 464 }
421 465
422 int IpcPacketSocket::Close() { 466 int IpcPacketSocket::Close() {
423 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 467 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
424 468
425 client_->Close(); 469 client_->Close();
426 state_ = IS_CLOSED; 470 state_ = IS_CLOSED;
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 596
553 rtc::SocketAddress remote_address; 597 rtc::SocketAddress remote_address;
554 if (!jingle_glue::IPEndPointToSocketAddress(address, &remote_address)) { 598 if (!jingle_glue::IPEndPointToSocketAddress(address, &remote_address)) {
555 // Always expect correct IPv4 address to be allocated. 599 // Always expect correct IPv4 address to be allocated.
556 NOTREACHED(); 600 NOTREACHED();
557 } 601 }
558 socket->InitAcceptedTcp(client, local_address_, remote_address); 602 socket->InitAcceptedTcp(client, local_address_, remote_address);
559 SignalNewConnection(this, socket.release()); 603 SignalNewConnection(this, socket.release());
560 } 604 }
561 605
562 void IpcPacketSocket::OnSendComplete() { 606 // For most of the case, the completion signal should be returned for the packet
607 // at the beginning of |in_flight_packet_records_| so the perf impact should be
608 // negligible.
609 IpcPacketSocket::InFlightPacketList::iterator
610 IpcPacketSocket::FindInFlightRecord(uint64 packet_id) {
611 CHECK(!in_flight_packet_records_.empty());
612 InFlightPacketList::iterator it = in_flight_packet_records_.begin();
613 for (; it != in_flight_packet_records_.end(); ++it) {
614 if (it->packet_id == packet_id) {
615 break;
616 }
617 }
618
619 // We should always be able to find matching packet_id in the
620 // in_flight_packet_records_.
621 DCHECK(it != in_flight_packet_records_.end());
622 return it;
623 }
624
625 void IpcPacketSocket::OnSendComplete(const P2PSendPacketMetrics& send_metrics) {
563 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 626 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
564 627
565 CHECK(!in_flight_packet_sizes_.empty()); 628 CHECK(!in_flight_packet_records_.empty());
566 send_bytes_available_ += in_flight_packet_sizes_.front(); 629
630 InFlightPacketList::iterator it;
631 if (send_metrics.packet_id == 0) {
Sergey Ulanov 2014/12/17 20:05:30 When does this happen? Why do you need this?
guoweis_left_chromium 2014/12/22 21:41:47 TCP. We're not tracking tcp's packet id so this is
632 // If send_metrics doesn't carry valid packet_id, it means that we should
633 // not try to detect mismatch packets.
634 it = in_flight_packet_records_.begin();
635 } else {
636 it = FindInFlightRecord(send_metrics.packet_id);
Sergey Ulanov 2014/12/17 20:05:30 I don't think you need this because we never expec
guoweis_left_chromium 2014/12/22 21:41:47 Done.
637
638 // If we can't find the record, something has gone very wrong at this point.
639 if (it == in_flight_packet_records_.end()) {
640 VLOG(1) << "Failed to find in-flight record with packet_id = "
641 << send_metrics.packet_id;
642 NOTREACHED();
643 return;
644 }
645 }
646
647 send_bytes_available_ += it->packet_size;
648
649 // Here is to detect a completion signal is not returned. We can't rely on the
650 // destructor since if a user closes the tab, the destructor is not
651 // invoked. Or if a user inputs another url, the destructor will be called
652 // before all completion signals return.
653 if (send_metrics.packet_id != 0 &&
654 in_flight_packet_records_.front().packet_id != send_metrics.packet_id) {
655 // Report an instance that a packet didn't have its completion
656 // signal returned.
657 UMA_HISTOGRAM_BOOLEAN("WebRTC.ApplicationSocketMismatchPacketsDetected_UDP",
Sergey Ulanov 2014/12/17 20:05:30 I don't think you need UMA metric for this. Just C
guoweis_left_chromium 2014/12/22 21:41:47 Done.
658 true);
659 }
567 660
568 DCHECK_LE(send_bytes_available_, kMaximumInFlightBytes); 661 DCHECK_LE(send_bytes_available_, kMaximumInFlightBytes);
569 662
570 in_flight_packet_sizes_.pop_front(); 663 in_flight_packet_records_.erase(it);
571 TraceSendThrottlingState(); 664 TraceSendThrottlingState();
572 665
573 if (writable_signal_expected_ && send_bytes_available_ > 0) { 666 if (writable_signal_expected_ && send_bytes_available_ > 0) {
574 WebRtcLogMessage(base::StringPrintf( 667 WebRtcLogMessage(base::StringPrintf(
575 "IpcPacketSocket: sending is unblocked. %d packets in flight.", 668 "IpcPacketSocket: sending is unblocked. %d packets in flight.",
576 static_cast<int>(in_flight_packet_sizes_.size()))); 669 static_cast<int>(in_flight_packet_records_.size())));
577 670
578 SignalReadyToSend(this); 671 SignalReadyToSend(this);
579 writable_signal_expected_ = false; 672 writable_signal_expected_ = false;
580 } 673 }
581 } 674 }
582 675
583 void IpcPacketSocket::OnError() { 676 void IpcPacketSocket::OnError() {
584 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 677 DCHECK_EQ(base::MessageLoop::current(), message_loop_);
585 bool was_closed = (state_ == IS_ERROR || state_ == IS_CLOSED); 678 bool was_closed = (state_ == IS_ERROR || state_ == IS_CLOSED);
586 state_ = IS_ERROR; 679 state_ = IS_ERROR;
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
740 } 833 }
741 834
742 rtc::AsyncResolverInterface* 835 rtc::AsyncResolverInterface*
743 IpcPacketSocketFactory::CreateAsyncResolver() { 836 IpcPacketSocketFactory::CreateAsyncResolver() {
744 scoped_ptr<AsyncAddressResolverImpl> resolver( 837 scoped_ptr<AsyncAddressResolverImpl> resolver(
745 new AsyncAddressResolverImpl(socket_dispatcher_)); 838 new AsyncAddressResolverImpl(socket_dispatcher_));
746 return resolver.release(); 839 return resolver.release();
747 } 840 }
748 841
749 } // namespace content 842 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698