/* * 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 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 SignalState; // Fired whenever we receive a terminate message along with a reason sigslot::signal2 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 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 ... bool Initiate(const std::string &to, std::vector* 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 XmlElements; void SendInfoMessage(const XmlElements& elems); sigslot::signal2 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 SignalChannelGone; private: typedef std::list TransportList; typedef std::map 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 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 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 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_