blob: 19286135b8b0a0ae25cb167afd8be04205cc7510 [file] [log] [blame]
// libjingle
// Copyright 2009 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.
#ifndef TALK_SESSION_PHONE_FAKESESSION_H_
#define TALK_SESSION_PHONE_FAKESESSION_H_
#include <map>
#include <string>
#include "talk/p2p/base/session.h"
#include "talk/p2p/base/transport.h"
#include "talk/p2p/base/transportchannel.h"
#include "talk/p2p/base/transportchannelimpl.h"
namespace cricket {
class FakeTransport;
// Fake transport channel class, which can be passed to anything that needs a
// transport channel. Can be informed of another FakeTransportChannel via
// SetDestination.
class FakeTransportChannel : public TransportChannelImpl {
public:
explicit FakeTransportChannel(Transport* transport,
const std::string& name,
const std::string& session_type)
: TransportChannelImpl(name, session_type),
transport_(transport),
dest_(NULL),
state_(STATE_INIT) {
}
~FakeTransportChannel() {
Reset();
}
virtual Transport* GetTransport() {
return transport_;
}
virtual void Connect() {
if (state_ == STATE_INIT) {
state_ = STATE_CONNECTING;
}
}
virtual void Reset() {
if (state_ != STATE_INIT) {
state_ = STATE_INIT;
if (dest_) {
dest_->state_ = STATE_INIT;
dest_->dest_ = NULL;
dest_ = NULL;
}
}
}
void SetDestination(FakeTransportChannel* dest) {
if (state_ == STATE_CONNECTING && dest) {
// This simulates the delivery of candidates.
dest_ = dest;
dest_->dest_ = this;
state_ = STATE_CONNECTED;
dest_->state_ = STATE_CONNECTED;
set_writable(true);
dest_->set_writable(true);
} else if (state_ == STATE_CONNECTED && !dest) {
// Simulates loss of connectivity, by asymmetrically forgetting dest_.
dest_ = NULL;
state_ = STATE_CONNECTING;
set_writable(false);
}
}
virtual int SendPacket(const char *data, size_t len) {
if (state_ != STATE_CONNECTED) {
return -1;
}
dest_->SignalReadPacket(dest_, data, len);
return len;
}
virtual int SetOption(talk_base::Socket::Option opt, int value) {
return true;
}
virtual int GetError() {
return 0;
}
virtual void OnSignalingReady() {
}
virtual void OnCandidate(const Candidate& candidate) {
}
private:
enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED };
Transport* transport_;
FakeTransportChannel* dest_;
State state_;
};
// Fake transport class, which can be passed to anything that needs a Transport.
// Can be informed of another FakeTransport via SetDestination (low-tech way
// of doing candidates)
class FakeTransport : public Transport {
public:
typedef std::map<std::string, FakeTransportChannel*> ChannelMap;
FakeTransport(talk_base::Thread* signaling_thread,
talk_base::Thread* worker_thread)
: Transport(signaling_thread, worker_thread, "test", NULL),
dest_(NULL) {
}
~FakeTransport() {
DestroyAllChannels();
}
const ChannelMap& channels() const { return channels_; }
void SetDestination(FakeTransport* dest) {
dest_ = dest;
for (ChannelMap::iterator it = channels_.begin(); it != channels_.end();
++it) {
SetChannelDestination(it->first, it->second);
}
}
protected:
virtual TransportChannelImpl* CreateTransportChannel(
const std::string& name, const std::string& session_type) {
if (channels_.find(name) != channels_.end()) {
return NULL;
}
FakeTransportChannel* channel =
new FakeTransportChannel(this, name, session_type);
SetChannelDestination(name, channel);
channels_[name] = channel;
return channel;
}
virtual void DestroyTransportChannel(TransportChannelImpl* channel) {
channels_.erase(channel->name());
delete channel;
}
private:
void SetChannelDestination(const std::string& name,
FakeTransportChannel* channel) {
FakeTransportChannel* dest_channel = NULL;
if (dest_) {
dest_channel =
static_cast<FakeTransportChannel*>(dest_->GetChannel(name));
}
channel->SetDestination(dest_channel);
}
ChannelMap channels_;
FakeTransport* dest_;
};
// Fake session class, which can be passed into a BaseChannel object for
// test purposes. Can be connected to other FakeSessions via Connect().
class FakeSession : public BaseSession {
public:
FakeSession()
: BaseSession(talk_base::Thread::Current(),
talk_base::Thread::Current(),
NULL, "", "", true),
fail_create_channel_(false) {
}
FakeTransport* GetTransport(const std::string& content_name) {
return static_cast<FakeTransport*>(
BaseSession::GetTransport(content_name));
}
void Connect(FakeSession* dest) {
// Simulate the exchange of candidates.
CompleteNegotiation();
dest->CompleteNegotiation();
for (TransportMap::const_iterator it = transport_proxies().begin();
it != transport_proxies().end(); ++it) {
static_cast<FakeTransport*>(it->second->impl())->SetDestination(
dest->GetTransport(it->first));
}
}
virtual cricket::TransportChannel* CreateChannel(
const std::string& content_name, const std::string& name) {
if (fail_create_channel_) {
return NULL;
}
return BaseSession::CreateChannel(content_name, name);
}
void set_fail_channel_creation(bool fail_channel_creation) {
fail_create_channel_ = fail_channel_creation;
}
protected:
virtual Transport* CreateTransport() {
return new FakeTransport(signaling_thread(), worker_thread());
}
void CompleteNegotiation() {
for (TransportMap::const_iterator it = transport_proxies().begin();
it != transport_proxies().end(); ++it) {
it->second->CompleteNegotiation();
}
}
private:
bool fail_create_channel_;
};
} // namespace cricket
#endif // TALK_SESSION_PHONE_FAKESESSION_H_