Allow DtlsTransport::Information() to be called off-thread

Bug: chromium:907849
Change-Id: I7e89aa21f26cbd858fa9845375681e5e6781fece
Reviewed-on: https://webrtc-review.googlesource.com/c/122503
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26686}
This commit is contained in:
Harald Alvestrand
2019-02-13 19:40:11 +01:00
committed by Commit Bot
parent 068fc359e5
commit 69fb6c8510
3 changed files with 56 additions and 27 deletions

View File

@ -55,15 +55,16 @@ class DtlsTransportObserverInterface {
}; };
// A DTLS transport, as represented to the outside world. // A DTLS transport, as represented to the outside world.
// This object is created on the signaling thread, and can only be // This object is created on the network thread, and can only be
// accessed on that thread. // accessed on that thread, except for functions explicitly marked otherwise.
// References can be held by other threads, and destruction can therefore // References can be held by other threads, and destruction can therefore
// be initiated by other threads. // be initiated by other threads.
class DtlsTransportInterface : public rtc::RefCountInterface { class DtlsTransportInterface : public rtc::RefCountInterface {
public: public:
// Returns a pointer to the ICE transport that is owned by the DTLS transport. // Returns a pointer to the ICE transport that is owned by the DTLS transport.
virtual rtc::scoped_refptr<IceTransportInterface> ice_transport() = 0; virtual rtc::scoped_refptr<IceTransportInterface> ice_transport() = 0;
// These functions can only be called from the signalling thread. // Returns information on the state of the DtlsTransport.
// This function can be called from other threads.
virtual DtlsTransportInformation Information() = 0; virtual DtlsTransportInformation Information() = 0;
// Observer management. // Observer management.
virtual void RegisterObserver(DtlsTransportObserverInterface* observer) = 0; virtual void RegisterObserver(DtlsTransportObserverInterface* observer) = 0;

View File

@ -43,69 +43,86 @@ DtlsTransportState TranslateState(cricket::DtlsTransportState internal_state) {
// Implementation of DtlsTransportInterface // Implementation of DtlsTransportInterface
DtlsTransport::DtlsTransport( DtlsTransport::DtlsTransport(
std::unique_ptr<cricket::DtlsTransportInternal> internal) std::unique_ptr<cricket::DtlsTransportInternal> internal)
: signaling_thread_(rtc::Thread::Current()), : owner_thread_(rtc::Thread::Current()),
info_(DtlsTransportState::kNew),
internal_dtls_transport_(std::move(internal)) { internal_dtls_transport_(std::move(internal)) {
RTC_DCHECK(internal_dtls_transport_.get()); RTC_DCHECK(internal_dtls_transport_.get());
internal_dtls_transport_->SignalDtlsState.connect( internal_dtls_transport_->SignalDtlsState.connect(
this, &DtlsTransport::OnInternalDtlsState); this, &DtlsTransport::OnInternalDtlsState);
ice_transport_ = new rtc::RefCountedObject<IceTransportWithPointer>( ice_transport_ = new rtc::RefCountedObject<IceTransportWithPointer>(
internal_dtls_transport_->ice_transport()); internal_dtls_transport_->ice_transport());
UpdateInformation();
} }
DtlsTransport::~DtlsTransport() { DtlsTransport::~DtlsTransport() {
// We depend on the signaling thread to call Clear() before dropping // We depend on the signaling thread to call Clear() before dropping
// its last reference to this object. // its last reference to this object.
RTC_DCHECK(signaling_thread_->IsCurrent() || !internal_dtls_transport_); RTC_DCHECK(owner_thread_->IsCurrent() || !internal_dtls_transport_);
} }
DtlsTransportInformation DtlsTransport::Information() { DtlsTransportInformation DtlsTransport::Information() {
RTC_DCHECK(signaling_thread_->IsCurrent()); rtc::CritScope scope(&lock_);
if (internal()) { return info_;
return DtlsTransportInformation(TranslateState(internal()->dtls_state()));
} else {
return DtlsTransportInformation(DtlsTransportState::kClosed);
}
} }
void DtlsTransport::RegisterObserver(DtlsTransportObserverInterface* observer) { void DtlsTransport::RegisterObserver(DtlsTransportObserverInterface* observer) {
RTC_DCHECK(signaling_thread_->IsCurrent()); RTC_DCHECK_RUN_ON(owner_thread_);
RTC_DCHECK(observer); RTC_DCHECK(observer);
observer_ = observer; observer_ = observer;
} }
void DtlsTransport::UnregisterObserver() { void DtlsTransport::UnregisterObserver() {
RTC_DCHECK(signaling_thread_->IsCurrent()); RTC_DCHECK_RUN_ON(owner_thread_);
observer_ = nullptr; observer_ = nullptr;
} }
rtc::scoped_refptr<IceTransportInterface> DtlsTransport::ice_transport() { rtc::scoped_refptr<IceTransportInterface> DtlsTransport::ice_transport() {
RTC_DCHECK_RUN_ON(owner_thread_);
rtc::CritScope scope(&lock_);
return ice_transport_; return ice_transport_;
} }
// Internal functions // Internal functions
void DtlsTransport::Clear() { void DtlsTransport::Clear() {
RTC_DCHECK(signaling_thread_->IsCurrent()); RTC_DCHECK_RUN_ON(owner_thread_);
RTC_DCHECK(internal()); RTC_DCHECK(internal());
if (internal()->dtls_state() != cricket::DTLS_TRANSPORT_CLOSED) { bool must_send_event =
internal_dtls_transport_.reset(); (internal()->dtls_state() != cricket::DTLS_TRANSPORT_CLOSED);
if (observer_) { // The destructor of cricket::DtlsTransportInternal calls back
observer_->OnStateChange(Information()); // into DtlsTransport, so we can't hold the lock while releasing.
} std::unique_ptr<cricket::DtlsTransportInternal> transport_to_release;
} else { {
internal_dtls_transport_.reset(); rtc::CritScope scope(&lock_);
transport_to_release = std::move(internal_dtls_transport_);
ice_transport_->Clear();
}
UpdateInformation();
if (observer_ && must_send_event) {
observer_->OnStateChange(Information());
} }
ice_transport_->Clear();
} }
void DtlsTransport::OnInternalDtlsState( void DtlsTransport::OnInternalDtlsState(
cricket::DtlsTransportInternal* transport, cricket::DtlsTransportInternal* transport,
cricket::DtlsTransportState state) { cricket::DtlsTransportState state) {
RTC_DCHECK(signaling_thread_->IsCurrent()); RTC_DCHECK_RUN_ON(owner_thread_);
RTC_DCHECK(transport == internal()); RTC_DCHECK(transport == internal());
RTC_DCHECK(state == internal()->dtls_state()); RTC_DCHECK(state == internal()->dtls_state());
UpdateInformation();
if (observer_) { if (observer_) {
observer_->OnStateChange(Information()); observer_->OnStateChange(Information());
} }
} }
void DtlsTransport::UpdateInformation() {
RTC_DCHECK_RUN_ON(owner_thread_);
rtc::CritScope scope(&lock_);
if (internal_dtls_transport_) {
info_ = DtlsTransportInformation(
TranslateState(internal_dtls_transport_->dtls_state()));
} else {
info_ = DtlsTransportInformation(DtlsTransportState::kClosed);
}
}
} // namespace webrtc } // namespace webrtc

View File

@ -28,7 +28,11 @@ class IceTransportWithPointer;
class DtlsTransport : public DtlsTransportInterface, class DtlsTransport : public DtlsTransportInterface,
public sigslot::has_slots<> { public sigslot::has_slots<> {
public: public:
// This object must be constructed on the signaling thread. // This object must be constructed and updated on a consistent thread,
// the same thread as the one the cricket::DtlsTransportInternal object
// lives on.
// The Information() function can be called from a different thread,
// such as the signalling thread.
explicit DtlsTransport( explicit DtlsTransport(
std::unique_ptr<cricket::DtlsTransportInternal> internal); std::unique_ptr<cricket::DtlsTransportInternal> internal);
@ -39,10 +43,12 @@ class DtlsTransport : public DtlsTransportInterface,
void Clear(); void Clear();
cricket::DtlsTransportInternal* internal() { cricket::DtlsTransportInternal* internal() {
rtc::CritScope scope(&lock_);
return internal_dtls_transport_.get(); return internal_dtls_transport_.get();
} }
const cricket::DtlsTransportInternal* internal() const { const cricket::DtlsTransportInternal* internal() const {
rtc::CritScope scope(&lock_);
return internal_dtls_transport_.get(); return internal_dtls_transport_.get();
} }
@ -52,11 +58,16 @@ class DtlsTransport : public DtlsTransportInterface,
private: private:
void OnInternalDtlsState(cricket::DtlsTransportInternal* transport, void OnInternalDtlsState(cricket::DtlsTransportInternal* transport,
cricket::DtlsTransportState state); cricket::DtlsTransportState state);
void UpdateInformation();
DtlsTransportObserverInterface* observer_ = nullptr; DtlsTransportObserverInterface* observer_ = nullptr;
rtc::Thread* signaling_thread_; rtc::Thread* owner_thread_;
std::unique_ptr<cricket::DtlsTransportInternal> internal_dtls_transport_; rtc::CriticalSection lock_;
rtc::scoped_refptr<IceTransportWithPointer> ice_transport_; DtlsTransportInformation info_ RTC_GUARDED_BY(lock_);
std::unique_ptr<cricket::DtlsTransportInternal> internal_dtls_transport_
RTC_GUARDED_BY(lock_);
rtc::scoped_refptr<IceTransportWithPointer> ice_transport_
RTC_GUARDED_BY(lock_);
}; };
} // namespace webrtc } // namespace webrtc