Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(881)

Side by Side Diff: webrtc/libjingle/session/sessionmanager.cc

Issue 1175243003: Remove webrtc/libjingle/{examples,session}. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/libjingle/session/sessionmanager.h"
12
13 #include "webrtc/base/common.h"
14 #include "webrtc/base/helpers.h"
15 #include "webrtc/base/logging.h"
16 #include "webrtc/base/scoped_ptr.h"
17 #include "webrtc/base/stringencode.h"
18 #include "webrtc/libjingle/session/p2ptransportparser.h"
19 #include "webrtc/libjingle/session/sessionmessages.h"
20 #include "webrtc/libjingle/xmpp/constants.h"
21 #include "webrtc/libjingle/xmpp/jid.h"
22 #include "webrtc/p2p/base/constants.h"
23
24 namespace cricket {
25
26 bool BadMessage(const buzz::QName type,
27 const std::string& text,
28 MessageError* err) {
29 err->SetType(type);
30 err->SetText(text);
31 return false;
32 }
33
34
35 Session::Session(SessionManager* session_manager,
36 const std::string& local_name,
37 const std::string& initiator_name,
38 const std::string& sid,
39 const std::string& content_type,
40 SessionClient* client)
41 : BaseSession(session_manager->signaling_thread(),
42 session_manager->worker_thread(),
43 session_manager->port_allocator(),
44 sid, content_type, initiator_name == local_name) {
45 ASSERT(client != NULL);
46 session_manager_ = session_manager;
47 local_name_ = local_name;
48 initiator_name_ = initiator_name;
49 transport_parser_ = new P2PTransportParser();
50 client_ = client;
51 initiate_acked_ = false;
52 current_protocol_ = PROTOCOL_HYBRID;
53 }
54
55 Session::~Session() {
56 delete transport_parser_;
57 }
58
59 bool Session::Initiate(const std::string& to,
60 const SessionDescription* sdesc) {
61 ASSERT(signaling_thread()->IsCurrent());
62 SessionError error;
63
64 // Only from STATE_INIT
65 if (state() != STATE_INIT)
66 return false;
67
68 // Setup for signaling.
69 set_remote_name(to);
70 set_local_description(sdesc);
71 if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()),
72 &error)) {
73 LOG(LS_ERROR) << "Could not create transports: " << error.text;
74 return false;
75 }
76
77 if (!SendInitiateMessage(sdesc, &error)) {
78 LOG(LS_ERROR) << "Could not send initiate message: " << error.text;
79 return false;
80 }
81
82 // We need to connect transport proxy and impl here so that we can process
83 // the TransportDescriptions.
84 SpeculativelyConnectAllTransportChannels();
85
86 PushdownTransportDescription(CS_LOCAL, CA_OFFER, NULL);
87 SetState(Session::STATE_SENTINITIATE);
88 return true;
89 }
90
91 bool Session::Accept(const SessionDescription* sdesc) {
92 ASSERT(signaling_thread()->IsCurrent());
93
94 // Only if just received initiate
95 if (state() != STATE_RECEIVEDINITIATE)
96 return false;
97
98 // Setup for signaling.
99 set_local_description(sdesc);
100
101 SessionError error;
102 if (!SendAcceptMessage(sdesc, &error)) {
103 LOG(LS_ERROR) << "Could not send accept message: " << error.text;
104 return false;
105 }
106 // TODO(juberti): Add BUNDLE support to transport-info messages.
107 PushdownTransportDescription(CS_LOCAL, CA_ANSWER, NULL);
108 MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
109 SetState(Session::STATE_SENTACCEPT);
110 return true;
111 }
112
113 bool Session::Reject(const std::string& reason) {
114 ASSERT(signaling_thread()->IsCurrent());
115
116 // Reject is sent in response to an initiate or modify, to reject the
117 // request
118 if (state() != STATE_RECEIVEDINITIATE && state() != STATE_RECEIVEDMODIFY)
119 return false;
120
121 SessionError error;
122 if (!SendRejectMessage(reason, &error)) {
123 LOG(LS_ERROR) << "Could not send reject message: " << error.text;
124 return false;
125 }
126
127 SetState(STATE_SENTREJECT);
128 return true;
129 }
130
131 bool Session::TerminateWithReason(const std::string& reason) {
132 ASSERT(signaling_thread()->IsCurrent());
133
134 // Either side can terminate, at any time.
135 switch (state()) {
136 case STATE_SENTTERMINATE:
137 case STATE_RECEIVEDTERMINATE:
138 return false;
139
140 case STATE_SENTREJECT:
141 case STATE_RECEIVEDREJECT:
142 // We don't need to send terminate if we sent or received a reject...
143 // it's implicit.
144 break;
145
146 default:
147 SessionError error;
148 if (!SendTerminateMessage(reason, &error)) {
149 LOG(LS_ERROR) << "Could not send terminate message: " << error.text;
150 return false;
151 }
152 break;
153 }
154
155 SetState(STATE_SENTTERMINATE);
156 return true;
157 }
158
159 bool Session::SendInfoMessage(const XmlElements& elems,
160 const std::string& remote_name) {
161 ASSERT(signaling_thread()->IsCurrent());
162 SessionError error;
163 if (!SendMessage(ACTION_SESSION_INFO, elems, remote_name, &error)) {
164 LOG(LS_ERROR) << "Could not send info message " << error.text;
165 return false;
166 }
167 return true;
168 }
169
170 bool Session::SendDescriptionInfoMessage(const ContentInfos& contents) {
171 XmlElements elems;
172 WriteError write_error;
173 if (!WriteDescriptionInfo(current_protocol_,
174 contents,
175 GetContentParsers(),
176 &elems, &write_error)) {
177 LOG(LS_ERROR) << "Could not write description info message: "
178 << write_error.text;
179 return false;
180 }
181 SessionError error;
182 if (!SendMessage(ACTION_DESCRIPTION_INFO, elems, &error)) {
183 LOG(LS_ERROR) << "Could not send description info message: "
184 << error.text;
185 return false;
186 }
187 return true;
188 }
189
190 TransportInfos Session::GetEmptyTransportInfos(
191 const ContentInfos& contents) const {
192 TransportInfos tinfos;
193 for (ContentInfos::const_iterator content = contents.begin();
194 content != contents.end(); ++content) {
195 tinfos.push_back(TransportInfo(content->name,
196 TransportDescription(transport_type(),
197 std::string(),
198 std::string())));
199 }
200 return tinfos;
201 }
202
203 bool Session::OnRemoteCandidates(
204 const TransportInfos& tinfos, ParseError* error) {
205 for (TransportInfos::const_iterator tinfo = tinfos.begin();
206 tinfo != tinfos.end(); ++tinfo) {
207 std::string str_error;
208 if (!BaseSession::OnRemoteCandidates(
209 tinfo->content_name, tinfo->description.candidates, &str_error)) {
210 return BadParse(str_error, error);
211 }
212 }
213 return true;
214 }
215
216 bool Session::CreateTransportProxies(const TransportInfos& tinfos,
217 SessionError* error) {
218 for (TransportInfos::const_iterator tinfo = tinfos.begin();
219 tinfo != tinfos.end(); ++tinfo) {
220 if (tinfo->description.transport_type != transport_type()) {
221 error->SetText("No supported transport in offer.");
222 return false;
223 }
224
225 GetOrCreateTransportProxy(tinfo->content_name);
226 }
227 return true;
228 }
229
230 TransportParserMap Session::GetTransportParsers() {
231 TransportParserMap parsers;
232 parsers[transport_type()] = transport_parser_;
233 return parsers;
234 }
235
236 CandidateTranslatorMap Session::GetCandidateTranslators() {
237 CandidateTranslatorMap translators;
238 // NOTE: This technique makes it impossible to parse G-ICE
239 // candidates in session-initiate messages because the channels
240 // aren't yet created at that point. Since we don't use candidates
241 // in session-initiate messages, we should be OK. Once we switch to
242 // ICE, this translation shouldn't be necessary.
243 for (TransportMap::const_iterator iter = transport_proxies().begin();
244 iter != transport_proxies().end(); ++iter) {
245 translators[iter->first] = iter->second;
246 }
247 return translators;
248 }
249
250 ContentParserMap Session::GetContentParsers() {
251 ContentParserMap parsers;
252 parsers[content_type()] = client_;
253 // We need to be able parse both RTP-based and SCTP-based Jingle
254 // with the same client.
255 if (content_type() == NS_JINGLE_RTP) {
256 parsers[NS_JINGLE_DRAFT_SCTP] = client_;
257 }
258 return parsers;
259 }
260
261 void Session::OnTransportRequestSignaling(Transport* transport) {
262 ASSERT(signaling_thread()->IsCurrent());
263 TransportProxy* transproxy = GetTransportProxy(transport);
264 ASSERT(transproxy != NULL);
265 if (transproxy) {
266 // Reset candidate allocation status for the transport proxy.
267 transproxy->set_candidates_allocated(false);
268 }
269 SignalRequestSignaling(this);
270 }
271
272 void Session::OnTransportConnecting(Transport* transport) {
273 // This is an indication that we should begin watching the writability
274 // state of the transport.
275 OnTransportWritable(transport);
276 }
277
278 void Session::OnTransportWritable(Transport* transport) {
279 ASSERT(signaling_thread()->IsCurrent());
280
281 // If the transport is not writable, start a timer to make sure that it
282 // becomes writable within a reasonable amount of time. If it does not, we
283 // terminate since we can't actually send data. If the transport is writable,
284 // cancel the timer. Note that writability transitions may occur repeatedly
285 // during the lifetime of the session.
286 signaling_thread()->Clear(this, MSG_TIMEOUT);
287 if (transport->HasChannels() && !transport->writable()) {
288 signaling_thread()->PostDelayed(
289 session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT);
290 }
291 }
292
293 void Session::OnTransportProxyCandidatesReady(TransportProxy* transproxy,
294 const Candidates& candidates) {
295 ASSERT(signaling_thread()->IsCurrent());
296 if (transproxy != NULL) {
297 if (initiator() && !initiate_acked_) {
298 // TODO: This is to work around server re-ordering
299 // messages. We send the candidates once the session-initiate
300 // is acked. Once we have fixed the server to guarantee message
301 // order, we can remove this case.
302 transproxy->AddUnsentCandidates(candidates);
303 } else {
304 if (!transproxy->negotiated()) {
305 transproxy->AddSentCandidates(candidates);
306 }
307 SessionError error;
308 if (!SendTransportInfoMessage(transproxy, candidates, &error)) {
309 LOG(LS_ERROR) << "Could not send transport info message: "
310 << error.text;
311 return;
312 }
313 }
314 }
315 }
316
317 void Session::OnIncomingMessage(const SessionMessage& msg) {
318 ASSERT(signaling_thread()->IsCurrent());
319 ASSERT(state() == STATE_INIT || msg.from == remote_name());
320
321 if (current_protocol_== PROTOCOL_HYBRID) {
322 if (msg.protocol == PROTOCOL_GINGLE) {
323 current_protocol_ = PROTOCOL_GINGLE;
324 } else {
325 current_protocol_ = PROTOCOL_JINGLE;
326 }
327 }
328
329 bool valid = false;
330 MessageError error;
331 switch (msg.type) {
332 case ACTION_SESSION_INITIATE:
333 valid = OnInitiateMessage(msg, &error);
334 break;
335 case ACTION_SESSION_INFO:
336 valid = OnInfoMessage(msg);
337 break;
338 case ACTION_SESSION_ACCEPT:
339 valid = OnAcceptMessage(msg, &error);
340 break;
341 case ACTION_SESSION_REJECT:
342 valid = OnRejectMessage(msg, &error);
343 break;
344 case ACTION_SESSION_TERMINATE:
345 valid = OnTerminateMessage(msg, &error);
346 break;
347 case ACTION_TRANSPORT_INFO:
348 valid = OnTransportInfoMessage(msg, &error);
349 break;
350 case ACTION_TRANSPORT_ACCEPT:
351 valid = OnTransportAcceptMessage(msg, &error);
352 break;
353 case ACTION_DESCRIPTION_INFO:
354 valid = OnDescriptionInfoMessage(msg, &error);
355 break;
356 default:
357 valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
358 "unknown session message type",
359 &error);
360 }
361
362 if (valid) {
363 SendAcknowledgementMessage(msg.stanza);
364 } else {
365 SignalErrorMessage(this, msg.stanza, error.type,
366 "modify", error.text, NULL);
367 }
368 }
369
370 void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
371 const buzz::XmlElement* response_stanza,
372 const SessionMessage& msg) {
373 ASSERT(signaling_thread()->IsCurrent());
374
375 if (msg.type == ACTION_SESSION_INITIATE) {
376 OnInitiateAcked();
377 }
378 }
379
380 void Session::OnInitiateAcked() {
381 // TODO: This is to work around server re-ordering
382 // messages. We send the candidates once the session-initiate
383 // is acked. Once we have fixed the server to guarantee message
384 // order, we can remove this case.
385 if (!initiate_acked_) {
386 initiate_acked_ = true;
387 SessionError error;
388 SendAllUnsentTransportInfoMessages(&error);
389 }
390 }
391
392 void Session::OnFailedSend(const buzz::XmlElement* orig_stanza,
393 const buzz::XmlElement* error_stanza) {
394 ASSERT(signaling_thread()->IsCurrent());
395
396 SessionMessage msg;
397 ParseError parse_error;
398 if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) {
399 LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text
400 << ":" << orig_stanza;
401 return;
402 }
403
404 // If the error is a session redirect, call OnRedirectError, which will
405 // continue the session with a new remote JID.
406 SessionRedirect redirect;
407 if (FindSessionRedirect(error_stanza, &redirect)) {
408 SessionError error;
409 if (!OnRedirectError(redirect, &error)) {
410 // TODO: Should we send a message back? The standard
411 // says nothing about it.
412 std::ostringstream desc;
413 desc << "Failed to redirect: " << error.text;
414 LOG(LS_ERROR) << desc.str();
415 SetError(ERROR_RESPONSE, desc.str());
416 }
417 return;
418 }
419
420 std::string error_type = "cancel";
421
422 const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
423 if (error) {
424 error_type = error->Attr(buzz::QN_TYPE);
425
426 LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n"
427 << "in response to:\n" << orig_stanza->Str();
428 } else {
429 // don't crash if <error> is missing
430 LOG(LS_ERROR) << "Session error without <error/> element, ignoring";
431 return;
432 }
433
434 if (msg.type == ACTION_TRANSPORT_INFO) {
435 // Transport messages frequently generate errors because they are sent right
436 // when we detect a network failure. For that reason, we ignore such
437 // errors, because if we do not establish writability again, we will
438 // terminate anyway. The exceptions are transport-specific error tags,
439 // which we pass on to the respective transport.
440 } else if ((error_type != "continue") && (error_type != "wait")) {
441 // We do not set an error if the other side said it is okay to continue
442 // (possibly after waiting). These errors can be ignored.
443 SetError(ERROR_RESPONSE, "");
444 }
445 }
446
447 bool Session::OnInitiateMessage(const SessionMessage& msg,
448 MessageError* error) {
449 if (!CheckState(STATE_INIT, error))
450 return false;
451
452 SessionInitiate init;
453 if (!ParseSessionInitiate(msg.protocol, msg.action_elem,
454 GetContentParsers(), GetTransportParsers(),
455 GetCandidateTranslators(),
456 &init, error))
457 return false;
458
459 SessionError session_error;
460 if (!CreateTransportProxies(init.transports, &session_error)) {
461 return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE,
462 session_error.text, error);
463 }
464
465 set_remote_name(msg.from);
466 set_initiator_name(msg.initiator);
467 set_remote_description(new SessionDescription(init.ClearContents(),
468 init.transports,
469 init.groups));
470 // Updating transport with TransportDescription.
471 PushdownTransportDescription(CS_REMOTE, CA_OFFER, NULL);
472 SetState(STATE_RECEIVEDINITIATE);
473
474 // Users of Session may listen to state change and call Reject().
475 if (state() != STATE_SENTREJECT) {
476 if (!OnRemoteCandidates(init.transports, error))
477 return false;
478
479 // TODO(juberti): Auto-generate and push down the local transport answer.
480 // This is necessary for trickling to work with RFC 5245 ICE.
481 }
482 return true;
483 }
484
485 bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) {
486 if (!CheckState(STATE_SENTINITIATE, error))
487 return false;
488
489 SessionAccept accept;
490 if (!ParseSessionAccept(msg.protocol, msg.action_elem,
491 GetContentParsers(), GetTransportParsers(),
492 GetCandidateTranslators(),
493 &accept, error)) {
494 return false;
495 }
496
497 // If we get an accept, we can assume the initiate has been
498 // received, even if we haven't gotten an IQ response.
499 OnInitiateAcked();
500
501 set_remote_description(new SessionDescription(accept.ClearContents(),
502 accept.transports,
503 accept.groups));
504 // Updating transport with TransportDescription.
505 PushdownTransportDescription(CS_REMOTE, CA_ANSWER, NULL);
506 MaybeEnableMuxingSupport(); // Enable transport channel mux if supported.
507 SetState(STATE_RECEIVEDACCEPT);
508
509 if (!OnRemoteCandidates(accept.transports, error))
510 return false;
511
512 return true;
513 }
514
515 bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) {
516 if (!CheckState(STATE_SENTINITIATE, error))
517 return false;
518
519 SetState(STATE_RECEIVEDREJECT);
520 return true;
521 }
522
523 bool Session::OnInfoMessage(const SessionMessage& msg) {
524 SignalInfoMessage(this, msg.action_elem);
525 return true;
526 }
527
528 bool Session::OnTerminateMessage(const SessionMessage& msg,
529 MessageError* error) {
530 SessionTerminate term;
531 if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error))
532 return false;
533
534 SignalReceivedTerminateReason(this, term.reason);
535 if (term.debug_reason != buzz::STR_EMPTY) {
536 LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason;
537 }
538
539 SetState(STATE_RECEIVEDTERMINATE);
540 return true;
541 }
542
543 bool Session::OnTransportInfoMessage(const SessionMessage& msg,
544 MessageError* error) {
545 TransportInfos tinfos;
546 if (!ParseTransportInfos(msg.protocol, msg.action_elem,
547 initiator_description()->contents(),
548 GetTransportParsers(), GetCandidateTranslators(),
549 &tinfos, error))
550 return false;
551
552 if (!OnRemoteCandidates(tinfos, error))
553 return false;
554
555 return true;
556 }
557
558 bool Session::OnTransportAcceptMessage(const SessionMessage& msg,
559 MessageError* error) {
560 // TODO: Currently here only for compatibility with
561 // Gingle 1.1 clients (notably, Google Voice).
562 return true;
563 }
564
565 bool Session::OnDescriptionInfoMessage(const SessionMessage& msg,
566 MessageError* error) {
567 if (!CheckState(STATE_INPROGRESS, error))
568 return false;
569
570 DescriptionInfo description_info;
571 if (!ParseDescriptionInfo(msg.protocol, msg.action_elem,
572 GetContentParsers(), GetTransportParsers(),
573 GetCandidateTranslators(),
574 &description_info, error)) {
575 return false;
576 }
577
578 ContentInfos& updated_contents = description_info.contents;
579
580 // TODO: Currently, reflector sends back
581 // video stream updates even for an audio-only call, which causes
582 // this to fail. Put this back once reflector is fixed.
583 //
584 // ContentInfos::iterator it;
585 // First, ensure all updates are valid before modifying remote_description_.
586 // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
587 // if (remote_description()->GetContentByName(it->name) == NULL) {
588 // return false;
589 // }
590 // }
591
592 // TODO: We used to replace contents from an update, but
593 // that no longer works with partial updates. We need to figure out
594 // a way to merge patial updates into contents. For now, users of
595 // Session should listen to SignalRemoteDescriptionUpdate and handle
596 // updates. They should not expect remote_description to be the
597 // latest value.
598 //
599 // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
600 // remote_description()->RemoveContentByName(it->name);
601 // remote_description()->AddContent(it->name, it->type, it->description);
602 // }
603 // }
604
605 SignalRemoteDescriptionUpdate(this, updated_contents);
606 return true;
607 }
608
609 bool BareJidsEqual(const std::string& name1,
610 const std::string& name2) {
611 buzz::Jid jid1(name1);
612 buzz::Jid jid2(name2);
613
614 return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2);
615 }
616
617 bool Session::OnRedirectError(const SessionRedirect& redirect,
618 SessionError* error) {
619 MessageError message_error;
620 if (!CheckState(STATE_SENTINITIATE, &message_error)) {
621 return BadWrite(message_error.text, error);
622 }
623
624 if (!BareJidsEqual(remote_name(), redirect.target))
625 return BadWrite("Redirection not allowed: must be the same bare jid.",
626 error);
627
628 // When we receive a redirect, we point the session at the new JID
629 // and resend the candidates.
630 set_remote_name(redirect.target);
631 return (SendInitiateMessage(local_description(), error) &&
632 ResendAllTransportInfoMessages(error));
633 }
634
635 bool Session::CheckState(State expected, MessageError* error) {
636 if (state() != expected) {
637 // The server can deliver messages out of order/repeated for various
638 // reasons. For example, if the server does not recive our iq response,
639 // it could assume that the iq it sent was lost, and will then send
640 // it again. Ideally, we should implement reliable messaging with
641 // duplicate elimination.
642 return BadMessage(buzz::QN_STANZA_NOT_ALLOWED,
643 "message not allowed in current state",
644 error);
645 }
646 return true;
647 }
648
649 void Session::SetError(Error error, const std::string& error_desc) {
650 BaseSession::SetError(error, error_desc);
651 if (error != ERROR_NONE)
652 signaling_thread()->Post(this, MSG_ERROR);
653 }
654
655 void Session::OnMessage(rtc::Message* pmsg) {
656 // preserve this because BaseSession::OnMessage may modify it
657 State orig_state = state();
658
659 BaseSession::OnMessage(pmsg);
660
661 switch (pmsg->message_id) {
662 case MSG_ERROR:
663 TerminateWithReason(STR_TERMINATE_ERROR);
664 break;
665
666 case MSG_STATE:
667 switch (orig_state) {
668 case STATE_SENTREJECT:
669 case STATE_RECEIVEDREJECT:
670 // Assume clean termination.
671 Terminate();
672 break;
673
674 case STATE_SENTTERMINATE:
675 case STATE_RECEIVEDTERMINATE:
676 session_manager_->DestroySession(this);
677 break;
678
679 default:
680 // Explicitly ignoring some states here.
681 break;
682 }
683 break;
684 }
685 }
686
687 bool Session::SendInitiateMessage(const SessionDescription* sdesc,
688 SessionError* error) {
689 SessionInitiate init;
690 init.contents = sdesc->contents();
691 init.transports = GetEmptyTransportInfos(init.contents);
692 init.groups = sdesc->groups();
693 return SendMessage(ACTION_SESSION_INITIATE, init, error);
694 }
695
696 bool Session::WriteSessionAction(
697 SignalingProtocol protocol, const SessionInitiate& init,
698 XmlElements* elems, WriteError* error) {
699 return WriteSessionInitiate(protocol, init.contents, init.transports,
700 GetContentParsers(), GetTransportParsers(),
701 GetCandidateTranslators(), init.groups,
702 elems, error);
703 }
704
705 bool Session::SendAcceptMessage(const SessionDescription* sdesc,
706 SessionError* error) {
707 XmlElements elems;
708 if (!WriteSessionAccept(current_protocol_,
709 sdesc->contents(),
710 GetEmptyTransportInfos(sdesc->contents()),
711 GetContentParsers(), GetTransportParsers(),
712 GetCandidateTranslators(), sdesc->groups(),
713 &elems, error)) {
714 return false;
715 }
716 return SendMessage(ACTION_SESSION_ACCEPT, elems, error);
717 }
718
719 bool Session::SendRejectMessage(const std::string& reason,
720 SessionError* error) {
721 SessionTerminate term(reason);
722 return SendMessage(ACTION_SESSION_REJECT, term, error);
723 }
724
725 bool Session::SendTerminateMessage(const std::string& reason,
726 SessionError* error) {
727 SessionTerminate term(reason);
728 return SendMessage(ACTION_SESSION_TERMINATE, term, error);
729 }
730
731 bool Session::WriteSessionAction(SignalingProtocol protocol,
732 const SessionTerminate& term,
733 XmlElements* elems, WriteError* error) {
734 WriteSessionTerminate(protocol, term, elems);
735 return true;
736 }
737
738 bool Session::SendTransportInfoMessage(const TransportInfo& tinfo,
739 SessionError* error) {
740 return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error);
741 }
742
743 bool Session::SendTransportInfoMessage(const TransportProxy* transproxy,
744 const Candidates& candidates,
745 SessionError* error) {
746 return SendTransportInfoMessage(TransportInfo(transproxy->content_name(),
747 TransportDescription(transproxy->type(), std::vector<std::string>(),
748 std::string(), std::string(), ICEMODE_FULL,
749 CONNECTIONROLE_NONE, NULL, candidates)), error);
750 }
751
752 bool Session::WriteSessionAction(SignalingProtocol protocol,
753 const TransportInfo& tinfo,
754 XmlElements* elems, WriteError* error) {
755 TransportInfos tinfos;
756 tinfos.push_back(tinfo);
757 return WriteTransportInfos(protocol, tinfos,
758 GetTransportParsers(), GetCandidateTranslators(),
759 elems, error);
760 }
761
762 bool Session::ResendAllTransportInfoMessages(SessionError* error) {
763 for (TransportMap::const_iterator iter = transport_proxies().begin();
764 iter != transport_proxies().end(); ++iter) {
765 TransportProxy* transproxy = iter->second;
766 if (transproxy->sent_candidates().size() > 0) {
767 if (!SendTransportInfoMessage(
768 transproxy, transproxy->sent_candidates(), error)) {
769 LOG(LS_ERROR) << "Could not resend transport info messages: "
770 << error->text;
771 return false;
772 }
773 transproxy->ClearSentCandidates();
774 }
775 }
776 return true;
777 }
778
779 bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) {
780 for (TransportMap::const_iterator iter = transport_proxies().begin();
781 iter != transport_proxies().end(); ++iter) {
782 TransportProxy* transproxy = iter->second;
783 if (transproxy->unsent_candidates().size() > 0) {
784 if (!SendTransportInfoMessage(
785 transproxy, transproxy->unsent_candidates(), error)) {
786 LOG(LS_ERROR) << "Could not send unsent transport info messages: "
787 << error->text;
788 return false;
789 }
790 transproxy->ClearUnsentCandidates();
791 }
792 }
793 return true;
794 }
795
796 bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
797 SessionError* error) {
798 return SendMessage(type, action_elems, remote_name(), error);
799 }
800
801 bool Session::SendMessage(ActionType type, const XmlElements& action_elems,
802 const std::string& remote_name, SessionError* error) {
803 rtc::scoped_ptr<buzz::XmlElement> stanza(
804 new buzz::XmlElement(buzz::QN_IQ));
805
806 SessionMessage msg(current_protocol_, type, id(), initiator_name());
807 msg.to = remote_name;
808 WriteSessionMessage(msg, action_elems, stanza.get());
809
810 SignalOutgoingMessage(this, stanza.get());
811 return true;
812 }
813
814 template <typename Action>
815 bool Session::SendMessage(ActionType type, const Action& action,
816 SessionError* error) {
817 rtc::scoped_ptr<buzz::XmlElement> stanza(
818 new buzz::XmlElement(buzz::QN_IQ));
819 if (!WriteActionMessage(type, action, stanza.get(), error))
820 return false;
821
822 SignalOutgoingMessage(this, stanza.get());
823 return true;
824 }
825
826 template <typename Action>
827 bool Session::WriteActionMessage(ActionType type, const Action& action,
828 buzz::XmlElement* stanza,
829 WriteError* error) {
830 if (current_protocol_ == PROTOCOL_HYBRID) {
831 if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error))
832 return false;
833 if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error))
834 return false;
835 } else {
836 if (!WriteActionMessage(current_protocol_, type, action, stanza, error))
837 return false;
838 }
839 return true;
840 }
841
842 template <typename Action>
843 bool Session::WriteActionMessage(SignalingProtocol protocol,
844 ActionType type, const Action& action,
845 buzz::XmlElement* stanza, WriteError* error) {
846 XmlElements action_elems;
847 if (!WriteSessionAction(protocol, action, &action_elems, error))
848 return false;
849
850 SessionMessage msg(protocol, type, id(), initiator_name());
851 msg.to = remote_name();
852
853 WriteSessionMessage(msg, action_elems, stanza);
854 return true;
855 }
856
857 void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) {
858 rtc::scoped_ptr<buzz::XmlElement> ack(
859 new buzz::XmlElement(buzz::QN_IQ));
860 ack->SetAttr(buzz::QN_TO, remote_name());
861 ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
862 ack->SetAttr(buzz::QN_TYPE, "result");
863
864 SignalOutgoingMessage(this, ack.get());
865 }
866
867 SessionManager::SessionManager(PortAllocator *allocator,
868 rtc::Thread *worker) {
869 allocator_ = allocator;
870 signaling_thread_ = rtc::Thread::Current();
871 if (worker == NULL) {
872 worker_thread_ = rtc::Thread::Current();
873 } else {
874 worker_thread_ = worker;
875 }
876 timeout_ = 50;
877 }
878
879 SessionManager::~SessionManager() {
880 // Note: Session::Terminate occurs asynchronously, so it's too late to
881 // delete them now. They better be all gone.
882 ASSERT(session_map_.empty());
883 // TerminateAll();
884 SignalDestroyed();
885 }
886
887 void SessionManager::AddClient(const std::string& content_type,
888 SessionClient* client) {
889 ASSERT(client_map_.find(content_type) == client_map_.end());
890 client_map_[content_type] = client;
891 }
892
893 void SessionManager::RemoveClient(const std::string& content_type) {
894 ClientMap::iterator iter = client_map_.find(content_type);
895 ASSERT(iter != client_map_.end());
896 client_map_.erase(iter);
897 }
898
899 SessionClient* SessionManager::GetClient(const std::string& content_type) {
900 ClientMap::iterator iter = client_map_.find(content_type);
901 return (iter != client_map_.end()) ? iter->second : NULL;
902 }
903
904 Session* SessionManager::CreateSession(const std::string& local_name,
905 const std::string& content_type) {
906 std::string id;
907 return CreateSession(id, local_name, content_type);
908 }
909
910 Session* SessionManager::CreateSession(const std::string& id,
911 const std::string& local_name,
912 const std::string& content_type) {
913 std::string sid =
914 id.empty() ? rtc::ToString(rtc::CreateRandomId64()) : id;
915 return CreateSession(local_name, local_name, sid, content_type, false);
916 }
917
918 Session* SessionManager::CreateSession(
919 const std::string& local_name, const std::string& initiator_name,
920 const std::string& sid, const std::string& content_type,
921 bool received_initiate) {
922 SessionClient* client = GetClient(content_type);
923 ASSERT(client != NULL);
924
925 Session* session = new Session(this, local_name, initiator_name,
926 sid, content_type, client);
927 session->SetIdentity(transport_desc_factory_.identity());
928 session_map_[session->id()] = session;
929 session->SignalRequestSignaling.connect(
930 this, &SessionManager::OnRequestSignaling);
931 session->SignalOutgoingMessage.connect(
932 this, &SessionManager::OnOutgoingMessage);
933 session->SignalErrorMessage.connect(this, &SessionManager::OnErrorMessage);
934 SignalSessionCreate(session, received_initiate);
935 session->client()->OnSessionCreate(session, received_initiate);
936 return session;
937 }
938
939 void SessionManager::DestroySession(Session* session) {
940 if (session != NULL) {
941 SessionMap::iterator it = session_map_.find(session->id());
942 if (it != session_map_.end()) {
943 SignalSessionDestroy(session);
944 session->client()->OnSessionDestroy(session);
945 session_map_.erase(it);
946 delete session;
947 }
948 }
949 }
950
951 Session* SessionManager::GetSession(const std::string& sid) {
952 SessionMap::iterator it = session_map_.find(sid);
953 if (it != session_map_.end())
954 return it->second;
955 return NULL;
956 }
957
958 void SessionManager::TerminateAll() {
959 while (session_map_.begin() != session_map_.end()) {
960 Session* session = session_map_.begin()->second;
961 session->Terminate();
962 }
963 }
964
965 bool SessionManager::IsSessionMessage(const buzz::XmlElement* stanza) {
966 return cricket::IsSessionMessage(stanza);
967 }
968
969 Session* SessionManager::FindSession(const std::string& sid,
970 const std::string& remote_name) {
971 SessionMap::iterator iter = session_map_.find(sid);
972 if (iter == session_map_.end())
973 return NULL;
974
975 Session* session = iter->second;
976 if (buzz::Jid(remote_name) != buzz::Jid(session->remote_name()))
977 return NULL;
978
979 return session;
980 }
981
982 void SessionManager::OnIncomingMessage(const buzz::XmlElement* stanza) {
983 SessionMessage msg;
984 ParseError error;
985
986 if (!ParseSessionMessage(stanza, &msg, &error)) {
987 SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
988 error.text, NULL);
989 return;
990 }
991
992 Session* session = FindSession(msg.sid, msg.from);
993 if (session) {
994 session->OnIncomingMessage(msg);
995 return;
996 }
997 if (msg.type != ACTION_SESSION_INITIATE) {
998 SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
999 "unknown session", NULL);
1000 return;
1001 }
1002
1003 std::string content_type;
1004 if (!ParseContentType(msg.protocol, msg.action_elem,
1005 &content_type, &error)) {
1006 SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
1007 error.text, NULL);
1008 return;
1009 }
1010
1011 if (!GetClient(content_type)) {
1012 SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify",
1013 "unknown content type: " + content_type, NULL);
1014 return;
1015 }
1016
1017 session = CreateSession(msg.to, msg.initiator, msg.sid,
1018 content_type, true);
1019 session->OnIncomingMessage(msg);
1020 }
1021
1022 void SessionManager::OnIncomingResponse(const buzz::XmlElement* orig_stanza,
1023 const buzz::XmlElement* response_stanza) {
1024 if (orig_stanza == NULL || response_stanza == NULL) {
1025 return;
1026 }
1027
1028 SessionMessage msg;
1029 ParseError error;
1030 if (!ParseSessionMessage(orig_stanza, &msg, &error)) {
1031 LOG(LS_WARNING) << "Error parsing incoming response: " << error.text
1032 << ":" << orig_stanza;
1033 return;
1034 }
1035
1036 Session* session = FindSession(msg.sid, msg.to);
1037 if (!session) {
1038 // Also try the QN_FROM in the response stanza, in case we sent the request
1039 // to a bare JID but got the response from a full JID.
1040 std::string ack_from = response_stanza->Attr(buzz::QN_FROM);
1041 session = FindSession(msg.sid, ack_from);
1042 }
1043 if (session) {
1044 session->OnIncomingResponse(orig_stanza, response_stanza, msg);
1045 }
1046 }
1047
1048 void SessionManager::OnFailedSend(const buzz::XmlElement* orig_stanza,
1049 const buzz::XmlElement* error_stanza) {
1050 SessionMessage msg;
1051 ParseError error;
1052 if (!ParseSessionMessage(orig_stanza, &msg, &error)) {
1053 return; // TODO: log somewhere?
1054 }
1055
1056 Session* session = FindSession(msg.sid, msg.to);
1057 if (session) {
1058 rtc::scoped_ptr<buzz::XmlElement> synthetic_error;
1059 if (!error_stanza) {
1060 // A failed send is semantically equivalent to an error response, so we
1061 // can just turn the former into the latter.
1062 synthetic_error.reset(
1063 CreateErrorMessage(orig_stanza, buzz::QN_STANZA_ITEM_NOT_FOUND,
1064 "cancel", "Recipient did not respond", NULL));
1065 error_stanza = synthetic_error.get();
1066 }
1067
1068 session->OnFailedSend(orig_stanza, error_stanza);
1069 }
1070 }
1071
1072 void SessionManager::SendErrorMessage(const buzz::XmlElement* stanza,
1073 const buzz::QName& name,
1074 const std::string& type,
1075 const std::string& text,
1076 const buzz::XmlElement* extra_info) {
1077 rtc::scoped_ptr<buzz::XmlElement> msg(
1078 CreateErrorMessage(stanza, name, type, text, extra_info));
1079 SignalOutgoingMessage(this, msg.get());
1080 }
1081
1082 buzz::XmlElement* SessionManager::CreateErrorMessage(
1083 const buzz::XmlElement* stanza,
1084 const buzz::QName& name,
1085 const std::string& type,
1086 const std::string& text,
1087 const buzz::XmlElement* extra_info) {
1088 buzz::XmlElement* iq = new buzz::XmlElement(buzz::QN_IQ);
1089 iq->SetAttr(buzz::QN_TO, stanza->Attr(buzz::QN_FROM));
1090 iq->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID));
1091 iq->SetAttr(buzz::QN_TYPE, "error");
1092
1093 CopyXmlChildren(stanza, iq);
1094
1095 buzz::XmlElement* error = new buzz::XmlElement(buzz::QN_ERROR);
1096 error->SetAttr(buzz::QN_TYPE, type);
1097 iq->AddElement(error);
1098
1099 // If the error name is not in the standard namespace, we have to first add
1100 // some error from that namespace.
1101 if (name.Namespace() != buzz::NS_STANZA) {
1102 error->AddElement(
1103 new buzz::XmlElement(buzz::QN_STANZA_UNDEFINED_CONDITION));
1104 }
1105 error->AddElement(new buzz::XmlElement(name));
1106
1107 if (extra_info)
1108 error->AddElement(new buzz::XmlElement(*extra_info));
1109
1110 if (text.size() > 0) {
1111 // It's okay to always use English here. This text is for debugging
1112 // purposes only.
1113 buzz::XmlElement* text_elem = new buzz::XmlElement(buzz::QN_STANZA_TEXT);
1114 text_elem->SetAttr(buzz::QN_XML_LANG, "en");
1115 text_elem->SetBodyText(text);
1116 error->AddElement(text_elem);
1117 }
1118
1119 // TODO: Should we include error codes as well for SIP compatibility?
1120
1121 return iq;
1122 }
1123
1124 void SessionManager::OnOutgoingMessage(Session* session,
1125 const buzz::XmlElement* stanza) {
1126 SignalOutgoingMessage(this, stanza);
1127 }
1128
1129 void SessionManager::OnErrorMessage(BaseSession* session,
1130 const buzz::XmlElement* stanza,
1131 const buzz::QName& name,
1132 const std::string& type,
1133 const std::string& text,
1134 const buzz::XmlElement* extra_info) {
1135 SendErrorMessage(stanza, name, type, text, extra_info);
1136 }
1137
1138 void SessionManager::OnSignalingReady() {
1139 for (SessionMap::iterator it = session_map_.begin();
1140 it != session_map_.end();
1141 ++it) {
1142 it->second->OnSignalingReady();
1143 }
1144 }
1145
1146 void SessionManager::OnRequestSignaling(Session* session) {
1147 SignalRequestSignaling();
1148 }
1149
1150 } // namespace cricket
OLDNEW
« no previous file with comments | « webrtc/libjingle/session/sessionmanager.h ('k') | webrtc/libjingle/session/sessionmanagertask.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698