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

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: Fixed dtlsidentitystore_unittest and made RequestIdentity etc take scoped_refptr instead of ptr 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 WorkerTask(DtlsIdentityStoreImpl* store, rtc::KeyType key_type)
58 : signaling_thread_(rtc::Thread::Current()), store_(store) { 57 : signaling_thread_(rtc::Thread::Current()),
58 store_(store),
59 key_type_(key_type) {
59 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed); 60 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed);
60 } 61 }
61 62
62 virtual ~WorkerTask() { DCHECK(rtc::Thread::Current() == signaling_thread_); } 63 virtual ~WorkerTask() { DCHECK(rtc::Thread::Current() == signaling_thread_); }
63 64
64 private: 65 private:
65 void GenerateIdentity_w() { 66 void GenerateIdentity_w() {
67 // TODO(hbos): Use key_type_ when torbjorng's CL has landed.
68 LOG(LS_INFO) << "Generating identity. Key type (TODO(hbos): should use): "
69 << key_type_;
66 rtc::scoped_ptr<rtc::SSLIdentity> identity( 70 rtc::scoped_ptr<rtc::SSLIdentity> identity(
67 rtc::SSLIdentity::Generate(DtlsIdentityStore::kIdentityName)); 71 rtc::SSLIdentity::Generate(common_name_));
68 72
69 { 73 {
70 rtc::CritScope cs(&cs_); 74 rtc::CritScope cs(&cs_);
71 if (store_) { 75 if (store_) {
72 store_->PostGenerateIdentityResult_w(identity.Pass()); 76 IdentityResultMessageData* msg = new IdentityResultMessageData(
77 new IdentityResult(key_type_, identity.release()));
tommi 2015/06/18 13:55:35 would be better to do identity.Pass() here I think
hbos 2015/06/18 15:45:48 Acknowledged.
78 signaling_thread_->Post(store_, MSG_GENERATE_IDENTITY_RESULT, msg);
tommi 2015/06/18 13:55:35 I think we can make the interface between the Work
hbos 2015/06/18 15:45:48 <This has not been addressed yet>
hbos 2015/07/02 09:32:23 Done!
73 } 79 }
74 } 80 }
75 } 81 }
76 82
77 void OnMessage(rtc::Message* msg) override { 83 void OnMessage(rtc::Message* msg) override {
78 switch (msg->message_id) { 84 switch (msg->message_id) {
79 case MSG_GENERATE_IDENTITY: 85 case MSG_GENERATE_IDENTITY:
80 // This message always runs on the worker thread. 86 // This message always runs on the worker thread.
81 GenerateIdentity_w(); 87 GenerateIdentity_w();
82 88
(...skipping 10 matching lines...) Expand all
93 CHECK(false) << "Unexpected message type"; 99 CHECK(false) << "Unexpected message type";
94 } 100 }
95 } 101 }
96 102
97 void OnStoreDestroyed() { 103 void OnStoreDestroyed() {
98 rtc::CritScope cs(&cs_); 104 rtc::CritScope cs(&cs_);
99 store_ = NULL; 105 store_ = NULL;
100 } 106 }
101 107
102 rtc::Thread* const signaling_thread_; 108 rtc::Thread* const signaling_thread_;
109 // Locking this prevents |store_| from being destroyed if it has not already
110 // been so.
tommi 2015/06/18 13:55:35 don't think we need this lock
hbos 2015/06/18 15:45:48 <This has not been addressed yet>
hbos 2015/07/02 09:32:23 Acknowledged.
103 rtc::CriticalSection cs_; 111 rtc::CriticalSection cs_;
104 DtlsIdentityStore* store_; 112 DtlsIdentityStoreImpl* store_;
113 rtc::KeyType key_type_;
tommi 2015/06/18 13:55:35 const?
hbos 2015/06/18 15:45:48 Acknowledged.
105 }; 114 };
106 115
107 // Arbitrary constant used as common name for the identity. 116 DtlsIdentityStoreImpl::DtlsIdentityStoreImpl(rtc::Thread* signaling_thread,
108 // Chosen to make the certificates more readable. 117 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), 118 : signaling_thread_(signaling_thread),
114 worker_thread_(worker_thread), 119 worker_thread_(worker_thread),
115 pending_jobs_(0) {} 120 request_observers_(),
121 gen_in_progress_counts_(),
122 free_identities_() { }
116 123
117 DtlsIdentityStore::~DtlsIdentityStore() { 124 DtlsIdentityStoreImpl::~DtlsIdentityStoreImpl() {
118 SignalDestroyed(); 125 SignalDestroyed();
tommi 2015/06/18 13:55:35 We should always be on the signaling thread here,
hbos 2015/06/18 15:45:47 I think so, want a DCHECK thread check? <This has
hbos 2015/07/02 09:32:23 Added DCHECK.
119 } 126 }
120 127
121 void DtlsIdentityStore::Initialize() { 128 void DtlsIdentityStoreImpl::Initialize() {
122 DCHECK(rtc::Thread::Current() == signaling_thread_); 129 DCHECK(rtc::Thread::Current() == signaling_thread_);
123 // Do not aggressively generate the free identity if the worker thread and the 130 // Preemptively generate identities unless the worker thread and signaling
124 // signaling thread are the same. 131 // thread are the same (only do preemptive work in the background).
125 if (worker_thread_ != signaling_thread_) { 132 if (worker_thread_ != signaling_thread_) {
126 GenerateIdentity(); 133 // Only necessary for RSA.
134 GenerateIdentity(rtc::KT_RSA, nullptr);
127 } 135 }
128 } 136 }
129 137
130 void DtlsIdentityStore::RequestIdentity(DTLSIdentityRequestObserver* observer) { 138 void DtlsIdentityStoreImpl::RequestIdentity(
139 rtc::KeyType key_type, ScopedRefPtrObserver observer) {
131 DCHECK(rtc::Thread::Current() == signaling_thread_); 140 DCHECK(rtc::Thread::Current() == signaling_thread_);
132 DCHECK(observer); 141 DCHECK(observer);
133 142
134 // Must return the free identity async. 143 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 } 144 }
144 145
145 void DtlsIdentityStore::OnMessage(rtc::Message* msg) { 146 void DtlsIdentityStoreImpl::OnMessage(rtc::Message* msg) {
146 DCHECK(rtc::Thread::Current() == signaling_thread_); 147 DCHECK(rtc::Thread::Current() == signaling_thread_);
147 switch (msg->message_id) { 148 switch (msg->message_id) {
148 case MSG_GENERATE_IDENTITY_RESULT: { 149 case MSG_GENERATE_IDENTITY_RESULT: {
149 rtc::scoped_ptr<IdentityResultMessageData> pdata( 150 rtc::scoped_ptr<IdentityResultMessageData> pdata(
150 static_cast<IdentityResultMessageData*>(msg->pdata)); 151 static_cast<IdentityResultMessageData*>(msg->pdata));
151 OnIdentityGenerated(pdata->data().Pass()); 152 OnIdentityGenerated(pdata->data()->key_type_,
152 break; 153 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; 154 break;
159 } 155 }
160 } 156 }
161 } 157 }
162 158
163 bool DtlsIdentityStore::HasFreeIdentityForTesting() const { 159 bool DtlsIdentityStoreImpl::HasFreeIdentityForTesting(
160 rtc::KeyType key_type) const {
164 DCHECK(rtc::Thread::Current() == signaling_thread_); 161 DCHECK(rtc::Thread::Current() == signaling_thread_);
165 return free_identity_.get() != nullptr; 162 return free_identities_[key_type].get() != nullptr;
166 } 163 }
167 164
168 void DtlsIdentityStore::GenerateIdentity() { 165 void DtlsIdentityStoreImpl::GenerateIdentity(
166 rtc::KeyType key_type, ScopedRefPtrObserver observer) {
169 DCHECK(rtc::Thread::Current() == signaling_thread_); 167 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 168
174 WorkerTask* task = new WorkerTask(this); 169 // Enqueue observer to be informed when generation of |key_type| is completed.
170 if (observer.get()) {
171 request_observers_[key_type].push_back(observer);
172
173 // Already have a free identity generated?
174 if (free_identities_[key_type].get()) {
175 // Return identity async - post even though we are on |signaling_thread_|.
176 LOG(LS_VERBOSE) << "Using a free DTLS identity.";
177 IdentityResultMessageData* msg = new IdentityResultMessageData(
178 new IdentityResult(key_type, free_identities_[key_type].release()));
179 ++gen_in_progress_counts_[key_type];
180 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
181 return;
182 }
183
184 // Free identity in the process of being generated?
185 if (gen_in_progress_counts_[key_type] ==
186 request_observers_[key_type].size()) {
187 // No need to do anything, the free identity will be returned to the
188 // observer in a MSG_GENERATE_IDENTITY_RESULT.
189 return;
190 }
191 }
192
193 // Enqueue/Post a worker task to do the generation.
194 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 195 // 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. 196 // leaked even if the task does not get run.
177 IdentityTaskMessageData* msg = new IdentityTaskMessageData(task); 197 WorkerTaskMessageData* msg = new WorkerTaskMessageData(task);
198 ++gen_in_progress_counts_[key_type];
178 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg); 199 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg);
179 } 200 }
180 201
181 void DtlsIdentityStore::OnIdentityGenerated( 202 void DtlsIdentityStoreImpl::OnIdentityGenerated(
182 rtc::scoped_ptr<rtc::SSLIdentity> identity) { 203 rtc::KeyType key_type, rtc::scoped_ptr<rtc::SSLIdentity> identity) {
183 DCHECK(rtc::Thread::Current() == signaling_thread_); 204 DCHECK(rtc::Thread::Current() == signaling_thread_);
184 205
185 pending_jobs_--; 206 DCHECK(gen_in_progress_counts_[key_type]);
186 LOG(LS_VERBOSE) << "A DTLS identity generation job returned, " 207 --gen_in_progress_counts_[key_type];
187 << "pending_identities=" << pending_jobs_;
188 208
189 if (pending_observers_.empty()) { 209 ScopedRefPtrObserver observer = nullptr;
190 if (!free_identity_.get()) { 210 if (!request_observers_[key_type].empty()) {
191 free_identity_.reset(identity.release()); 211 observer = request_observers_[key_type].front();
192 LOG(LS_VERBOSE) << "A free DTLS identity is saved"; 212 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 } 213 }
216 214
217 // Do not aggressively generate the free identity if the worker thread and the 215 if (observer.get() == nullptr) {
218 // signaling thread are the same. 216 // No observer - store result in |free_identities_|.
219 if (worker_thread_ != signaling_thread_ && 217 DCHECK(!free_identities_[key_type].get());
220 pending_observers_.empty() && 218 free_identities_[key_type].reset(identity.release());
tommi 2015/06/18 13:55:35 nit: swap()?
hbos 2015/06/18 15:45:47 Acknowledged.
221 pending_jobs_ == 0) { 219 if (free_identities_[key_type].get())
222 // Generate a free identity in the background. 220 LOG(LS_VERBOSE) << "A free DTLS identity was saved.";
223 GenerateIdentity(); 221 else
222 LOG(LS_WARNING) << "Failed to generate DTLS identity (preemptively).";
223 } else {
224 // Return the result to the observer.
225 if (identity.get()) {
226 LOG(LS_VERBOSE) << "A DTLS identity is returned to an observer.";
227 observer->OnSuccessWithIdentityObj(identity.Pass());
228 } else {
229 LOG(LS_WARNING) << "Failed to generate DTLS identity.";
230 observer->OnFailure(0);
231 }
232
233 // Preemptively generate another identity of the same type?
234 if (worker_thread_ != signaling_thread_ // Only do on a background thread.
235 && (key_type == rtc::KT_RSA) // Only necessary for RSA.
tommi 2015/06/18 13:55:35 && at the end of the previous line
hbos 2015/06/18 15:45:48 Acknowledged.
236 && !free_identities_[key_type].get()
237 && request_observers_[key_type].size() <=
238 gen_in_progress_counts_[key_type]) {
239 GenerateIdentity(key_type, nullptr);
240 }
224 } 241 }
225 } 242 }
226 243
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 244 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698