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, 48 uint16_t min_port, 49 uint16_t max_port) { 50 // UDP sockets are simple. 51 rtc::AsyncSocket* socket = 52 socket_factory()->CreateAsyncSocket( 53 address.family(), SOCK_DGRAM); 54 if (!socket) { 55 return NULL; 56 } 57 if (BindSocket(socket, address, min_port, max_port) < 0) { 58 LOG(LS_ERROR) << "UDP bind failed with error " 59 << socket->GetError(); 60 delete socket; 61 return NULL; 62 } 63 return new rtc::AsyncUDPSocket(socket); 64 } 65 66 AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket( 67 const SocketAddress& local_address, 68 uint16_t min_port, 69 uint16_t max_port, 70 int opts) { 71 // Fail if TLS is required. 72 if (opts & PacketSocketFactory::OPT_TLS) { 73 LOG(LS_ERROR) << "TLS support currently is not available."; 74 return NULL; 75 } 76 77 rtc::AsyncSocket* socket = 78 socket_factory()->CreateAsyncSocket(local_address.family(), 79 SOCK_STREAM); 80 if (!socket) { 81 return NULL; 82 } 83 84 if (BindSocket(socket, local_address, min_port, max_port) < 0) { 85 LOG(LS_ERROR) << "TCP bind failed with error " 86 << socket->GetError(); 87 delete socket; 88 return NULL; 89 } 90 91 // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket. 92 if (opts & PacketSocketFactory::OPT_SSLTCP) { 93 ASSERT(!(opts & PacketSocketFactory::OPT_TLS)); 94 socket = new rtc::AsyncSSLSocket(socket); 95 } 96 97 // Set TCP_NODELAY (via OPT_NODELAY) for improved performance. 98 // See http://go/gtalktcpnodelayexperiment 99 socket->SetOption(rtc::Socket::OPT_NODELAY, 1); 100 101 if (opts & PacketSocketFactory::OPT_STUN) 102 return new cricket::AsyncStunTCPSocket(socket, true); 103 104 return new rtc::AsyncTCPSocket(socket, true); 105 } 106 107 AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket( 108 const SocketAddress& local_address, const SocketAddress& remote_address, 109 const ProxyInfo& proxy_info, const std::string& user_agent, int opts) { 110 111 rtc::AsyncSocket* socket = 112 socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM); 113 if (!socket) { 114 return NULL; 115 } 116 117 if (BindSocket(socket, local_address, 0, 0) < 0) { 118 LOG(LS_ERROR) << "TCP bind failed with error " 119 << socket->GetError(); 120 delete socket; 121 return NULL; 122 } 123 124 // If using a proxy, wrap the socket in a proxy socket. 125 if (proxy_info.type == rtc::PROXY_SOCKS5) { 126 socket = new rtc::AsyncSocksProxySocket( 127 socket, proxy_info.address, proxy_info.username, proxy_info.password); 128 } else if (proxy_info.type == rtc::PROXY_HTTPS) { 129 socket = new rtc::AsyncHttpsProxySocket( 130 socket, user_agent, proxy_info.address, 131 proxy_info.username, proxy_info.password); 132 } 133 134 // If using TLS, wrap the socket in an SSL adapter. 135 if (opts & PacketSocketFactory::OPT_TLS) { 136 ASSERT(!(opts & PacketSocketFactory::OPT_SSLTCP)); 137 138 rtc::SSLAdapter* ssl_adapter = rtc::SSLAdapter::Create(socket); 139 if (!ssl_adapter) { 140 return NULL; 141 } 142 143 socket = ssl_adapter; 144 145 if (ssl_adapter->StartSSL(remote_address.hostname().c_str(), false) != 0) { 146 delete ssl_adapter; 147 return NULL; 148 } 149 150 // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket. 151 } else if (opts & PacketSocketFactory::OPT_SSLTCP) { 152 ASSERT(!(opts & PacketSocketFactory::OPT_TLS)); 153 socket = new rtc::AsyncSSLSocket(socket); 154 } 155 156 if (socket->Connect(remote_address) < 0) { 157 LOG(LS_ERROR) << "TCP connect failed with error " 158 << socket->GetError(); 159 delete socket; 160 return NULL; 161 } 162 163 // Finally, wrap that socket in a TCP or STUN TCP packet socket. 164 AsyncPacketSocket* tcp_socket; 165 if (opts & PacketSocketFactory::OPT_STUN) { 166 tcp_socket = new cricket::AsyncStunTCPSocket(socket, false); 167 } else { 168 tcp_socket = new rtc::AsyncTCPSocket(socket, false); 169 } 170 171 // Set TCP_NODELAY (via OPT_NODELAY) for improved performance. 172 // See http://go/gtalktcpnodelayexperiment 173 tcp_socket->SetOption(rtc::Socket::OPT_NODELAY, 1); 174 175 return tcp_socket; 176 } 177 178 AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() { 179 return new rtc::AsyncResolver(); 180 } 181 182 int BasicPacketSocketFactory::BindSocket(AsyncSocket* socket, 183 const SocketAddress& local_address, 184 uint16_t min_port, 185 uint16_t max_port) { 186 int ret = -1; 187 if (min_port == 0 && max_port == 0) { 188 // If there's no port range, let the OS pick a port for us. 189 ret = socket->Bind(local_address); 190 } else { 191 // Otherwise, try to find a port in the provided range. 192 for (int port = min_port; ret < 0 && port <= max_port; ++port) { 193 ret = socket->Bind(rtc::SocketAddress(local_address.ipaddr(), 194 port)); 195 } 196 } 197 return ret; 198 } 199 200 SocketFactory* BasicPacketSocketFactory::socket_factory() { 201 if (thread_) { 202 ASSERT(thread_ == Thread::Current()); 203 return thread_->socketserver(); 204 } else { 205 return socket_factory_; 206 } 207 } 208 209 } // namespace rtc 210