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