1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/* 2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle 3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2005, Google Inc. 4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without 6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met: 7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 1. Redistributions of source code must retain the above copyright notice, 9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer. 10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright notice, 11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer in the documentation 12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * and/or other materials provided with the distribution. 13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 3. The name of the author may not be used to endorse or promote products 14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * derived from this software without specific prior written permission. 15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */ 27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "talk/base/asyncpacketsocket.h" 29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/helpers.h" 30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/logging.h" 31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/relayport.h" 32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace cricket { 34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const uint32 kMessageConnectTimeout = 1; 36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const int kKeepAliveDelay = 10 * 60 * 1000; 37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const int kRetryTimeout = 50 * 1000; // ICE says 50 secs 38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// How long to wait for a socket to connect to remote host in milliseconds 39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// before trying another connection. 40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const int kSoftConnectTimeoutMs = 3 * 1000; 41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Handles a connection to one address/port/protocol combination for a 43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// particular RelayEntry. 44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochclass RelayConnection : public sigslot::has_slots<> { 45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public: 46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayConnection(const ProtocolAddress* protocol_address, 47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::AsyncPacketSocket* socket, 48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::Thread* thread); 49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ~RelayConnection(); 50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::AsyncPacketSocket* socket() const { return socket_; } 51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const ProtocolAddress* protocol_address() { 53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return protocol_address_; 54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::SocketAddress GetAddress() const { 57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return protocol_address_->address; 58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ProtocolType GetProtocol() const { 61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return protocol_address_->proto; 62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int SetSocketOption(talk_base::Socket::Option opt, int value); 65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Validates a response to a STUN allocate request. 67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool CheckResponse(StunMessage* msg); 68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Sends data to the relay server. 70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int Send(const void* pv, size_t cb); 71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Sends a STUN allocate request message to the relay server. 73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void SendAllocateRequest(RelayEntry* entry, int delay); 74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Return the latest error generated by the socket. 76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int GetError() { return socket_->GetError(); } 77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Called on behalf of a StunRequest to write data to the socket. This is 79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // already STUN intended for the server, so no wrapping is necessary. 80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void OnSendPacket(const void* data, size_t size, StunRequest* req); 81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch private: 83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::AsyncPacketSocket* socket_; 84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const ProtocolAddress* protocol_address_; 85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunRequestManager *request_manager_; 86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}; 87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Manages a number of connections to the relayserver, one for each 89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// available protocol. We aim to use each connection for only a 90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// specific destination address so that we can avoid wrapping every 91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// packet in a STUN send / data indication. 92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochclass RelayEntry : public talk_base::MessageHandler, 93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public sigslot::has_slots<> { 94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public: 95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr); 96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ~RelayEntry(); 97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayPort* port() { return port_; } 99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const talk_base::SocketAddress& address() const { return ext_addr_; } 101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void set_address(const talk_base::SocketAddress& addr) { ext_addr_ = addr; } 102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool connected() const { return connected_; } 104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool locked() const { return locked_; } 105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Returns the last error on the socket of this entry. 107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int GetError(); 108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Returns the most preferred connection of the given 110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // ones. Connections are rated based on protocol in the order of: 111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // UDP, TCP and SSLTCP, where UDP is the most preferred protocol 112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch static RelayConnection* GetBestConnection(RelayConnection* conn1, 113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayConnection* conn2); 114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Sends the STUN requests to the server to initiate this connection. 116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void Connect(); 117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Called when this entry becomes connected. The address given is the one 119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // exposed to the outside world on the relay server. 120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void OnConnect(const talk_base::SocketAddress& mapped_addr, 121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayConnection* socket); 122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Sends a packet to the given destination address using the socket of this 124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // entry. This will wrap the packet in STUN if necessary. 125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int SendTo(const void* data, size_t size, 126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const talk_base::SocketAddress& addr); 127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Schedules a keep-alive allocate request. 129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void ScheduleKeepAlive(); 130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void SetServerIndex(size_t sindex) { server_index_ = sindex; } 132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Sets this option on the socket of each connection. 134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int SetSocketOption(talk_base::Socket::Option opt, int value); 135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t ServerIndex() const { return server_index_; } 137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Try a different server address 139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch void HandleConnectFailure(talk_base::AsyncPacketSocket* socket); 140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Implementation of the MessageHandler Interface. 142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void OnMessage(talk_base::Message *pmsg); 143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch private: 145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayPort* port_; 146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen talk_base::SocketAddress ext_addr_; 147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t server_index_; 148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool connected_; 149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool locked_; 150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayConnection* current_connection_; 151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Called when a TCP connection is established or fails 153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen void OnSocketConnect(talk_base::AsyncPacketSocket* socket); 154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen void OnSocketClose(talk_base::AsyncPacketSocket* socket, int error); 155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Called when a packet is received on this socket. 157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen void OnReadPacket(talk_base::AsyncPacketSocket* socket, 158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const char* data, size_t size, 159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const talk_base::SocketAddress& remote_addr); 160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Sends the given data on the socket to the server with no wrapping. This 162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // returns the number of bytes written or -1 if an error occurred. 163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int SendPacket(const void* data, size_t size); 164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}; 165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Handles an allocate request for a particular RelayEntry. 167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochclass AllocateRequest : public StunRequest { 168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch public: 169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AllocateRequest(RelayEntry* entry, RelayConnection* connection); 170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual ~AllocateRequest() {} 171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void Prepare(StunMessage* request); 173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual int GetNextDelay(); 175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void OnResponse(StunMessage* response); 177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void OnErrorResponse(StunMessage* response); 178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch virtual void OnTimeout(); 179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch private: 181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayEntry* entry_; 182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayConnection* connection_; 183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch uint32 start_time_; 184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}; 185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst std::string RELAY_PORT_TYPE("relay"); 187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayPort::RelayPort( 189dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen talk_base::Thread* thread, talk_base::PacketSocketFactory* factory, 190dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen talk_base::Network* network, uint32 ip, int min_port, int max_port, 191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string& username, const std::string& password, 192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string& magic_cookie) 193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port), 194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ready_(false), 195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen magic_cookie_(magic_cookie), 196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen error_(0) { 197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entries_.push_back( 198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen new RelayEntry(this, talk_base::SocketAddress())); 199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch set_username_fragment(username); 201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch set_password(password); 202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (magic_cookie_.size() == 0) 203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch magic_cookie_.append(STUN_MAGIC_COOKIE_VALUE, 4); 204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayPort::~RelayPort() { 207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i = 0; i < entries_.size(); ++i) 208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete entries_[i]; 209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch thread_->Clear(this); 210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::AddServerAddress(const ProtocolAddress& addr) { 213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Since HTTP proxies usually only allow 443, 214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // let's up the priority on PROTO_SSLTCP 215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (addr.proto == PROTO_SSLTCP && 216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch (proxy().type == talk_base::PROXY_HTTPS || 217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch proxy().type == talk_base::PROXY_UNKNOWN)) { 218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch server_addr_.push_front(addr); 219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch server_addr_.push_back(addr); 221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::AddExternalAddress(const ProtocolAddress& addr) { 225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string proto_name = ProtoToString(addr.proto); 226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (std::vector<Candidate>::const_iterator it = candidates().begin(); 227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch it != candidates().end(); ++it) { 228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((it->address() == addr.address) && (it->protocol() == proto_name)) { 229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Redundant relay address: " << proto_name 230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << " @ " << addr.address.ToString(); 231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AddAddress(addr.address, proto_name, false); 235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::SetReady() { 238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!ready_) { 239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ready_ = true; 240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SignalAddressReady(this); 241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst ProtocolAddress * RelayPort::ServerAddress(size_t index) const { 245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (index < server_addr_.size()) 246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return &server_addr_[index]; 247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return NULL; 248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool RelayPort::HasMagicCookie(const char* data, size_t size) { 251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (size < 24 + magic_cookie_.size()) { 252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0 == std::memcmp(data + 24, 255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch magic_cookie_.c_str(), 256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch magic_cookie_.size()); 257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::PrepareAddress() { 261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We initiate a connect on the first entry. If this completes, it will fill 262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // in the server address as the address of this port. 263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(entries_.size() == 1); 264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entries_[0]->Connect(); 265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ready_ = false; 266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochConnection* RelayPort::CreateConnection(const Candidate& address, 269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CandidateOrigin origin) { 270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We only create conns to non-udp sockets if they are incoming on this port 271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((address.protocol() != "udp") && (origin != ORIGIN_THIS_PORT)) { 272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We don't support loopback on relays 276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (address.type() == type()) { 277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t index = 0; 281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i = 0; i < candidates().size(); ++i) { 282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const Candidate& local = candidates()[i]; 283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (local.protocol() == address.protocol()) { 284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch index = i; 285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Connection * conn = new ProxyConnection(this, index, address); 290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AddConnection(conn); 291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return conn; 292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayPort::SendTo(const void* data, size_t size, 295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const talk_base::SocketAddress& addr, bool payload) { 296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Try to find an entry for this specific address. Note that the first entry 297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // created was not given an address initially, so it can be set to the first 298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // address that comes along. 299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayEntry* entry = 0; 300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i = 0; i < entries_.size(); ++i) { 302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (entries_[i]->address().IsAny() && payload) { 303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry = entries_[i]; 304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry->set_address(addr); 305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (entries_[i]->address() == addr) { 307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry = entries_[i]; 308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If we did not find one, then we make a new one. This will not be useable 313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // until it becomes connected, however. 314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!entry && payload) { 315dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry = new RelayEntry(this, addr); 316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!entries_.empty()) { 317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry->SetServerIndex(entries_[0]->ServerIndex()); 318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry->Connect(); 320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entries_.push_back(entry); 321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If the entry is connected, then we can send on it (though wrapping may 324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // still be necessary). Otherwise, we can't yet use this connection, so we 325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // default to the first one. 326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!entry || !entry->connected()) { 327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(!entries_.empty()); 328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry = entries_[0]; 329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!entry->connected()) { 330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error_ = EWOULDBLOCK; 331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Send the actual contents to the server using the usual mechanism. 336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int sent = entry->SendTo(data, size, addr); 337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (sent <= 0) { 338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(sent < 0); 339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error_ = entry->GetError(); 340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // The caller of the function is expecting the number of user data bytes, 343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // rather than the size of the packet. 344dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return size; 345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayPort::SetOption(talk_base::Socket::Option opt, int value) { 348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int result = 0; 349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i = 0; i < entries_.size(); ++i) { 350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (entries_[i]->SetSocketOption(opt, value) < 0) { 351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch result = -1; 352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error_ = entries_[i]->GetError(); 353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch options_.push_back(OptionValue(opt, value)); 356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return result; 357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayPort::GetError() { 360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return error_; 361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayPort::OnReadPacket( 364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const char* data, size_t size, 365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const talk_base::SocketAddress& remote_addr) { 366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (Connection* conn = GetConnection(remote_addr)) { 367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch conn->OnReadPacket(data, size); 368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Port::OnReadPacket(data, size, remote_addr); 370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayConnection::RelayConnection(const ProtocolAddress* protocol_address, 374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::AsyncPacketSocket* socket, 375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::Thread* thread) 376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch : socket_(socket), 377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch protocol_address_(protocol_address) { 378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request_manager_ = new StunRequestManager(thread); 379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request_manager_->SignalSendPacket.connect(this, 380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &RelayConnection::OnSendPacket); 381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayConnection::~RelayConnection() { 384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete request_manager_; 3853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick delete socket_; 386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayConnection::SetSocketOption(talk_base::Socket::Option opt, 389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int value) { 390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (socket_) { 391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return socket_->SetOption(opt, value); 392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool RelayConnection::CheckResponse(StunMessage* msg) { 397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return request_manager_->CheckResponse(msg); 398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayConnection::OnSendPacket(const void* data, size_t size, 401f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunRequest* req) { 402f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int sent = socket_->SendTo(data, size, GetAddress()); 403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (sent <= 0) { 404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << "OnSendPacket: failed sending to " << GetAddress() << 405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::strerror(socket_->GetError()); 406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(sent < 0); 407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayConnection::Send(const void* pv, size_t cb) { 411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return socket_->SendTo(pv, cb, GetAddress()); 412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayConnection::SendAllocateRequest(RelayEntry* entry, int delay) { 415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request_manager_->SendDelayed(new AllocateRequest(entry, this), delay); 416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayEntry::RelayEntry(RelayPort* port, 419dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const talk_base::SocketAddress& ext_addr) 420dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen : port_(port), ext_addr_(ext_addr), 421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch server_index_(0), connected_(false), locked_(false), 422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_connection_(NULL) { 423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayEntry::~RelayEntry() { 426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Remove all RelayConnections and dispose sockets. 427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete current_connection_; 428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_connection_ = NULL; 429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::Connect() { 432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If we're already connected, return. 433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (connected_) 434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 436f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If we've exhausted all options, bail out. 437f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const ProtocolAddress* ra = port()->ServerAddress(server_index_); 438f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!ra) { 439f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_WARNING) << "No more relay addresses left to try"; 440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 443f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Remove any previous connection. 444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_) { 4453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick port()->thread()->Dispose(current_connection_); 446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_connection_ = NULL; 447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Try to set up our new socket. 450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto) << 451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch " @ " << ra->address.ToString(); 452f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 453dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen talk_base::AsyncPacketSocket* socket = NULL; 454dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 455dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (ra->proto == PROTO_UDP) { 456dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // UDP sockets are simple. 457dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen socket = port_->socket_factory()->CreateUdpSocket( 458dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen talk_base::SocketAddress(port_->ip_, 0), 459dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen port_->min_port_, port_->max_port_); 460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) { 461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen socket = port_->socket_factory()->CreateClientTcpSocket( 462dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen talk_base::SocketAddress(port_->ip_, 0), ra->address, 463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen port_->proxy(), port_->user_agent(), ra->proto == PROTO_SSLTCP); 464dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } else { 465dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen LOG(LS_WARNING) << "Unknown protocol (" << ra->proto << ")"; 466dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 467dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!socket) { 469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_WARNING) << "Socket creation failed"; 470f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 471f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 472f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If we failed to get a socket, move on to the next protocol. 473f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!socket) { 474f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port()->thread()->Post(this, kMessageConnectTimeout); 475f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 476f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 477f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 478f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Otherwise, create the new connection and configure any socket options. 479f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch socket->SignalReadPacket.connect(this, &RelayEntry::OnReadPacket); 480f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_connection_ = new RelayConnection(ra, socket, port()->thread()); 481f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i = 0; i < port_->options().size(); ++i) { 482f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_connection_->SetSocketOption(port_->options()[i].first, 483f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port_->options()[i].second); 484f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 485f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 486f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If we're trying UDP, start binding requests. 487dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // If we're trying TCP, wait for connection with a fixed timeout. 488f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) { 489dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen socket->SignalClose.connect(this, &RelayEntry::OnSocketClose); 490dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect); 491f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this, 492f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch kMessageConnectTimeout); 493f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 494f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_connection_->SendAllocateRequest(this, 0); 495f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 496f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 497f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 498f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayEntry::GetError() { 499f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_ != NULL) { 500f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return current_connection_->GetError(); 501f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 502f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 503f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 504f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 505f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochRelayConnection* RelayEntry::GetBestConnection(RelayConnection* conn1, 506f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayConnection* conn2) { 507f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return conn1->GetProtocol() <= conn2->GetProtocol() ? conn1 : conn2; 508f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 509f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 510f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::OnConnect(const talk_base::SocketAddress& mapped_addr, 511f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayConnection* connection) { 512f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We are connected, notify our parent. 513f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ProtocolType proto = PROTO_UDP; 514f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Relay allocate succeeded: " << ProtoToString(proto) 515f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << " @ " << mapped_addr.ToString(); 516f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch connected_ = true; 517f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 518f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port_->AddExternalAddress(ProtocolAddress(mapped_addr, proto)); 519f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port_->SetReady(); 520f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 521f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 522f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayEntry::SendTo(const void* data, size_t size, 523f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const talk_base::SocketAddress& addr) { 524f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If this connection is locked to the address given, then we can send the 525f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // packet with no wrapper. 526f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (locked_ && (ext_addr_ == addr)) 527f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SendPacket(data, size); 528f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 529f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Otherwise, we must wrap the given data in a STUN SEND request so that we 530f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // can communicate the destination address to the server. 531f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // 532f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Note that we do not use a StunRequest here. This is because there is 533f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // likely no reason to resend this packet. If it is late, we just drop it. 534f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // The next send to this address will try again. 535f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 536f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunMessage request; 537f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.SetType(STUN_SEND_REQUEST); 538f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.SetTransactionID(talk_base::CreateRandomString(16)); 539f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 540f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunByteStringAttribute* magic_cookie_attr = 541f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE); 542f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch magic_cookie_attr->CopyBytes(port_->magic_cookie().c_str(), 543dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen port_->magic_cookie().size()); 544f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.AddAttribute(magic_cookie_attr); 545f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 546f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunByteStringAttribute* username_attr = 547f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunAttribute::CreateByteString(STUN_ATTR_USERNAME); 548f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch username_attr->CopyBytes(port_->username_fragment().c_str(), 549dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen port_->username_fragment().size()); 550f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.AddAttribute(username_attr); 551f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 552f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunAddressAttribute* addr_attr = 553f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS); 554f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch addr_attr->SetFamily(1); 555f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch addr_attr->SetIP(addr.ip()); 556f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch addr_attr->SetPort(addr.port()); 557f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.AddAttribute(addr_attr); 558f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 559f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Attempt to lock 560f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (ext_addr_ == addr) { 561f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunUInt32Attribute* options_attr = 562f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunAttribute::CreateUInt32(STUN_ATTR_OPTIONS); 563f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch options_attr->SetValue(0x1); 564f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.AddAttribute(options_attr); 565f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 566f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 567f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunByteStringAttribute* data_attr = 568f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunAttribute::CreateByteString(STUN_ATTR_DATA); 569dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen data_attr->CopyBytes(data, size); 570f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.AddAttribute(data_attr); 571f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 572f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: compute the HMAC. 573f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 574f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::ByteBuffer buf; 575f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.Write(&buf); 576f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 577f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SendPacket(buf.Data(), buf.Length()); 578f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 579f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 580f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::ScheduleKeepAlive() { 581f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_) { 582f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_connection_->SendAllocateRequest(this, kKeepAliveDelay); 583f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 584f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 585f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 586f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayEntry::SetSocketOption(talk_base::Socket::Option opt, int value) { 587f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Set the option on all available sockets. 588f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int socket_error = 0; 589f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_) { 590f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch socket_error = current_connection_->SetSocketOption(opt, value); 591f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 592f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return socket_error; 593f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 594f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 595f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::HandleConnectFailure( 596f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::AsyncPacketSocket* socket) { 597f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Make sure it's the current connection that has failed, it might 598f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // be an old socked that has not yet been disposed. 599f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!socket || socket == current_connection_->socket()) { 600f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_) 601f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port()->SignalConnectFailure(current_connection_->protocol_address()); 602f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 603f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Try to connect to the next server address. 604f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch server_index_ += 1; 605f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Connect(); 606f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 607f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 608f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 609f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid RelayEntry::OnMessage(talk_base::Message *pmsg) { 610f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(pmsg->message_id == kMessageConnectTimeout); 611f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_) { 612f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const ProtocolAddress* ra = current_connection_->protocol_address(); 613f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_WARNING) << "Relay " << ra->proto << " connection to " << 614f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ra->address << " timed out"; 615f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 616f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Currently we connect to each server address in sequence. If we 617f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // have more addresses to try, treat this is an error and move on to 618f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // the next address, otherwise give this connection more time and 619f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // await the real timeout. 620f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // 621dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // TODO: Connect to servers in parallel to speed up connect time 622dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // and to avoid giving up too early. 623f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port_->SignalSoftTimeout(ra); 624f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HandleConnectFailure(current_connection_->socket()); 625f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 626f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HandleConnectFailure(NULL); 627f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 628f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 629f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 630dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid RelayEntry::OnSocketConnect(talk_base::AsyncPacketSocket* socket) { 631f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "relay tcp connected to " << 632f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch socket->GetRemoteAddress().ToString(); 633f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_ != NULL) { 634f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch current_connection_->SendAllocateRequest(this, 0); 635f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 636f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 637f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 638dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid RelayEntry::OnSocketClose(talk_base::AsyncPacketSocket* socket, 639dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int error) { 640f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch PLOG(LERROR, error) << "Relay connection failed: socket closed"; 641f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HandleConnectFailure(socket); 642f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 643f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 644dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid RelayEntry::OnReadPacket(talk_base::AsyncPacketSocket* socket, 645dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const char* data, size_t size, 646dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const talk_base::SocketAddress& remote_addr) { 647f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // ASSERT(remote_addr == port_->server_addr()); 648f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: are we worried about this? 649f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 650f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_ == NULL || socket != current_connection_->socket()) { 651f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // This packet comes from an unknown address. 652f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(WARNING) << "Dropping packet: unknown address"; 653f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 654f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 655f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 656f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If the magic cookie is not present, then this is an unwrapped packet sent 657f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // by the server, The actual remote address is the one we recorded. 658f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!port_->HasMagicCookie(data, size)) { 659f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (locked_) { 660f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port_->OnReadPacket(data, size, ext_addr_); 661f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 662f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(WARNING) << "Dropping packet: entry not locked"; 663f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 664f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 665f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 666f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 667f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::ByteBuffer buf(data, size); 668f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunMessage msg; 669f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!msg.Read(&buf)) { 670f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Incoming packet was not STUN"; 671f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 672f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 673f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 674f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // The incoming packet should be a STUN ALLOCATE response, SEND response, or 675f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // DATA indication. 676f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_->CheckResponse(&msg)) { 677f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 678f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (msg.type() == STUN_SEND_RESPONSE) { 679f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (const StunUInt32Attribute* options_attr = 680f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch msg.GetUInt32(STUN_ATTR_OPTIONS)) { 681f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (options_attr->value() & 0x1) { 682f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch locked_ = true; 683f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 684f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 685f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 686f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (msg.type() != STUN_DATA_INDICATION) { 687f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Received BAD stun type from server: " << msg.type(); 688f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 689f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 690f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 691f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // This must be a data indication. 692f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 693f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const StunAddressAttribute* addr_attr = 694f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2); 695f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!addr_attr) { 696f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Data indication has no source address"; 697f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 698f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (addr_attr->family() != 1) { 699f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Source address has bad family"; 700f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 701f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 702f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 703f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::SocketAddress remote_addr2(addr_attr->ip(), addr_attr->port()); 704f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 705f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA); 706f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!data_attr) { 707f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Data indication has no data"; 708f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 709f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 710f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 711f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Process the actual data and remote address in the normal manner. 712f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch port_->OnReadPacket(data_attr->bytes(), data_attr->length(), remote_addr2); 713f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 714f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 715f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint RelayEntry::SendPacket(const void* data, size_t size) { 716f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int sent = 0; 717f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (current_connection_) { 718f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We are connected, no need to send packets anywere else than to 719f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // the current connection. 720f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sent = current_connection_->Send(data, size); 721f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 722f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return sent; 723f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 724f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 725f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochAllocateRequest::AllocateRequest(RelayEntry* entry, 726f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch RelayConnection* connection) : 727f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry_(entry), connection_(connection) { 728f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch start_time_ = talk_base::Time(); 729f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 730f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 731f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid AllocateRequest::Prepare(StunMessage* request) { 732f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request->SetType(STUN_ALLOCATE_REQUEST); 733f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 734f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunByteStringAttribute* magic_cookie_attr = 735f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE); 736f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch magic_cookie_attr->CopyBytes( 737f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry_->port()->magic_cookie().c_str(), 738dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry_->port()->magic_cookie().size()); 739f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request->AddAttribute(magic_cookie_attr); 740f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 741f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunByteStringAttribute* username_attr = 742f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StunAttribute::CreateByteString(STUN_ATTR_USERNAME); 743f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch username_attr->CopyBytes( 744f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry_->port()->username_fragment().c_str(), 745dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen entry_->port()->username_fragment().size()); 746f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request->AddAttribute(username_attr); 747f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 748f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 749f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint AllocateRequest::GetNextDelay() { 750f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int delay = 100 * talk_base::_max(1 << count_, 2); 751f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch count_ += 1; 752f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (count_ == 5) 753f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch timeout_ = true; 754f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return delay; 755f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 756f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 757f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid AllocateRequest::OnResponse(StunMessage* response) { 758f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const StunAddressAttribute* addr_attr = 759f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response->GetAddress(STUN_ATTR_MAPPED_ADDRESS); 760f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!addr_attr) { 761f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Allocate response missing mapped address."; 762f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (addr_attr->family() != 1) { 763f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Mapped address has bad family"; 764f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 765f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch talk_base::SocketAddress addr(addr_attr->ip(), addr_attr->port()); 766f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry_->OnConnect(addr, connection_); 767f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 768f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 769f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We will do a keep-alive regardless of whether this request suceeds. 770f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // This should have almost no impact on network usage. 771f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry_->ScheduleKeepAlive(); 772f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 773f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 774f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid AllocateRequest::OnErrorResponse(StunMessage* response) { 775f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const StunErrorCodeAttribute* attr = response->GetErrorCode(); 776f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!attr) { 777f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Bad allocate response error code"; 778f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 779f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Allocate error response:" 780f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << " code=" << static_cast<int>(attr->error_code()) 781f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << " reason='" << attr->reason() << "'"; 782f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 783f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 784f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (talk_base::TimeSince(start_time_) <= kRetryTimeout) 785f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry_->ScheduleKeepAlive(); 786f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 787f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 788f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid AllocateRequest::OnTimeout() { 789f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Allocate request timed out"; 790f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch entry_->HandleConnectFailure(connection_->socket()); 791f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 792f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 793f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // namespace cricket 794