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

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 tommi's comments 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() {
69 // TODO(hbos): Use key_type_ when torbjorng's CL has landed.
70 LOG(LS_INFO) << "Generating identity. Key type (TODO(hbos): should use): "
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 {
95 rtc::scoped_ptr<IdentityResultMessageData> pdata(
96 static_cast<IdentityResultMessageData*>(msg->pdata));
97 if (store_) {
98 store_->OnIdentityGenerated(pdata->data()->key_type_,
99 pdata->data()->identity_.Pass());
100 }
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,
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_() {
128 DCHECK(signaling_thread_->IsCurrent());
129 // Preemptively generate identities unless the worker thread and signaling
130 // thread are the same (only do preemptive work in the background).
131 if (worker_thread_ != signaling_thread_) {
132 // Only necessary for RSA.
133 GenerateIdentity(rtc::KT_RSA, nullptr);
134 }
135 }
116 136
117 DtlsIdentityStore::~DtlsIdentityStore() { 137 DtlsIdentityStoreImpl::~DtlsIdentityStoreImpl() {
138 DCHECK(signaling_thread_->IsCurrent());
118 SignalDestroyed(); 139 SignalDestroyed();
119 } 140 }
120 141
121 void DtlsIdentityStore::Initialize() { 142 void DtlsIdentityStoreImpl::RequestIdentity(
122 DCHECK(rtc::Thread::Current() == signaling_thread_); 143 rtc::KeyType key_type,
123 // Do not aggressively generate the free identity if the worker thread and the 144 const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer) {
124 // signaling thread are the same. 145 DCHECK(signaling_thread_->IsCurrent());
125 if (worker_thread_ != signaling_thread_) { 146 DCHECK(observer);
126 GenerateIdentity(); 147
127 } 148 GenerateIdentity(key_type, observer);
128 } 149 }
129 150
130 void DtlsIdentityStore::RequestIdentity(DTLSIdentityRequestObserver* observer) { 151 void DtlsIdentityStoreImpl::OnMessage(rtc::Message* msg) {
131 DCHECK(rtc::Thread::Current() == signaling_thread_); 152 DCHECK(signaling_thread_->IsCurrent());
132 DCHECK(observer);
133
134 // Must return the free identity async.
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 }
144
145 void DtlsIdentityStore::OnMessage(rtc::Message* msg) {
146 DCHECK(rtc::Thread::Current() == signaling_thread_);
147 switch (msg->message_id) { 153 switch (msg->message_id) {
148 case MSG_GENERATE_IDENTITY_RESULT: { 154 case MSG_GENERATE_IDENTITY_RESULT: {
149 rtc::scoped_ptr<IdentityResultMessageData> pdata( 155 rtc::scoped_ptr<IdentityResultMessageData> pdata(
150 static_cast<IdentityResultMessageData*>(msg->pdata)); 156 static_cast<IdentityResultMessageData*>(msg->pdata));
151 OnIdentityGenerated(pdata->data().Pass()); 157 OnIdentityGenerated(pdata->data()->key_type_,
152 break; 158 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; 159 break;
159 } 160 }
160 } 161 }
161 } 162 }
162 163
163 bool DtlsIdentityStore::HasFreeIdentityForTesting() const { 164 bool DtlsIdentityStoreImpl::HasFreeIdentityForTesting(
164 DCHECK(rtc::Thread::Current() == signaling_thread_); 165 rtc::KeyType key_type) const {
165 return free_identity_.get() != nullptr; 166 DCHECK(signaling_thread_->IsCurrent());
167 return request_info_[key_type].free_identity_.get() != nullptr;
166 } 168 }
167 169
168 void DtlsIdentityStore::GenerateIdentity() { 170 void DtlsIdentityStoreImpl::GenerateIdentity(
169 DCHECK(rtc::Thread::Current() == signaling_thread_); 171 rtc::KeyType key_type,
170 pending_jobs_++; 172 const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer) {
171 LOG(LS_VERBOSE) << "New DTLS identity generation is posted, " 173 DCHECK(signaling_thread_->IsCurrent());
172 << "pending_identities=" << pending_jobs_;
173 174
174 WorkerTask* task = new WorkerTask(this); 175 // Enqueue observer to be informed when generation of |key_type| is completed.
176 if (observer.get()) {
177 request_info_[key_type].request_observers_.push_back(observer);
178
179 // Already have a free identity generated?
180 if (request_info_[key_type].free_identity_.get()) {
181 // Return identity async - post even though we are on |signaling_thread_|.
182 LOG(LS_VERBOSE) << "Using a free DTLS identity.";
183 ++request_info_[key_type].gen_in_progress_counts_;
184 IdentityResultMessageData* msg = new IdentityResultMessageData(
185 new IdentityResult(key_type,
186 request_info_[key_type].free_identity_.Pass()));
187 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
188 return;
189 }
190
191 // Free identity in the process of being generated?
192 if (request_info_[key_type].gen_in_progress_counts_ ==
193 request_info_[key_type].request_observers_.size()) {
194 // No need to do anything, the free identity will be returned to the
195 // observer in a MSG_GENERATE_IDENTITY_RESULT.
196 return;
197 }
198 }
199
200 // Enqueue/Post a worker task to do the generation.
201 ++request_info_[key_type].gen_in_progress_counts_;
202 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 203 // 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. 204 // leaked even if the task does not get run.
177 IdentityTaskMessageData* msg = new IdentityTaskMessageData(task); 205 WorkerTaskMessageData* msg = new WorkerTaskMessageData(task);
178 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg); 206 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg);
179 } 207 }
180 208
181 void DtlsIdentityStore::OnIdentityGenerated( 209 void DtlsIdentityStoreImpl::OnIdentityGenerated(
182 rtc::scoped_ptr<rtc::SSLIdentity> identity) { 210 rtc::KeyType key_type, rtc::scoped_ptr<rtc::SSLIdentity> identity) {
183 DCHECK(rtc::Thread::Current() == signaling_thread_); 211 DCHECK(signaling_thread_->IsCurrent());
184 212
185 pending_jobs_--; 213 DCHECK(request_info_[key_type].gen_in_progress_counts_);
186 LOG(LS_VERBOSE) << "A DTLS identity generation job returned, " 214 --request_info_[key_type].gen_in_progress_counts_;
187 << "pending_identities=" << pending_jobs_;
188 215
189 if (pending_observers_.empty()) { 216 rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver> observer;
190 if (!free_identity_.get()) { 217 if (!request_info_[key_type].request_observers_.empty()) {
191 free_identity_.reset(identity.release()); 218 observer = request_info_[key_type].request_observers_.front();
192 LOG(LS_VERBOSE) << "A free DTLS identity is saved"; 219 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 } 220 }
216 221
217 // Do not aggressively generate the free identity if the worker thread and the 222 if (observer.get() == nullptr) {
218 // signaling thread are the same. 223 // No observer - store result in |free_identities_|.
219 if (worker_thread_ != signaling_thread_ && 224 DCHECK(!request_info_[key_type].free_identity_.get());
220 pending_observers_.empty() && 225 request_info_[key_type].free_identity_.swap(identity);
221 pending_jobs_ == 0) { 226 if (request_info_[key_type].free_identity_.get())
222 // Generate a free identity in the background. 227 LOG(LS_VERBOSE) << "A free DTLS identity was saved.";
223 GenerateIdentity(); 228 else
229 LOG(LS_WARNING) << "Failed to generate DTLS identity (preemptively).";
230 } else {
231 // Return the result to the observer.
232 if (identity.get()) {
233 LOG(LS_VERBOSE) << "A DTLS identity is returned to an observer.";
234 observer->OnSuccess(identity.Pass());
235 } else {
236 LOG(LS_WARNING) << "Failed to generate DTLS identity.";
237 observer->OnFailure(0);
238 }
239
240 // Preemptively generate another identity of the same type?
241 if (worker_thread_ != signaling_thread_ && // Only do in background thread.
242 key_type == rtc::KT_RSA && // Only necessary for RSA.
243 !request_info_[key_type].free_identity_.get() &&
244 request_info_[key_type].request_observers_.size() <=
245 request_info_[key_type].gen_in_progress_counts_) {
246 GenerateIdentity(key_type, nullptr);
247 }
224 } 248 }
225 } 249 }
226 250
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 251 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698