• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2005, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifndef TALK_P2P_BASE_SESSION_H_
29 #define TALK_P2P_BASE_SESSION_H_
30 
31 #include <list>
32 #include <map>
33 #include <string>
34 #include <vector>
35 
36 #include "talk/p2p/base/sessionmessages.h"
37 #include "talk/p2p/base/sessionmanager.h"
38 #include "talk/base/socketaddress.h"
39 #include "talk/p2p/base/sessionclient.h"
40 #include "talk/p2p/base/parsing.h"
41 #include "talk/p2p/base/port.h"
42 #include "talk/xmllite/xmlelement.h"
43 #include "talk/xmpp/constants.h"
44 
45 namespace cricket {
46 
47 class P2PTransportChannel;
48 class Transport;
49 class TransportChannel;
50 class TransportChannelProxy;
51 class TransportChannelImpl;
52 
53 // Used for errors that will send back a specific error message to the
54 // remote peer.  We add "type" to the errors because it's needed for
55 // SignalErrorMessage.
56 struct MessageError : ParseError {
57   buzz::QName type;
58 
59   // if unset, assume type is a parse error
MessageErrorMessageError60   MessageError() : ParseError(), type(buzz::QN_STANZA_BAD_REQUEST) {}
61 
SetTypeMessageError62   void SetType(const buzz::QName type) {
63     this->type = type;
64   }
65 };
66 
67 // Used for errors that may be returned by public session methods that
68 // can fail.
69 // TODO: Use this error in Session::Initiate and
70 // Session::Accept.
71 struct SessionError : WriteError {
72 };
73 
74 // Bundles a Transport and ChannelMap together. ChannelMap is used to
75 // create transport channels before receiving or sending a session
76 // initiate, and for speculatively connecting channels.  Previously, a
77 // session had one ChannelMap and transport.  Now, with multiple
78 // transports per session, we need multiple ChannelMaps as well.
79 class TransportProxy {
80  public:
TransportProxy(const std::string & content_name,Transport * transport)81   TransportProxy(const std::string& content_name, Transport* transport)
82       : content_name_(content_name),
83         transport_(transport),
84         state_(STATE_INIT),
85         sent_candidates_(false) {}
86   ~TransportProxy();
87 
content_name()88   std::string content_name() const { return content_name_; }
impl()89   Transport* impl() const { return transport_; }
90   std::string type() const;
negotiated()91   bool negotiated() const { return state_ == STATE_NEGOTIATED; }
sent_candidates()92   const Candidates& sent_candidates() const { return sent_candidates_; }
93 
94   TransportChannel* GetChannel(const std::string& name);
95   TransportChannel* CreateChannel(const std::string& name,
96                                   const std::string& content_type);
97   void DestroyChannel(const std::string& name);
98   void AddSentCandidates(const Candidates& candidates);
ClearSentCandidates()99   void ClearSentCandidates() { sent_candidates_.clear(); }
100   void SpeculativelyConnectChannels();
101   void CompleteNegotiation();
102 
103  private:
104   enum TransportState {
105     STATE_INIT,
106     STATE_CONNECTING,
107     STATE_NEGOTIATED
108   };
109 
110   typedef std::map<std::string, TransportChannelProxy*> ChannelMap;
111 
112   TransportChannelProxy* GetProxy(const std::string& name);
113   TransportChannelImpl* GetOrCreateImpl(const std::string& name,
114                                         const std::string& content_type);
115   void SetProxyImpl(const std::string& name, TransportChannelProxy* proxy);
116 
117   std::string content_name_;
118   Transport* transport_;
119   TransportState state_;
120   ChannelMap channels_;
121   Candidates sent_candidates_;
122 };
123 
124 typedef std::map<std::string, TransportProxy*> TransportMap;
125 
126 // TODO: Consider simplifying the dependency from Voice/VideoChannel
127 // on Session. Right now the Channel class requires a BaseSession, but it only
128 // uses CreateChannel/DestroyChannel. Perhaps something like a
129 // TransportChannelFactory could be hoisted up out of BaseSession, or maybe
130 // the transports could be passed in directly.
131 
132 // A BaseSession manages general session state. This includes negotiation
133 // of both the application-level and network-level protocols:  the former
134 // defines what will be sent and the latter defines how it will be sent.  Each
135 // network-level protocol is represented by a Transport object.  Each Transport
136 // participates in the network-level negotiation.  The individual streams of
137 // packets are represented by TransportChannels.  The application-level protocol
138 // is represented by SessionDecription objects.
139 class BaseSession : public sigslot::has_slots<>,
140                     public talk_base::MessageHandler {
141  public:
142   enum State {
143     STATE_INIT = 0,
144     STATE_SENTINITIATE,       // sent initiate, waiting for Accept or Reject
145     STATE_RECEIVEDINITIATE,   // received an initiate. Call Accept or Reject
146     STATE_SENTACCEPT,         // sent accept. begin connecting transport
147     STATE_RECEIVEDACCEPT,     // received accept. begin connecting transport
148     STATE_SENTMODIFY,         // sent modify, waiting for Accept or Reject
149     STATE_RECEIVEDMODIFY,     // received modify, call Accept or Reject
150     STATE_SENTREJECT,         // sent reject after receiving initiate
151     STATE_RECEIVEDREJECT,     // received reject after sending initiate
152     STATE_SENTREDIRECT,       // sent direct after receiving initiate
153     STATE_SENTTERMINATE,      // sent terminate (any time / either side)
154     STATE_RECEIVEDTERMINATE,  // received terminate (any time / either side)
155     STATE_INPROGRESS,         // session accepted and in progress
156     STATE_DEINIT,             // session is being destroyed
157   };
158 
159   enum Error {
160     ERROR_NONE = 0,      // no error
161     ERROR_TIME = 1,      // no response to signaling
162     ERROR_RESPONSE = 2,  // error during signaling
163     ERROR_NETWORK = 3,   // network error, could not allocate network resources
164     ERROR_CONTENT = 4,   // channel errors in SetLocalContent/SetRemoteContent
165   };
166 
167   explicit BaseSession(talk_base::Thread *signaling_thread);
168   virtual ~BaseSession();
169 
170   // Updates the state, signaling if necessary.
171   void SetState(State state);
172 
173   // Updates the error state, signaling if necessary.
174   virtual void SetError(Error error);
175 
176   // Handles messages posted to us.
177   virtual void OnMessage(talk_base::Message *pmsg);
178 
179   // Returns the current state of the session.  See the enum above for details.
180   // Each time the state changes, we will fire this signal.
state()181   State state() const { return state_; }
182   sigslot::signal2<BaseSession *, State> SignalState;
183 
184   // Returns the last error in the session.  See the enum above for details.
185   // Each time the an error occurs, we will fire this signal.
error()186   Error error() const { return error_; }
187   sigslot::signal2<BaseSession *, Error> SignalError;
188 
189   // Creates a new channel with the given names.  This method may be called
190   // immediately after creating the session.  However, the actual
191   // implementation may not be fixed until transport negotiation completes.
192   // This will usually be called from the worker thread, but that
193   // shouldn't be an issue since the main thread will be blocked in
194   // Send when doing so.
195   virtual TransportChannel* CreateChannel(const std::string& content_name,
196                                           const std::string& channel_name) = 0;
197 
198   // Returns the channel with the given names.
199   virtual TransportChannel* GetChannel(const std::string& content_name,
200                                        const std::string& channel_name) = 0;
201 
202   // Destroys the channel with the given names.
203   // This will usually be called from the worker thread, but that
204   // shouldn't be an issue since the main thread will be blocked in
205   // Send when doing so.
206   virtual void DestroyChannel(const std::string& content_name,
207                               const std::string& channel_name) = 0;
208 
209   // Invoked when we notice that there is no matching channel on our peer.
210   sigslot::signal2<Session*, const std::string&> SignalChannelGone;
211 
212   // Returns the application-level description given by our client.
213   // If we are the recipient, this will be NULL until we send an accept.
local_description()214   const SessionDescription* local_description() const {
215     return local_description_;
216   }
217   // Takes ownership of SessionDescription*
set_local_description(const SessionDescription * sdesc)218   bool set_local_description(const SessionDescription* sdesc) {
219     if (sdesc != local_description_) {
220       delete local_description_;
221       local_description_ = sdesc;
222     }
223     return true;
224   }
225 
226   // Returns the application-level description given by the other client.
227   // If we are the initiator, this will be NULL until we receive an accept.
remote_description()228   const SessionDescription* remote_description() const {
229     return remote_description_;
230   }
231   // Takes ownership of SessionDescription*
set_remote_description(const SessionDescription * sdesc)232   bool set_remote_description(const SessionDescription* sdesc) {
233     if (sdesc != remote_description_) {
234       delete remote_description_;
235       remote_description_ = sdesc;
236     }
237     return true;
238   }
239 
240   // When we receive an initiate, we create a session in the
241   // RECEIVEDINITIATE state and respond by accepting or rejecting.
242   // Takes ownership of session description.
243   virtual bool Accept(const SessionDescription* sdesc) = 0;
244   virtual bool Reject(const std::string& reason) = 0;
Terminate()245   bool Terminate() {
246     return TerminateWithReason(STR_TERMINATE_SUCCESS);
247   }
248   virtual bool TerminateWithReason(const std::string& reason) = 0;
249 
250   // The worker thread used by the session manager
251   virtual talk_base::Thread *worker_thread() = 0;
252 
signaling_thread()253   talk_base::Thread *signaling_thread() {
254     return signaling_thread_;
255   }
256 
257   // Returns the JID of this client.
local_name()258   const std::string& local_name() const { return local_name_; }
259 
260   // Returns the JID of the other peer in this session.
remote_name()261   const std::string& remote_name() const { return remote_name_; }
262 
263   // Set the JID of the other peer in this session.
264   // Typically the remote_name_ is set when the session is initiated.
265   // However, sometimes (e.g when a proxy is used) the peer name is
266   // known after the BaseSession has been initiated and it must be updated
267   // explicitly.
set_remote_name(const std::string & name)268   void set_remote_name(const std::string& name) { remote_name_ = name; }
269 
id()270   const std::string& id() const { return sid_; }
271 
272  protected:
273   State state_;
274   Error error_;
275   const SessionDescription* local_description_;
276   const SessionDescription* remote_description_;
277   std::string sid_;
278   // We don't use buzz::Jid because changing to buzz:Jid here has a
279   // cascading effect that requires an enormous number places to
280   // change to buzz::Jid as well.
281   std::string local_name_;
282   std::string remote_name_;
283   talk_base::Thread *signaling_thread_;
284 };
285 
286 // A specific Session created by the SessionManager, using XMPP for protocol.
287 class Session : public BaseSession {
288  public:
289   // Returns the manager that created and owns this session.
session_manager()290   SessionManager* session_manager() const { return session_manager_; }
291 
292   // the worker thread used by the session manager
worker_thread()293   talk_base::Thread *worker_thread() {
294     return session_manager_->worker_thread();
295   }
296 
297   // Returns the XML namespace identifying the type of this session.
content_type()298   const std::string& content_type() const { return content_type_; }
299 
300   // Returns the client that is handling the application data of this session.
client()301   SessionClient* client() const { return client_; }
302 
current_protocol()303   SignalingProtocol current_protocol() const { return current_protocol_; }
304 
set_current_protocol(SignalingProtocol protocol)305   void set_current_protocol(SignalingProtocol protocol) {
306     current_protocol_ = protocol;
307   }
308 
309   // Indicates whether we initiated this session.
initiator()310   bool initiator() const { return initiator_; }
311 
initiator_description()312   const SessionDescription* initiator_description() const {
313     if (initiator_) {
314       return local_description_;
315     } else {
316       return remote_description_;
317     }
318   }
319 
320   // Fired whenever we receive a terminate message along with a reason
321   sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason;
322 
323   void set_allow_local_ips(bool allow);
324 
325   // Returns the transport that has been negotiated or NULL if
326   // negotiation is still in progress.
327   Transport* GetTransport(const std::string& content_name);
328 
329   // Takes ownership of session description.
330   // TODO: Add an error argument to pass back to the caller.
331   bool Initiate(const std::string& to,
332                 const SessionDescription* sdesc);
333 
334   // When we receive an initiate, we create a session in the
335   // RECEIVEDINITIATE state and respond by accepting or rejecting.
336   // Takes ownership of session description.
337   // TODO: Add an error argument to pass back to the caller.
338   virtual bool Accept(const SessionDescription* sdesc);
339   virtual bool Reject(const std::string& reason);
340   virtual bool TerminateWithReason(const std::string& reason);
341 
342   // The two clients in the session may also send one another arbitrary XML
343   // messages, which are called "info" messages.  Both of these functions take
344   // ownership of the XmlElements and delete them when done.
345   bool SendInfoMessage(const XmlElements& elems);
346   sigslot::signal2<Session*, const XmlElements&> SignalInfoMessage;
347 
348   // Maps passed to serialization functions.
349   TransportParserMap GetTransportParsers();
350   ContentParserMap GetContentParsers();
351 
352   // Creates a new channel with the given names.  This method may be called
353   // immediately after creating the session.  However, the actual
354   // implementation may not be fixed until transport negotiation completes.
355   virtual TransportChannel* CreateChannel(const std::string& content_name,
356                                           const std::string& channel_name);
357 
358   // Returns the channel with the given names.
359   virtual TransportChannel* GetChannel(const std::string& content_name,
360                                        const std::string& channel_name);
361 
362   // Destroys the channel with the given names.
363   virtual void DestroyChannel(const std::string& content_name,
364                               const std::string& channel_name);
365 
366   // Updates the error state, signaling if necessary.
367   virtual void SetError(Error error);
368 
369   // Handles messages posted to us.
370   virtual void OnMessage(talk_base::Message *pmsg);
371 
372   // Fired when notification of media sources is received from the server.
373   // Passes a map whose keys are strings containing nick names for users
374   // in the session and whose values contain the SSRCs for each user.
375   sigslot::signal1<const StringToMediaSourcesMap&> SignalMediaSources;
376 
377   // Sets the video streams to receive from the server.
378   bool SetVideoView(const VideoViewRequestVector& view_requests);
379 
380  private:
381   // Creates or destroys a session.  (These are called only SessionManager.)
382   Session(SessionManager *session_manager,
383           const std::string& local_name, const std::string& initiator_name,
384           const std::string& sid, const std::string& content_type,
385           SessionClient* client);
386   ~Session();
387 
388   // Get a TransportProxy by content_name or transport. NULL if not found.
389   TransportProxy* GetTransportProxy(const std::string& content_name);
390   TransportProxy* GetTransportProxy(const Transport* transport);
391   TransportProxy* GetFirstTransportProxy();
392   // TransportProxy is owned by session.  Return proxy just for convenience.
393   TransportProxy* GetOrCreateTransportProxy(const std::string& content_name);
394   // For each transport info, create a transport proxy.  Can fail for
395   // incompatible transport types.
396   bool CreateTransportProxies(const TransportInfos& tinfos,
397                               SessionError* error);
398   void SpeculativelyConnectAllTransportChannels();
399   bool OnRemoteCandidates(const TransportInfos& tinfos,
400                           ParseError* error);
401   // Returns a TransportInfo without candidates for each content name.
402   // Uses the transport_type_ of the session.
403   TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const;
404 
405   // Called when the first channel of a transport begins connecting.  We use
406   // this to start a timer, to make sure that the connection completes in a
407   // reasonable amount of time.
408   void OnTransportConnecting(Transport* transport);
409 
410   // Called when a transport changes its writable state.  We track this to make
411   // sure that the transport becomes writable within a reasonable amount of
412   // time.  If this does not occur, we signal an error.
413   void OnTransportWritable(Transport* transport);
414 
415   // Called when a transport requests signaling.
416   void OnTransportRequestSignaling(Transport* transport);
417 
418   // Called when a transport signals that it has a message to send.   Note that
419   // these messages are just the transport part of the stanza; they need to be
420   // wrapped in the appropriate session tags.
421   void OnTransportCandidatesReady(Transport* transport,
422                                   const Candidates& candidates);
423 
424   // Called when a transport signals that it found an error in an incoming
425   // message.
426   void OnTransportSendError(Transport* transport,
427                             const buzz::XmlElement* stanza,
428                             const buzz::QName& name,
429                             const std::string& type,
430                             const std::string& text,
431                             const buzz::XmlElement* extra_info);
432 
433   // Called when we notice that one of our local channels has no peer, so it
434   // should be destroyed.
435   void OnTransportChannelGone(Transport* transport, const std::string& name);
436 
437   // When the session needs to send signaling messages, it beings by requesting
438   // signaling.  The client should handle this by calling OnSignalingReady once
439   // it is ready to send the messages.
440   // (These are called only by SessionManager.)
441   sigslot::signal1<Session*> SignalRequestSignaling;
442   void OnSignalingReady();
443 
444   // Send various kinds of session messages.
445   bool SendInitiateMessage(const SessionDescription* sdesc,
446                            SessionError* error);
447   bool SendAcceptMessage(const SessionDescription* sdesc, SessionError* error);
448   bool SendRejectMessage(const std::string& reason, SessionError* error);
449   bool SendTerminateMessage(const std::string& reason, SessionError* error);
450   bool SendTransportInfoMessage(const TransportInfo& tinfo,
451                                 SessionError* error);
452   bool SendViewMessage(const SessionView& view, SessionError* error);
453   bool ResendAllTransportInfoMessages(SessionError* error);
454 
455   // Both versions of SendMessage send a message of the given type to
456   // the other client.  Can pass either a set of elements or an
457   // "action", which must have a WriteSessionAction method to go along
458   // with it.  Sending with an action supports sending a "hybrid"
459   // message.  Sending with elements must be sent as Jingle or Gingle.
460 
461   // When passing elems, must be either Jingle or Gingle protocol.
462   // Takes ownership of action_elems.
463   bool SendMessage(ActionType type, const XmlElements& action_elems,
464                    SessionError* error);
465   // When passing an action, may be Hybrid protocol.
466   template <typename Action>
467   bool SendMessage(ActionType type, const Action& action,
468                    SessionError* error);
469 
470   // Helper methods to write the session message stanza.
471   template <typename Action>
472   bool WriteActionMessage(ActionType type, const Action& action,
473                           buzz::XmlElement* stanza, WriteError* error);
474   template <typename Action>
475   bool WriteActionMessage(SignalingProtocol protocol,
476                           ActionType type, const Action& action,
477                           buzz::XmlElement* stanza, WriteError* error);
478 
479   // Sending messages in hybrid form requires being able to write them
480   // on a per-protocol basis with a common method signature, which all
481   // of these have.
482   bool WriteSessionAction(SignalingProtocol protocol,
483                           const SessionInitiate& init,
484                           XmlElements* elems, WriteError* error);
485   bool WriteSessionAction(SignalingProtocol protocol,
486                           const TransportInfo& tinfo,
487                           XmlElements* elems, WriteError* error);
488   bool WriteSessionAction(SignalingProtocol protocol,
489                           const SessionTerminate& term,
490                           XmlElements* elems, WriteError* error);
491 
492   // Sends a message back to the other client indicating that we have received
493   // and accepted their message.
494   void SendAcknowledgementMessage(const buzz::XmlElement* stanza);
495 
496   // Once signaling is ready, the session will use this signal to request the
497   // sending of each message.  When messages are received by the other client,
498   // they should be handed to OnIncomingMessage.
499   // (These are called only by SessionManager.)
500   sigslot::signal2<Session *, const buzz::XmlElement*> SignalOutgoingMessage;
501   void OnIncomingMessage(const SessionMessage& msg);
502 
503   void OnFailedSend(const buzz::XmlElement* orig_stanza,
504                     const buzz::XmlElement* error_stanza);
505 
506   // Invoked when an error is found in an incoming message.  This is translated
507   // into the appropriate XMPP response by SessionManager.
508   sigslot::signal6<BaseSession*,
509                    const buzz::XmlElement*,
510                    const buzz::QName&,
511                    const std::string&,
512                    const std::string&,
513                    const buzz::XmlElement*> SignalErrorMessage;
514 
515   // Handlers for the various types of messages.  These functions may take
516   // pointers to the whole stanza or to just the session element.
517   bool OnInitiateMessage(const SessionMessage& msg, MessageError* error);
518   bool OnAcceptMessage(const SessionMessage& msg, MessageError* error);
519   bool OnRejectMessage(const SessionMessage& msg, MessageError* error);
520   bool OnInfoMessage(const SessionMessage& msg);
521   bool OnTerminateMessage(const SessionMessage& msg, MessageError* error);
522   bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error);
523   bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error);
524   bool OnNotifyMessage(const SessionMessage& msg, MessageError* error);
525   bool OnUpdateMessage(const SessionMessage& msg, MessageError* error);
526   bool OnRedirectError(const SessionRedirect& redirect, SessionError* error);
527 
528   // Verifies that we are in the appropriate state to receive this message.
529   bool CheckState(State state, MessageError* error);
530 
531   SessionManager *session_manager_;
532   bool initiator_;
533   std::string initiator_name_;
534   std::string content_type_;
535   SessionClient* client_;
536   std::string transport_type_;
537   TransportParser* transport_parser_;
538   // This is transport-specific but required so much by unit tests
539   // that it's much easier to put it here.
540   bool allow_local_ips_;
541   TransportMap transports_;
542   // Keeps track of what protocol we are speaking.
543   SignalingProtocol current_protocol_;
544 
545   friend class SessionManager;  // For access to constructor, destructor,
546                                 // and signaling related methods.
547 };
548 
549 }  // namespace cricket
550 
551 #endif  // TALK_P2P_BASE_SESSION_H_
552