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