From a06e2c2f225d76b67b0058a9880222f75d5495c3 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Wed, 9 Dec 2020 14:11:22 +0900 Subject: Renaming of files in preparation for code style tools. Signed-off-by: Michele Calgaro --- .../libjingle/talk/p2p/client/CMakeLists.txt | 2 +- .../jingle/libjingle/talk/p2p/client/Makefile.am | 6 +- .../talk/p2p/client/basicportallocator.cc | 667 --------------------- .../talk/p2p/client/basicportallocator.cpp | 667 +++++++++++++++++++++ .../libjingle/talk/p2p/client/sessionclient.cc | 545 ----------------- .../libjingle/talk/p2p/client/sessionclient.cpp | 545 +++++++++++++++++ .../libjingle/talk/p2p/client/socketmonitor.cc | 149 ----- .../libjingle/talk/p2p/client/socketmonitor.cpp | 149 +++++ 8 files changed, 1365 insertions(+), 1365 deletions(-) delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cpp delete mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc create mode 100644 kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cpp (limited to 'kopete/protocols/jabber/jingle/libjingle/talk/p2p/client') diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/CMakeLists.txt b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/CMakeLists.txt index 7ede9820..8ccce5f8 100644 --- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/CMakeLists.txt +++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/CMakeLists.txt @@ -26,5 +26,5 @@ include_directories( tde_add_library( cricketp2pclient STATIC_PIC SOURCES - sessionclient.cc basicportallocator.cc socketmonitor.cc + sessionclient.cpp basicportallocator.cpp socketmonitor.cpp ) diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am index 2bdd95ff..4a461b93 100644 --- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am +++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/Makefile.am @@ -1,6 +1,6 @@ -libcricketp2pclient_la_SOURCES = sessionclient.cc \ - basicportallocator.cc \ - socketmonitor.cc +libcricketp2pclient_la_SOURCES = sessionclient.cpp \ + basicportallocator.cpp \ + socketmonitor.cpp noinst_HEADERS = basicportallocator.h \ sessionclient.h \ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc deleted file mode 100644 index 5192595c..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cc +++ /dev/null @@ -1,667 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#pragma warning(disable:4786) -#endif -#include "talk/base/host.h" -#include "talk/base/logging.h" -#include "talk/p2p/client/basicportallocator.h" -#include "talk/p2p/base/port.h" -#include "talk/p2p/base/udpport.h" -#include "talk/p2p/base/tcpport.h" -#include "talk/p2p/base/stunport.h" -#include "talk/p2p/base/relayport.h" -#include "talk/p2p/base/helpers.h" -#include - -namespace { - -const uint32 MSG_CONFIG_START = 1; -const uint32 MSG_CONFIG_READY = 2; -const uint32 MSG_ALLOCATE = 3; -const uint32 MSG_ALLOCATION_PHASE = 4; -const uint32 MSG_SHAKE = 5; - -const uint32 ALLOCATE_DELAY = 250; -const uint32 ALLOCATION_STEP_DELAY = 1 * 1000; - -const int PHASE_UDP = 0; -const int PHASE_RELAY = 1; -const int PHASE_TCP = 2; -const int PHASE_SSLTCP = 3; -const int kNumPhases = 4; - -const float PREF_LOCAL_UDP = 1.0f; -const float PREF_LOCAL_STUN = 0.9f; -const float PREF_LOCAL_TCP = 0.8f; -const float PREF_RELAY = 0.5f; - -const float RELAY_PRIMARY_PREF_MODIFIER = 0.0f; // modifiers of the above constants -const float RELAY_BACKUP_PREF_MODIFIER = -0.2f; - - -// Returns the phase in which a given local candidate (or rather, the port that -// gave rise to that local candidate) would have been created. -int LocalCandidateToPhase(const cricket::Candidate& candidate) { - cricket::ProtocolType proto; - bool result = cricket::StringToProto(candidate.protocol().c_str(), proto); - if (result) { - if (candidate.type() == cricket::LOCAL_PORT_TYPE) { - switch (proto) { - case cricket::PROTO_UDP: return PHASE_UDP; - case cricket::PROTO_TCP: return PHASE_TCP; - default: assert(false); - } - } else if (candidate.type() == cricket::STUN_PORT_TYPE) { - return PHASE_UDP; - } else if (candidate.type() == cricket::RELAY_PORT_TYPE) { - switch (proto) { - case cricket::PROTO_UDP: return PHASE_RELAY; - case cricket::PROTO_TCP: return PHASE_TCP; - case cricket::PROTO_SSLTCP: return PHASE_SSLTCP; - default: assert(false); - } - } else { - assert(false); - } - } else { - assert(false); - } - return PHASE_UDP; // reached only with assert failure -} - -const int SHAKE_MIN_DELAY = 45 * 1000; // 45 seconds -const int SHAKE_MAX_DELAY = 90 * 1000; // 90 seconds - -int ShakeDelay() { - int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1; - return SHAKE_MIN_DELAY + cricket::CreateRandomId() % range; -} - -} - -namespace cricket { - -// Performs the allocation of ports, in a sequenced (timed) manner, for a given -// network and IP address. -class AllocationSequence: public MessageHandler { -public: - AllocationSequence(BasicPortAllocatorSession* session, - Network* network, - PortConfiguration* config); - ~AllocationSequence(); - - // Determines whether this sequence is operating on an equivalent network - // setup to the one given. - bool IsEquivalent(Network* network); - - // Starts and stops the sequence. When started, it will continue allocating - // new ports on its own timed schedule. - void Start(); - void Stop(); - - // MessageHandler: - void OnMessage(Message* msg); - - void EnableProtocol(ProtocolType proto); - bool ProtocolEnabled(ProtocolType proto) const; - -private: - BasicPortAllocatorSession* session_; - Network* network_; - uint32 ip_; - PortConfiguration* config_; - bool running_; - int step_; - int step_of_phase_[kNumPhases]; - - typedef std::vector ProtocolList; - ProtocolList protocols_; - - void CreateUDPPorts(); - void CreateTCPPorts(); - void CreateStunPorts(); - void CreateRelayPorts(); -}; - - -// BasicPortAllocator - -BasicPortAllocator::BasicPortAllocator(NetworkManager* network_manager) - : network_manager_(network_manager), best_writable_phase_(-1), stun_address_(NULL), relay_address_(NULL) { -} - -BasicPortAllocator::BasicPortAllocator(NetworkManager* network_manager, SocketAddress* stun_address, SocketAddress *relay_address) - : network_manager_(network_manager), best_writable_phase_(-1), stun_address_(stun_address), relay_address_(relay_address) { -} - -BasicPortAllocator::~BasicPortAllocator() { -} - -int BasicPortAllocator::best_writable_phase() const { - // If we are configured with an HTTP proxy, the best bet is to use the relay - if ((best_writable_phase_ == -1) - && ((proxy().type == PROXY_HTTPS) || (proxy().type == PROXY_UNKNOWN))) { - return PHASE_RELAY; - } - return best_writable_phase_; -} - -PortAllocatorSession *BasicPortAllocator::CreateSession(const std::string &name) { - return new BasicPortAllocatorSession(this, name, stun_address_, relay_address_); -} - -void BasicPortAllocator::AddWritablePhase(int phase) { - if ((best_writable_phase_ == -1) || (phase < best_writable_phase_)) - best_writable_phase_ = phase; -} - -// BasicPortAllocatorSession - -BasicPortAllocatorSession::BasicPortAllocatorSession( - BasicPortAllocator *allocator, - const std::string &name) - : allocator_(allocator), name_(name), network_thread_(NULL), - config_thread_(NULL), allocation_started_(false), running_(false), - stun_address_(NULL), relay_address_(NULL) { -} - -BasicPortAllocatorSession::BasicPortAllocatorSession( - BasicPortAllocator *allocator, - const std::string &name, - SocketAddress *stun_address, - SocketAddress *relay_address) - : allocator_(allocator), name_(name), network_thread_(NULL), - config_thread_(NULL), allocation_started_(false), running_(false), - stun_address_(stun_address), relay_address_(relay_address) { -} - -BasicPortAllocatorSession::~BasicPortAllocatorSession() { - if (config_thread_ != NULL) - config_thread_->Clear(this); - if (network_thread_ != NULL) - network_thread_->Clear(this); - - std::vector::iterator it; - for (it = ports_.begin(); it != ports_.end(); it++) - delete it->port; - - for (uint32 i = 0; i < configs_.size(); ++i) - delete configs_[i]; - - for (uint32 i = 0; i < sequences_.size(); ++i) - delete sequences_[i]; -} - -void BasicPortAllocatorSession::GetInitialPorts() { - network_thread_ = Thread::Current(); - if (!config_thread_) - config_thread_ = network_thread_; - - config_thread_->Post(this, MSG_CONFIG_START); - - if (allocator()->flags() & PORTALLOCATOR_ENABLE_SHAKER) - network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE); -} - -void BasicPortAllocatorSession::StartGetAllPorts() { - assert(Thread::Current() == network_thread_); - running_ = true; - if (allocation_started_) - network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE); - for (uint32 i = 0; i < sequences_.size(); ++i) - sequences_[i]->Start(); - for (size_t i = 0; i < ports_.size(); ++i) - ports_[i].port->Start(); -} - -void BasicPortAllocatorSession::StopGetAllPorts() { - assert(Thread::Current() == network_thread_); - running_ = false; - network_thread_->Clear(this, MSG_ALLOCATE); - for (uint32 i = 0; i < sequences_.size(); ++i) - sequences_[i]->Stop(); -} - -void BasicPortAllocatorSession::OnMessage(Message *message) { - switch (message->message_id) { - case MSG_CONFIG_START: - assert(Thread::Current() == config_thread_); - GetPortConfigurations(); - break; - - case MSG_CONFIG_READY: - assert(Thread::Current() == network_thread_); - OnConfigReady(static_cast(message->pdata)); - break; - - case MSG_ALLOCATE: - assert(Thread::Current() == network_thread_); - OnAllocate(); - break; - - case MSG_SHAKE: - assert(Thread::Current() == network_thread_); - OnShake(); - break; - - default: - assert(false); - } -} - -void BasicPortAllocatorSession::GetPortConfigurations() { - PortConfiguration* config = NULL; - if (stun_address_ != NULL) - config = new PortConfiguration(*stun_address_, - CreateRandomString(16), - CreateRandomString(16), - ""); - PortConfiguration::PortList ports; - if (relay_address_ != NULL) { - ports.push_back(ProtocolAddress(*relay_address_, PROTO_UDP)); - config->AddRelay(ports, RELAY_PRIMARY_PREF_MODIFIER); - } - - ConfigReady(config); -} - -void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) { - network_thread_->Post(this, MSG_CONFIG_READY, config); -} - -// Adds a configuration to the list. -void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) { - if (config) - configs_.push_back(config); - - AllocatePorts(); -} - -void BasicPortAllocatorSession::AllocatePorts() { - assert(Thread::Current() == network_thread_); - - if (allocator_->proxy().type != PROXY_NONE) - Port::set_proxy(allocator_->proxy()); - - network_thread_->Post(this, MSG_ALLOCATE); -} - -// For each network, see if we have a sequence that covers it already. If not, -// create a new sequence to create the appropriate ports. -void BasicPortAllocatorSession::OnAllocate() { - std::vector networks; - allocator_->network_manager()->GetNetworks(networks); - - for (uint32 i = 0; i < networks.size(); ++i) { - if (HasEquivalentSequence(networks[i])) - continue; - - PortConfiguration* config = NULL; - if (configs_.size() > 0) - config = configs_.back(); - - AllocationSequence* sequence = - new AllocationSequence(this, networks[i], config); - if (running_) - sequence->Start(); - - sequences_.push_back(sequence); - } - - allocation_started_ = true; - if (running_) - network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE); -} - -bool BasicPortAllocatorSession::HasEquivalentSequence(Network* network) { - for (uint32 i = 0; i < sequences_.size(); ++i) - if (sequences_[i]->IsEquivalent(network)) - return true; - return false; -} - -void BasicPortAllocatorSession::AddAllocatedPort(Port* port, - AllocationSequence * seq, - float pref, - bool prepare_address) { - if (!port) - return; - - port->set_name(name_); - port->set_preference(pref); - port->set_generation(generation()); - PortData data; - data.port = port; - data.sequence = seq; - data.ready = false; - ports_.push_back(data); - port->SignalAddressReady.connect(this, &BasicPortAllocatorSession::OnAddressReady); - port->SignalConnectionCreated.connect(this, &BasicPortAllocatorSession::OnConnectionCreated); - port->SignalDestroyed.connect(this, &BasicPortAllocatorSession::OnPortDestroyed); - if (prepare_address) - port->PrepareAddress(); - if (running_) - port->Start(); -} - -void BasicPortAllocatorSession::OnAddressReady(Port *port) { - assert(Thread::Current() == network_thread_); - std::vector::iterator it = std::find(ports_.begin(), ports_.end(), port); - assert(it != ports_.end()); - assert(!it->ready); - it->ready = true; - SignalPortReady(this, port); - - // Only accumulate the candidates whose protocol has been enabled - std::vector candidates; - const std::vector& potentials = port->candidates(); - for (size_t i=0; isequence->ProtocolEnabled(pvalue)) { - candidates.push_back(potentials[i]); - } - } - if (!candidates.empty()) { - SignalCandidatesReady(this, candidates); - } -} - -void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence * seq, ProtocolType proto) { - std::vector candidates; - for (std::vector::iterator it = ports_.begin(); it != ports_.end(); ++it) { - if (!it->ready || (it->sequence != seq)) - continue; - - const std::vector& potentials = it->port->candidates(); - for (size_t i=0; i::iterator iter = - find(ports_.begin(), ports_.end(), port); - assert(iter != ports_.end()); - ports_.erase(iter); - - LOG(INFO) << "Removed port from allocator: " - << static_cast(ports_.size()) << " remaining"; -} - -void BasicPortAllocatorSession::OnConnectionCreated(Port* port, Connection* conn) { - conn->SignalStateChange.connect(this, &BasicPortAllocatorSession::OnConnectionStateChange); -} - -void BasicPortAllocatorSession::OnConnectionStateChange(Connection* conn) { - if (conn->write_state() == Connection::STATE_WRITABLE) - allocator_->AddWritablePhase(LocalCandidateToPhase(conn->local_candidate())); -} - -void BasicPortAllocatorSession::OnShake() { - LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<"; - - std::vector ports; - std::vector connections; - - for (size_t i = 0; i < ports_.size(); ++i) { - if (ports_[i].ready) - ports.push_back(ports_[i].port); - } - - for (size_t i = 0; i < ports.size(); ++i) { - Port::AddressMap::const_iterator iter; - for (iter = ports[i]->connections().begin(); - iter != ports[i]->connections().end(); - ++iter) { - connections.push_back(iter->second); - } - } - - LOG(INFO) << ">>>>> Destroying " << (int)ports.size() << " ports and " - << (int)connections.size() << " connections"; - - for (size_t i = 0; i < connections.size(); ++i) - connections[i]->Destroy(); - - if (running_ || (ports.size() > 0) || (connections.size() > 0)) - network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE); -} - -// AllocationSequence - -AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session, - Network* network, - PortConfiguration* config) - : session_(session), network_(network), ip_(network->ip()), config_(config), - running_(false), step_(0) { - - // All of the phases up until the best-writable phase so far run in step 0. - // The other phases follow sequentially in the steps after that. If there is - // no best-writable so far, then only phase 0 occurs in step 0. - int last_phase_in_step_zero = - _max(0, session->allocator()->best_writable_phase()); - for (int phase = 0; phase < kNumPhases; ++phase) - step_of_phase_[phase] = _max(0, phase - last_phase_in_step_zero); - - // Immediately perform phase 0. - OnMessage(NULL); -} - -AllocationSequence::~AllocationSequence() { - session_->network_thread()->Clear(this); -} - -bool AllocationSequence::IsEquivalent(Network* network) { - return (network == network_) && (ip_ == network->ip()); -} - -void AllocationSequence::Start() { - running_ = true; - session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY, - this, - MSG_ALLOCATION_PHASE); -} - -void AllocationSequence::Stop() { - running_ = false; - session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE); -} - -void AllocationSequence::OnMessage(Message* msg) { - assert(Thread::Current() == session_->network_thread()); - if (msg) - assert(msg->message_id == MSG_ALLOCATION_PHASE); - - // Perform all of the phases in the current step. - for (int phase = 0; phase < kNumPhases; phase++) { - if (step_of_phase_[phase] != step_) - continue; - - switch (phase) { - case PHASE_UDP: - LOG(INFO) << "Phase=UDP Step=" << step_; - CreateUDPPorts(); - CreateStunPorts(); - EnableProtocol(PROTO_UDP); - break; - - case PHASE_RELAY: - LOG(INFO) << "Phase=RELAY Step=" << step_; - CreateRelayPorts(); - break; - - case PHASE_TCP: - LOG(INFO) << "Phase=TCP Step=" << step_; - CreateTCPPorts(); - EnableProtocol(PROTO_TCP); - break; - - case PHASE_SSLTCP: - LOG(INFO) << "Phase=SSLTCP Step=" << step_; - EnableProtocol(PROTO_SSLTCP); - break; - - default: - // Nothing else we can do. - return; - } - } - - // TODO: use different delays for each stage - step_ += 1; - if (running_) { - session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY, - this, - MSG_ALLOCATION_PHASE); - } -} - -void AllocationSequence::EnableProtocol(ProtocolType proto) { - if (!ProtocolEnabled(proto)) { - protocols_.push_back(proto); - session_->OnProtocolEnabled(this, proto); - } -} - -bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const { - for (ProtocolList::const_iterator it = protocols_.begin(); it != protocols_.end(); ++it) { - if (*it == proto) - return true; - } - return false; -} - -void AllocationSequence::CreateUDPPorts() { - if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_UDP) - return; - - Port* port = new UDPPort(session_->network_thread(), NULL, network_, - SocketAddress(ip_, 0)); - session_->AddAllocatedPort(port, this, PREF_LOCAL_UDP); -} - -void AllocationSequence::CreateTCPPorts() { - if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_TCP) - return; - - Port* port = new TCPPort(session_->network_thread(), NULL, network_, - SocketAddress(ip_, 0)); - session_->AddAllocatedPort(port, this, PREF_LOCAL_TCP); -} - -void AllocationSequence::CreateStunPorts() { - if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_STUN) - return; - - if (!config_ || config_->stun_address.IsAny()) - return; - - Port* port = new StunPort(session_->network_thread(), NULL, network_, - SocketAddress(ip_, 0), config_->stun_address); - session_->AddAllocatedPort(port, this, PREF_LOCAL_STUN); -} - -void AllocationSequence::CreateRelayPorts() { - if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY) - return; - - if (!config_) - return; - - PortConfiguration::RelayList::const_iterator relay; - for (relay = config_->relays.begin(); - relay != config_->relays.end(); - ++relay) { - - RelayPort *port = new RelayPort(session_->network_thread(), NULL, network_, - SocketAddress(ip_, 0), - config_->username, config_->password, - config_->magic_cookie); - // Note: We must add the allocated port before we add addresses because - // the latter will create candidates that need name and preference - // settings. However, we also can't prepare the address (normally - // done by AddAllocatedPort) until we have these addresses. So we - // wait to do that until below. - session_->AddAllocatedPort(port, this, PREF_RELAY + relay->pref_modifier, false); - - // Add the addresses of this protocol. - PortConfiguration::PortList::const_iterator relay_port; - for (relay_port = relay->ports.begin(); - relay_port != relay->ports.end(); - ++relay_port) { - port->AddServerAddress(*relay_port); - port->AddExternalAddress(*relay_port); - } - - // Start fetching an address for this port. - port->PrepareAddress(); - } -} - -// PortConfiguration - -PortConfiguration::PortConfiguration(const SocketAddress& sa, - const std::string& un, - const std::string& pw, - const std::string& mc) - : stun_address(sa), username(un), password(pw), magic_cookie(mc) { -} - -void PortConfiguration::AddRelay(const PortList& ports, float pref_modifier) { - RelayServer relay; - relay.ports = ports; - relay.pref_modifier = pref_modifier; - relays.push_back(relay); -} - -bool PortConfiguration::SupportsProtocol( - const PortConfiguration::RelayServer& relay, ProtocolType type) { - PortConfiguration::PortList::const_iterator relay_port; - for (relay_port = relay.ports.begin(); - relay_port != relay.ports.end(); - ++relay_port) { - if (relay_port->proto == type) - return true; - } - return false; -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cpp new file mode 100644 index 00000000..5192595c --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/basicportallocator.cpp @@ -0,0 +1,667 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable:4786) +#endif +#include "talk/base/host.h" +#include "talk/base/logging.h" +#include "talk/p2p/client/basicportallocator.h" +#include "talk/p2p/base/port.h" +#include "talk/p2p/base/udpport.h" +#include "talk/p2p/base/tcpport.h" +#include "talk/p2p/base/stunport.h" +#include "talk/p2p/base/relayport.h" +#include "talk/p2p/base/helpers.h" +#include + +namespace { + +const uint32 MSG_CONFIG_START = 1; +const uint32 MSG_CONFIG_READY = 2; +const uint32 MSG_ALLOCATE = 3; +const uint32 MSG_ALLOCATION_PHASE = 4; +const uint32 MSG_SHAKE = 5; + +const uint32 ALLOCATE_DELAY = 250; +const uint32 ALLOCATION_STEP_DELAY = 1 * 1000; + +const int PHASE_UDP = 0; +const int PHASE_RELAY = 1; +const int PHASE_TCP = 2; +const int PHASE_SSLTCP = 3; +const int kNumPhases = 4; + +const float PREF_LOCAL_UDP = 1.0f; +const float PREF_LOCAL_STUN = 0.9f; +const float PREF_LOCAL_TCP = 0.8f; +const float PREF_RELAY = 0.5f; + +const float RELAY_PRIMARY_PREF_MODIFIER = 0.0f; // modifiers of the above constants +const float RELAY_BACKUP_PREF_MODIFIER = -0.2f; + + +// Returns the phase in which a given local candidate (or rather, the port that +// gave rise to that local candidate) would have been created. +int LocalCandidateToPhase(const cricket::Candidate& candidate) { + cricket::ProtocolType proto; + bool result = cricket::StringToProto(candidate.protocol().c_str(), proto); + if (result) { + if (candidate.type() == cricket::LOCAL_PORT_TYPE) { + switch (proto) { + case cricket::PROTO_UDP: return PHASE_UDP; + case cricket::PROTO_TCP: return PHASE_TCP; + default: assert(false); + } + } else if (candidate.type() == cricket::STUN_PORT_TYPE) { + return PHASE_UDP; + } else if (candidate.type() == cricket::RELAY_PORT_TYPE) { + switch (proto) { + case cricket::PROTO_UDP: return PHASE_RELAY; + case cricket::PROTO_TCP: return PHASE_TCP; + case cricket::PROTO_SSLTCP: return PHASE_SSLTCP; + default: assert(false); + } + } else { + assert(false); + } + } else { + assert(false); + } + return PHASE_UDP; // reached only with assert failure +} + +const int SHAKE_MIN_DELAY = 45 * 1000; // 45 seconds +const int SHAKE_MAX_DELAY = 90 * 1000; // 90 seconds + +int ShakeDelay() { + int range = SHAKE_MAX_DELAY - SHAKE_MIN_DELAY + 1; + return SHAKE_MIN_DELAY + cricket::CreateRandomId() % range; +} + +} + +namespace cricket { + +// Performs the allocation of ports, in a sequenced (timed) manner, for a given +// network and IP address. +class AllocationSequence: public MessageHandler { +public: + AllocationSequence(BasicPortAllocatorSession* session, + Network* network, + PortConfiguration* config); + ~AllocationSequence(); + + // Determines whether this sequence is operating on an equivalent network + // setup to the one given. + bool IsEquivalent(Network* network); + + // Starts and stops the sequence. When started, it will continue allocating + // new ports on its own timed schedule. + void Start(); + void Stop(); + + // MessageHandler: + void OnMessage(Message* msg); + + void EnableProtocol(ProtocolType proto); + bool ProtocolEnabled(ProtocolType proto) const; + +private: + BasicPortAllocatorSession* session_; + Network* network_; + uint32 ip_; + PortConfiguration* config_; + bool running_; + int step_; + int step_of_phase_[kNumPhases]; + + typedef std::vector ProtocolList; + ProtocolList protocols_; + + void CreateUDPPorts(); + void CreateTCPPorts(); + void CreateStunPorts(); + void CreateRelayPorts(); +}; + + +// BasicPortAllocator + +BasicPortAllocator::BasicPortAllocator(NetworkManager* network_manager) + : network_manager_(network_manager), best_writable_phase_(-1), stun_address_(NULL), relay_address_(NULL) { +} + +BasicPortAllocator::BasicPortAllocator(NetworkManager* network_manager, SocketAddress* stun_address, SocketAddress *relay_address) + : network_manager_(network_manager), best_writable_phase_(-1), stun_address_(stun_address), relay_address_(relay_address) { +} + +BasicPortAllocator::~BasicPortAllocator() { +} + +int BasicPortAllocator::best_writable_phase() const { + // If we are configured with an HTTP proxy, the best bet is to use the relay + if ((best_writable_phase_ == -1) + && ((proxy().type == PROXY_HTTPS) || (proxy().type == PROXY_UNKNOWN))) { + return PHASE_RELAY; + } + return best_writable_phase_; +} + +PortAllocatorSession *BasicPortAllocator::CreateSession(const std::string &name) { + return new BasicPortAllocatorSession(this, name, stun_address_, relay_address_); +} + +void BasicPortAllocator::AddWritablePhase(int phase) { + if ((best_writable_phase_ == -1) || (phase < best_writable_phase_)) + best_writable_phase_ = phase; +} + +// BasicPortAllocatorSession + +BasicPortAllocatorSession::BasicPortAllocatorSession( + BasicPortAllocator *allocator, + const std::string &name) + : allocator_(allocator), name_(name), network_thread_(NULL), + config_thread_(NULL), allocation_started_(false), running_(false), + stun_address_(NULL), relay_address_(NULL) { +} + +BasicPortAllocatorSession::BasicPortAllocatorSession( + BasicPortAllocator *allocator, + const std::string &name, + SocketAddress *stun_address, + SocketAddress *relay_address) + : allocator_(allocator), name_(name), network_thread_(NULL), + config_thread_(NULL), allocation_started_(false), running_(false), + stun_address_(stun_address), relay_address_(relay_address) { +} + +BasicPortAllocatorSession::~BasicPortAllocatorSession() { + if (config_thread_ != NULL) + config_thread_->Clear(this); + if (network_thread_ != NULL) + network_thread_->Clear(this); + + std::vector::iterator it; + for (it = ports_.begin(); it != ports_.end(); it++) + delete it->port; + + for (uint32 i = 0; i < configs_.size(); ++i) + delete configs_[i]; + + for (uint32 i = 0; i < sequences_.size(); ++i) + delete sequences_[i]; +} + +void BasicPortAllocatorSession::GetInitialPorts() { + network_thread_ = Thread::Current(); + if (!config_thread_) + config_thread_ = network_thread_; + + config_thread_->Post(this, MSG_CONFIG_START); + + if (allocator()->flags() & PORTALLOCATOR_ENABLE_SHAKER) + network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE); +} + +void BasicPortAllocatorSession::StartGetAllPorts() { + assert(Thread::Current() == network_thread_); + running_ = true; + if (allocation_started_) + network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE); + for (uint32 i = 0; i < sequences_.size(); ++i) + sequences_[i]->Start(); + for (size_t i = 0; i < ports_.size(); ++i) + ports_[i].port->Start(); +} + +void BasicPortAllocatorSession::StopGetAllPorts() { + assert(Thread::Current() == network_thread_); + running_ = false; + network_thread_->Clear(this, MSG_ALLOCATE); + for (uint32 i = 0; i < sequences_.size(); ++i) + sequences_[i]->Stop(); +} + +void BasicPortAllocatorSession::OnMessage(Message *message) { + switch (message->message_id) { + case MSG_CONFIG_START: + assert(Thread::Current() == config_thread_); + GetPortConfigurations(); + break; + + case MSG_CONFIG_READY: + assert(Thread::Current() == network_thread_); + OnConfigReady(static_cast(message->pdata)); + break; + + case MSG_ALLOCATE: + assert(Thread::Current() == network_thread_); + OnAllocate(); + break; + + case MSG_SHAKE: + assert(Thread::Current() == network_thread_); + OnShake(); + break; + + default: + assert(false); + } +} + +void BasicPortAllocatorSession::GetPortConfigurations() { + PortConfiguration* config = NULL; + if (stun_address_ != NULL) + config = new PortConfiguration(*stun_address_, + CreateRandomString(16), + CreateRandomString(16), + ""); + PortConfiguration::PortList ports; + if (relay_address_ != NULL) { + ports.push_back(ProtocolAddress(*relay_address_, PROTO_UDP)); + config->AddRelay(ports, RELAY_PRIMARY_PREF_MODIFIER); + } + + ConfigReady(config); +} + +void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) { + network_thread_->Post(this, MSG_CONFIG_READY, config); +} + +// Adds a configuration to the list. +void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) { + if (config) + configs_.push_back(config); + + AllocatePorts(); +} + +void BasicPortAllocatorSession::AllocatePorts() { + assert(Thread::Current() == network_thread_); + + if (allocator_->proxy().type != PROXY_NONE) + Port::set_proxy(allocator_->proxy()); + + network_thread_->Post(this, MSG_ALLOCATE); +} + +// For each network, see if we have a sequence that covers it already. If not, +// create a new sequence to create the appropriate ports. +void BasicPortAllocatorSession::OnAllocate() { + std::vector networks; + allocator_->network_manager()->GetNetworks(networks); + + for (uint32 i = 0; i < networks.size(); ++i) { + if (HasEquivalentSequence(networks[i])) + continue; + + PortConfiguration* config = NULL; + if (configs_.size() > 0) + config = configs_.back(); + + AllocationSequence* sequence = + new AllocationSequence(this, networks[i], config); + if (running_) + sequence->Start(); + + sequences_.push_back(sequence); + } + + allocation_started_ = true; + if (running_) + network_thread_->PostDelayed(ALLOCATE_DELAY, this, MSG_ALLOCATE); +} + +bool BasicPortAllocatorSession::HasEquivalentSequence(Network* network) { + for (uint32 i = 0; i < sequences_.size(); ++i) + if (sequences_[i]->IsEquivalent(network)) + return true; + return false; +} + +void BasicPortAllocatorSession::AddAllocatedPort(Port* port, + AllocationSequence * seq, + float pref, + bool prepare_address) { + if (!port) + return; + + port->set_name(name_); + port->set_preference(pref); + port->set_generation(generation()); + PortData data; + data.port = port; + data.sequence = seq; + data.ready = false; + ports_.push_back(data); + port->SignalAddressReady.connect(this, &BasicPortAllocatorSession::OnAddressReady); + port->SignalConnectionCreated.connect(this, &BasicPortAllocatorSession::OnConnectionCreated); + port->SignalDestroyed.connect(this, &BasicPortAllocatorSession::OnPortDestroyed); + if (prepare_address) + port->PrepareAddress(); + if (running_) + port->Start(); +} + +void BasicPortAllocatorSession::OnAddressReady(Port *port) { + assert(Thread::Current() == network_thread_); + std::vector::iterator it = std::find(ports_.begin(), ports_.end(), port); + assert(it != ports_.end()); + assert(!it->ready); + it->ready = true; + SignalPortReady(this, port); + + // Only accumulate the candidates whose protocol has been enabled + std::vector candidates; + const std::vector& potentials = port->candidates(); + for (size_t i=0; isequence->ProtocolEnabled(pvalue)) { + candidates.push_back(potentials[i]); + } + } + if (!candidates.empty()) { + SignalCandidatesReady(this, candidates); + } +} + +void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence * seq, ProtocolType proto) { + std::vector candidates; + for (std::vector::iterator it = ports_.begin(); it != ports_.end(); ++it) { + if (!it->ready || (it->sequence != seq)) + continue; + + const std::vector& potentials = it->port->candidates(); + for (size_t i=0; i::iterator iter = + find(ports_.begin(), ports_.end(), port); + assert(iter != ports_.end()); + ports_.erase(iter); + + LOG(INFO) << "Removed port from allocator: " + << static_cast(ports_.size()) << " remaining"; +} + +void BasicPortAllocatorSession::OnConnectionCreated(Port* port, Connection* conn) { + conn->SignalStateChange.connect(this, &BasicPortAllocatorSession::OnConnectionStateChange); +} + +void BasicPortAllocatorSession::OnConnectionStateChange(Connection* conn) { + if (conn->write_state() == Connection::STATE_WRITABLE) + allocator_->AddWritablePhase(LocalCandidateToPhase(conn->local_candidate())); +} + +void BasicPortAllocatorSession::OnShake() { + LOG(INFO) << ">>>>> SHAKE <<<<< >>>>> SHAKE <<<<< >>>>> SHAKE <<<<<"; + + std::vector ports; + std::vector connections; + + for (size_t i = 0; i < ports_.size(); ++i) { + if (ports_[i].ready) + ports.push_back(ports_[i].port); + } + + for (size_t i = 0; i < ports.size(); ++i) { + Port::AddressMap::const_iterator iter; + for (iter = ports[i]->connections().begin(); + iter != ports[i]->connections().end(); + ++iter) { + connections.push_back(iter->second); + } + } + + LOG(INFO) << ">>>>> Destroying " << (int)ports.size() << " ports and " + << (int)connections.size() << " connections"; + + for (size_t i = 0; i < connections.size(); ++i) + connections[i]->Destroy(); + + if (running_ || (ports.size() > 0) || (connections.size() > 0)) + network_thread_->PostDelayed(ShakeDelay(), this, MSG_SHAKE); +} + +// AllocationSequence + +AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session, + Network* network, + PortConfiguration* config) + : session_(session), network_(network), ip_(network->ip()), config_(config), + running_(false), step_(0) { + + // All of the phases up until the best-writable phase so far run in step 0. + // The other phases follow sequentially in the steps after that. If there is + // no best-writable so far, then only phase 0 occurs in step 0. + int last_phase_in_step_zero = + _max(0, session->allocator()->best_writable_phase()); + for (int phase = 0; phase < kNumPhases; ++phase) + step_of_phase_[phase] = _max(0, phase - last_phase_in_step_zero); + + // Immediately perform phase 0. + OnMessage(NULL); +} + +AllocationSequence::~AllocationSequence() { + session_->network_thread()->Clear(this); +} + +bool AllocationSequence::IsEquivalent(Network* network) { + return (network == network_) && (ip_ == network->ip()); +} + +void AllocationSequence::Start() { + running_ = true; + session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY, + this, + MSG_ALLOCATION_PHASE); +} + +void AllocationSequence::Stop() { + running_ = false; + session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE); +} + +void AllocationSequence::OnMessage(Message* msg) { + assert(Thread::Current() == session_->network_thread()); + if (msg) + assert(msg->message_id == MSG_ALLOCATION_PHASE); + + // Perform all of the phases in the current step. + for (int phase = 0; phase < kNumPhases; phase++) { + if (step_of_phase_[phase] != step_) + continue; + + switch (phase) { + case PHASE_UDP: + LOG(INFO) << "Phase=UDP Step=" << step_; + CreateUDPPorts(); + CreateStunPorts(); + EnableProtocol(PROTO_UDP); + break; + + case PHASE_RELAY: + LOG(INFO) << "Phase=RELAY Step=" << step_; + CreateRelayPorts(); + break; + + case PHASE_TCP: + LOG(INFO) << "Phase=TCP Step=" << step_; + CreateTCPPorts(); + EnableProtocol(PROTO_TCP); + break; + + case PHASE_SSLTCP: + LOG(INFO) << "Phase=SSLTCP Step=" << step_; + EnableProtocol(PROTO_SSLTCP); + break; + + default: + // Nothing else we can do. + return; + } + } + + // TODO: use different delays for each stage + step_ += 1; + if (running_) { + session_->network_thread()->PostDelayed(ALLOCATION_STEP_DELAY, + this, + MSG_ALLOCATION_PHASE); + } +} + +void AllocationSequence::EnableProtocol(ProtocolType proto) { + if (!ProtocolEnabled(proto)) { + protocols_.push_back(proto); + session_->OnProtocolEnabled(this, proto); + } +} + +bool AllocationSequence::ProtocolEnabled(ProtocolType proto) const { + for (ProtocolList::const_iterator it = protocols_.begin(); it != protocols_.end(); ++it) { + if (*it == proto) + return true; + } + return false; +} + +void AllocationSequence::CreateUDPPorts() { + if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_UDP) + return; + + Port* port = new UDPPort(session_->network_thread(), NULL, network_, + SocketAddress(ip_, 0)); + session_->AddAllocatedPort(port, this, PREF_LOCAL_UDP); +} + +void AllocationSequence::CreateTCPPorts() { + if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_TCP) + return; + + Port* port = new TCPPort(session_->network_thread(), NULL, network_, + SocketAddress(ip_, 0)); + session_->AddAllocatedPort(port, this, PREF_LOCAL_TCP); +} + +void AllocationSequence::CreateStunPorts() { + if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_STUN) + return; + + if (!config_ || config_->stun_address.IsAny()) + return; + + Port* port = new StunPort(session_->network_thread(), NULL, network_, + SocketAddress(ip_, 0), config_->stun_address); + session_->AddAllocatedPort(port, this, PREF_LOCAL_STUN); +} + +void AllocationSequence::CreateRelayPorts() { + if (session_->allocator()->flags() & PORTALLOCATOR_DISABLE_RELAY) + return; + + if (!config_) + return; + + PortConfiguration::RelayList::const_iterator relay; + for (relay = config_->relays.begin(); + relay != config_->relays.end(); + ++relay) { + + RelayPort *port = new RelayPort(session_->network_thread(), NULL, network_, + SocketAddress(ip_, 0), + config_->username, config_->password, + config_->magic_cookie); + // Note: We must add the allocated port before we add addresses because + // the latter will create candidates that need name and preference + // settings. However, we also can't prepare the address (normally + // done by AddAllocatedPort) until we have these addresses. So we + // wait to do that until below. + session_->AddAllocatedPort(port, this, PREF_RELAY + relay->pref_modifier, false); + + // Add the addresses of this protocol. + PortConfiguration::PortList::const_iterator relay_port; + for (relay_port = relay->ports.begin(); + relay_port != relay->ports.end(); + ++relay_port) { + port->AddServerAddress(*relay_port); + port->AddExternalAddress(*relay_port); + } + + // Start fetching an address for this port. + port->PrepareAddress(); + } +} + +// PortConfiguration + +PortConfiguration::PortConfiguration(const SocketAddress& sa, + const std::string& un, + const std::string& pw, + const std::string& mc) + : stun_address(sa), username(un), password(pw), magic_cookie(mc) { +} + +void PortConfiguration::AddRelay(const PortList& ports, float pref_modifier) { + RelayServer relay; + relay.ports = ports; + relay.pref_modifier = pref_modifier; + relays.push_back(relay); +} + +bool PortConfiguration::SupportsProtocol( + const PortConfiguration::RelayServer& relay, ProtocolType type) { + PortConfiguration::PortList::const_iterator relay_port; + for (relay_port = relay.ports.begin(); + relay_port != relay.ports.end(); + ++relay_port) { + if (relay_port->proto == type) + return true; + } + return false; +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc deleted file mode 100644 index b64c444a..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cc +++ /dev/null @@ -1,545 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#pragma warning(disable:4786) -#endif -#include "talk/p2p/client/sessionclient.h" -#include "talk/p2p/base/helpers.h" -#include "talk/base/logging.h" -#include "talk/xmllite/qname.h" -#include "talk/xmpp/constants.h" -#include "talk/xmllite/xmlprinter.h" -#include -#undef SetPort - -namespace { - -// We only allow usernames to be this many characters or fewer. -const size_t kMaxUsernameSize = 16; - -} - -namespace cricket { - -#if 0 ->>>>>> - - - - ... - - - - -<<<<<< - - ->>>>>> - - - - - - -> - -<<<<<< - - -#endif - -const std::string NS_GOOGLESESSION("http://www.google.com/session"); -const buzz::TQName TQN_GOOGLESESSION_SESSION(true, NS_GOOGLESESSION, "session"); -const buzz::TQName TQN_GOOGLESESSION_CANDIDATE(true, NS_GOOGLESESSION, "candidate"); -const buzz::TQName TQN_GOOGLESESSION_TARGET(true, NS_GOOGLESESSION, "target"); -const buzz::TQName TQN_GOOGLESESSION_COOKIE(true, NS_GOOGLESESSION, "cookie"); -const buzz::TQName TQN_GOOGLESESSION_REGARDING(true, NS_GOOGLESESSION, "regarding"); - -const buzz::TQName TQN_TYPE(true, buzz::STR_EMPTY, "type"); -const buzz::TQName TQN_ID(true, buzz::STR_EMPTY, "id"); -const buzz::TQName TQN_INITIATOR(true, buzz::STR_EMPTY, "initiator"); -const buzz::TQName TQN_NAME(true, buzz::STR_EMPTY, "name"); -const buzz::TQName TQN_PORT(true, buzz::STR_EMPTY, "port"); -const buzz::TQName TQN_NETWORK(true, buzz::STR_EMPTY, "network"); -const buzz::TQName TQN_GENERATION(true, buzz::STR_EMPTY, "generation"); -const buzz::TQName TQN_ADDRESS(true, buzz::STR_EMPTY, "address"); -const buzz::TQName TQN_USERNAME(true, buzz::STR_EMPTY, "username"); -const buzz::TQName TQN_PASSWORD(true, buzz::STR_EMPTY, "password"); -const buzz::TQName TQN_PREFERENCE(true, buzz::STR_EMPTY, "preference"); -const buzz::TQName TQN_PROTOCOL(true, buzz::STR_EMPTY, "protocol"); -const buzz::TQName TQN_KEY(true, buzz::STR_EMPTY, "key"); - -class XmlCookie: public SessionMessage::Cookie { -public: - XmlCookie(const buzz::XmlElement* elem) - : elem_(new buzz::XmlElement(*elem)) { - } - - virtual ~XmlCookie() { - delete elem_; - } - - const buzz::XmlElement* elem() const { return elem_; } - - virtual Cookie* Copy() { - return new XmlCookie(elem_); - } - -private: - buzz::XmlElement* elem_; -}; - -SessionClient::SessionClient(SessionManager *session_manager) { - session_manager_ = session_manager; - session_manager_->SignalSessionCreate.connect(this, &SessionClient::OnSessionCreateSlot); - session_manager_->SignalSessionDestroy.connect(this, &SessionClient::OnSessionDestroySlot); -} - -SessionClient::~SessionClient() { -} - -void SessionClient::OnSessionCreateSlot(Session *session, bool received_initiate) { - // Does this session belong to this session client? - if (session->name() == GetSessionDescriptionName()) { - session->SignalOutgoingMessage.connect(this, &SessionClient::OnOutgoingMessage); - OnSessionCreate(session, received_initiate); - } -} - -void SessionClient::OnSessionDestroySlot(Session *session) { - if (session->name() == GetSessionDescriptionName()) { - session->SignalOutgoingMessage.disconnect(this); - OnSessionDestroy(session); - } -} - -bool SessionClient::IsClientStanza(const buzz::XmlElement *stanza) { - // Is it a IQ set stanza? - if (stanza->Name() != buzz::TQN_IQ) - return false; - if (stanza->Attr(buzz::TQN_TYPE) != buzz::STR_SET) - return false; - - // Make sure it has the right child element - const buzz::XmlElement* element - = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); - if (element == NULL) - return false; - - // Is it one of the allowed types? - std::string type; - if (element->HasAttr(TQN_TYPE)) { - type = element->Attr(TQN_TYPE); - if (type != "initiate" && type != "accept" && type != "modify" && - type != "candidates" && type != "reject" && type != "redirect" && - type != "terminate") { - return false; - } - } - - // Does this client own the session description namespace? - buzz::TQName qn_session_desc(GetSessionDescriptionName(), "description"); - const buzz::XmlElement* description = element->FirstNamed(qn_session_desc); - if (type == "initiate" || type == "accept" || type == "modify") { - if (description == NULL) - return false; - } else { - if (description != NULL) - return false; - } - - // It's good - return true; -} - -void SessionClient::OnIncomingStanza(const buzz::XmlElement *stanza) { - SessionMessage message; - if (!ParseIncomingMessage(stanza, message)) - return; - - session_manager_->OnIncomingMessage(message); -} - -void SessionClient::OnFailedSend(const buzz::XmlElement *original_stanza, - const buzz::XmlElement *failure_stanza) { - SessionMessage message; - if (!ParseIncomingMessage(original_stanza, message)) - return; - - // Note the from/to represents the *original* stanza and not the from/to - // on any return path - session_manager_->OnIncomingError(message); -} - -bool SessionClient::ParseIncomingMessage(const buzz::XmlElement *stanza, - SessionMessage& message) { - // Parse stanza into SessionMessage - const buzz::XmlElement* element - = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); - - std::string type = element->Attr(TQN_TYPE); - if (type == "initiate" || type == "accept" || type == "modify") { - ParseInitiateAcceptModify(stanza, message); - } else if (type == "candidates") { - ParseCandidates(stanza, message); - } else if (type == "reject" || type == "terminate") { - ParseRejectTerminate(stanza, message); - } else if (type == "redirect") { - ParseRedirect(stanza, message); - } else { - return false; - } - - return true; -} - -void SessionClient::ParseHeader(const buzz::XmlElement *stanza, SessionMessage &message) { - if (stanza->HasAttr(buzz::TQN_FROM)) - message.set_from(stanza->Attr(buzz::TQN_FROM)); - if (stanza->HasAttr(buzz::TQN_TO)) - message.set_to(stanza->Attr(buzz::TQN_TO)); - - const buzz::XmlElement *element - = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); - if (element->HasAttr(TQN_ID)) - message.session_id().set_id_str(element->Attr(TQN_ID)); - - if (element->HasAttr(TQN_INITIATOR)) - message.session_id().set_initiator(element->Attr(TQN_INITIATOR)); - - std::string type = element->Attr(TQN_TYPE); - if (type == "initiate") { - message.set_type(SessionMessage::TYPE_INITIATE); - } else if (type == "accept") { - message.set_type(SessionMessage::TYPE_ACCEPT); - } else if (type == "modify") { - message.set_type(SessionMessage::TYPE_MODIFY); - } else if (type == "candidates") { - message.set_type(SessionMessage::TYPE_CANDIDATES); - } else if (type == "reject") { - message.set_type(SessionMessage::TYPE_REJECT); - } else if (type == "redirect") { - message.set_type(SessionMessage::TYPE_REDIRECT); - } else if (type == "terminate") { - message.set_type(SessionMessage::TYPE_TERMINATE); - } else { - assert(false); - } -} - -void SessionClient::ParseInitiateAcceptModify(const buzz::XmlElement *stanza, SessionMessage &message) { - // Pull the standard header pieces out - ParseHeader(stanza, message); - - // Parse session description - const buzz::XmlElement *session - = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); - buzz::TQName qn_session_desc(GetSessionDescriptionName(), "description"); - const buzz::XmlElement* desc_elem = session->FirstNamed(qn_session_desc); - const SessionDescription *description = NULL; - if (desc_elem) - description = CreateSessionDescription(desc_elem); - message.set_name(GetSessionDescriptionName()); - message.set_description(description); -} - -void SessionClient::ParseCandidates(const buzz::XmlElement *stanza, SessionMessage &message) { - // Pull the standard header pieces out - ParseHeader(stanza, message); - - // Parse candidates and session description - std::vector candidates; - const buzz::XmlElement *element - = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); - const buzz::XmlElement *child = element->FirstElement(); - while (child != NULL) { - if (child->Name() == TQN_GOOGLESESSION_CANDIDATE) { - Candidate candidate; - if (ParseCandidate(child, &candidate)) - candidates.push_back(candidate); - } - child = child->NextElement(); - } - message.set_name(GetSessionDescriptionName()); - message.set_candidates(candidates); -} - -void SessionClient::ParseRejectTerminate(const buzz::XmlElement *stanza, SessionMessage &message) { - // Reject and terminate are very simple - ParseHeader(stanza, message); -} - -bool SessionClient::ParseCandidate(const buzz::XmlElement *child, - Candidate* candidate) { - // Check for all of the required attributes. - if (!child->HasAttr(TQN_NAME) || - !child->HasAttr(TQN_ADDRESS) || - !child->HasAttr(TQN_PORT) || - !child->HasAttr(TQN_USERNAME) || - !child->HasAttr(TQN_PREFERENCE) || - !child->HasAttr(TQN_PROTOCOL) || - !child->HasAttr(TQN_GENERATION)) { - LOG(LERROR) << "Candidate missing required attribute"; - return false; - } - - SocketAddress address; - address.SetIP(child->Attr(TQN_ADDRESS)); - std::istringstream ist(child->Attr(TQN_PORT)); - int port; - ist >> port; - address.SetPort(port); - - if (address.IsAny()) { - LOG(LERROR) << "Candidate has address 0"; - return false; - } - - // Always disallow addresses that refer to the local host. - if (address.IsLocalIP()) { - LOG(LERROR) << "Candidate has local IP address"; - return false; - } - - // Disallow all ports below 1024, except for 80 and 443 on public addresses. - if (port < 1024) { - if ((port != 80) && (port != 443)) { - LOG(LERROR) << "Candidate has port below 1024, not 80 or 443"; - return false; - } - if (address.IsPrivateIP()) { - LOG(LERROR) << "Candidate has port of 80 or 443 with private IP address"; - return false; - } - } - - candidate->set_name(child->Attr(TQN_NAME)); - candidate->set_address(address); - candidate->set_username(child->Attr(TQN_USERNAME)); - candidate->set_preference_str(child->Attr(TQN_PREFERENCE)); - candidate->set_protocol(child->Attr(TQN_PROTOCOL)); - candidate->set_generation_str(child->Attr(TQN_GENERATION)); - - // Check that the username is not too long and does not use any bad chars. - if (candidate->username().size() > kMaxUsernameSize) { - LOG(LERROR) << "Candidate username is too long"; - return false; - } - if (!IsBase64Encoded(candidate->username())) { - LOG(LERROR) << "Candidate username has non-base64 encoded characters"; - return false; - } - - // Look for the non-required attributes. - if (child->HasAttr(TQN_PASSWORD)) - candidate->set_password(child->Attr(TQN_PASSWORD)); - if (child->HasAttr(TQN_TYPE)) - candidate->set_type(child->Attr(TQN_TYPE)); - if (child->HasAttr(TQN_NETWORK)) - candidate->set_network_name(child->Attr(TQN_NETWORK)); - - return true; -} - -void SessionClient::ParseRedirect(const buzz::XmlElement *stanza, SessionMessage &message) { - // Pull the standard header pieces out - ParseHeader(stanza, message); - const buzz::XmlElement *session = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); - - // Parse the target and cookie. - - const buzz::XmlElement* target = session->FirstNamed(TQN_GOOGLESESSION_TARGET); - if (target) - message.set_redirect_target(target->Attr(TQN_NAME)); - - const buzz::XmlElement* cookie = session->FirstNamed(TQN_GOOGLESESSION_COOKIE); - if (cookie) - message.set_redirect_cookie(new XmlCookie(cookie)); -} - -void SessionClient::OnOutgoingMessage(Session *session, const SessionMessage &message) { - // Translate the message into an XMPP stanza - - buzz::XmlElement *result = NULL; - switch (message.type()) { - case SessionMessage::TYPE_INITIATE: - case SessionMessage::TYPE_ACCEPT: - case SessionMessage::TYPE_MODIFY: - result = TranslateInitiateAcceptModify(message); - break; - - case SessionMessage::TYPE_CANDIDATES: - result = TranslateCandidates(message); - break; - - case SessionMessage::TYPE_REJECT: - case SessionMessage::TYPE_TERMINATE: - result = TranslateRejectTerminate(message); - break; - - case SessionMessage::TYPE_REDIRECT: - result = TranslateRedirect(message); - break; - } - - // Send the stanza. Note that SessionClient is passing on ownership - // of result. - if (result != NULL) { - SignalSendStanza(this, result); - } -} - -buzz::XmlElement *SessionClient::TranslateHeader(const SessionMessage &message) { - buzz::XmlElement *result = new buzz::XmlElement(buzz::TQN_IQ); - result->AddAttr(buzz::TQN_TO, message.to()); - result->AddAttr(buzz::TQN_TYPE, buzz::STR_SET); - buzz::XmlElement *session = new buzz::XmlElement(TQN_GOOGLESESSION_SESSION, true); - result->AddElement(session); - switch (message.type()) { - case SessionMessage::TYPE_INITIATE: - session->AddAttr(TQN_TYPE, "initiate"); - break; - case SessionMessage::TYPE_ACCEPT: - session->AddAttr(TQN_TYPE, "accept"); - break; - case SessionMessage::TYPE_MODIFY: - session->AddAttr(TQN_TYPE, "modify"); - break; - case SessionMessage::TYPE_CANDIDATES: - session->AddAttr(TQN_TYPE, "candidates"); - break; - case SessionMessage::TYPE_REJECT: - session->AddAttr(TQN_TYPE, "reject"); - break; - case SessionMessage::TYPE_REDIRECT: - session->AddAttr(TQN_TYPE, "redirect"); - break; - case SessionMessage::TYPE_TERMINATE: - session->AddAttr(TQN_TYPE, "terminate"); - break; - } - session->AddAttr(TQN_ID, message.session_id().id_str()); - session->AddAttr(TQN_INITIATOR, message.session_id().initiator()); - return result; -} - -buzz::XmlElement *SessionClient::TranslateCandidate(const Candidate &candidate) { - buzz::XmlElement *result = new buzz::XmlElement(TQN_GOOGLESESSION_CANDIDATE); - result->AddAttr(TQN_NAME, candidate.name()); - result->AddAttr(TQN_ADDRESS, candidate.address().IPAsString()); - result->AddAttr(TQN_PORT, candidate.address().PortAsString()); - result->AddAttr(TQN_USERNAME, candidate.username()); - result->AddAttr(TQN_PASSWORD, candidate.password()); - result->AddAttr(TQN_PREFERENCE, candidate.preference_str()); - result->AddAttr(TQN_PROTOCOL, candidate.protocol()); - result->AddAttr(TQN_TYPE, candidate.type()); - result->AddAttr(TQN_NETWORK, candidate.network_name()); - result->AddAttr(TQN_GENERATION, candidate.generation_str()); - return result; -} - -buzz::XmlElement *SessionClient::TranslateInitiateAcceptModify(const SessionMessage &message) { - // Header info common to all message types - buzz::XmlElement *result = TranslateHeader(message); - buzz::XmlElement *session = result->FirstNamed(TQN_GOOGLESESSION_SESSION); - - // Candidates - assert(message.candidates().size() == 0); - - // Session Description - buzz::XmlElement* description = TranslateSessionDescription(message.description()); - assert(description->Name().LocalPart() == "description"); - assert(description->Name().Namespace() == GetSessionDescriptionName()); - session->AddElement(description); - - if (message.redirect_cookie() != NULL) { - const buzz::XmlElement* cookie = - reinterpret_cast(message.redirect_cookie())->elem(); - for (const buzz::XmlElement* elem = cookie->FirstElement(); elem; elem = elem->NextElement()) - session->AddElement(new buzz::XmlElement(*elem)); - } - - return result; -} - -buzz::XmlElement *SessionClient::TranslateCandidates(const SessionMessage &message) { - // Header info common to all message types - buzz::XmlElement *result = TranslateHeader(message); - buzz::XmlElement *session = result->FirstNamed(TQN_GOOGLESESSION_SESSION); - - // Candidates - std::vector::const_iterator it; - for (it = message.candidates().begin(); it != message.candidates().end(); it++) - session->AddElement(TranslateCandidate(*it)); - - return result; -} - -buzz::XmlElement *SessionClient::TranslateRejectTerminate(const SessionMessage &message) { - // These messages are simple, and only have a header - return TranslateHeader(message); -} - -buzz::XmlElement *SessionClient::TranslateRedirect(const SessionMessage &message) { - // Header info common to all message types - buzz::XmlElement *result = TranslateHeader(message); - buzz::XmlElement *session = result->FirstNamed(TQN_GOOGLESESSION_SESSION); - - assert(message.candidates().size() == 0); - assert(message.description() == NULL); - - assert(message.redirect_target().size() > 0); - buzz::XmlElement* target = new buzz::XmlElement(TQN_GOOGLESESSION_TARGET); - target->AddAttr(TQN_NAME, message.redirect_target()); - session->AddElement(target); - - buzz::XmlElement* cookie = new buzz::XmlElement(TQN_GOOGLESESSION_COOKIE); - session->AddElement(cookie); - - // If the message does not have a redirect cookie, then this is a redirect - // initiated by us. We will automatically add a regarding cookie. - if (message.redirect_cookie() == NULL) { - buzz::XmlElement* regarding = new buzz::XmlElement(TQN_GOOGLESESSION_REGARDING); - regarding->AddAttr(TQN_NAME, GetJid().BareJid().Str()); - cookie->AddElement(regarding); - } else { - const buzz::XmlElement* cookie_elem = - reinterpret_cast(message.redirect_cookie())->elem(); - const buzz::XmlElement* elem; - for (elem = cookie_elem->FirstElement(); elem; elem = elem->NextElement()) - cookie->AddElement(new buzz::XmlElement(*elem)); - } - - return result; -} - -SessionManager *SessionClient::session_manager() { - return session_manager_; -} - -} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cpp new file mode 100644 index 00000000..b64c444a --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/sessionclient.cpp @@ -0,0 +1,545 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#pragma warning(disable:4786) +#endif +#include "talk/p2p/client/sessionclient.h" +#include "talk/p2p/base/helpers.h" +#include "talk/base/logging.h" +#include "talk/xmllite/qname.h" +#include "talk/xmpp/constants.h" +#include "talk/xmllite/xmlprinter.h" +#include +#undef SetPort + +namespace { + +// We only allow usernames to be this many characters or fewer. +const size_t kMaxUsernameSize = 16; + +} + +namespace cricket { + +#if 0 +>>>>>> + + + + ... + + + + +<<<<<< + + +>>>>>> + + + + + + +> + +<<<<<< + + +#endif + +const std::string NS_GOOGLESESSION("http://www.google.com/session"); +const buzz::TQName TQN_GOOGLESESSION_SESSION(true, NS_GOOGLESESSION, "session"); +const buzz::TQName TQN_GOOGLESESSION_CANDIDATE(true, NS_GOOGLESESSION, "candidate"); +const buzz::TQName TQN_GOOGLESESSION_TARGET(true, NS_GOOGLESESSION, "target"); +const buzz::TQName TQN_GOOGLESESSION_COOKIE(true, NS_GOOGLESESSION, "cookie"); +const buzz::TQName TQN_GOOGLESESSION_REGARDING(true, NS_GOOGLESESSION, "regarding"); + +const buzz::TQName TQN_TYPE(true, buzz::STR_EMPTY, "type"); +const buzz::TQName TQN_ID(true, buzz::STR_EMPTY, "id"); +const buzz::TQName TQN_INITIATOR(true, buzz::STR_EMPTY, "initiator"); +const buzz::TQName TQN_NAME(true, buzz::STR_EMPTY, "name"); +const buzz::TQName TQN_PORT(true, buzz::STR_EMPTY, "port"); +const buzz::TQName TQN_NETWORK(true, buzz::STR_EMPTY, "network"); +const buzz::TQName TQN_GENERATION(true, buzz::STR_EMPTY, "generation"); +const buzz::TQName TQN_ADDRESS(true, buzz::STR_EMPTY, "address"); +const buzz::TQName TQN_USERNAME(true, buzz::STR_EMPTY, "username"); +const buzz::TQName TQN_PASSWORD(true, buzz::STR_EMPTY, "password"); +const buzz::TQName TQN_PREFERENCE(true, buzz::STR_EMPTY, "preference"); +const buzz::TQName TQN_PROTOCOL(true, buzz::STR_EMPTY, "protocol"); +const buzz::TQName TQN_KEY(true, buzz::STR_EMPTY, "key"); + +class XmlCookie: public SessionMessage::Cookie { +public: + XmlCookie(const buzz::XmlElement* elem) + : elem_(new buzz::XmlElement(*elem)) { + } + + virtual ~XmlCookie() { + delete elem_; + } + + const buzz::XmlElement* elem() const { return elem_; } + + virtual Cookie* Copy() { + return new XmlCookie(elem_); + } + +private: + buzz::XmlElement* elem_; +}; + +SessionClient::SessionClient(SessionManager *session_manager) { + session_manager_ = session_manager; + session_manager_->SignalSessionCreate.connect(this, &SessionClient::OnSessionCreateSlot); + session_manager_->SignalSessionDestroy.connect(this, &SessionClient::OnSessionDestroySlot); +} + +SessionClient::~SessionClient() { +} + +void SessionClient::OnSessionCreateSlot(Session *session, bool received_initiate) { + // Does this session belong to this session client? + if (session->name() == GetSessionDescriptionName()) { + session->SignalOutgoingMessage.connect(this, &SessionClient::OnOutgoingMessage); + OnSessionCreate(session, received_initiate); + } +} + +void SessionClient::OnSessionDestroySlot(Session *session) { + if (session->name() == GetSessionDescriptionName()) { + session->SignalOutgoingMessage.disconnect(this); + OnSessionDestroy(session); + } +} + +bool SessionClient::IsClientStanza(const buzz::XmlElement *stanza) { + // Is it a IQ set stanza? + if (stanza->Name() != buzz::TQN_IQ) + return false; + if (stanza->Attr(buzz::TQN_TYPE) != buzz::STR_SET) + return false; + + // Make sure it has the right child element + const buzz::XmlElement* element + = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); + if (element == NULL) + return false; + + // Is it one of the allowed types? + std::string type; + if (element->HasAttr(TQN_TYPE)) { + type = element->Attr(TQN_TYPE); + if (type != "initiate" && type != "accept" && type != "modify" && + type != "candidates" && type != "reject" && type != "redirect" && + type != "terminate") { + return false; + } + } + + // Does this client own the session description namespace? + buzz::TQName qn_session_desc(GetSessionDescriptionName(), "description"); + const buzz::XmlElement* description = element->FirstNamed(qn_session_desc); + if (type == "initiate" || type == "accept" || type == "modify") { + if (description == NULL) + return false; + } else { + if (description != NULL) + return false; + } + + // It's good + return true; +} + +void SessionClient::OnIncomingStanza(const buzz::XmlElement *stanza) { + SessionMessage message; + if (!ParseIncomingMessage(stanza, message)) + return; + + session_manager_->OnIncomingMessage(message); +} + +void SessionClient::OnFailedSend(const buzz::XmlElement *original_stanza, + const buzz::XmlElement *failure_stanza) { + SessionMessage message; + if (!ParseIncomingMessage(original_stanza, message)) + return; + + // Note the from/to represents the *original* stanza and not the from/to + // on any return path + session_manager_->OnIncomingError(message); +} + +bool SessionClient::ParseIncomingMessage(const buzz::XmlElement *stanza, + SessionMessage& message) { + // Parse stanza into SessionMessage + const buzz::XmlElement* element + = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); + + std::string type = element->Attr(TQN_TYPE); + if (type == "initiate" || type == "accept" || type == "modify") { + ParseInitiateAcceptModify(stanza, message); + } else if (type == "candidates") { + ParseCandidates(stanza, message); + } else if (type == "reject" || type == "terminate") { + ParseRejectTerminate(stanza, message); + } else if (type == "redirect") { + ParseRedirect(stanza, message); + } else { + return false; + } + + return true; +} + +void SessionClient::ParseHeader(const buzz::XmlElement *stanza, SessionMessage &message) { + if (stanza->HasAttr(buzz::TQN_FROM)) + message.set_from(stanza->Attr(buzz::TQN_FROM)); + if (stanza->HasAttr(buzz::TQN_TO)) + message.set_to(stanza->Attr(buzz::TQN_TO)); + + const buzz::XmlElement *element + = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); + if (element->HasAttr(TQN_ID)) + message.session_id().set_id_str(element->Attr(TQN_ID)); + + if (element->HasAttr(TQN_INITIATOR)) + message.session_id().set_initiator(element->Attr(TQN_INITIATOR)); + + std::string type = element->Attr(TQN_TYPE); + if (type == "initiate") { + message.set_type(SessionMessage::TYPE_INITIATE); + } else if (type == "accept") { + message.set_type(SessionMessage::TYPE_ACCEPT); + } else if (type == "modify") { + message.set_type(SessionMessage::TYPE_MODIFY); + } else if (type == "candidates") { + message.set_type(SessionMessage::TYPE_CANDIDATES); + } else if (type == "reject") { + message.set_type(SessionMessage::TYPE_REJECT); + } else if (type == "redirect") { + message.set_type(SessionMessage::TYPE_REDIRECT); + } else if (type == "terminate") { + message.set_type(SessionMessage::TYPE_TERMINATE); + } else { + assert(false); + } +} + +void SessionClient::ParseInitiateAcceptModify(const buzz::XmlElement *stanza, SessionMessage &message) { + // Pull the standard header pieces out + ParseHeader(stanza, message); + + // Parse session description + const buzz::XmlElement *session + = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); + buzz::TQName qn_session_desc(GetSessionDescriptionName(), "description"); + const buzz::XmlElement* desc_elem = session->FirstNamed(qn_session_desc); + const SessionDescription *description = NULL; + if (desc_elem) + description = CreateSessionDescription(desc_elem); + message.set_name(GetSessionDescriptionName()); + message.set_description(description); +} + +void SessionClient::ParseCandidates(const buzz::XmlElement *stanza, SessionMessage &message) { + // Pull the standard header pieces out + ParseHeader(stanza, message); + + // Parse candidates and session description + std::vector candidates; + const buzz::XmlElement *element + = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); + const buzz::XmlElement *child = element->FirstElement(); + while (child != NULL) { + if (child->Name() == TQN_GOOGLESESSION_CANDIDATE) { + Candidate candidate; + if (ParseCandidate(child, &candidate)) + candidates.push_back(candidate); + } + child = child->NextElement(); + } + message.set_name(GetSessionDescriptionName()); + message.set_candidates(candidates); +} + +void SessionClient::ParseRejectTerminate(const buzz::XmlElement *stanza, SessionMessage &message) { + // Reject and terminate are very simple + ParseHeader(stanza, message); +} + +bool SessionClient::ParseCandidate(const buzz::XmlElement *child, + Candidate* candidate) { + // Check for all of the required attributes. + if (!child->HasAttr(TQN_NAME) || + !child->HasAttr(TQN_ADDRESS) || + !child->HasAttr(TQN_PORT) || + !child->HasAttr(TQN_USERNAME) || + !child->HasAttr(TQN_PREFERENCE) || + !child->HasAttr(TQN_PROTOCOL) || + !child->HasAttr(TQN_GENERATION)) { + LOG(LERROR) << "Candidate missing required attribute"; + return false; + } + + SocketAddress address; + address.SetIP(child->Attr(TQN_ADDRESS)); + std::istringstream ist(child->Attr(TQN_PORT)); + int port; + ist >> port; + address.SetPort(port); + + if (address.IsAny()) { + LOG(LERROR) << "Candidate has address 0"; + return false; + } + + // Always disallow addresses that refer to the local host. + if (address.IsLocalIP()) { + LOG(LERROR) << "Candidate has local IP address"; + return false; + } + + // Disallow all ports below 1024, except for 80 and 443 on public addresses. + if (port < 1024) { + if ((port != 80) && (port != 443)) { + LOG(LERROR) << "Candidate has port below 1024, not 80 or 443"; + return false; + } + if (address.IsPrivateIP()) { + LOG(LERROR) << "Candidate has port of 80 or 443 with private IP address"; + return false; + } + } + + candidate->set_name(child->Attr(TQN_NAME)); + candidate->set_address(address); + candidate->set_username(child->Attr(TQN_USERNAME)); + candidate->set_preference_str(child->Attr(TQN_PREFERENCE)); + candidate->set_protocol(child->Attr(TQN_PROTOCOL)); + candidate->set_generation_str(child->Attr(TQN_GENERATION)); + + // Check that the username is not too long and does not use any bad chars. + if (candidate->username().size() > kMaxUsernameSize) { + LOG(LERROR) << "Candidate username is too long"; + return false; + } + if (!IsBase64Encoded(candidate->username())) { + LOG(LERROR) << "Candidate username has non-base64 encoded characters"; + return false; + } + + // Look for the non-required attributes. + if (child->HasAttr(TQN_PASSWORD)) + candidate->set_password(child->Attr(TQN_PASSWORD)); + if (child->HasAttr(TQN_TYPE)) + candidate->set_type(child->Attr(TQN_TYPE)); + if (child->HasAttr(TQN_NETWORK)) + candidate->set_network_name(child->Attr(TQN_NETWORK)); + + return true; +} + +void SessionClient::ParseRedirect(const buzz::XmlElement *stanza, SessionMessage &message) { + // Pull the standard header pieces out + ParseHeader(stanza, message); + const buzz::XmlElement *session = stanza->FirstNamed(TQN_GOOGLESESSION_SESSION); + + // Parse the target and cookie. + + const buzz::XmlElement* target = session->FirstNamed(TQN_GOOGLESESSION_TARGET); + if (target) + message.set_redirect_target(target->Attr(TQN_NAME)); + + const buzz::XmlElement* cookie = session->FirstNamed(TQN_GOOGLESESSION_COOKIE); + if (cookie) + message.set_redirect_cookie(new XmlCookie(cookie)); +} + +void SessionClient::OnOutgoingMessage(Session *session, const SessionMessage &message) { + // Translate the message into an XMPP stanza + + buzz::XmlElement *result = NULL; + switch (message.type()) { + case SessionMessage::TYPE_INITIATE: + case SessionMessage::TYPE_ACCEPT: + case SessionMessage::TYPE_MODIFY: + result = TranslateInitiateAcceptModify(message); + break; + + case SessionMessage::TYPE_CANDIDATES: + result = TranslateCandidates(message); + break; + + case SessionMessage::TYPE_REJECT: + case SessionMessage::TYPE_TERMINATE: + result = TranslateRejectTerminate(message); + break; + + case SessionMessage::TYPE_REDIRECT: + result = TranslateRedirect(message); + break; + } + + // Send the stanza. Note that SessionClient is passing on ownership + // of result. + if (result != NULL) { + SignalSendStanza(this, result); + } +} + +buzz::XmlElement *SessionClient::TranslateHeader(const SessionMessage &message) { + buzz::XmlElement *result = new buzz::XmlElement(buzz::TQN_IQ); + result->AddAttr(buzz::TQN_TO, message.to()); + result->AddAttr(buzz::TQN_TYPE, buzz::STR_SET); + buzz::XmlElement *session = new buzz::XmlElement(TQN_GOOGLESESSION_SESSION, true); + result->AddElement(session); + switch (message.type()) { + case SessionMessage::TYPE_INITIATE: + session->AddAttr(TQN_TYPE, "initiate"); + break; + case SessionMessage::TYPE_ACCEPT: + session->AddAttr(TQN_TYPE, "accept"); + break; + case SessionMessage::TYPE_MODIFY: + session->AddAttr(TQN_TYPE, "modify"); + break; + case SessionMessage::TYPE_CANDIDATES: + session->AddAttr(TQN_TYPE, "candidates"); + break; + case SessionMessage::TYPE_REJECT: + session->AddAttr(TQN_TYPE, "reject"); + break; + case SessionMessage::TYPE_REDIRECT: + session->AddAttr(TQN_TYPE, "redirect"); + break; + case SessionMessage::TYPE_TERMINATE: + session->AddAttr(TQN_TYPE, "terminate"); + break; + } + session->AddAttr(TQN_ID, message.session_id().id_str()); + session->AddAttr(TQN_INITIATOR, message.session_id().initiator()); + return result; +} + +buzz::XmlElement *SessionClient::TranslateCandidate(const Candidate &candidate) { + buzz::XmlElement *result = new buzz::XmlElement(TQN_GOOGLESESSION_CANDIDATE); + result->AddAttr(TQN_NAME, candidate.name()); + result->AddAttr(TQN_ADDRESS, candidate.address().IPAsString()); + result->AddAttr(TQN_PORT, candidate.address().PortAsString()); + result->AddAttr(TQN_USERNAME, candidate.username()); + result->AddAttr(TQN_PASSWORD, candidate.password()); + result->AddAttr(TQN_PREFERENCE, candidate.preference_str()); + result->AddAttr(TQN_PROTOCOL, candidate.protocol()); + result->AddAttr(TQN_TYPE, candidate.type()); + result->AddAttr(TQN_NETWORK, candidate.network_name()); + result->AddAttr(TQN_GENERATION, candidate.generation_str()); + return result; +} + +buzz::XmlElement *SessionClient::TranslateInitiateAcceptModify(const SessionMessage &message) { + // Header info common to all message types + buzz::XmlElement *result = TranslateHeader(message); + buzz::XmlElement *session = result->FirstNamed(TQN_GOOGLESESSION_SESSION); + + // Candidates + assert(message.candidates().size() == 0); + + // Session Description + buzz::XmlElement* description = TranslateSessionDescription(message.description()); + assert(description->Name().LocalPart() == "description"); + assert(description->Name().Namespace() == GetSessionDescriptionName()); + session->AddElement(description); + + if (message.redirect_cookie() != NULL) { + const buzz::XmlElement* cookie = + reinterpret_cast(message.redirect_cookie())->elem(); + for (const buzz::XmlElement* elem = cookie->FirstElement(); elem; elem = elem->NextElement()) + session->AddElement(new buzz::XmlElement(*elem)); + } + + return result; +} + +buzz::XmlElement *SessionClient::TranslateCandidates(const SessionMessage &message) { + // Header info common to all message types + buzz::XmlElement *result = TranslateHeader(message); + buzz::XmlElement *session = result->FirstNamed(TQN_GOOGLESESSION_SESSION); + + // Candidates + std::vector::const_iterator it; + for (it = message.candidates().begin(); it != message.candidates().end(); it++) + session->AddElement(TranslateCandidate(*it)); + + return result; +} + +buzz::XmlElement *SessionClient::TranslateRejectTerminate(const SessionMessage &message) { + // These messages are simple, and only have a header + return TranslateHeader(message); +} + +buzz::XmlElement *SessionClient::TranslateRedirect(const SessionMessage &message) { + // Header info common to all message types + buzz::XmlElement *result = TranslateHeader(message); + buzz::XmlElement *session = result->FirstNamed(TQN_GOOGLESESSION_SESSION); + + assert(message.candidates().size() == 0); + assert(message.description() == NULL); + + assert(message.redirect_target().size() > 0); + buzz::XmlElement* target = new buzz::XmlElement(TQN_GOOGLESESSION_TARGET); + target->AddAttr(TQN_NAME, message.redirect_target()); + session->AddElement(target); + + buzz::XmlElement* cookie = new buzz::XmlElement(TQN_GOOGLESESSION_COOKIE); + session->AddElement(cookie); + + // If the message does not have a redirect cookie, then this is a redirect + // initiated by us. We will automatically add a regarding cookie. + if (message.redirect_cookie() == NULL) { + buzz::XmlElement* regarding = new buzz::XmlElement(TQN_GOOGLESESSION_REGARDING); + regarding->AddAttr(TQN_NAME, GetJid().BareJid().Str()); + cookie->AddElement(regarding); + } else { + const buzz::XmlElement* cookie_elem = + reinterpret_cast(message.redirect_cookie())->elem(); + const buzz::XmlElement* elem; + for (elem = cookie_elem->FirstElement(); elem; elem = elem->NextElement()) + cookie->AddElement(new buzz::XmlElement(*elem)); + } + + return result; +} + +SessionManager *SessionClient::session_manager() { + return session_manager_; +} + +} // namespace cricket diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc deleted file mode 100644 index dd9fa67c..00000000 --- a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cc +++ /dev/null @@ -1,149 +0,0 @@ -/* - * libjingle - * Copyright 2004--2005, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "socketmonitor.h" -#include - -namespace cricket { - -const uint32 MSG_MONITOR_POLL = 1; -const uint32 MSG_MONITOR_START = 2; -const uint32 MSG_MONITOR_STOP = 3; -const uint32 MSG_MONITOR_SIGNAL = 4; - -SocketMonitor::SocketMonitor(P2PSocket *socket, Thread *monitor_thread) { - socket_ = socket; - monitoring_thread_ = monitor_thread; - monitoring_ = false; -} - -SocketMonitor::~SocketMonitor() { - socket_->thread()->Clear(this); - monitoring_thread_->Clear(this); -} - -void SocketMonitor::Start(int milliseconds) { - rate_ = milliseconds; - if (rate_ < 250) - rate_ = 250; - socket_->thread()->Post(this, MSG_MONITOR_START); -} - -void SocketMonitor::Stop() { - socket_->thread()->Post(this, MSG_MONITOR_STOP); -} - -void SocketMonitor::OnMessage(Message *message) { - CritScope cs(&crit_); - - switch (message->message_id) { - case MSG_MONITOR_START: - assert(Thread::Current() == socket_->thread()); - if (!monitoring_) { - monitoring_ = true; - socket_->SignalConnectionMonitor.connect(this, &SocketMonitor::OnConnectionMonitor); - PollSocket(true); - } - break; - - case MSG_MONITOR_STOP: - assert(Thread::Current() == socket_->thread()); - if (monitoring_) { - monitoring_ = false; - socket_->SignalConnectionMonitor.disconnect(this); - socket_->thread()->Clear(this); - } - break; - - case MSG_MONITOR_POLL: - assert(Thread::Current() == socket_->thread()); - PollSocket(true); - break; - - case MSG_MONITOR_SIGNAL: - { - assert(Thread::Current() == monitoring_thread_); - std::vector infos = connection_infos_; - crit_.Leave(); - SignalUpdate(this, infos); - crit_.Enter(); - } - break; - } -} - -void SocketMonitor::OnConnectionMonitor(P2PSocket *socket) { - CritScope cs(&crit_); - if (monitoring_) - PollSocket(false); -} - -void SocketMonitor::PollSocket(bool poll) { - CritScope cs(&crit_); - assert(Thread::Current() == socket_->thread()); - - // Gather connection infos - - connection_infos_.clear(); - const std::vector &connections = socket_->connections(); - std::vector::const_iterator it; - for (it = connections.begin(); it != connections.end(); it++) { - Connection *connection = *it; - ConnectionInfo info; - info.best_connection = socket_->best_connection() == connection; - info.readable = connection->read_state() == Connection::STATE_READABLE; - info.writable = connection->write_state() == Connection::STATE_WRITABLE; - info.timeout = connection->write_state() == Connection::STATE_WRITE_TIMEOUT; - info.new_connection = false; // connection->new_connection(); - info.rtt = connection->rtt(); - info.sent_total_bytes = connection->sent_total_bytes(); - info.sent_bytes_second = connection->sent_bytes_second(); - info.recv_total_bytes = connection->recv_total_bytes(); - info.recv_bytes_second = connection->recv_bytes_second(); - info.local_candidate = connection->local_candidate(); - info.remote_candidate = connection->remote_candidate(); - info.est_quality = connection->port()->network()->quality(); - info.key = reinterpret_cast(connection); - connection_infos_.push_back(info); - } - - // Signal the monitoring thread, start another poll timer - - monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL); - if (poll) - socket_->thread()->PostDelayed(rate_, this, MSG_MONITOR_POLL); -} - -P2PSocket *SocketMonitor::socket() { - return socket_; -} - -Thread *SocketMonitor::monitor_thread() { - return monitoring_thread_; -} - -} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cpp b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cpp new file mode 100644 index 00000000..dd9fa67c --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/p2p/client/socketmonitor.cpp @@ -0,0 +1,149 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "socketmonitor.h" +#include + +namespace cricket { + +const uint32 MSG_MONITOR_POLL = 1; +const uint32 MSG_MONITOR_START = 2; +const uint32 MSG_MONITOR_STOP = 3; +const uint32 MSG_MONITOR_SIGNAL = 4; + +SocketMonitor::SocketMonitor(P2PSocket *socket, Thread *monitor_thread) { + socket_ = socket; + monitoring_thread_ = monitor_thread; + monitoring_ = false; +} + +SocketMonitor::~SocketMonitor() { + socket_->thread()->Clear(this); + monitoring_thread_->Clear(this); +} + +void SocketMonitor::Start(int milliseconds) { + rate_ = milliseconds; + if (rate_ < 250) + rate_ = 250; + socket_->thread()->Post(this, MSG_MONITOR_START); +} + +void SocketMonitor::Stop() { + socket_->thread()->Post(this, MSG_MONITOR_STOP); +} + +void SocketMonitor::OnMessage(Message *message) { + CritScope cs(&crit_); + + switch (message->message_id) { + case MSG_MONITOR_START: + assert(Thread::Current() == socket_->thread()); + if (!monitoring_) { + monitoring_ = true; + socket_->SignalConnectionMonitor.connect(this, &SocketMonitor::OnConnectionMonitor); + PollSocket(true); + } + break; + + case MSG_MONITOR_STOP: + assert(Thread::Current() == socket_->thread()); + if (monitoring_) { + monitoring_ = false; + socket_->SignalConnectionMonitor.disconnect(this); + socket_->thread()->Clear(this); + } + break; + + case MSG_MONITOR_POLL: + assert(Thread::Current() == socket_->thread()); + PollSocket(true); + break; + + case MSG_MONITOR_SIGNAL: + { + assert(Thread::Current() == monitoring_thread_); + std::vector infos = connection_infos_; + crit_.Leave(); + SignalUpdate(this, infos); + crit_.Enter(); + } + break; + } +} + +void SocketMonitor::OnConnectionMonitor(P2PSocket *socket) { + CritScope cs(&crit_); + if (monitoring_) + PollSocket(false); +} + +void SocketMonitor::PollSocket(bool poll) { + CritScope cs(&crit_); + assert(Thread::Current() == socket_->thread()); + + // Gather connection infos + + connection_infos_.clear(); + const std::vector &connections = socket_->connections(); + std::vector::const_iterator it; + for (it = connections.begin(); it != connections.end(); it++) { + Connection *connection = *it; + ConnectionInfo info; + info.best_connection = socket_->best_connection() == connection; + info.readable = connection->read_state() == Connection::STATE_READABLE; + info.writable = connection->write_state() == Connection::STATE_WRITABLE; + info.timeout = connection->write_state() == Connection::STATE_WRITE_TIMEOUT; + info.new_connection = false; // connection->new_connection(); + info.rtt = connection->rtt(); + info.sent_total_bytes = connection->sent_total_bytes(); + info.sent_bytes_second = connection->sent_bytes_second(); + info.recv_total_bytes = connection->recv_total_bytes(); + info.recv_bytes_second = connection->recv_bytes_second(); + info.local_candidate = connection->local_candidate(); + info.remote_candidate = connection->remote_candidate(); + info.est_quality = connection->port()->network()->quality(); + info.key = reinterpret_cast(connection); + connection_infos_.push_back(info); + } + + // Signal the monitoring thread, start another poll timer + + monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL); + if (poll) + socket_->thread()->PostDelayed(rate_, this, MSG_MONITOR_POLL); +} + +P2PSocket *SocketMonitor::socket() { + return socket_; +} + +Thread *SocketMonitor::monitor_thread() { + return monitoring_thread_; +} + +} -- cgit v1.2.1