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

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: Addressed rest of tommi's comments: Removed need for lock Created 5 years, 5 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 // Passed to SSLIdentity::Generate, "WebRTC". Used for the certificates'
39 // subject and issuer name.
40 static const char kIdentityName[] = "WebRTC";
41
38 namespace { 42 namespace {
39 43
40 enum { 44 enum {
41 MSG_DESTROY, 45 MSG_DESTROY,
42 MSG_GENERATE_IDENTITY, 46 MSG_GENERATE_IDENTITY,
43 MSG_GENERATE_IDENTITY_RESULT, 47 MSG_GENERATE_IDENTITY_RESULT
44 MSG_RETURN_FREE_IDENTITY
45 }; 48 };
46 49
47 typedef rtc::ScopedMessageData<rtc::SSLIdentity> IdentityResultMessageData;
48
49 } // namespace 50 } // namespace
50 51
51 // This class runs on the worker thread to generate the identity. It's necessary 52 // 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 53 // to separate this class from DtlsIdentityStore so that it can live on the
53 // worker thread after DtlsIdentityStore is destroyed. 54 // worker thread after DtlsIdentityStore is destroyed.
54 class DtlsIdentityStore::WorkerTask : public sigslot::has_slots<>, 55 class DtlsIdentityStoreImpl::WorkerTask : public sigslot::has_slots<>,
55 public rtc::MessageHandler { 56 public rtc::MessageHandler {
56 public: 57 public:
57 explicit WorkerTask(DtlsIdentityStore* store) 58 WorkerTask(DtlsIdentityStoreImpl* store, rtc::KeyType key_type)
58 : signaling_thread_(rtc::Thread::Current()), store_(store) { 59 : signaling_thread_(rtc::Thread::Current()),
60 store_(store),
61 key_type_(key_type) {
59 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed); 62 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed);
60 } 63 }
61 64
62 virtual ~WorkerTask() { DCHECK(rtc::Thread::Current() == signaling_thread_); } 65 virtual ~WorkerTask() { DCHECK(signaling_thread_->IsCurrent()); }
63 66
64 private: 67 private:
65 void GenerateIdentity_w() { 68 void GenerateIdentity_w() {
tommi 2015/07/02 11:22:59 can we dcheck thread correctness?
hbos 2015/07/02 12:28:27 That probably requires a pointer to the worker thr
tommi 2015/07/09 16:13:56 What about using ThreadChecker?
hbos 2015/07/27 13:29:00 Hmh. But it's constructed on the signaling thread
tommi 2015/08/04 10:47:20 If I'm parsing GenerateIdentity() correctly, then
hbos 2015/08/04 11:38:48 I don't think so? While we may do multiple identit
hbos 2015/08/04 12:16:19 Actually, there may be some test code that use the
69 // TODO(hbos): Use key_type_ when torbjorng's CL has landed.
70 LOG(LS_INFO) << "Generating identity. Key type (TODO(hbos): should use): "
tommi 2015/07/02 11:22:59 will you remove this before committing?
hbos 2015/07/02 12:28:27 Think I should remove the LOG even if this lands b
tommi 2015/07/09 16:13:56 nah, OK to keep in until then.
71 << key_type_;
66 rtc::scoped_ptr<rtc::SSLIdentity> identity( 72 rtc::scoped_ptr<rtc::SSLIdentity> identity(
67 rtc::SSLIdentity::Generate(DtlsIdentityStore::kIdentityName)); 73 rtc::SSLIdentity::Generate(kIdentityName));
68 74
69 { 75 // Posting to |this| avoids touching |store_| on threads other than
70 rtc::CritScope cs(&cs_); 76 // |signaling_thread_| and thus avoids having to use locks.
71 if (store_) { 77 IdentityResultMessageData* msg = new IdentityResultMessageData(
72 store_->PostGenerateIdentityResult_w(identity.Pass()); 78 new IdentityResult(key_type_, identity.Pass()));
73 } 79 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
74 }
75 } 80 }
76 81
77 void OnMessage(rtc::Message* msg) override { 82 void OnMessage(rtc::Message* msg) override {
78 switch (msg->message_id) { 83 switch (msg->message_id) {
79 case MSG_GENERATE_IDENTITY: 84 case MSG_GENERATE_IDENTITY:
80 // This message always runs on the worker thread. 85 // This message always runs on the worker thread.
81 GenerateIdentity_w(); 86 GenerateIdentity_w();
82 87
83 // Must delete |this|, owned by msg->pdata, on the signaling thread to 88 // Must delete |this|, owned by msg->pdata, on the signaling thread to
84 // avoid races on disconnecting the signal. 89 // avoid races on disconnecting the signal.
85 signaling_thread_->Post(this, MSG_DESTROY, msg->pdata); 90 signaling_thread_->Post(this, MSG_DESTROY, msg->pdata);
86 break; 91 break;
92 case MSG_GENERATE_IDENTITY_RESULT:
93 DCHECK(signaling_thread_->IsCurrent());
94 if (store_) {
95 rtc::scoped_ptr<IdentityResultMessageData> pdata(
96 static_cast<IdentityResultMessageData*>(msg->pdata));
97 store_->OnIdentityGenerated(pdata->data()->key_type_,
98 pdata->data()->identity_.Pass());
99 } else {
100 delete msg->pdata;
101 }
102 break;
87 case MSG_DESTROY: 103 case MSG_DESTROY:
88 DCHECK(rtc::Thread::Current() == signaling_thread_); 104 DCHECK(signaling_thread_->IsCurrent());
89 delete msg->pdata; 105 delete msg->pdata;
90 // |this| has now been deleted. Don't touch member variables. 106 // |this| has now been deleted. Don't touch member variables.
91 break; 107 break;
92 default: 108 default:
93 CHECK(false) << "Unexpected message type"; 109 CHECK(false) << "Unexpected message type";
94 } 110 }
95 } 111 }
96 112
97 void OnStoreDestroyed() { 113 void OnStoreDestroyed() {
98 rtc::CritScope cs(&cs_); 114 DCHECK(signaling_thread_->IsCurrent());
99 store_ = NULL; 115 store_ = nullptr;
100 } 116 }
101 117
102 rtc::Thread* const signaling_thread_; 118 rtc::Thread* const signaling_thread_;
103 rtc::CriticalSection cs_; 119 DtlsIdentityStoreImpl* store_; // Only touched on |signaling_thread_|.
104 DtlsIdentityStore* store_; 120 const rtc::KeyType key_type_;
105 }; 121 };
106 122
107 // Arbitrary constant used as common name for the identity. 123 DtlsIdentityStoreImpl::DtlsIdentityStoreImpl(rtc::Thread* signaling_thread,
tommi 2015/07/02 11:22:59 if the object is always constructed on a known thr
hbos 2015/07/02 12:28:27 Acknowledged.
108 // Chosen to make the certificates more readable. 124 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), 125 : signaling_thread_(signaling_thread),
114 worker_thread_(worker_thread), 126 worker_thread_(worker_thread),
115 pending_jobs_(0) {} 127 request_info_() { }
116 128
117 DtlsIdentityStore::~DtlsIdentityStore() { 129 DtlsIdentityStoreImpl::~DtlsIdentityStoreImpl() {
130 DCHECK(signaling_thread_->IsCurrent());
118 SignalDestroyed(); 131 SignalDestroyed();
119 } 132 }
120 133
121 void DtlsIdentityStore::Initialize() { 134 void DtlsIdentityStoreImpl::Initialize() {
122 DCHECK(rtc::Thread::Current() == signaling_thread_); 135 DCHECK(signaling_thread_->IsCurrent());
123 // Do not aggressively generate the free identity if the worker thread and the 136 // Preemptively generate identities unless the worker thread and signaling
124 // signaling thread are the same. 137 // thread are the same (only do preemptive work in the background).
125 if (worker_thread_ != signaling_thread_) { 138 if (worker_thread_ != signaling_thread_) {
126 GenerateIdentity(); 139 // Only necessary for RSA.
tommi 2015/07/02 11:22:59 I wonder if we should skip doing this at some poin
hbos 2015/07/02 12:28:27 Yeah, this is especially a bad idea if we use 2048
tommi 2015/07/09 16:13:56 Acknowledged.
140 GenerateIdentity(rtc::KT_RSA, nullptr);
127 } 141 }
128 } 142 }
129 143
130 void DtlsIdentityStore::RequestIdentity(DTLSIdentityRequestObserver* observer) { 144 void DtlsIdentityStoreImpl::RequestIdentity(
131 DCHECK(rtc::Thread::Current() == signaling_thread_); 145 rtc::KeyType key_type,
146 const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer) {
147 DCHECK(signaling_thread_->IsCurrent());
132 DCHECK(observer); 148 DCHECK(observer);
133 149
134 // Must return the free identity async. 150 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 } 151 }
144 152
145 void DtlsIdentityStore::OnMessage(rtc::Message* msg) { 153 void DtlsIdentityStoreImpl::OnMessage(rtc::Message* msg) {
146 DCHECK(rtc::Thread::Current() == signaling_thread_); 154 DCHECK(signaling_thread_->IsCurrent());
147 switch (msg->message_id) { 155 switch (msg->message_id) {
148 case MSG_GENERATE_IDENTITY_RESULT: { 156 case MSG_GENERATE_IDENTITY_RESULT: {
149 rtc::scoped_ptr<IdentityResultMessageData> pdata( 157 rtc::scoped_ptr<IdentityResultMessageData> pdata(
150 static_cast<IdentityResultMessageData*>(msg->pdata)); 158 static_cast<IdentityResultMessageData*>(msg->pdata));
151 OnIdentityGenerated(pdata->data().Pass()); 159 OnIdentityGenerated(pdata->data()->key_type_,
152 break; 160 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; 161 break;
159 } 162 }
160 } 163 }
161 } 164 }
162 165
163 bool DtlsIdentityStore::HasFreeIdentityForTesting() const { 166 bool DtlsIdentityStoreImpl::HasFreeIdentityForTesting(
164 DCHECK(rtc::Thread::Current() == signaling_thread_); 167 rtc::KeyType key_type) const {
165 return free_identity_.get() != nullptr; 168 DCHECK(signaling_thread_->IsCurrent());
169 return request_info_[key_type].free_identity_.get() != nullptr;
166 } 170 }
167 171
168 void DtlsIdentityStore::GenerateIdentity() { 172 void DtlsIdentityStoreImpl::GenerateIdentity(
169 DCHECK(rtc::Thread::Current() == signaling_thread_); 173 rtc::KeyType key_type,
170 pending_jobs_++; 174 const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer) {
171 LOG(LS_VERBOSE) << "New DTLS identity generation is posted, " 175 DCHECK(signaling_thread_->IsCurrent());
172 << "pending_identities=" << pending_jobs_;
173 176
174 WorkerTask* task = new WorkerTask(this); 177 // Enqueue observer to be informed when generation of |key_type| is completed.
178 if (observer.get()) {
179 request_info_[key_type].request_observers_.push_back(observer);
180
181 // Already have a free identity generated?
182 if (request_info_[key_type].free_identity_.get()) {
183 // Return identity async - post even though we are on |signaling_thread_|.
184 LOG(LS_VERBOSE) << "Using a free DTLS identity.";
185 IdentityResultMessageData* msg = new IdentityResultMessageData(
186 new IdentityResult(key_type,
187 request_info_[key_type].free_identity_.Pass()));
188 ++request_info_[key_type].gen_in_progress_counts_;
189 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
190 return;
191 }
192
193 // Free identity in the process of being generated?
194 if (request_info_[key_type].gen_in_progress_counts_ ==
195 request_info_[key_type].request_observers_.size()) {
196 // No need to do anything, the free identity will be returned to the
197 // observer in a MSG_GENERATE_IDENTITY_RESULT.
198 return;
199 }
200 }
201
202 // Enqueue/Post a worker task to do the generation.
203 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 204 // 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. 205 // leaked even if the task does not get run.
177 IdentityTaskMessageData* msg = new IdentityTaskMessageData(task); 206 WorkerTaskMessageData* msg = new WorkerTaskMessageData(task);
207 ++request_info_[key_type].gen_in_progress_counts_;
tommi 2015/07/02 11:22:59 nit: do this after or before using |msg|
hbos 2015/07/02 12:28:27 Acknowledged.
178 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg); 208 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg);
179 } 209 }
180 210
181 void DtlsIdentityStore::OnIdentityGenerated( 211 void DtlsIdentityStoreImpl::OnIdentityGenerated(
182 rtc::scoped_ptr<rtc::SSLIdentity> identity) { 212 rtc::KeyType key_type, rtc::scoped_ptr<rtc::SSLIdentity> identity) {
183 DCHECK(rtc::Thread::Current() == signaling_thread_); 213 DCHECK(signaling_thread_->IsCurrent());
184 214
185 pending_jobs_--; 215 DCHECK(request_info_[key_type].gen_in_progress_counts_);
186 LOG(LS_VERBOSE) << "A DTLS identity generation job returned, " 216 --request_info_[key_type].gen_in_progress_counts_;
187 << "pending_identities=" << pending_jobs_;
188 217
189 if (pending_observers_.empty()) { 218 rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver> observer = nullptr;
tommi 2015/07/02 11:22:59 initialization to nullptr not necessary
hbos 2015/07/02 12:28:27 Acknowledged.
190 if (!free_identity_.get()) { 219 if (!request_info_[key_type].request_observers_.empty()) {
191 free_identity_.reset(identity.release()); 220 observer = request_info_[key_type].request_observers_.front();
192 LOG(LS_VERBOSE) << "A free DTLS identity is saved"; 221 request_info_[key_type].request_observers_.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 } 222 }
216 223
217 // Do not aggressively generate the free identity if the worker thread and the 224 if (observer.get() == nullptr) {
218 // signaling thread are the same. 225 // No observer - store result in |free_identities_|.
219 if (worker_thread_ != signaling_thread_ && 226 DCHECK(!request_info_[key_type].free_identity_.get());
220 pending_observers_.empty() && 227 request_info_[key_type].free_identity_.swap(identity);
221 pending_jobs_ == 0) { 228 if (request_info_[key_type].free_identity_.get())
222 // Generate a free identity in the background. 229 LOG(LS_VERBOSE) << "A free DTLS identity was saved.";
223 GenerateIdentity(); 230 else
231 LOG(LS_WARNING) << "Failed to generate DTLS identity (preemptively).";
232 } else {
233 // Return the result to the observer.
234 if (identity.get()) {
235 LOG(LS_VERBOSE) << "A DTLS identity is returned to an observer.";
236 observer->OnSuccess(identity.Pass());
237 } else {
238 LOG(LS_WARNING) << "Failed to generate DTLS identity.";
239 observer->OnFailure(0);
240 }
241
242 // Preemptively generate another identity of the same type?
243 if (worker_thread_ != signaling_thread_ && // Only do in background thread.
244 (key_type == rtc::KT_RSA) && // Only necessary for RSA.
tommi 2015/07/02 11:22:59 parens not needed
hbos 2015/07/02 12:28:26 Acknowledged.
245 !request_info_[key_type].free_identity_.get() &&
246 request_info_[key_type].request_observers_.size() <=
247 request_info_[key_type].gen_in_progress_counts_) {
248 GenerateIdentity(key_type, nullptr);
249 }
224 } 250 }
225 } 251 }
226 252
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 253 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698