910e62b5创建于 1月15日历史提交
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/signaling/fake_signal_strategy.h"

#include <utility>

#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/notimplemented.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "remoting/signaling/signaling_id_util.h"
#include "remoting/signaling/xmpp_constants.h"
#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"

namespace remoting {

// static
void FakeSignalStrategy::Connect(FakeSignalStrategy* peer1,
                                 FakeSignalStrategy* peer2) {
  DCHECK(peer1->main_thread_->BelongsToCurrentThread());
  DCHECK(peer2->main_thread_->BelongsToCurrentThread());
  peer1->ConnectTo(peer2);
  peer2->ConnectTo(peer1);
}

FakeSignalStrategy::FakeSignalStrategy(const SignalingAddress& address)
    : main_thread_(base::SingleThreadTaskRunner::GetCurrentDefault()),
      address_(address),
      last_id_(0) {
  DETACH_FROM_SEQUENCE(sequence_checker_);
}

FakeSignalStrategy::~FakeSignalStrategy() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}

void FakeSignalStrategy::SetError(Error error) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  error_ = error;
}

void FakeSignalStrategy::SetIsSignInError(bool is_sign_in_error) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  is_sign_in_error_ = is_sign_in_error;
}

void FakeSignalStrategy::SetState(State state) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (state == state_) {
    return;
  }
  state_ = state;
  for (auto& observer : listeners_) {
    observer.OnSignalStrategyStateChange(state_);
  }
}

void FakeSignalStrategy::SetPeerCallback(const PeerCallback& peer_callback) {
  peer_callback_ = peer_callback;
}

void FakeSignalStrategy::ConnectTo(FakeSignalStrategy* peer) {
  PeerCallback peer_callback =
      base::BindRepeating(&FakeSignalStrategy::DeliverMessageOnThread,
                          main_thread_, weak_factory_.GetWeakPtr());
  if (peer->main_thread_->BelongsToCurrentThread()) {
    peer->SetPeerCallback(std::move(peer_callback));
  } else {
    peer->main_thread_->PostTask(
        FROM_HERE,
        base::BindOnce(&FakeSignalStrategy::SetPeerCallback,
                       base::Unretained(peer), std::move(peer_callback)));
  }
}

void FakeSignalStrategy::SetLocalAddress(const SignalingAddress& address) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  address_ = address;
}

void FakeSignalStrategy::SimulateMessageReordering() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  simulate_reorder_ = true;
}

void FakeSignalStrategy::SimulateTwoStageConnect() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  simulate_two_stage_connect_ = true;
}

void FakeSignalStrategy::OnIncomingMessage(
    std::unique_ptr<jingle_xmpp::XmlElement> stanza) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  if (!simulate_reorder_) {
    NotifyListeners(std::move(stanza));
    return;
  }

  // Simulate IQ messages re-ordering by swapping the delivery order of
  // next pair of messages.
  if (pending_stanza_) {
    NotifyListeners(std::move(stanza));
    NotifyListeners(std::move(pending_stanza_));
    pending_stanza_.reset();
  } else {
    pending_stanza_ = std::move(stanza);
  }
}

void FakeSignalStrategy::ProceedConnect() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  SetState(CONNECTED);
}

void FakeSignalStrategy::Connect() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  SetState(simulate_two_stage_connect_ ? CONNECTING : CONNECTED);
}

void FakeSignalStrategy::Disconnect() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  SetState(DISCONNECTED);
}

SignalStrategy::State FakeSignalStrategy::GetState() const {
  return state_;
}

SignalStrategy::Error FakeSignalStrategy::GetError() const {
  return error_;
}

const SignalingAddress& FakeSignalStrategy::GetLocalAddress() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return address_;
}

void FakeSignalStrategy::AddListener(Listener* listener) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  listeners_.AddObserver(listener);
}

void FakeSignalStrategy::RemoveListener(Listener* listener) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  listeners_.RemoveObserver(listener);
}

bool FakeSignalStrategy::SendStanza(
    std::unique_ptr<jingle_xmpp::XmlElement> stanza) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  address_.SetInMessage(stanza.get(), SignalingAddress::FROM);

  if (peer_callback_.is_null()) {
    return false;
  }

  if (send_delay_.is_zero()) {
    peer_callback_.Run(std::move(stanza));
  } else {
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
        FROM_HERE, base::BindOnce(peer_callback_, std::move(stanza)),
        send_delay_);
  }
  return true;
}

bool FakeSignalStrategy::SendMessage(
    const SignalingAddress& destination_address,
    const ftl::ChromotingMessage& message) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  NOTIMPLEMENTED();
  return false;
}

std::string FakeSignalStrategy::GetNextId() {
  ++last_id_;
  return base::NumberToString(last_id_);
}

bool FakeSignalStrategy::IsSignInError() const {
  return is_sign_in_error_;
}

// static
void FakeSignalStrategy::DeliverMessageOnThread(
    scoped_refptr<base::SingleThreadTaskRunner> thread,
    base::WeakPtr<FakeSignalStrategy> target,
    std::unique_ptr<jingle_xmpp::XmlElement> stanza) {
  thread->PostTask(
      FROM_HERE, base::BindOnce(&FakeSignalStrategy::OnIncomingMessage, target,
                                std::move(stanza)));
}

void FakeSignalStrategy::NotifyListeners(
    std::unique_ptr<jingle_xmpp::XmlElement> stanza) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  jingle_xmpp::XmlElement* stanza_ptr = stanza.get();
  received_messages_.push_back(std::move(stanza));

  std::string to_error;
  SignalingAddress to =
      SignalingAddress::Parse(stanza_ptr, SignalingAddress::TO, &to_error);
  if (to != address_) {
    LOG(WARNING) << "Dropping stanza that is addressed to " << to.id()
                 << ". Local address: " << address_.id()
                 << ". Message content: " << stanza_ptr->Str();
    return;
  }

  for (auto& listener : listeners_) {
    if (listener.OnSignalStrategyIncomingStanza(stanza_ptr)) {
      break;
    }
  }
}

}  // namespace remoting