blob: 615bbfe55a0b1859d6218df12603609020dcf0f8 [file] [log] [blame]
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +00001/*
2 * Copyright 2004 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/stunport.h"
12
13#include "webrtc/p2p/base/common.h"
14#include "webrtc/p2p/base/portallocator.h"
15#include "webrtc/p2p/base/stun.h"
16#include "webrtc/base/common.h"
17#include "webrtc/base/helpers.h"
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -070018#include "webrtc/base/ipaddress.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000019#include "webrtc/base/logging.h"
20#include "webrtc/base/nethelpers.h"
21
22namespace cricket {
23
24// TODO: Move these to a common place (used in relayport too)
25const int KEEPALIVE_DELAY = 10 * 1000; // 10 seconds - sort timeouts
26const int RETRY_DELAY = 50; // 50ms, from ICE spec
27const int RETRY_TIMEOUT = 50 * 1000; // ICE says 50 secs
28
29// Handles a binding request sent to the STUN server.
30class StunBindingRequest : public StunRequest {
31 public:
32 StunBindingRequest(UDPPort* port, bool keep_alive,
33 const rtc::SocketAddress& addr)
34 : port_(port), keep_alive_(keep_alive), server_addr_(addr) {
35 start_time_ = rtc::Time();
36 }
37
38 virtual ~StunBindingRequest() {
39 }
40
41 const rtc::SocketAddress& server_addr() const { return server_addr_; }
42
Peter Thatcher1cf6f812015-05-15 10:40:45 -070043 virtual void Prepare(StunMessage* request) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000044 request->SetType(STUN_BINDING_REQUEST);
45 }
46
Peter Thatcher1cf6f812015-05-15 10:40:45 -070047 virtual void OnResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000048 const StunAddressAttribute* addr_attr =
49 response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
50 if (!addr_attr) {
51 LOG(LS_ERROR) << "Binding response missing mapped address.";
52 } else if (addr_attr->family() != STUN_ADDRESS_IPV4 &&
53 addr_attr->family() != STUN_ADDRESS_IPV6) {
54 LOG(LS_ERROR) << "Binding address has bad family";
55 } else {
56 rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
57 port_->OnStunBindingRequestSucceeded(server_addr_, addr);
58 }
59
60 // We will do a keep-alive regardless of whether this request succeeds.
61 // This should have almost no impact on network usage.
62 if (keep_alive_) {
63 port_->requests_.SendDelayed(
64 new StunBindingRequest(port_, true, server_addr_),
65 port_->stun_keepalive_delay());
66 }
67 }
68
Peter Thatcher1cf6f812015-05-15 10:40:45 -070069 virtual void OnErrorResponse(StunMessage* response) override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000070 const StunErrorCodeAttribute* attr = response->GetErrorCode();
71 if (!attr) {
72 LOG(LS_ERROR) << "Bad allocate response error code";
73 } else {
74 LOG(LS_ERROR) << "Binding error response:"
75 << " class=" << attr->eclass()
76 << " number=" << attr->number()
77 << " reason='" << attr->reason() << "'";
78 }
79
80 port_->OnStunBindingOrResolveRequestFailed(server_addr_);
81
82 if (keep_alive_
83 && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) {
84 port_->requests_.SendDelayed(
85 new StunBindingRequest(port_, true, server_addr_),
86 port_->stun_keepalive_delay());
87 }
88 }
89
Peter Thatcher1cf6f812015-05-15 10:40:45 -070090 virtual void OnTimeout() override {
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000091 LOG(LS_ERROR) << "Binding request timed out from "
92 << port_->GetLocalAddress().ToSensitiveString()
93 << " (" << port_->Network()->name() << ")";
94
95 port_->OnStunBindingOrResolveRequestFailed(server_addr_);
96
97 if (keep_alive_
98 && (rtc::TimeSince(start_time_) <= RETRY_TIMEOUT)) {
99 port_->requests_.SendDelayed(
100 new StunBindingRequest(port_, true, server_addr_),
101 RETRY_DELAY);
102 }
103 }
104
105 private:
106 UDPPort* port_;
107 bool keep_alive_;
108 const rtc::SocketAddress server_addr_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200109 uint32_t start_time_;
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000110};
111
112UDPPort::AddressResolver::AddressResolver(
113 rtc::PacketSocketFactory* factory)
114 : socket_factory_(factory) {}
115
116UDPPort::AddressResolver::~AddressResolver() {
117 for (ResolverMap::iterator it = resolvers_.begin();
118 it != resolvers_.end(); ++it) {
119 it->second->Destroy(true);
120 }
121}
122
123void UDPPort::AddressResolver::Resolve(
124 const rtc::SocketAddress& address) {
125 if (resolvers_.find(address) != resolvers_.end())
126 return;
127
128 rtc::AsyncResolverInterface* resolver =
129 socket_factory_->CreateAsyncResolver();
130 resolvers_.insert(
131 std::pair<rtc::SocketAddress, rtc::AsyncResolverInterface*>(
132 address, resolver));
133
134 resolver->SignalDone.connect(this,
135 &UDPPort::AddressResolver::OnResolveResult);
136
137 resolver->Start(address);
138}
139
140bool UDPPort::AddressResolver::GetResolvedAddress(
141 const rtc::SocketAddress& input,
142 int family,
143 rtc::SocketAddress* output) const {
144 ResolverMap::const_iterator it = resolvers_.find(input);
145 if (it == resolvers_.end())
146 return false;
147
148 return it->second->GetResolvedAddress(family, output);
149}
150
151void UDPPort::AddressResolver::OnResolveResult(
152 rtc::AsyncResolverInterface* resolver) {
153 for (ResolverMap::iterator it = resolvers_.begin();
154 it != resolvers_.end(); ++it) {
155 if (it->second == resolver) {
156 SignalDone(it->first, resolver->GetError());
157 return;
158 }
159 }
160}
161
162UDPPort::UDPPort(rtc::Thread* thread,
163 rtc::PacketSocketFactory* factory,
164 rtc::Network* network,
165 rtc::AsyncPacketSocket* socket,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000166 const std::string& username,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000167 const std::string& password,
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700168 const std::string& origin,
169 bool emit_localhost_for_anyaddress)
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000170 : Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
171 username, password),
172 requests_(thread),
173 socket_(socket),
174 error_(0),
175 ready_(false),
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700176 stun_keepalive_delay_(KEEPALIVE_DELAY),
177 emit_localhost_for_anyaddress_(emit_localhost_for_anyaddress) {
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000178 requests_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000179}
180
181UDPPort::UDPPort(rtc::Thread* thread,
182 rtc::PacketSocketFactory* factory,
183 rtc::Network* network,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000184 const rtc::IPAddress& ip,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200185 uint16_t min_port,
186 uint16_t max_port,
pkasting@chromium.org332331f2014-11-06 20:19:22 +0000187 const std::string& username,
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000188 const std::string& password,
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700189 const std::string& origin,
190 bool emit_localhost_for_anyaddress)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200191 : Port(thread,
192 LOCAL_PORT_TYPE,
193 factory,
194 network,
195 ip,
196 min_port,
197 max_port,
198 username,
199 password),
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000200 requests_(thread),
201 socket_(NULL),
202 error_(0),
203 ready_(false),
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700204 stun_keepalive_delay_(KEEPALIVE_DELAY),
205 emit_localhost_for_anyaddress_(emit_localhost_for_anyaddress) {
pthatcher@webrtc.org0ba15332015-01-10 00:47:02 +0000206 requests_.set_origin(origin);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000207}
208
209bool UDPPort::Init() {
210 if (!SharedSocket()) {
211 ASSERT(socket_ == NULL);
212 socket_ = socket_factory()->CreateUdpSocket(
213 rtc::SocketAddress(ip(), 0), min_port(), max_port());
214 if (!socket_) {
215 LOG_J(LS_WARNING, this) << "UDP socket creation failed";
216 return false;
217 }
218 socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
219 }
220 socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend);
221 socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady);
222 requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket);
223 return true;
224}
225
226UDPPort::~UDPPort() {
227 if (!SharedSocket())
228 delete socket_;
229}
230
231void UDPPort::PrepareAddress() {
232 ASSERT(requests_.empty());
233 if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
234 OnLocalAddressReady(socket_, socket_->GetLocalAddress());
235 }
236}
237
238void UDPPort::MaybePrepareStunCandidate() {
239 // Sending binding request to the STUN server if address is available to
240 // prepare STUN candidate.
241 if (!server_addresses_.empty()) {
242 SendStunBindingRequests();
243 } else {
244 // Port is done allocating candidates.
245 MaybeSetPortCompleteOrError();
246 }
247}
248
249Connection* UDPPort::CreateConnection(const Candidate& address,
250 CandidateOrigin origin) {
251 if (address.protocol() != "udp")
252 return NULL;
253
254 if (!IsCompatibleAddress(address.address())) {
255 return NULL;
256 }
257
258 if (SharedSocket() && Candidates()[0].type() != LOCAL_PORT_TYPE) {
259 ASSERT(false);
260 return NULL;
261 }
262
263 Connection* conn = new ProxyConnection(this, 0, address);
264 AddConnection(conn);
265 return conn;
266}
267
268int UDPPort::SendTo(const void* data, size_t size,
269 const rtc::SocketAddress& addr,
270 const rtc::PacketOptions& options,
271 bool payload) {
272 int sent = socket_->SendTo(data, size, addr, options);
273 if (sent < 0) {
274 error_ = socket_->GetError();
275 LOG_J(LS_ERROR, this) << "UDP send of " << size
276 << " bytes failed with error " << error_;
277 }
278 return sent;
279}
280
281int UDPPort::SetOption(rtc::Socket::Option opt, int value) {
282 return socket_->SetOption(opt, value);
283}
284
285int UDPPort::GetOption(rtc::Socket::Option opt, int* value) {
286 return socket_->GetOption(opt, value);
287}
288
289int UDPPort::GetError() {
290 return error_;
291}
292
293void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket,
294 const rtc::SocketAddress& address) {
Guo-wei Shiehfe3bc9d2015-08-20 08:48:20 -0700295 // When adapter enumeration is disabled and binding to the any address, the
296 // loopback address will be issued as a candidate instead if
297 // |emit_localhost_for_anyaddress| is true. This is to allow connectivity on
298 // demo pages without STUN/TURN to work.
299 rtc::SocketAddress addr = address;
300 if (addr.IsAnyIP() && emit_localhost_for_anyaddress_) {
301 addr.SetIP(rtc::GetLoopbackIP(addr.family()));
302 }
303
304 AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME, "", "",
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700305 LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000306 MaybePrepareStunCandidate();
307}
308
309void UDPPort::OnReadPacket(
310 rtc::AsyncPacketSocket* socket, const char* data, size_t size,
311 const rtc::SocketAddress& remote_addr,
312 const rtc::PacketTime& packet_time) {
313 ASSERT(socket == socket_);
314 ASSERT(!remote_addr.IsUnresolved());
315
316 // Look for a response from the STUN server.
317 // Even if the response doesn't match one of our outstanding requests, we
318 // will eat it because it might be a response to a retransmitted packet, and
319 // we already cleared the request when we got the first response.
320 if (server_addresses_.find(remote_addr) != server_addresses_.end()) {
321 requests_.CheckResponse(data, size);
322 return;
323 }
324
325 if (Connection* conn = GetConnection(remote_addr)) {
326 conn->OnReadPacket(data, size, packet_time);
327 } else {
328 Port::OnReadPacket(data, size, remote_addr, PROTO_UDP);
329 }
330}
331
332void UDPPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) {
333 Port::OnReadyToSend();
334}
335
336void UDPPort::SendStunBindingRequests() {
337 // We will keep pinging the stun server to make sure our NAT pin-hole stays
338 // open during the call.
339 ASSERT(requests_.empty());
340
341 for (ServerAddresses::const_iterator it = server_addresses_.begin();
342 it != server_addresses_.end(); ++it) {
343 SendStunBindingRequest(*it);
344 }
345}
346
347void UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) {
348 if (!resolver_) {
349 resolver_.reset(new AddressResolver(socket_factory()));
350 resolver_->SignalDone.connect(this, &UDPPort::OnResolveResult);
351 }
352
353 resolver_->Resolve(stun_addr);
354}
355
356void UDPPort::OnResolveResult(const rtc::SocketAddress& input,
357 int error) {
358 ASSERT(resolver_.get() != NULL);
359
360 rtc::SocketAddress resolved;
361 if (error != 0 ||
362 !resolver_->GetResolvedAddress(input, ip().family(), &resolved)) {
363 LOG_J(LS_WARNING, this) << "StunPort: stun host lookup received error "
364 << error;
365 OnStunBindingOrResolveRequestFailed(input);
366 return;
367 }
368
369 server_addresses_.erase(input);
370
371 if (server_addresses_.find(resolved) == server_addresses_.end()) {
372 server_addresses_.insert(resolved);
373 SendStunBindingRequest(resolved);
374 }
375}
376
377void UDPPort::SendStunBindingRequest(
378 const rtc::SocketAddress& stun_addr) {
379 if (stun_addr.IsUnresolved()) {
380 ResolveStunAddress(stun_addr);
381
382 } else if (socket_->GetState() == rtc::AsyncPacketSocket::STATE_BOUND) {
383 // Check if |server_addr_| is compatible with the port's ip.
384 if (IsCompatibleAddress(stun_addr)) {
385 requests_.Send(new StunBindingRequest(this, true, stun_addr));
386 } else {
387 // Since we can't send stun messages to the server, we should mark this
388 // port ready.
389 LOG(LS_WARNING) << "STUN server address is incompatible.";
390 OnStunBindingOrResolveRequestFailed(stun_addr);
391 }
392 }
393}
394
395void UDPPort::OnStunBindingRequestSucceeded(
396 const rtc::SocketAddress& stun_server_addr,
397 const rtc::SocketAddress& stun_reflected_addr) {
398 if (bind_request_succeeded_servers_.find(stun_server_addr) !=
399 bind_request_succeeded_servers_.end()) {
400 return;
401 }
402 bind_request_succeeded_servers_.insert(stun_server_addr);
403
404 // If socket is shared and |stun_reflected_addr| is equal to local socket
405 // address, or if the same address has been added by another STUN server,
406 // then discarding the stun address.
407 // For STUN, related address is the local socket address.
408 if ((!SharedSocket() || stun_reflected_addr != socket_->GetLocalAddress()) &&
409 !HasCandidateWithAddress(stun_reflected_addr)) {
410
411 rtc::SocketAddress related_address = socket_->GetLocalAddress();
412 if (!(candidate_filter() & CF_HOST)) {
413 // If candidate filter doesn't have CF_HOST specified, empty raddr to
414 // avoid local address leakage.
415 related_address = rtc::EmptySocketAddressWithFamily(
416 related_address.family());
417 }
418
Guo-wei Shieh3d564c12015-08-19 16:51:15 -0700419 AddAddress(stun_reflected_addr, socket_->GetLocalAddress(), related_address,
420 UDP_PROTOCOL_NAME, "", "", STUN_PORT_TYPE,
421 ICE_TYPE_PREFERENCE_SRFLX, 0, false);
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +0000422 }
423 MaybeSetPortCompleteOrError();
424}
425
426void UDPPort::OnStunBindingOrResolveRequestFailed(
427 const rtc::SocketAddress& stun_server_addr) {
428 if (bind_request_failed_servers_.find(stun_server_addr) !=
429 bind_request_failed_servers_.end()) {
430 return;
431 }
432 bind_request_failed_servers_.insert(stun_server_addr);
433 MaybeSetPortCompleteOrError();
434}
435
436void UDPPort::MaybeSetPortCompleteOrError() {
437 if (ready_)
438 return;
439
440 // Do not set port ready if we are still waiting for bind responses.
441 const size_t servers_done_bind_request = bind_request_failed_servers_.size() +
442 bind_request_succeeded_servers_.size();
443 if (server_addresses_.size() != servers_done_bind_request) {
444 return;
445 }
446
447 // Setting ready status.
448 ready_ = true;
449
450 // The port is "completed" if there is no stun server provided, or the bind
451 // request succeeded for any stun server, or the socket is shared.
452 if (server_addresses_.empty() ||
453 bind_request_succeeded_servers_.size() > 0 ||
454 SharedSocket()) {
455 SignalPortComplete(this);
456 } else {
457 SignalPortError(this);
458 }
459}
460
461// TODO: merge this with SendTo above.
462void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
463 StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
464 rtc::PacketOptions options(DefaultDscpValue());
465 if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0)
466 PLOG(LERROR, socket_->GetError()) << "sendto";
467}
468
469bool UDPPort::HasCandidateWithAddress(const rtc::SocketAddress& addr) const {
470 const std::vector<Candidate>& existing_candidates = Candidates();
471 std::vector<Candidate>::const_iterator it = existing_candidates.begin();
472 for (; it != existing_candidates.end(); ++it) {
473 if (it->address() == addr)
474 return true;
475 }
476 return false;
477}
478
479} // namespace cricket