| Index: talk/app/webrtc/webrtcsessiondescriptionfactory.cc
 | 
| diff --git a/talk/app/webrtc/webrtcsessiondescriptionfactory.cc b/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
 | 
| index 6c6981ce5a9987e12f185cc4b351bb105d438bbf..4336372b5707211c5fd53beebde2f937fe6115e8 100644
 | 
| --- a/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
 | 
| +++ b/talk/app/webrtc/webrtcsessiondescriptionfactory.cc
 | 
| @@ -68,7 +68,8 @@ static bool ValidStreams(const MediaSessionOptions::Streams& streams) {
 | 
|  
 | 
|  enum {
 | 
|    MSG_CREATE_SESSIONDESCRIPTION_SUCCESS,
 | 
| -  MSG_CREATE_SESSIONDESCRIPTION_FAILED
 | 
| +  MSG_CREATE_SESSIONDESCRIPTION_FAILED,
 | 
| +  MSG_USE_CONSTRUCTOR_CERTIFICATE
 | 
|  };
 | 
|  
 | 
|  struct CreateSessionDescriptionMsg : public rtc::MessageData {
 | 
| @@ -126,11 +127,14 @@ void WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
 | 
|    }
 | 
|  }
 | 
|  
 | 
| +// Private constructor called by other constructors.
 | 
|  WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
 | 
|      rtc::Thread* signaling_thread,
 | 
|      cricket::ChannelManager* channel_manager,
 | 
|      MediaStreamSignaling* mediastream_signaling,
 | 
|      rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
 | 
| +    const rtc::scoped_refptr<WebRtcIdentityRequestObserver>&
 | 
| +        identity_request_observer,
 | 
|      WebRtcSession* session,
 | 
|      const std::string& session_id,
 | 
|      cricket::DataChannelType dct,
 | 
| @@ -144,31 +148,87 @@ WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
 | 
|        // |kInitSessionVersion|.
 | 
|        session_version_(kInitSessionVersion),
 | 
|        dtls_identity_store_(dtls_identity_store.Pass()),
 | 
| +      identity_request_observer_(identity_request_observer),
 | 
|        session_(session),
 | 
|        session_id_(session_id),
 | 
|        data_channel_type_(dct),
 | 
| -      identity_request_state_(IDENTITY_NOT_NEEDED) {
 | 
| +      certificate_request_state_(CERTIFICATE_NOT_NEEDED) {
 | 
|    session_desc_factory_.set_add_legacy_streams(false);
 | 
|    // SRTP-SDES is disabled if DTLS is on.
 | 
|    SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED);
 | 
| +}
 | 
|  
 | 
| -  // If |dtls_enabled| we must have a |dtls_identity_store_|.
 | 
| -  DCHECK(!dtls_enabled || dtls_identity_store_);
 | 
| -
 | 
| -  if (dtls_enabled && dtls_identity_store_) {
 | 
| -    identity_request_observer_ =
 | 
| -      new rtc::RefCountedObject<WebRtcIdentityRequestObserver>();
 | 
| +WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
 | 
| +    rtc::Thread* signaling_thread,
 | 
| +    cricket::ChannelManager* channel_manager,
 | 
| +    MediaStreamSignaling* mediastream_signaling,
 | 
| +    WebRtcSession* session,
 | 
| +    const std::string& session_id,
 | 
| +    cricket::DataChannelType dct)
 | 
| +    : WebRtcSessionDescriptionFactory(
 | 
| +        signaling_thread, channel_manager, mediastream_signaling, nullptr,
 | 
| +        nullptr, session, session_id, dct, false) {
 | 
| +  LOG(LS_VERBOSE) << "DTLS-SRTP disabled.";
 | 
| +}
 | 
|  
 | 
| -    identity_request_observer_->SignalRequestFailed.connect(
 | 
| -        this, &WebRtcSessionDescriptionFactory::OnIdentityRequestFailed);
 | 
| -    identity_request_observer_->SignalIdentityReady.connect(
 | 
| -        this, &WebRtcSessionDescriptionFactory::SetIdentity);
 | 
| +WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
 | 
| +    rtc::Thread* signaling_thread,
 | 
| +    cricket::ChannelManager* channel_manager,
 | 
| +    MediaStreamSignaling* mediastream_signaling,
 | 
| +    rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
 | 
| +    WebRtcSession* session,
 | 
| +    const std::string& session_id,
 | 
| +    cricket::DataChannelType dct)
 | 
| +    : WebRtcSessionDescriptionFactory(
 | 
| +        signaling_thread,
 | 
| +        channel_manager,
 | 
| +        mediastream_signaling,
 | 
| +        dtls_identity_store.Pass(),
 | 
| +        new rtc::RefCountedObject<WebRtcIdentityRequestObserver>(),
 | 
| +        session,
 | 
| +        session_id,
 | 
| +        dct,
 | 
| +        true) {
 | 
| +  DCHECK(dtls_identity_store_);
 | 
| +
 | 
| +  certificate_request_state_ = CERTIFICATE_WAITING;
 | 
| +
 | 
| +  identity_request_observer_->SignalRequestFailed.connect(
 | 
| +      this, &WebRtcSessionDescriptionFactory::OnIdentityRequestFailed);
 | 
| +  identity_request_observer_->SignalIdentityReady.connect(
 | 
| +      this, &WebRtcSessionDescriptionFactory::SetIdentity);
 | 
| +
 | 
| +  rtc::KeyType key_type = rtc::KT_DEFAULT;
 | 
| +  LOG(LS_VERBOSE) << "DTLS-SRTP enabled; sending DTLS identity request (key "
 | 
| +                  << "type: " << key_type << ").";
 | 
| +
 | 
| +  // Request identity. This happens asynchronously, so the caller will have a
 | 
| +  // chance to connect to SignalIdentityReady.
 | 
| +  dtls_identity_store_->RequestIdentity(key_type, identity_request_observer_);
 | 
| +}
 | 
|  
 | 
| -    LOG(LS_VERBOSE) << "DTLS-SRTP enabled; sending DTLS identity request.";
 | 
| -    identity_request_state_ = IDENTITY_WAITING;
 | 
| -    dtls_identity_store_->RequestIdentity(rtc::KT_DEFAULT,
 | 
| -                                          identity_request_observer_);
 | 
| -  }
 | 
| +WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
 | 
| +    rtc::Thread* signaling_thread,
 | 
| +    cricket::ChannelManager* channel_manager,
 | 
| +    MediaStreamSignaling* mediastream_signaling,
 | 
| +    const rtc::scoped_refptr<rtc::RTCCertificate>& certificate,
 | 
| +    WebRtcSession* session,
 | 
| +    const std::string& session_id,
 | 
| +    cricket::DataChannelType dct)
 | 
| +    : WebRtcSessionDescriptionFactory(
 | 
| +        signaling_thread, channel_manager, mediastream_signaling, nullptr,
 | 
| +        nullptr, session, session_id, dct, true) {
 | 
| +  DCHECK(certificate);
 | 
| +
 | 
| +  certificate_request_state_ = CERTIFICATE_WAITING;
 | 
| +
 | 
| +  LOG(LS_VERBOSE) << "DTLS-SRTP enabled; has certificate parameter.";
 | 
| +  // We already have a certificate but we wait to do SetIdentity; if we do
 | 
| +  // it in the constructor then the caller has not had a chance to connect to
 | 
| +  // SignalIdentityReady.
 | 
| +  signaling_thread_->Post(this, MSG_USE_CONSTRUCTOR_CERTIFICATE,
 | 
| +                          new rtc::ScopedRefMessageData<rtc::RTCCertificate>(
 | 
| +                              certificate));
 | 
|  }
 | 
|  
 | 
|  WebRtcSessionDescriptionFactory::~WebRtcSessionDescriptionFactory() {
 | 
| @@ -181,8 +241,19 @@ WebRtcSessionDescriptionFactory::~WebRtcSessionDescriptionFactory() {
 | 
|    // this, requests will linger and not know they succeeded or failed.
 | 
|    rtc::MessageList list;
 | 
|    signaling_thread_->Clear(this, rtc::MQID_ANY, &list);
 | 
| -  for (auto& msg : list)
 | 
| -    OnMessage(&msg);
 | 
| +  for (auto& msg : list) {
 | 
| +    if (msg.message_id != MSG_USE_CONSTRUCTOR_CERTIFICATE) {
 | 
| +      OnMessage(&msg);
 | 
| +    } else {
 | 
| +      // Skip MSG_USE_CONSTRUCTOR_CERTIFICATE because we don't want to trigger
 | 
| +      // SetIdentity-related callbacks in the destructor. This can be a problem
 | 
| +      // when WebRtcSession listens to the callback but it was the WebRtcSession
 | 
| +      // destructor that caused WebRtcSessionDescriptionFactory's destruction.
 | 
| +      // The callback is then ignored, leaking memory allocated by OnMessage for
 | 
| +      // MSG_USE_CONSTRUCTOR_CERTIFICATE.
 | 
| +      delete msg.pdata;
 | 
| +    }
 | 
| +  }
 | 
|  
 | 
|    transport_desc_factory_.set_identity(NULL);
 | 
|  }
 | 
| @@ -193,7 +264,7 @@ void WebRtcSessionDescriptionFactory::CreateOffer(
 | 
|    cricket::MediaSessionOptions session_options;
 | 
|  
 | 
|    std::string error = "CreateOffer";
 | 
| -  if (identity_request_state_ == IDENTITY_FAILED) {
 | 
| +  if (certificate_request_state_ == CERTIFICATE_FAILED) {
 | 
|      error += kFailedDueToIdentityFailed;
 | 
|      LOG(LS_ERROR) << error;
 | 
|      PostCreateSessionDescriptionFailed(observer, error);
 | 
| @@ -222,11 +293,11 @@ void WebRtcSessionDescriptionFactory::CreateOffer(
 | 
|  
 | 
|    CreateSessionDescriptionRequest request(
 | 
|        CreateSessionDescriptionRequest::kOffer, observer, session_options);
 | 
| -  if (identity_request_state_ == IDENTITY_WAITING) {
 | 
| +  if (certificate_request_state_ == CERTIFICATE_WAITING) {
 | 
|      create_session_description_requests_.push(request);
 | 
|    } else {
 | 
| -    ASSERT(identity_request_state_ == IDENTITY_SUCCEEDED ||
 | 
| -           identity_request_state_ == IDENTITY_NOT_NEEDED);
 | 
| +    ASSERT(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
 | 
| +           certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
 | 
|      InternalCreateOffer(request);
 | 
|    }
 | 
|  }
 | 
| @@ -235,7 +306,7 @@ void WebRtcSessionDescriptionFactory::CreateAnswer(
 | 
|      CreateSessionDescriptionObserver* observer,
 | 
|      const MediaConstraintsInterface* constraints) {
 | 
|    std::string error = "CreateAnswer";
 | 
| -  if (identity_request_state_ == IDENTITY_FAILED) {
 | 
| +  if (certificate_request_state_ == CERTIFICATE_FAILED) {
 | 
|      error += kFailedDueToIdentityFailed;
 | 
|      LOG(LS_ERROR) << error;
 | 
|      PostCreateSessionDescriptionFailed(observer, error);
 | 
| @@ -277,11 +348,11 @@ void WebRtcSessionDescriptionFactory::CreateAnswer(
 | 
|  
 | 
|    CreateSessionDescriptionRequest request(
 | 
|        CreateSessionDescriptionRequest::kAnswer, observer, options);
 | 
| -  if (identity_request_state_ == IDENTITY_WAITING) {
 | 
| +  if (certificate_request_state_ == CERTIFICATE_WAITING) {
 | 
|      create_session_description_requests_.push(request);
 | 
|    } else {
 | 
| -    ASSERT(identity_request_state_ == IDENTITY_SUCCEEDED ||
 | 
| -           identity_request_state_ == IDENTITY_NOT_NEEDED);
 | 
| +    ASSERT(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
 | 
| +           certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
 | 
|      InternalCreateAnswer(request);
 | 
|    }
 | 
|  }
 | 
| @@ -311,6 +382,17 @@ void WebRtcSessionDescriptionFactory::OnMessage(rtc::Message* msg) {
 | 
|        delete param;
 | 
|        break;
 | 
|      }
 | 
| +    case MSG_USE_CONSTRUCTOR_CERTIFICATE: {
 | 
| +      rtc::ScopedRefMessageData<rtc::RTCCertificate>* param =
 | 
| +          static_cast<rtc::ScopedRefMessageData<rtc::RTCCertificate>*>(
 | 
| +              msg->pdata);
 | 
| +      LOG(LS_INFO) << "Using certificate supplied to the constructor.";
 | 
| +      // TODO(hbos): Pass around scoped_refptr<RTCCertificate> instead of
 | 
| +      // SSLIdentity* (then there will be no need to do GetReference here).
 | 
| +      SetIdentity(param->data()->identity()->GetReference());
 | 
| +      delete param;
 | 
| +      break;
 | 
| +    }
 | 
|      default:
 | 
|        ASSERT(false);
 | 
|        break;
 | 
| @@ -429,7 +511,7 @@ void WebRtcSessionDescriptionFactory::OnIdentityRequestFailed(int error) {
 | 
|    ASSERT(signaling_thread_->IsCurrent());
 | 
|  
 | 
|    LOG(LS_ERROR) << "Async identity request failed: error = " << error;
 | 
| -  identity_request_state_ = IDENTITY_FAILED;
 | 
| +  certificate_request_state_ = CERTIFICATE_FAILED;
 | 
|  
 | 
|    FailPendingRequests(kFailedDueToIdentityFailed);
 | 
|  }
 | 
| @@ -438,7 +520,7 @@ void WebRtcSessionDescriptionFactory::SetIdentity(
 | 
|      rtc::SSLIdentity* identity) {
 | 
|    LOG(LS_VERBOSE) << "Setting new identity";
 | 
|  
 | 
| -  identity_request_state_ = IDENTITY_SUCCEEDED;
 | 
| +  certificate_request_state_ = CERTIFICATE_SUCCEEDED;
 | 
|    SignalIdentityReady(identity);
 | 
|  
 | 
|    transport_desc_factory_.set_identity(identity);
 | 
| 
 |