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

Side by Side Diff: talk/app/webrtc/dtlsidentitystore.cc

Issue 1176383004: DtlsIdentityStore[Interface/Impl] updated, DtlsIdentityService to be removed (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: DtlsIdentityStoreImpl made simpler and better and not using any locks. 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
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2015 Google Inc. 3 * Copyright 2015 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 12 matching lines...) Expand all
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 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 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28 #include "talk/app/webrtc/dtlsidentitystore.h" 28 #include "talk/app/webrtc/dtlsidentitystore.h"
29 29
30 #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" 30 #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h"
31 #include "webrtc/base/logging.h" 31 #include "webrtc/base/logging.h"
32 32
33 using webrtc::DTLSIdentityRequestObserver; 33 using webrtc::DtlsIdentityRequestObserver;
34 using webrtc::WebRtcSessionDescriptionFactory; 34 using webrtc::WebRtcSessionDescriptionFactory;
35 35
36 namespace webrtc { 36 namespace webrtc {
37 37
38 const char* DtlsIdentityStoreImpl::common_name_ = "WebRTC";
39
38 namespace { 40 namespace {
39 41
40 enum { 42 enum {
41 MSG_DESTROY, 43 MSG_DESTROY,
42 MSG_GENERATE_IDENTITY, 44 MSG_GENERATE_IDENTITY,
43 MSG_GENERATE_IDENTITY_RESULT, 45 MSG_GENERATE_IDENTITY_RESULT
44 MSG_RETURN_FREE_IDENTITY
45 }; 46 };
46 47
47 typedef rtc::ScopedMessageData<rtc::SSLIdentity> IdentityResultMessageData;
48
49 } // namespace 48 } // namespace
50 49
51 // This class runs on the worker thread to generate the identity. It's necessary 50 // This class runs on the worker thread to generate the identity. It's necessary
52 // to separate this class from DtlsIdentityStore so that it can live on the 51 // to separate this class from DtlsIdentityStore so that it can live on the
53 // worker thread after DtlsIdentityStore is destroyed. 52 // worker thread after DtlsIdentityStore is destroyed.
54 class DtlsIdentityStore::WorkerTask : public sigslot::has_slots<>, 53 class DtlsIdentityStoreImpl::WorkerTask : public sigslot::has_slots<>,
55 public rtc::MessageHandler { 54 public rtc::MessageHandler {
56 public: 55 public:
57 explicit WorkerTask(DtlsIdentityStore* store) 56 explicit WorkerTask(
58 : signaling_thread_(rtc::Thread::Current()), store_(store) { 57 DtlsIdentityStoreImpl* store, rtc::KeyType key_type)
58 : signaling_thread_(rtc::Thread::Current()),
59 store_(store),
60 key_type_(key_type) {
59 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed); 61 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed);
60 } 62 }
61 63
62 virtual ~WorkerTask() { DCHECK(rtc::Thread::Current() == signaling_thread_); } 64 virtual ~WorkerTask() { DCHECK(rtc::Thread::Current() == signaling_thread_); }
63 65
64 private: 66 private:
65 void GenerateIdentity_w() { 67 void GenerateIdentity_w() {
68 // TODO(hbos): Use key_type_ when torbjorng's CL has landed.
69 LOG(LS_INFO) << "Generating identity. Key type (TODO(hbos): should use): "
70 << key_type_;
66 rtc::scoped_ptr<rtc::SSLIdentity> identity( 71 rtc::scoped_ptr<rtc::SSLIdentity> identity(
67 rtc::SSLIdentity::Generate(DtlsIdentityStore::kIdentityName)); 72 rtc::SSLIdentity::Generate(common_name_));
68 73
69 { 74 {
70 rtc::CritScope cs(&cs_); 75 rtc::CritScope cs(&cs_);
71 if (store_) { 76 if (store_) {
72 store_->PostGenerateIdentityResult_w(identity.Pass()); 77 IdentityResultMessageData* msg = new IdentityResultMessageData(
78 new IdentityResult(key_type_, identity.release()));
79 signaling_thread_->Post(store_, MSG_GENERATE_IDENTITY_RESULT, msg);
73 } 80 }
74 } 81 }
75 } 82 }
76 83
77 void OnMessage(rtc::Message* msg) override { 84 void OnMessage(rtc::Message* msg) override {
78 switch (msg->message_id) { 85 switch (msg->message_id) {
79 case MSG_GENERATE_IDENTITY: 86 case MSG_GENERATE_IDENTITY:
80 // This message always runs on the worker thread. 87 // This message always runs on the worker thread.
81 GenerateIdentity_w(); 88 GenerateIdentity_w();
82 89
(...skipping 10 matching lines...) Expand all
93 CHECK(false) << "Unexpected message type"; 100 CHECK(false) << "Unexpected message type";
94 } 101 }
95 } 102 }
96 103
97 void OnStoreDestroyed() { 104 void OnStoreDestroyed() {
98 rtc::CritScope cs(&cs_); 105 rtc::CritScope cs(&cs_);
99 store_ = NULL; 106 store_ = NULL;
100 } 107 }
101 108
102 rtc::Thread* const signaling_thread_; 109 rtc::Thread* const signaling_thread_;
110 // Locking this prevents |store_| from being destroyed if it has not already
111 // been so.
103 rtc::CriticalSection cs_; 112 rtc::CriticalSection cs_;
104 DtlsIdentityStore* store_; 113 DtlsIdentityStoreImpl* store_;
114 rtc::KeyType key_type_;
105 }; 115 };
106 116
107 // Arbitrary constant used as common name for the identity. 117 DtlsIdentityStoreImpl::DtlsIdentityStoreImpl(rtc::Thread* signaling_thread,
108 // Chosen to make the certificates more readable. 118 rtc::Thread* worker_thread)
109 const char DtlsIdentityStore::kIdentityName[] = "WebRTC";
110
111 DtlsIdentityStore::DtlsIdentityStore(rtc::Thread* signaling_thread,
112 rtc::Thread* worker_thread)
113 : signaling_thread_(signaling_thread), 119 : signaling_thread_(signaling_thread),
114 worker_thread_(worker_thread), 120 worker_thread_(worker_thread),
115 pending_jobs_(0) {} 121 request_observers_(),
122 gen_in_progress_counts_(),
123 free_identities_() { }
116 124
117 DtlsIdentityStore::~DtlsIdentityStore() { 125 DtlsIdentityStoreImpl::~DtlsIdentityStoreImpl() {
118 SignalDestroyed(); 126 SignalDestroyed();
119 } 127 }
120 128
121 void DtlsIdentityStore::Initialize() { 129 void DtlsIdentityStoreImpl::Initialize() {
122 DCHECK(rtc::Thread::Current() == signaling_thread_); 130 DCHECK(rtc::Thread::Current() == signaling_thread_);
123 // Do not aggressively generate the free identity if the worker thread and the 131 // Preemptively generate identities unless the worker thread and signaling
124 // signaling thread are the same. 132 // thread are the same (only do preemptive work in the background).
125 if (worker_thread_ != signaling_thread_) { 133 if (worker_thread_ != signaling_thread_) {
126 GenerateIdentity(); 134 // Only necessary for RSA.
135 GenerateIdentity(rtc::KT_RSA, nullptr);
127 } 136 }
128 } 137 }
129 138
130 void DtlsIdentityStore::RequestIdentity(DTLSIdentityRequestObserver* observer) { 139 void DtlsIdentityStoreImpl::RequestIdentity(
140 rtc::KeyType key_type, DtlsIdentityRequestObserver* observer) {
131 DCHECK(rtc::Thread::Current() == signaling_thread_); 141 DCHECK(rtc::Thread::Current() == signaling_thread_);
132 DCHECK(observer); 142 DCHECK(observer);
133 143
134 // Must return the free identity async. 144 GenerateIdentity(key_type, observer);
135 if (free_identity_.get()) {
136 IdentityResultMessageData* msg =
137 new IdentityResultMessageData(free_identity_.release());
138 signaling_thread_->Post(this, MSG_RETURN_FREE_IDENTITY, msg);
139 }
140
141 pending_observers_.push(observer);
142 GenerateIdentity();
143 } 145 }
144 146
145 void DtlsIdentityStore::OnMessage(rtc::Message* msg) { 147 void DtlsIdentityStoreImpl::OnMessage(rtc::Message* msg) {
146 DCHECK(rtc::Thread::Current() == signaling_thread_); 148 DCHECK(rtc::Thread::Current() == signaling_thread_);
147 switch (msg->message_id) { 149 switch (msg->message_id) {
148 case MSG_GENERATE_IDENTITY_RESULT: { 150 case MSG_GENERATE_IDENTITY_RESULT: {
149 rtc::scoped_ptr<IdentityResultMessageData> pdata( 151 rtc::scoped_ptr<IdentityResultMessageData> pdata(
150 static_cast<IdentityResultMessageData*>(msg->pdata)); 152 static_cast<IdentityResultMessageData*>(msg->pdata));
151 OnIdentityGenerated(pdata->data().Pass()); 153 OnIdentityGenerated(pdata->data()->key_type_,
152 break; 154 pdata->data()->identity_.Pass());
153 }
154 case MSG_RETURN_FREE_IDENTITY: {
155 rtc::scoped_ptr<IdentityResultMessageData> pdata(
156 static_cast<IdentityResultMessageData*>(msg->pdata));
157 ReturnIdentity(pdata->data().Pass());
158 break; 155 break;
159 } 156 }
160 } 157 }
161 } 158 }
162 159
163 bool DtlsIdentityStore::HasFreeIdentityForTesting() const { 160 bool DtlsIdentityStoreImpl::HasFreeIdentityForTesting(
161 rtc::KeyType key_type) const {
164 DCHECK(rtc::Thread::Current() == signaling_thread_); 162 DCHECK(rtc::Thread::Current() == signaling_thread_);
165 return free_identity_.get() != nullptr; 163 return free_identities_[key_type].get() != nullptr;
166 } 164 }
167 165
168 void DtlsIdentityStore::GenerateIdentity() { 166 // TODO(hbos): observer parameters should use scoped_refptr too?
167 void DtlsIdentityStoreImpl::GenerateIdentity(
168 rtc::KeyType key_type, DtlsIdentityRequestObserver* observer) {
169 DCHECK(rtc::Thread::Current() == signaling_thread_); 169 DCHECK(rtc::Thread::Current() == signaling_thread_);
170 pending_jobs_++;
171 LOG(LS_VERBOSE) << "New DTLS identity generation is posted, "
172 << "pending_identities=" << pending_jobs_;
173 170
174 WorkerTask* task = new WorkerTask(this); 171 // Enqueue observer to be informed when generation of |key_type| is completed.
172 if (observer) {
173 request_observers_[key_type].push_back(observer);
174
175 // Already have a free identity generated?
176 if (free_identities_[key_type].get()) {
177 // Return identity async - post even though we are on |signaling_thread_|.
178 LOG(LS_VERBOSE) << "Using a free DTLS identity.";
179 IdentityResultMessageData* msg = new IdentityResultMessageData(
180 new IdentityResult(key_type, free_identities_[key_type].release()));
181 ++gen_in_progress_counts_[key_type];
182 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
183 return;
184 }
185
186 // Free identity in the process of being generated?
187 if (gen_in_progress_counts_[key_type] ==
188 request_observers_[key_type].size()) {
189 // No need to do anything, the free identity will be returned to the
190 // observer in a MSG_GENERATE_IDENTITY_RESULT.
191 return;
192 }
193 }
194
195 // Enqueue/Post a worker task to do the generation.
196 WorkerTask* task = new WorkerTask(this, key_type); // Post 1 task/request.
175 // The WorkerTask is owned by the message data to make sure it will not be 197 // The WorkerTask is owned by the message data to make sure it will not be
176 // leaked even if the task does not get run. 198 // leaked even if the task does not get run.
177 IdentityTaskMessageData* msg = new IdentityTaskMessageData(task); 199 WorkerTaskMessageData* msg = new WorkerTaskMessageData(task);
200 ++gen_in_progress_counts_[key_type];
178 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg); 201 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg);
179 } 202 }
180 203
181 void DtlsIdentityStore::OnIdentityGenerated( 204 void DtlsIdentityStoreImpl::OnIdentityGenerated(
182 rtc::scoped_ptr<rtc::SSLIdentity> identity) { 205 rtc::KeyType key_type, rtc::scoped_ptr<rtc::SSLIdentity> identity) {
183 DCHECK(rtc::Thread::Current() == signaling_thread_); 206 DCHECK(rtc::Thread::Current() == signaling_thread_);
184 207
185 pending_jobs_--; 208 DCHECK(gen_in_progress_counts_[key_type]);
186 LOG(LS_VERBOSE) << "A DTLS identity generation job returned, " 209 --gen_in_progress_counts_[key_type];
187 << "pending_identities=" << pending_jobs_;
188 210
189 if (pending_observers_.empty()) { 211 RefObserver observer = nullptr;
190 if (!free_identity_.get()) { 212 if (!request_observers_[key_type].empty()) {
191 free_identity_.reset(identity.release()); 213 observer = request_observers_[key_type].front();
192 LOG(LS_VERBOSE) << "A free DTLS identity is saved"; 214 request_observers_[key_type].pop_front();
193 }
194 return;
195 }
196 ReturnIdentity(identity.Pass());
197 }
198
199 void DtlsIdentityStore::ReturnIdentity(
200 rtc::scoped_ptr<rtc::SSLIdentity> identity) {
201 DCHECK(rtc::Thread::Current() == signaling_thread_);
202 DCHECK(!free_identity_.get());
203 DCHECK(!pending_observers_.empty());
204
205 rtc::scoped_refptr<DTLSIdentityRequestObserver> observer =
206 pending_observers_.front();
207 pending_observers_.pop();
208
209 if (identity.get()) {
210 observer->OnSuccessWithIdentityObj(identity.Pass());
211 } else {
212 // Pass an arbitrary error code.
213 observer->OnFailure(0);
214 LOG(LS_WARNING) << "Failed to generate SSL identity";
215 } 215 }
216 216
217 // Do not aggressively generate the free identity if the worker thread and the 217 if (observer.get() == nullptr) {
218 // signaling thread are the same. 218 // No observer - store result in |free_identities_|.
219 if (worker_thread_ != signaling_thread_ && 219 DCHECK(!free_identities_[key_type].get());
220 pending_observers_.empty() && 220 free_identities_[key_type].reset(identity.release());
221 pending_jobs_ == 0) { 221 if (free_identities_[key_type].get())
222 // Generate a free identity in the background. 222 LOG(LS_VERBOSE) << "A free DTLS identity was saved.";
223 GenerateIdentity(); 223 else
224 LOG(LS_WARNING) << "Failed to generate DTLS identity (preemptively).";
225 } else {
226 // Return the result to the observer.
227 if (identity.get()) {
228 LOG(LS_VERBOSE) << "A DTLS identity is returned to an observer.";
229 observer->OnSuccessWithIdentityObj(identity.Pass());
230 } else {
231 LOG(LS_WARNING) << "Failed to generate DTLS identity.";
232 observer->OnFailure(0);
233 }
234
235 // Preemptively generate another identity of the same type?
236 if (worker_thread_ != signaling_thread_ // Only do on a background thread.
237 && (key_type == rtc::KT_RSA) // Only necessary for RSA.
238 && !free_identities_[key_type].get()
239 && request_observers_[key_type].size() <=
240 gen_in_progress_counts_[key_type]) {
241 GenerateIdentity(key_type, nullptr);
242 }
224 } 243 }
225 } 244 }
226 245
227 void DtlsIdentityStore::PostGenerateIdentityResult_w(
228 rtc::scoped_ptr<rtc::SSLIdentity> identity) {
229 DCHECK(rtc::Thread::Current() == worker_thread_);
230
231 IdentityResultMessageData* msg =
232 new IdentityResultMessageData(identity.release());
233 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
234 }
235 } // namespace webrtc 246 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698