1 /* 2 * Copyright 2011 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/p2p/base/basicpacketsocketfactory.h" 12 13 #include "webrtc/p2p/base/asyncstuntcpsocket.h" 14 #include "webrtc/p2p/base/stun.h" 15 #include "webrtc/base/asynctcpsocket.h" 16 #include "webrtc/base/asyncudpsocket.h" 17 #include "webrtc/base/logging.h" 18 #include "webrtc/base/nethelpers.h" 19 #include "webrtc/base/physicalsocketserver.h" 20 #include "webrtc/base/scoped_ptr.h" 21 #include "webrtc/base/socketadapters.h" 22 #include "webrtc/base/ssladapter.h" 23 #include "webrtc/base/thread.h" 24 25 namespace rtc { 26 27 BasicPacketSocketFactory::BasicPacketSocketFactory() 28 : thread_(Thread::Current()), 29 socket_factory_(NULL) { 30 } 31 32 BasicPacketSocketFactory::BasicPacketSocketFactory(Thread* thread) 33 : thread_(thread), 34 socket_factory_(NULL) { 35 } 36 37 BasicPacketSocketFactory::BasicPacketSocketFactory( 38 SocketFactory* socket_factory) 39 : thread_(NULL), 40 socket_factory_(socket_factory) { 41 } 42 43 BasicPacketSocketFactory::~BasicPacketSocketFactory() { 44 } 45 46 AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket( 47 const SocketAddress& address, uint16 min_port, uint16 max_port) { 48 // UDP sockets are simple. 49 rtc::AsyncSocket* socket = 50 socket_factory()->CreateAsyncSocket( 51 address.family(), SOCK_DGRAM); 52 if (!socket) { 53 return NULL; 54 } 55 if (BindSocket(socket, address, min_port, max_port) < 0) { 56 LOG(LS_ERROR) << "UDP bind failed with error " 57 << socket->GetError(); 58 delete socket; 59 return NULL; 60 } 61 return new rtc::AsyncUDPSocket(socket); 62 } 63 64 AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket( 65 const SocketAddress& local_address, uint16 min_port, uint16 max_port, 66 int opts) { 67 68 // Fail if TLS is required. 69 if (opts & PacketSocketFactory::OPT_TLS) { 70 LOG(LS_ERROR) << "TLS support currently is not available."; 71 return NULL; 72 } 73 74 rtc::AsyncSocket* socket = 75 socket_factory()->CreateAsyncSocket(local_address.family(), 76 SOCK_STREAM); 77 if (!socket) { 78 return NULL; 79 } 80 81 if (BindSocket(socket, local_address, min_port, max_port) < 0) { 82 LOG(LS_ERROR) << "TCP bind failed with error " 83 << socket->GetError(); 84 delete socket; 85 return NULL; 86 } 87 88 // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket. 89 if (opts & PacketSocketFactory::OPT_SSLTCP) { 90 ASSERT(!(opts & PacketSocketFactory::OPT_TLS)); 91 socket = new rtc::AsyncSSLSocket(socket); 92 } 93 94 // Set TCP_NODELAY (via OPT_NODELAY) for improved performance. 95 // See http://go/gtalktcpnodelayexperiment 96 socket->SetOption(rtc::Socket::OPT_NODELAY, 1); 97 98 if (opts & PacketSocketFactory::OPT_STUN) 99 return new cricket::AsyncStunTCPSocket(socket, true); 100 101 return new rtc::AsyncTCPSocket(socket, true); 102 } 103 104 AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket( 105 const SocketAddress& local_address, const SocketAddress& remote_address, 106 const ProxyInfo& proxy_info, const std::string& user_agent, int opts) { 107 108 rtc::AsyncSocket* socket = 109 socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM); 110 if (!socket) { 111 return NULL; 112 } 113 114 if (BindSocket(socket, local_address, 0, 0) < 0) { 115 LOG(LS_ERROR) << "TCP bind failed with error " 116 << socket->GetError(); 117 delete socket; 118 return NULL; 119 } 120 121 // If using a proxy, wrap the socket in a proxy socket. 122 if (proxy_info.type == rtc::PROXY_SOCKS5) { 123 socket = new rtc::AsyncSocksProxySocket( 124 socket, proxy_info.address, proxy_info.username, proxy_info.password); 125 } else if (proxy_info.type == rtc::PROXY_HTTPS) { 126 socket = new rtc::AsyncHttpsProxySocket( 127 socket, user_agent, proxy_info.address, 128 proxy_info.username, proxy_info.password); 129 } 130 131 // If using TLS, wrap the socket in an SSL adapter. 132 if (opts & PacketSocketFactory::OPT_TLS) { 133 ASSERT(!(opts & PacketSocketFactory::OPT_SSLTCP)); 134 135 rtc::SSLAdapter* ssl_adapter = rtc::SSLAdapter::Create(socket); 136 if (!ssl_adapter) { 137 return NULL; 138 } 139 140 socket = ssl_adapter; 141 142 if (ssl_adapter->StartSSL(remote_address.hostname().c_str(), false) != 0) { 143 delete ssl_adapter; 144 return NULL; 145 } 146 147 // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket. 148 } else if (opts & PacketSocketFactory::OPT_SSLTCP) { 149 ASSERT(!(opts & PacketSocketFactory::OPT_TLS)); 150 socket = new rtc::AsyncSSLSocket(socket); 151 } 152 153 if (socket->Connect(remote_address) < 0) { 154 LOG(LS_ERROR) << "TCP connect failed with error " 155 << socket->GetError(); 156 delete socket; 157 return NULL; 158 } 159 160 // Finally, wrap that socket in a TCP or STUN TCP packet socket. 161 AsyncPacketSocket* tcp_socket; 162 if (opts & PacketSocketFactory::OPT_STUN) { 163 tcp_socket = new cricket::AsyncStunTCPSocket(socket, false); 164 } else { 165 tcp_socket = new rtc::AsyncTCPSocket(socket, false); 166 } 167 168 // Set TCP_NODELAY (via OPT_NODELAY) for improved performance. 169 // See http://go/gtalktcpnodelayexperiment 170 tcp_socket->SetOption(rtc::Socket::OPT_NODELAY, 1); 171 172 return tcp_socket; 173 } 174 175 AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() { 176 return new rtc::AsyncResolver(); 177 } 178 179 int BasicPacketSocketFactory::BindSocket( 180 AsyncSocket* socket, const SocketAddress& local_address, 181 uint16 min_port, uint16 max_port) { 182 int ret = -1; 183 if (min_port == 0 && max_port == 0) { 184 // If there's no port range, let the OS pick a port for us. 185 ret = socket->Bind(local_address); 186 } else { 187 // Otherwise, try to find a port in the provided range. 188 for (int port = min_port; ret < 0 && port <= max_port; ++port) { 189 ret = socket->Bind(rtc::SocketAddress(local_address.ipaddr(), 190 port)); 191 } 192 } 193 return ret; 194 } 195 196 SocketFactory* BasicPacketSocketFactory::socket_factory() { 197 if (thread_) { 198 ASSERT(thread_ == Thread::Current()); 199 return thread_->socketserver(); 200 } else { 201 return socket_factory_; 202 } 203 } 204 205 } // namespace rtc 206