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 "p2p/base/basic_packet_socket_factory.h"
12
13 #include <stddef.h>
14
15 #include <string>
16
17 #include "p2p/base/async_stun_tcp_socket.h"
18 #include "rtc_base/async_tcp_socket.h"
19 #include "rtc_base/async_udp_socket.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/logging.h"
22 #include "rtc_base/net_helpers.h"
23 #include "rtc_base/socket.h"
24 #include "rtc_base/socket_adapters.h"
25 #include "rtc_base/socket_server.h"
26 #include "rtc_base/ssl_adapter.h"
27 #include "rtc_base/thread.h"
28
29 namespace rtc {
30
BasicPacketSocketFactory()31 BasicPacketSocketFactory::BasicPacketSocketFactory()
32 : thread_(Thread::Current()), socket_factory_(NULL) {}
33
BasicPacketSocketFactory(Thread * thread)34 BasicPacketSocketFactory::BasicPacketSocketFactory(Thread* thread)
35 : thread_(thread), socket_factory_(NULL) {}
36
BasicPacketSocketFactory(SocketFactory * socket_factory)37 BasicPacketSocketFactory::BasicPacketSocketFactory(
38 SocketFactory* socket_factory)
39 : thread_(NULL), socket_factory_(socket_factory) {}
40
~BasicPacketSocketFactory()41 BasicPacketSocketFactory::~BasicPacketSocketFactory() {}
42
CreateUdpSocket(const SocketAddress & address,uint16_t min_port,uint16_t max_port)43 AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket(
44 const SocketAddress& address,
45 uint16_t min_port,
46 uint16_t max_port) {
47 // UDP sockets are simple.
48 AsyncSocket* socket =
49 socket_factory()->CreateAsyncSocket(address.family(), SOCK_DGRAM);
50 if (!socket) {
51 return NULL;
52 }
53 if (BindSocket(socket, address, min_port, max_port) < 0) {
54 RTC_LOG(LS_ERROR) << "UDP bind failed with error " << socket->GetError();
55 delete socket;
56 return NULL;
57 }
58 return new AsyncUDPSocket(socket);
59 }
60
CreateServerTcpSocket(const SocketAddress & local_address,uint16_t min_port,uint16_t max_port,int opts)61 AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket(
62 const SocketAddress& local_address,
63 uint16_t min_port,
64 uint16_t max_port,
65 int opts) {
66 // Fail if TLS is required.
67 if (opts & PacketSocketFactory::OPT_TLS) {
68 RTC_LOG(LS_ERROR) << "TLS support currently is not available.";
69 return NULL;
70 }
71
72 AsyncSocket* socket =
73 socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM);
74 if (!socket) {
75 return NULL;
76 }
77
78 if (BindSocket(socket, local_address, min_port, max_port) < 0) {
79 RTC_LOG(LS_ERROR) << "TCP bind failed with error " << socket->GetError();
80 delete socket;
81 return NULL;
82 }
83
84 // If using fake TLS, wrap the TCP socket in a pseudo-SSL socket.
85 if (opts & PacketSocketFactory::OPT_TLS_FAKE) {
86 RTC_DCHECK(!(opts & PacketSocketFactory::OPT_TLS));
87 socket = new AsyncSSLSocket(socket);
88 }
89
90 // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
91 // See http://go/gtalktcpnodelayexperiment
92 socket->SetOption(Socket::OPT_NODELAY, 1);
93
94 if (opts & PacketSocketFactory::OPT_STUN)
95 return new cricket::AsyncStunTCPSocket(socket, true);
96
97 return new AsyncTCPSocket(socket, true);
98 }
99
CreateClientTcpSocket(const SocketAddress & local_address,const SocketAddress & remote_address,const ProxyInfo & proxy_info,const std::string & user_agent,const PacketSocketTcpOptions & tcp_options)100 AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
101 const SocketAddress& local_address,
102 const SocketAddress& remote_address,
103 const ProxyInfo& proxy_info,
104 const std::string& user_agent,
105 const PacketSocketTcpOptions& tcp_options) {
106 AsyncSocket* socket =
107 socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM);
108 if (!socket) {
109 return NULL;
110 }
111
112 if (BindSocket(socket, local_address, 0, 0) < 0) {
113 // Allow BindSocket to fail if we're binding to the ANY address, since this
114 // is mostly redundant in the first place. The socket will be bound when we
115 // call Connect() instead.
116 if (local_address.IsAnyIP()) {
117 RTC_LOG(LS_WARNING) << "TCP bind failed with error " << socket->GetError()
118 << "; ignoring since socket is using 'any' address.";
119 } else {
120 RTC_LOG(LS_ERROR) << "TCP bind failed with error " << socket->GetError();
121 delete socket;
122 return NULL;
123 }
124 }
125
126 // If using a proxy, wrap the socket in a proxy socket.
127 if (proxy_info.type == PROXY_SOCKS5) {
128 socket = new AsyncSocksProxySocket(
129 socket, proxy_info.address, proxy_info.username, proxy_info.password);
130 } else if (proxy_info.type == PROXY_HTTPS) {
131 socket =
132 new AsyncHttpsProxySocket(socket, user_agent, proxy_info.address,
133 proxy_info.username, proxy_info.password);
134 }
135
136 // Assert that at most one TLS option is used.
137 int tlsOpts = tcp_options.opts & (PacketSocketFactory::OPT_TLS |
138 PacketSocketFactory::OPT_TLS_FAKE |
139 PacketSocketFactory::OPT_TLS_INSECURE);
140 RTC_DCHECK((tlsOpts & (tlsOpts - 1)) == 0);
141
142 if ((tlsOpts & PacketSocketFactory::OPT_TLS) ||
143 (tlsOpts & PacketSocketFactory::OPT_TLS_INSECURE)) {
144 // Using TLS, wrap the socket in an SSL adapter.
145 SSLAdapter* ssl_adapter = SSLAdapter::Create(socket);
146 if (!ssl_adapter) {
147 return NULL;
148 }
149
150 if (tlsOpts & PacketSocketFactory::OPT_TLS_INSECURE) {
151 ssl_adapter->SetIgnoreBadCert(true);
152 }
153
154 ssl_adapter->SetAlpnProtocols(tcp_options.tls_alpn_protocols);
155 ssl_adapter->SetEllipticCurves(tcp_options.tls_elliptic_curves);
156 ssl_adapter->SetCertVerifier(tcp_options.tls_cert_verifier);
157
158 socket = ssl_adapter;
159
160 if (ssl_adapter->StartSSL(remote_address.hostname().c_str()) != 0) {
161 delete ssl_adapter;
162 return NULL;
163 }
164
165 } else if (tlsOpts & PacketSocketFactory::OPT_TLS_FAKE) {
166 // Using fake TLS, wrap the TCP socket in a pseudo-SSL socket.
167 socket = new AsyncSSLSocket(socket);
168 }
169
170 if (socket->Connect(remote_address) < 0) {
171 RTC_LOG(LS_ERROR) << "TCP connect failed with error " << socket->GetError();
172 delete socket;
173 return NULL;
174 }
175
176 // Finally, wrap that socket in a TCP or STUN TCP packet socket.
177 AsyncPacketSocket* tcp_socket;
178 if (tcp_options.opts & PacketSocketFactory::OPT_STUN) {
179 tcp_socket = new cricket::AsyncStunTCPSocket(socket, false);
180 } else {
181 tcp_socket = new AsyncTCPSocket(socket, false);
182 }
183
184 // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
185 // See http://go/gtalktcpnodelayexperiment
186 tcp_socket->SetOption(Socket::OPT_NODELAY, 1);
187
188 return tcp_socket;
189 }
190
CreateAsyncResolver()191 AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() {
192 return new AsyncResolver();
193 }
194
BindSocket(AsyncSocket * socket,const SocketAddress & local_address,uint16_t min_port,uint16_t max_port)195 int BasicPacketSocketFactory::BindSocket(AsyncSocket* socket,
196 const SocketAddress& local_address,
197 uint16_t min_port,
198 uint16_t max_port) {
199 int ret = -1;
200 if (min_port == 0 && max_port == 0) {
201 // If there's no port range, let the OS pick a port for us.
202 ret = socket->Bind(local_address);
203 } else {
204 // Otherwise, try to find a port in the provided range.
205 for (int port = min_port; ret < 0 && port <= max_port; ++port) {
206 ret = socket->Bind(SocketAddress(local_address.ipaddr(), port));
207 }
208 }
209 return ret;
210 }
211
socket_factory()212 SocketFactory* BasicPacketSocketFactory::socket_factory() {
213 if (thread_) {
214 RTC_DCHECK(thread_ == Thread::Current());
215 return thread_->socketserver();
216 } else {
217 return socket_factory_;
218 }
219 }
220
221 } // namespace rtc
222