blob: 5146ea0bcdb17479ac4ec2e5fa7f42b88552ece0 [file] [log] [blame]
/*
* 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.
*/
#ifndef _SESSION_H_
#define _SESSION_H_
#include "talk/base/socketaddress.h"
#include "talk/p2p/base/sessiondescription.h"
#include "talk/p2p/base/sessionmanager.h"
#include "talk/p2p/base/sessionclient.h"
#include "talk/p2p/base/sessionid.h"
#include "talk/p2p/base/port.h"
#include "talk/xmllite/xmlelement.h"
#include <string>
namespace cricket {
class SessionManager;
class Transport;
class TransportChannel;
class TransportChannelProxy;
class TransportChannelImpl;
// A specific Session created by the SessionManager. A Session manages
// signaling for session setup and tear down. This setup includes negotiation
// of both the application-level and network-level protocols: the former
// defines what will be sent and the latter defines how it will be sent. Each
// network-level protocol is represented by a Transport object. Each Transport
// participates in the network-level negotiation. The individual streams of
// packets are represented by TransportChannels.
class Session : public talk_base::MessageHandler, public sigslot::has_slots<> {
public:
enum State {
STATE_INIT = 0,
STATE_SENTINITIATE, // sent initiate, waiting for Accept or Reject
STATE_RECEIVEDINITIATE, // received an initiate. Call Accept or Reject
STATE_SENTACCEPT, // sent accept. begin connecting transport
STATE_RECEIVEDACCEPT, // received accept. begin connecting transport
STATE_SENTMODIFY, // sent modify, waiting for Accept or Reject
STATE_RECEIVEDMODIFY, // received modify, call Accept or Reject
STATE_SENTREJECT, // sent reject after receiving initiate
STATE_RECEIVEDREJECT, // received reject after sending initiate
STATE_SENTREDIRECT, // sent direct after receiving initiate
STATE_SENTTERMINATE, // sent terminate (any time / either side)
STATE_RECEIVEDTERMINATE, // received terminate (any time / either side)
STATE_INPROGRESS, // session accepted and in progress
STATE_DEINIT, // session is being destroyed
};
enum Error {
ERROR_NONE = 0, // no error
ERROR_TIME, // no response to signaling
ERROR_RESPONSE, // error during signaling
ERROR_NETWORK, // network error, could not allocate network resources
};
// Returns the manager that created and owns this session.
SessionManager* session_manager() const { return session_manager_; }
// Returns the XML namespace identifying the type of this session.
const std::string& session_type() const { return session_type_; }
// Returns the client that is handling the application data of this session.
SessionClient* client() const { return client_; }
// Returns the JID this client.
const std::string &name() const { return name_; }
// Returns the JID of the other peer in this session.
const std::string &remote_name() const { return remote_name_; }
// Indicates whether we initiated this session.
bool initiator() const { return initiator_; }
// Holds the ID of this session, which should be unique across the world.
const SessionID& id() const { return id_; }
// Returns the applicication-level description given by our client. This
// will be null until Initiate or Accept.
const SessionDescription *description() const { return description_; }
// Returns the applicication-level description given by the other client.
// If we are the initiator, this will be null until we receive an accept.
const SessionDescription *remote_description() const {
return remote_description_;
}
// Returns the current state of the session. See the enum above for details.
// Each time the state changes, we will fire this signal.
State state() const { return state_; }
sigslot::signal2<Session *, State> SignalState;
// Fired whenever we receive a terminate message along with a reason
sigslot::signal2<Session *, const std::string &> SignalReceivedTerminateReason;
// Returns the last error in the session. See the enum above for details.
// Each time the an error occurs, we will fire this signal.
Error error() const { return error_; }
sigslot::signal2<Session *, Error> SignalError;
// Returns the transport that has been negotiated or NULL if negotiation is
// still in progress.
Transport* transport() const { return transport_; }
// When a session was created by us, we are the initiator, and we send the
// initiate message when this method is invoked. The extra_xml parameter is
// a list of elements that will get inserted inside <Session> ... </Session>
bool Initiate(const std::string &to, std::vector<buzz::XmlElement*>* extra_xml,
const SessionDescription *description);
// When we receive a session initiation from another client, we create a
// session in the RECEIVEDINITIATE state. We respond by accepting,
// rejecting, or redirecting the session somewhere else.
bool Accept(const SessionDescription *description);
bool Reject();
bool Redirect(const std::string& target);
// At any time, we may terminate an outstanding session.
bool Terminate();
// The two clients in the session may also send one another arbitrary XML
// messages, which are called "info" messages. Both of these functions take
// ownership of the XmlElements and delete them when done.
typedef std::vector<buzz::XmlElement*> XmlElements;
void SendInfoMessage(const XmlElements& elems);
sigslot::signal2<Session*, const XmlElements&> SignalInfoMessage;
// Controls the set of transports that will be allowed for this session. If
// we are initiating, then this list will be used to construct the transports
// that we will offer to the other side. In that case, the order of the
// transport names indicates our preference (first has highest preference).
// If we are receiving, then this list indicates the set of transports that
// we will allow. We will choose the first transport in the offered list
// (1) whose name appears in the given list and (2) that can accept the offer
// provided (which may include parameters particular to the transport).
//
// If this function is not called (or if it is called with a NULL array),
// then we will use a default set of transports.
void SetPotentialTransports(const std::string names[], size_t length);
// Once transports have been created (by SetTransports), this function will
// return the transport with the given name or NULL if none was created.
// Once a particular transport has been chosen, only that transport will be
// returned.
Transport* GetTransport(const std::string& name);
// Creates a new channel with the given name. This method may be called
// immediately after creating the session. However, the actual
// implementation may not be fixed until transport negotiation completes.
TransportChannel* CreateChannel(const std::string& name);
// Returns the channel with the given name.
TransportChannel* GetChannel(const std::string& name);
// Destroys the given channel.
void DestroyChannel(TransportChannel* channel);
// Note: This function is a hack and should not be used.
TransportChannelImpl* GetImplementation(TransportChannel* channel);
// Invoked when we notice that there is no matching channel on our peer.
sigslot::signal2<Session*, const std::string&> SignalChannelGone;
private:
typedef std::list<Transport*> TransportList;
typedef std::map<std::string, TransportChannelProxy*> ChannelMap;
SessionManager *session_manager_;
std::string name_;
std::string remote_name_;
bool initiator_;
SessionID id_;
std::string session_type_;
SessionClient* client_;
const SessionDescription *description_;
const SessionDescription *remote_description_;
State state_;
Error error_;
std::string redirect_target_;
// Note that the following two members are mutually exclusive
TransportList potential_transports_; // order implies preference
Transport* transport_; // negotiated transport
ChannelMap channels_;
bool compatibility_mode_; // indicates talking to an old client
XmlElements candidates_; // holds candidates sent in case of compat-mode
// Creates or destroys a session. (These are called only SessionManager.)
Session(SessionManager *session_manager,
const std::string& name,
const SessionID& id,
const std::string& session_type,
SessionClient* client);
~Session();
// Updates the state, signaling if necessary.
void SetState(State state);
// Updates the error state, signaling if necessary.
void SetError(Error error);
// To improve connection time, this creates the channels on the most common
// transport type and initiates connection.
void ConnectDefaultTransportChannels(bool create);
// If a new channel is created after we have created the default transport,
// then we should create this channel as well and let it connect.
void CreateDefaultTransportChannel(const std::string& name);
// Creates a default set of transports if the client did not specify some.
void CreateTransports();
// Attempts to choose a transport that is in both our list and the other
// clients. This will examine the children of the given XML element to find
// the descriptions of the other client's transports. We will pick the first
// transport in the other client's list that we also support.
// (This is called only by SessionManager.)
bool ChooseTransport(const buzz::XmlElement* msg);
// Called when a single transport has been negotiated.
void SetTransport(Transport* transport);
// Called when the first channel of a transport begins connecting. We use
// this to start a timer, to make sure that the connection completes in a
// reasonable amount of time.
void OnTransportConnecting(Transport* transport);
// Called when a transport changes its writable state. We track this to make
// sure that the transport becomes writable within a reasonable amount of
// time. If this does not occur, we signal an error.
void OnTransportWritable(Transport* transport);
// Called when a transport requests signaling.
void OnTransportRequestSignaling(Transport* transport);
// Called when a transport signals that it has a message to send. Note that
// these messages are just the transport part of the stanza; they need to be
// wrapped in the appropriate session tags.
void OnTransportSendMessage(Transport* transport, const XmlElements& elems);
// Called when a transport signals that it found an error in an incoming
// message.
void OnTransportSendError(Transport* transport,
const buzz::XmlElement* stanza,
const buzz::QName& name,
const std::string& type,
const std::string& text,
const buzz::XmlElement* extra_info);
// Called when we notice that one of our local channels has no peer, so it
// should be destroyed.
void OnTransportChannelGone(Transport* transport, const std::string& name);
// When the session needs to send signaling messages, it beings by requesting
// signaling. The client should handle this by calling OnSignalingReady once
// it is ready to send the messages.
// (These are called only by SessionManager.)
sigslot::signal1<Session*> SignalRequestSignaling;
void OnSignalingReady();
// Sends a message of the given type to the other client. The body will
// contain the given list of elements (which are consumed by the function).
void SendSessionMessage(const std::string& type,
const XmlElements& elems);
// Sends a message back to the other client indicating that we have received
// and accepted their message.
void SendAcknowledgementMessage(const buzz::XmlElement* stanza);
// Once signaling is ready, the session will use this signal to request the
// sending of each message. When messages are received by the other client,
// they should be handed to OnIncomingMessage.
// (These are called only by SessionManager.)
sigslot::signal2<Session *, const buzz::XmlElement*> SignalOutgoingMessage;
void OnIncomingMessage(const buzz::XmlElement* stanza);
void OnFailedSend(const buzz::XmlElement* orig_stanza,
const buzz::XmlElement* error_stanza);
// Invoked when an error is found in an incoming message. This is translated
// into the appropriate XMPP response by SessionManager.
sigslot::signal6<Session*,
const buzz::XmlElement*,
const buzz::QName&,
const std::string&,
const std::string&,
const buzz::XmlElement*> SignalErrorMessage;
// Handlers for the various types of messages. These functions may take
// pointers to the whole stanza or to just the session element.
bool OnInitiateMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool OnAcceptMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool OnRejectMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool OnRedirectMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool OnInfoMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool OnTransportAcceptMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool OnTransportInfoMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool OnTerminateMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool OnCandidatesMessage(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
// Helper functions for parsing various message types. CheckState verifies
// that we are in the appropriate state to receive this message. The latter
// three verify that an element has the required child or attribute.
bool CheckState(const buzz::XmlElement* stanza, State state);
bool FindRequiredElement(const buzz::XmlElement* stanza,
const buzz::XmlElement* parent,
const buzz::QName& name,
const buzz::XmlElement** elem);
bool FindRemoteSessionDescription(const buzz::XmlElement* stanza,
const buzz::XmlElement* session);
bool FindRequiredAttribute(const buzz::XmlElement* stanza,
const buzz::XmlElement* elem,
const buzz::QName& name,
std::string* value);
// Handles messages posted to us.
void OnMessage(talk_base::Message *pmsg);
friend class SessionManager; // For access to constructor, destructor,
// and signaling related methods.
};
} // namespace cricket
#endif // _SESSION_H_