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. 4 5 #include "content/renderer/p2p/ipc_socket_factory.h" 6 7 #include <algorithm> 8 #include <deque> 9 10 #include "base/compiler_specific.h" 11 #include "base/debug/trace_event.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/strings/stringprintf.h" 15 #include "base/threading/non_thread_safe.h" 16 #include "content/renderer/media/webrtc_logging.h" 17 #include "content/renderer/p2p/host_address_request.h" 18 #include "content/renderer/p2p/socket_client_delegate.h" 19 #include "content/renderer/p2p/socket_client_impl.h" 20 #include "content/renderer/p2p/socket_dispatcher.h" 21 #include "jingle/glue/utils.h" 22 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" 23 24 namespace content { 25 26 namespace { 27 28 const int kDefaultNonSetOptionValue = -1; 29 30 bool IsTcpClientSocket(P2PSocketType type) { 31 return (type == P2P_SOCKET_STUN_TCP_CLIENT) || 32 (type == P2P_SOCKET_TCP_CLIENT) || 33 (type == P2P_SOCKET_STUN_SSLTCP_CLIENT) || 34 (type == P2P_SOCKET_SSLTCP_CLIENT) || 35 (type == P2P_SOCKET_TLS_CLIENT) || 36 (type == P2P_SOCKET_STUN_TLS_CLIENT); 37 } 38 39 bool JingleSocketOptionToP2PSocketOption(talk_base::Socket::Option option, 40 P2PSocketOption* ipc_option) { 41 switch (option) { 42 case talk_base::Socket::OPT_RCVBUF: 43 *ipc_option = P2P_SOCKET_OPT_RCVBUF; 44 break; 45 case talk_base::Socket::OPT_SNDBUF: 46 *ipc_option = P2P_SOCKET_OPT_SNDBUF; 47 break; 48 case talk_base::Socket::OPT_DSCP: 49 *ipc_option = P2P_SOCKET_OPT_DSCP; 50 break; 51 case talk_base::Socket::OPT_DONTFRAGMENT: 52 case talk_base::Socket::OPT_NODELAY: 53 case talk_base::Socket::OPT_IPV6_V6ONLY: 54 case talk_base::Socket::OPT_RTP_SENDTIME_EXTN_ID: 55 return false; // Not supported by the chrome sockets. 56 default: 57 NOTREACHED(); 58 return false; 59 } 60 return true; 61 } 62 63 // TODO(miu): This needs tuning. http://crbug.com/237960 64 const size_t kMaximumInFlightBytes = 64 * 1024; // 64 KB 65 66 // IpcPacketSocket implements talk_base::AsyncPacketSocket interface 67 // using P2PSocketClient that works over IPC-channel. It must be used 68 // on the thread it was created. 69 class IpcPacketSocket : public talk_base::AsyncPacketSocket, 70 public P2PSocketClientDelegate { 71 public: 72 IpcPacketSocket(); 73 virtual ~IpcPacketSocket(); 74 75 // Always takes ownership of client even if initialization fails. 76 bool Init(P2PSocketType type, P2PSocketClientImpl* client, 77 const talk_base::SocketAddress& local_address, 78 const talk_base::SocketAddress& remote_address); 79 80 // talk_base::AsyncPacketSocket interface. 81 virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE; 82 virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE; 83 virtual int Send(const void *pv, size_t cb, 84 const talk_base::PacketOptions& options) OVERRIDE; 85 virtual int SendTo(const void *pv, size_t cb, 86 const talk_base::SocketAddress& addr, 87 const talk_base::PacketOptions& options) OVERRIDE; 88 virtual int Close() OVERRIDE; 89 virtual State GetState() const OVERRIDE; 90 virtual int GetOption(talk_base::Socket::Option option, int* value) OVERRIDE; 91 virtual int SetOption(talk_base::Socket::Option option, int value) OVERRIDE; 92 virtual int GetError() const OVERRIDE; 93 virtual void SetError(int error) OVERRIDE; 94 95 // P2PSocketClientDelegate implementation. 96 virtual void OnOpen(const net::IPEndPoint& address) OVERRIDE; 97 virtual void OnIncomingTcpConnection( 98 const net::IPEndPoint& address, 99 P2PSocketClient* client) OVERRIDE; 100 virtual void OnSendComplete() OVERRIDE; 101 virtual void OnError() OVERRIDE; 102 virtual void OnDataReceived(const net::IPEndPoint& address, 103 const std::vector<char>& data, 104 const base::TimeTicks& timestamp) OVERRIDE; 105 106 private: 107 enum InternalState { 108 IS_UNINITIALIZED, 109 IS_OPENING, 110 IS_OPEN, 111 IS_CLOSED, 112 IS_ERROR, 113 }; 114 115 // Update trace of send throttling internal state. This should be called 116 // immediately after any changes to |send_bytes_available_| and/or 117 // |in_flight_packet_sizes_|. 118 void TraceSendThrottlingState() const; 119 120 void InitAcceptedTcp(P2PSocketClient* client, 121 const talk_base::SocketAddress& local_address, 122 const talk_base::SocketAddress& remote_address); 123 124 int DoSetOption(P2PSocketOption option, int value); 125 126 P2PSocketType type_; 127 128 // Message loop on which this socket was created and being used. 129 base::MessageLoop* message_loop_; 130 131 // Corresponding P2P socket client. 132 scoped_refptr<P2PSocketClient> client_; 133 134 // Local address is allocated by the browser process, and the 135 // renderer side doesn't know the address until it receives OnOpen() 136 // event from the browser. 137 talk_base::SocketAddress local_address_; 138 139 // Remote address for client TCP connections. 140 talk_base::SocketAddress remote_address_; 141 142 // Current state of the object. 143 InternalState state_; 144 145 // Track the number of bytes allowed to be sent non-blocking. This is used to 146 // throttle the sending of packets to the browser process. For each packet 147 // sent, the value is decreased. As callbacks to OnSendComplete() (as IPCs 148 // from the browser process) are made, the value is increased back. This 149 // allows short bursts of high-rate sending without dropping packets, but 150 // quickly restricts the client to a sustainable steady-state rate. 151 size_t send_bytes_available_; 152 std::deque<size_t> in_flight_packet_sizes_; 153 154 // Set to true once EWOULDBLOCK was returned from Send(). Indicates that the 155 // caller expects SignalWritable notification. 156 bool writable_signal_expected_; 157 158 // Current error code. Valid when state_ == IS_ERROR. 159 int error_; 160 int options_[P2P_SOCKET_OPT_MAX]; 161 162 DISALLOW_COPY_AND_ASSIGN(IpcPacketSocket); 163 }; 164 165 // Simple wrapper around P2PAsyncAddressResolver. The main purpose of this 166 // class is to send SignalDone, after OnDone callback from 167 // P2PAsyncAddressResolver. Libjingle sig slots are not thread safe. In case 168 // of MT sig slots clients must call disconnect. This class is to make sure 169 // we destruct from the same thread on which is created. 170 class AsyncAddressResolverImpl : public base::NonThreadSafe, 171 public talk_base::AsyncResolverInterface { 172 public: 173 AsyncAddressResolverImpl(P2PSocketDispatcher* dispatcher); 174 virtual ~AsyncAddressResolverImpl(); 175 176 // talk_base::AsyncResolverInterface interface. 177 virtual void Start(const talk_base::SocketAddress& addr) OVERRIDE; 178 virtual bool GetResolvedAddress( 179 int family, talk_base::SocketAddress* addr) const OVERRIDE; 180 virtual int GetError() const OVERRIDE; 181 virtual void Destroy(bool wait) OVERRIDE; 182 183 private: 184 virtual void OnAddressResolved(const net::IPAddressList& addresses); 185 186 scoped_refptr<P2PAsyncAddressResolver> resolver_; 187 int port_; // Port number in |addr| from Start() method. 188 std::vector<talk_base::IPAddress> addresses_; // Resolved addresses. 189 }; 190 191 IpcPacketSocket::IpcPacketSocket() 192 : type_(P2P_SOCKET_UDP), 193 message_loop_(base::MessageLoop::current()), 194 state_(IS_UNINITIALIZED), 195 send_bytes_available_(kMaximumInFlightBytes), 196 writable_signal_expected_(false), 197 error_(0) { 198 COMPILE_ASSERT(kMaximumInFlightBytes > 0, would_send_at_zero_rate); 199 std::fill_n(options_, static_cast<int> (P2P_SOCKET_OPT_MAX), 200 kDefaultNonSetOptionValue); 201 } 202 203 IpcPacketSocket::~IpcPacketSocket() { 204 if (state_ == IS_OPENING || state_ == IS_OPEN || 205 state_ == IS_ERROR) { 206 Close(); 207 } 208 } 209 210 void IpcPacketSocket::TraceSendThrottlingState() const { 211 TRACE_COUNTER_ID1("p2p", "P2PSendBytesAvailable", local_address_.port(), 212 send_bytes_available_); 213 TRACE_COUNTER_ID1("p2p", "P2PSendPacketsInFlight", local_address_.port(), 214 in_flight_packet_sizes_.size()); 215 } 216 217 bool IpcPacketSocket::Init(P2PSocketType type, 218 P2PSocketClientImpl* client, 219 const talk_base::SocketAddress& local_address, 220 const talk_base::SocketAddress& remote_address) { 221 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 222 DCHECK_EQ(state_, IS_UNINITIALIZED); 223 224 type_ = type; 225 client_ = client; 226 local_address_ = local_address; 227 remote_address_ = remote_address; 228 state_ = IS_OPENING; 229 230 net::IPEndPoint local_endpoint; 231 if (!jingle_glue::SocketAddressToIPEndPoint( 232 local_address, &local_endpoint)) { 233 return false; 234 } 235 236 net::IPEndPoint remote_endpoint; 237 if (!remote_address.IsNil() && 238 !jingle_glue::SocketAddressToIPEndPoint( 239 remote_address, &remote_endpoint)) { 240 return false; 241 } 242 243 // We need to send both resolved and unresolved address in Init. Unresolved 244 // address will be used in case of TLS for certificate hostname matching. 245 // Certificate will be tied to domain name not to IP address. 246 P2PHostAndIPEndPoint remote_info(remote_address.hostname(), remote_endpoint); 247 248 client->Init(type, local_endpoint, remote_info, this); 249 250 return true; 251 } 252 253 void IpcPacketSocket::InitAcceptedTcp( 254 P2PSocketClient* client, 255 const talk_base::SocketAddress& local_address, 256 const talk_base::SocketAddress& remote_address) { 257 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 258 DCHECK_EQ(state_, IS_UNINITIALIZED); 259 260 client_ = client; 261 local_address_ = local_address; 262 remote_address_ = remote_address; 263 state_ = IS_OPEN; 264 TraceSendThrottlingState(); 265 client_->SetDelegate(this); 266 } 267 268 // talk_base::AsyncPacketSocket interface. 269 talk_base::SocketAddress IpcPacketSocket::GetLocalAddress() const { 270 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 271 return local_address_; 272 } 273 274 talk_base::SocketAddress IpcPacketSocket::GetRemoteAddress() const { 275 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 276 return remote_address_; 277 } 278 279 int IpcPacketSocket::Send(const void *data, size_t data_size, 280 const talk_base::PacketOptions& options) { 281 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 282 return SendTo(data, data_size, remote_address_, options); 283 } 284 285 int IpcPacketSocket::SendTo(const void *data, size_t data_size, 286 const talk_base::SocketAddress& address, 287 const talk_base::PacketOptions& options) { 288 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 289 290 switch (state_) { 291 case IS_UNINITIALIZED: 292 NOTREACHED(); 293 return EWOULDBLOCK; 294 case IS_OPENING: 295 return EWOULDBLOCK; 296 case IS_CLOSED: 297 return ENOTCONN; 298 case IS_ERROR: 299 return error_; 300 case IS_OPEN: 301 // Continue sending the packet. 302 break; 303 } 304 305 if (data_size == 0) { 306 NOTREACHED(); 307 return 0; 308 } 309 310 if (data_size > send_bytes_available_) { 311 TRACE_EVENT_INSTANT1("p2p", "MaxPendingBytesWouldBlock", 312 TRACE_EVENT_SCOPE_THREAD, 313 "id", 314 client_->GetSocketID()); 315 if (!writable_signal_expected_) { 316 WebRtcLogMessage(base::StringPrintf( 317 "IpcPacketSocket: sending is blocked. %d packets_in_flight.", 318 static_cast<int>(in_flight_packet_sizes_.size()))); 319 320 writable_signal_expected_ = true; 321 } 322 323 error_ = EWOULDBLOCK; 324 return -1; 325 } 326 327 net::IPEndPoint address_chrome; 328 if (!jingle_glue::SocketAddressToIPEndPoint(address, &address_chrome)) { 329 NOTREACHED(); 330 error_ = EINVAL; 331 return -1; 332 } 333 334 send_bytes_available_ -= data_size; 335 in_flight_packet_sizes_.push_back(data_size); 336 TraceSendThrottlingState(); 337 338 const char* data_char = reinterpret_cast<const char*>(data); 339 std::vector<char> data_vector(data_char, data_char + data_size); 340 client_->SendWithDscp(address_chrome, data_vector, options); 341 342 // Fake successful send. The caller ignores result anyway. 343 return data_size; 344 } 345 346 int IpcPacketSocket::Close() { 347 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 348 349 client_->Close(); 350 state_ = IS_CLOSED; 351 352 return 0; 353 } 354 355 talk_base::AsyncPacketSocket::State IpcPacketSocket::GetState() const { 356 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 357 358 switch (state_) { 359 case IS_UNINITIALIZED: 360 NOTREACHED(); 361 return STATE_CLOSED; 362 363 case IS_OPENING: 364 return STATE_BINDING; 365 366 case IS_OPEN: 367 if (IsTcpClientSocket(type_)) { 368 return STATE_CONNECTED; 369 } else { 370 return STATE_BOUND; 371 } 372 373 case IS_CLOSED: 374 case IS_ERROR: 375 return STATE_CLOSED; 376 } 377 378 NOTREACHED(); 379 return STATE_CLOSED; 380 } 381 382 int IpcPacketSocket::GetOption(talk_base::Socket::Option option, int* value) { 383 P2PSocketOption p2p_socket_option = P2P_SOCKET_OPT_MAX; 384 if (!JingleSocketOptionToP2PSocketOption(option, &p2p_socket_option)) { 385 // unsupported option. 386 return -1; 387 } 388 389 *value = options_[p2p_socket_option]; 390 return 0; 391 } 392 393 int IpcPacketSocket::SetOption(talk_base::Socket::Option option, int value) { 394 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 395 396 P2PSocketOption p2p_socket_option = P2P_SOCKET_OPT_MAX; 397 if (!JingleSocketOptionToP2PSocketOption(option, &p2p_socket_option)) { 398 // Option is not supported. 399 return -1; 400 } 401 402 options_[p2p_socket_option] = value; 403 404 if (state_ == IS_OPEN) { 405 // Options will be applied when state becomes IS_OPEN in OnOpen. 406 return DoSetOption(p2p_socket_option, value); 407 } 408 return 0; 409 } 410 411 int IpcPacketSocket::DoSetOption(P2PSocketOption option, int value) { 412 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 413 DCHECK_EQ(state_, IS_OPEN); 414 415 client_->SetOption(option, value); 416 return 0; 417 } 418 419 int IpcPacketSocket::GetError() const { 420 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 421 return error_; 422 } 423 424 void IpcPacketSocket::SetError(int error) { 425 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 426 error_ = error; 427 } 428 429 void IpcPacketSocket::OnOpen(const net::IPEndPoint& address) { 430 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 431 432 if (!jingle_glue::IPEndPointToSocketAddress(address, &local_address_)) { 433 // Always expect correct IPv4 address to be allocated. 434 NOTREACHED(); 435 OnError(); 436 return; 437 } 438 439 state_ = IS_OPEN; 440 TraceSendThrottlingState(); 441 442 // Set all pending options if any. 443 for (int i = 0; i < P2P_SOCKET_OPT_MAX; ++i) { 444 if (options_[i] != kDefaultNonSetOptionValue) 445 DoSetOption(static_cast<P2PSocketOption> (i), options_[i]); 446 } 447 448 SignalAddressReady(this, local_address_); 449 if (IsTcpClientSocket(type_)) 450 SignalConnect(this); 451 } 452 453 void IpcPacketSocket::OnIncomingTcpConnection( 454 const net::IPEndPoint& address, 455 P2PSocketClient* client) { 456 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 457 458 scoped_ptr<IpcPacketSocket> socket(new IpcPacketSocket()); 459 460 talk_base::SocketAddress remote_address; 461 if (!jingle_glue::IPEndPointToSocketAddress(address, &remote_address)) { 462 // Always expect correct IPv4 address to be allocated. 463 NOTREACHED(); 464 } 465 socket->InitAcceptedTcp(client, local_address_, remote_address); 466 SignalNewConnection(this, socket.release()); 467 } 468 469 void IpcPacketSocket::OnSendComplete() { 470 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 471 472 CHECK(!in_flight_packet_sizes_.empty()); 473 send_bytes_available_ += in_flight_packet_sizes_.front(); 474 475 DCHECK_LE(send_bytes_available_, kMaximumInFlightBytes); 476 477 in_flight_packet_sizes_.pop_front(); 478 TraceSendThrottlingState(); 479 480 if (writable_signal_expected_ && send_bytes_available_ > 0) { 481 WebRtcLogMessage(base::StringPrintf( 482 "IpcPacketSocket: sending is unblocked. %d packets in flight.", 483 static_cast<int>(in_flight_packet_sizes_.size()))); 484 485 SignalReadyToSend(this); 486 writable_signal_expected_ = false; 487 } 488 } 489 490 void IpcPacketSocket::OnError() { 491 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 492 bool was_closed = (state_ == IS_ERROR || state_ == IS_CLOSED); 493 state_ = IS_ERROR; 494 error_ = ECONNABORTED; 495 if (!was_closed) { 496 SignalClose(this, 0); 497 } 498 } 499 500 void IpcPacketSocket::OnDataReceived(const net::IPEndPoint& address, 501 const std::vector<char>& data, 502 const base::TimeTicks& timestamp) { 503 DCHECK_EQ(base::MessageLoop::current(), message_loop_); 504 505 talk_base::SocketAddress address_lj; 506 if (!jingle_glue::IPEndPointToSocketAddress(address, &address_lj)) { 507 // We should always be able to convert address here because we 508 // don't expect IPv6 address on IPv4 connections. 509 NOTREACHED(); 510 return; 511 } 512 513 talk_base::PacketTime packet_time(timestamp.ToInternalValue(), 0); 514 SignalReadPacket(this, &data[0], data.size(), address_lj, 515 packet_time); 516 } 517 518 AsyncAddressResolverImpl::AsyncAddressResolverImpl( 519 P2PSocketDispatcher* dispatcher) 520 : resolver_(new P2PAsyncAddressResolver(dispatcher)) { 521 } 522 523 AsyncAddressResolverImpl::~AsyncAddressResolverImpl() { 524 } 525 526 void AsyncAddressResolverImpl::Start(const talk_base::SocketAddress& addr) { 527 DCHECK(CalledOnValidThread()); 528 // Copy port number from |addr|. |port_| must be copied 529 // when resolved address is returned in GetResolvedAddress. 530 port_ = addr.port(); 531 532 resolver_->Start(addr, base::Bind( 533 &AsyncAddressResolverImpl::OnAddressResolved, 534 base::Unretained(this))); 535 } 536 537 bool AsyncAddressResolverImpl::GetResolvedAddress( 538 int family, talk_base::SocketAddress* addr) const { 539 DCHECK(CalledOnValidThread()); 540 541 if (addresses_.empty()) 542 return false; 543 544 for (size_t i = 0; i < addresses_.size(); ++i) { 545 if (family == addresses_[i].family()) { 546 addr->SetResolvedIP(addresses_[i]); 547 addr->SetPort(port_); 548 return true; 549 } 550 } 551 return false; 552 } 553 554 int AsyncAddressResolverImpl::GetError() const { 555 DCHECK(CalledOnValidThread()); 556 return addresses_.empty() ? -1 : 0; 557 } 558 559 void AsyncAddressResolverImpl::Destroy(bool wait) { 560 DCHECK(CalledOnValidThread()); 561 resolver_->Cancel(); 562 // Libjingle doesn't need this object any more and it's not going to delete 563 // it explicitly. 564 delete this; 565 } 566 567 void AsyncAddressResolverImpl::OnAddressResolved( 568 const net::IPAddressList& addresses) { 569 DCHECK(CalledOnValidThread()); 570 for (size_t i = 0; i < addresses.size(); ++i) { 571 talk_base::SocketAddress socket_address; 572 if (!jingle_glue::IPEndPointToSocketAddress( 573 net::IPEndPoint(addresses[i], 0), &socket_address)) { 574 NOTREACHED(); 575 } 576 addresses_.push_back(socket_address.ipaddr()); 577 } 578 SignalDone(this); 579 } 580 581 } // namespace 582 583 IpcPacketSocketFactory::IpcPacketSocketFactory( 584 P2PSocketDispatcher* socket_dispatcher) 585 : socket_dispatcher_(socket_dispatcher) { 586 } 587 588 IpcPacketSocketFactory::~IpcPacketSocketFactory() { 589 } 590 591 talk_base::AsyncPacketSocket* IpcPacketSocketFactory::CreateUdpSocket( 592 const talk_base::SocketAddress& local_address, int min_port, int max_port) { 593 talk_base::SocketAddress crome_address; 594 P2PSocketClientImpl* socket_client = 595 new P2PSocketClientImpl(socket_dispatcher_); 596 scoped_ptr<IpcPacketSocket> socket(new IpcPacketSocket()); 597 // TODO(sergeyu): Respect local_address and port limits here (need 598 // to pass them over IPC channel to the browser). 599 if (!socket->Init(P2P_SOCKET_UDP, socket_client, 600 local_address, talk_base::SocketAddress())) { 601 return NULL; 602 } 603 return socket.release(); 604 } 605 606 talk_base::AsyncPacketSocket* IpcPacketSocketFactory::CreateServerTcpSocket( 607 const talk_base::SocketAddress& local_address, int min_port, int max_port, 608 int opts) { 609 // TODO(sergeyu): Implement SSL support. 610 if (opts & talk_base::PacketSocketFactory::OPT_SSLTCP) 611 return NULL; 612 613 P2PSocketType type = (opts & talk_base::PacketSocketFactory::OPT_STUN) ? 614 P2P_SOCKET_STUN_TCP_SERVER : P2P_SOCKET_TCP_SERVER; 615 P2PSocketClientImpl* socket_client = 616 new P2PSocketClientImpl(socket_dispatcher_); 617 scoped_ptr<IpcPacketSocket> socket(new IpcPacketSocket()); 618 if (!socket->Init(type, socket_client, local_address, 619 talk_base::SocketAddress())) { 620 return NULL; 621 } 622 return socket.release(); 623 } 624 625 talk_base::AsyncPacketSocket* IpcPacketSocketFactory::CreateClientTcpSocket( 626 const talk_base::SocketAddress& local_address, 627 const talk_base::SocketAddress& remote_address, 628 const talk_base::ProxyInfo& proxy_info, 629 const std::string& user_agent, int opts) { 630 P2PSocketType type; 631 if (opts & talk_base::PacketSocketFactory::OPT_SSLTCP) { 632 type = (opts & talk_base::PacketSocketFactory::OPT_STUN) ? 633 P2P_SOCKET_STUN_SSLTCP_CLIENT : P2P_SOCKET_SSLTCP_CLIENT; 634 } else if (opts & talk_base::PacketSocketFactory::OPT_TLS) { 635 type = (opts & talk_base::PacketSocketFactory::OPT_STUN) ? 636 P2P_SOCKET_STUN_TLS_CLIENT : P2P_SOCKET_TLS_CLIENT; 637 } else { 638 type = (opts & talk_base::PacketSocketFactory::OPT_STUN) ? 639 P2P_SOCKET_STUN_TCP_CLIENT : P2P_SOCKET_TCP_CLIENT; 640 } 641 P2PSocketClientImpl* socket_client = 642 new P2PSocketClientImpl(socket_dispatcher_); 643 scoped_ptr<IpcPacketSocket> socket(new IpcPacketSocket()); 644 if (!socket->Init(type, socket_client, local_address, remote_address)) 645 return NULL; 646 return socket.release(); 647 } 648 649 talk_base::AsyncResolverInterface* 650 IpcPacketSocketFactory::CreateAsyncResolver() { 651 scoped_ptr<AsyncAddressResolverImpl> resolver( 652 new AsyncAddressResolverImpl(socket_dispatcher_)); 653 return resolver.release(); 654 } 655 656 } // namespace content 657