📄 session.cc
字号:
error_type = error->Attr(buzz::QN_TYPE); LOG(LERROR) << "Session error:\n" << error->Str() << "\n" << "in response to:\n" << orig_session->Str(); } bool fatal_error = false; ASSERT(orig_session->HasAttr(buzz::QN_TYPE)); if ((orig_session->Attr(buzz::QN_TYPE) == "transport-info") || (orig_session->Attr(buzz::QN_TYPE) == "candidates")) { // Transport messages frequently generate errors because they are sent right // when we detect a network failure. For that reason, we ignore such // errors, because if we do not establish writability again, we will // terminate anyway. The exceptions are transport-specific error tags, // which we pass on to the respective transport. for (const buzz::XmlElement* elem = error->FirstElement(); NULL != elem; elem = elem->NextElement()) { if (Transport* transport = GetTransport(elem->Name().Namespace())) { if (!transport->OnTransportError(orig_session, elem)) { fatal_error = true; break; } } } } else if ((error_type != "continue") && (error_type != "wait")) { // We do not set an error if the other side said it is okay to continue // (possibly after waiting). These errors can be ignored. fatal_error = true; } if (fatal_error) { SetError(ERROR_RESPONSE); }}bool Session::OnInitiateMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { if (!CheckState(stanza, STATE_INIT)) return false; if (!FindRemoteSessionDescription(stanza, session)) return false; initiator_ = false; remote_name_ = stanza->Attr(buzz::QN_FROM); SetState(STATE_RECEIVEDINITIATE); return true;}bool Session::OnAcceptMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { if (!CheckState(stanza, STATE_SENTINITIATE)) return false; if (!FindRemoteSessionDescription(stanza, session)) return false; SetState(STATE_RECEIVEDACCEPT); return true;}bool Session::OnRejectMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { if (!CheckState(stanza, STATE_SENTINITIATE)) return false; SetState(STATE_RECEIVEDREJECT); return true;}bool Session::OnRedirectMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { if (!CheckState(stanza, STATE_SENTINITIATE)) return false; const buzz::XmlElement *redirect_target; if (!FindRequiredElement(stanza, session, QN_REDIRECT_TARGET, &redirect_target)) return false; if (!FindRequiredAttribute(stanza, redirect_target, buzz::QN_NAME, &remote_name_)) return false; const buzz::XmlElement* redirect_cookie = session->FirstNamed(QN_REDIRECT_COOKIE); XmlElements elems; elems.push_back(client_->TranslateSessionDescription(description_)); if (redirect_cookie) elems.push_back(new buzz::XmlElement(*redirect_cookie)); SendSessionMessage("initiate", elems); // Clear the connection timeout (if any). We will start the connection // timer from scratch when SignalConnecting fires. session_manager_->signaling_thread()->Clear(this, MSG_TIMEOUT); // Reset all of the sockets back into the initial state. for (TransportList::iterator iter = potential_transports_.begin(); iter != potential_transports_.end(); ++iter) { (*iter)->ResetChannels(); } ConnectDefaultTransportChannels(false); return true;}bool Session::OnInfoMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { XmlElements elems; for (const buzz::XmlElement* elem = session->FirstElement(); elem != NULL; elem = elem->NextElement()) { elems.push_back(new buzz::XmlElement(*elem)); } SignalInfoMessage(this, elems); return true;}bool Session::OnTransportAcceptMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { if (!CheckState(stanza, STATE_SENTINITIATE)) return false; Transport* transport = NULL; const buzz::XmlElement* transport_elem = NULL; for(const buzz::XmlElement* elem = session->FirstElement(); elem != NULL; elem = elem->NextElement()) { if (elem->Name().LocalPart() == "transport") { Transport* transport = GetTransport(elem->Name().Namespace()); if (transport) { if (transport_elem) { // trying to accept two transport? SignalErrorMessage(this, stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", "transport-accept has two answers", NULL); return false; } transport_elem = elem; if (!transport->OnTransportAnswer(transport_elem)) { SignalErrorMessage(this, stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", "transport-accept is not acceptable", NULL); return false; } SetTransport(transport); } } } if (!transport_elem) { SignalErrorMessage(this, stanza, buzz::QN_STANZA_NOT_ALLOWED, "modify", "no supported transport in answer", NULL); return false; } // If we discovered that we need compatibility mode and we have sent some // candidates already (using transport-info), then we need to re-send them // using the candidates message. if (compatibility_mode_ && (candidates_.size() > 0)) { ASSERT(transport_ != NULL); ASSERT(transport_->name() == kNsP2pTransport); OnTransportSendMessage(transport_, candidates_); } else { for (size_t i = 0; i < candidates_.size(); ++i) delete candidates_[i]; } candidates_.clear(); return true;}bool Session::OnTransportInfoMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { for(const buzz::XmlElement* elem = session->FirstElement(); elem != NULL; elem = elem->NextElement()) { if (elem->Name().LocalPart() == "transport") { Transport* transport = GetTransport(elem->Name().Namespace()); if (transport) { if (!transport->OnTransportMessage(elem, stanza)) return false; } } } return true;}bool Session::OnTerminateMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { for (const buzz::XmlElement *elem = session->FirstElement(); elem != NULL; elem = elem->NextElement()) { // elem->Name().LocalPart() is the reason for termination SignalReceivedTerminateReason(this, elem->Name().LocalPart()); // elem->FirstElement() might contain a debug string for termination const buzz::XmlElement *debugElement = elem->FirstElement(); if (debugElement != NULL) { LOG(LS_VERBOSE) << "Received error on call: " << debugElement->Name().LocalPart(); } } SetState(STATE_RECEIVEDTERMINATE); return true;}bool Session::OnCandidatesMessage(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { // If we don't have a transport, then this is the first candidates message. // We first create a fake transport-accept message in order to finish the // negotiation and create a transport. if (!transport_) { compatibility_mode_ = true; scoped_ptr<buzz::XmlElement> transport_accept( new buzz::XmlElement(QN_SESSION)); transport_accept->SetAttr(buzz::QN_TYPE, "transport-accept"); buzz::XmlElement* transport_offer = new buzz::XmlElement(kQnP2pTransport, true); transport_accept->AddElement(transport_offer); // It is okay to pass the original stanza here. That is only used if we // send an error message. Normal processing looks only at transport_accept. bool valid = OnTransportAcceptMessage(stanza, transport_accept.get()); ASSERT(valid); } ASSERT(transport_ != NULL); ASSERT(transport_->name() == kNsP2pTransport); // Wrap the candidates in a transport element as they would appear in a // transport-info message and send this to the transport. scoped_ptr<buzz::XmlElement> transport_info( new buzz::XmlElement(kQnP2pTransport, true)); for (const buzz::XmlElement* elem = session->FirstNamed(kQnLegacyCandidate); elem != NULL; elem = elem->NextNamed(kQnLegacyCandidate)) { buzz::XmlElement* new_candidate = new buzz::XmlElement(*elem); new_candidate->SetName(kQnP2pCandidate); transport_info->AddElement(new_candidate); } return transport_->OnTransportMessage(transport_info.get(), stanza);}bool Session::CheckState(const buzz::XmlElement* stanza, State state) { ASSERT(state_ == state); if (state_ != state) { SignalErrorMessage(this, stanza, buzz::QN_STANZA_NOT_ALLOWED, "modify", "message not allowed in current state", NULL); return false; } return true;}bool Session::FindRequiredElement(const buzz::XmlElement* stanza, const buzz::XmlElement* parent, const buzz::QName& name, const buzz::XmlElement** elem) { *elem = parent->FirstNamed(name); if (*elem == NULL) { std::string text; text += "element '" + parent->Name().Merged() + "' missing required child '" + name.Merged() + "'"; SignalErrorMessage(this, stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", text, NULL); return false; } return true;}bool Session::FindRemoteSessionDescription(const buzz::XmlElement* stanza, const buzz::XmlElement* session) { buzz::QName qn_session(session_type_, "description"); const buzz::XmlElement* desc; if (!FindRequiredElement(stanza, session, qn_session, &desc)) return false; remote_description_ = client_->CreateSessionDescription(desc); return true;}bool Session::FindRequiredAttribute(const buzz::XmlElement* stanza, const buzz::XmlElement* elem, const buzz::QName& name, std::string* value) { if (!elem->HasAttr(name)) { std::string text; text += "element '" + elem->Name().Merged() + "' missing required attribute '" + name.Merged() + "'"; SignalErrorMessage(this, stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", text, NULL); return false; } else { *value = elem->Attr(name); return true; }}void Session::OnMessage(talk_base::Message *pmsg) { switch(pmsg->message_id) { case MSG_TIMEOUT: // Session timeout has occured. SetError(ERROR_TIME); break; case MSG_ERROR: // Any of the defined errors is most likely fatal. Terminate(); break; case MSG_STATE: switch (state_) { case STATE_SENTACCEPT: case STATE_RECEIVEDACCEPT: SetState(STATE_INPROGRESS); ASSERT(transport_ != NULL); break; case STATE_SENTREJECT: case STATE_SENTREDIRECT: case STATE_RECEIVEDREJECT: Terminate(); break; case STATE_SENTTERMINATE: case STATE_RECEIVEDTERMINATE: session_manager_->DestroySession(this); break; default: // Explicitly ignoring some states here. break; } break; }}} // namespace cricket
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -