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