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

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: Merge w master AFTER the landing of 1268363002. "CreatePC(service,store)" using store instead of service. Created 5 years, 4 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
« no previous file with comments | « talk/app/webrtc/dtlsidentitystore.h ('k') | talk/app/webrtc/dtlsidentitystore_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 34
35 namespace webrtc { 35 namespace webrtc {
36 36
37 // Passed to SSLIdentity::Generate, "WebRTC". Used for the certificates'
38 // subject and issuer name.
39 static const char kIdentityName[] = "WebRTC";
40
37 namespace { 41 namespace {
38 42
39 enum { 43 enum {
40 MSG_DESTROY, 44 MSG_DESTROY,
41 MSG_GENERATE_IDENTITY, 45 MSG_GENERATE_IDENTITY,
42 MSG_GENERATE_IDENTITY_RESULT, 46 MSG_GENERATE_IDENTITY_RESULT
43 MSG_RETURN_FREE_IDENTITY
44 }; 47 };
45 48
46 typedef rtc::ScopedMessageData<rtc::SSLIdentity> IdentityResultMessageData;
47
48 } // namespace 49 } // namespace
49 50
50 // This class runs on the worker thread to generate the identity. It's necessary 51 // This class runs on the worker thread to generate the identity. It's necessary
51 // to separate this class from DtlsIdentityStore so that it can live on the 52 // to separate this class from DtlsIdentityStore so that it can live on the
52 // worker thread after DtlsIdentityStore is destroyed. 53 // worker thread after DtlsIdentityStore is destroyed.
53 class DtlsIdentityStore::WorkerTask : public sigslot::has_slots<>, 54 class DtlsIdentityStoreImpl::WorkerTask : public sigslot::has_slots<>,
54 public rtc::MessageHandler { 55 public rtc::MessageHandler {
55 public: 56 public:
56 explicit WorkerTask(DtlsIdentityStore* store) 57 WorkerTask(DtlsIdentityStoreImpl* store, rtc::KeyType key_type)
57 : signaling_thread_(rtc::Thread::Current()), store_(store) { 58 : signaling_thread_(rtc::Thread::Current()),
59 store_(store),
60 key_type_(key_type) {
58 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed); 61 store_->SignalDestroyed.connect(this, &WorkerTask::OnStoreDestroyed);
59 } 62 }
60 63
61 virtual ~WorkerTask() { DCHECK(rtc::Thread::Current() == signaling_thread_); } 64 virtual ~WorkerTask() { DCHECK(signaling_thread_->IsCurrent()); }
62 65
63 private: 66 private:
64 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_;
65 rtc::scoped_ptr<rtc::SSLIdentity> identity( 71 rtc::scoped_ptr<rtc::SSLIdentity> identity(
66 rtc::SSLIdentity::Generate(DtlsIdentityStore::kIdentityName)); 72 rtc::SSLIdentity::Generate(kIdentityName));
67 73
68 { 74 // Posting to |this| avoids touching |store_| on threads other than
69 rtc::CritScope cs(&cs_); 75 // |signaling_thread_| and thus avoids having to use locks.
70 if (store_) { 76 IdentityResultMessageData* msg = new IdentityResultMessageData(
71 store_->PostGenerateIdentityResult_w(identity.Pass()); 77 new IdentityResult(key_type_, identity.Pass()));
72 } 78 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
73 }
74 } 79 }
75 80
76 void OnMessage(rtc::Message* msg) override { 81 void OnMessage(rtc::Message* msg) override {
77 switch (msg->message_id) { 82 switch (msg->message_id) {
78 case MSG_GENERATE_IDENTITY: 83 case MSG_GENERATE_IDENTITY:
79 // This message always runs on the worker thread. 84 // This message always runs on the worker thread.
80 GenerateIdentity_w(); 85 GenerateIdentity_w();
81 86
82 // Must delete |this|, owned by msg->pdata, on the signaling thread to 87 // Must delete |this|, owned by msg->pdata, on the signaling thread to
83 // avoid races on disconnecting the signal. 88 // avoid races on disconnecting the signal.
84 signaling_thread_->Post(this, MSG_DESTROY, msg->pdata); 89 signaling_thread_->Post(this, MSG_DESTROY, msg->pdata);
85 break; 90 break;
91 case MSG_GENERATE_IDENTITY_RESULT:
92 DCHECK(signaling_thread_->IsCurrent());
93 {
94 rtc::scoped_ptr<IdentityResultMessageData> pdata(
95 static_cast<IdentityResultMessageData*>(msg->pdata));
96 if (store_) {
97 store_->OnIdentityGenerated(pdata->data()->key_type_,
98 pdata->data()->identity_.Pass());
99 }
100 }
101 break;
86 case MSG_DESTROY: 102 case MSG_DESTROY:
87 DCHECK(rtc::Thread::Current() == signaling_thread_); 103 DCHECK(signaling_thread_->IsCurrent());
88 delete msg->pdata; 104 delete msg->pdata;
89 // |this| has now been deleted. Don't touch member variables. 105 // |this| has now been deleted. Don't touch member variables.
90 break; 106 break;
91 default: 107 default:
92 CHECK(false) << "Unexpected message type"; 108 CHECK(false) << "Unexpected message type";
93 } 109 }
94 } 110 }
95 111
96 void OnStoreDestroyed() { 112 void OnStoreDestroyed() {
97 rtc::CritScope cs(&cs_); 113 DCHECK(signaling_thread_->IsCurrent());
98 store_ = NULL; 114 store_ = nullptr;
99 } 115 }
100 116
101 rtc::Thread* const signaling_thread_; 117 rtc::Thread* const signaling_thread_;
102 rtc::CriticalSection cs_; 118 DtlsIdentityStoreImpl* store_; // Only touched on |signaling_thread_|.
103 DtlsIdentityStore* store_; 119 const rtc::KeyType key_type_;
104 }; 120 };
105 121
106 // Arbitrary constant used as common name for the identity. 122 DtlsIdentityStoreImpl::DtlsIdentityStoreImpl(rtc::Thread* signaling_thread,
107 // Chosen to make the certificates more readable. 123 rtc::Thread* worker_thread)
108 const char DtlsIdentityStore::kIdentityName[] = "WebRTC";
109
110 DtlsIdentityStore::DtlsIdentityStore(rtc::Thread* signaling_thread,
111 rtc::Thread* worker_thread)
112 : signaling_thread_(signaling_thread), 124 : signaling_thread_(signaling_thread),
113 worker_thread_(worker_thread), 125 worker_thread_(worker_thread),
114 pending_jobs_(0) {} 126 request_info_() {
127 DCHECK(signaling_thread_->IsCurrent());
128 // Preemptively generate identities unless the worker thread and signaling
129 // thread are the same (only do preemptive work in the background).
130 if (worker_thread_ != signaling_thread_) {
131 // Only necessary for RSA.
132 GenerateIdentity(rtc::KT_RSA, nullptr);
133 }
134 }
115 135
116 DtlsIdentityStore::~DtlsIdentityStore() { 136 DtlsIdentityStoreImpl::~DtlsIdentityStoreImpl() {
137 DCHECK(signaling_thread_->IsCurrent());
117 SignalDestroyed(); 138 SignalDestroyed();
118 } 139 }
119 140
120 void DtlsIdentityStore::Initialize() { 141 void DtlsIdentityStoreImpl::RequestIdentity(
121 DCHECK(rtc::Thread::Current() == signaling_thread_); 142 rtc::KeyType key_type,
122 // Do not aggressively generate the free identity if the worker thread and the 143 const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer) {
123 // signaling thread are the same. 144 DCHECK(signaling_thread_->IsCurrent());
124 if (worker_thread_ != signaling_thread_) { 145 DCHECK(observer);
125 GenerateIdentity(); 146
126 } 147 GenerateIdentity(key_type, observer);
127 } 148 }
128 149
129 void DtlsIdentityStore::RequestIdentity(DTLSIdentityRequestObserver* observer) { 150 void DtlsIdentityStoreImpl::OnMessage(rtc::Message* msg) {
130 DCHECK(rtc::Thread::Current() == signaling_thread_); 151 DCHECK(signaling_thread_->IsCurrent());
131 DCHECK(observer);
132
133 // Must return the free identity async.
134 if (free_identity_.get()) {
135 IdentityResultMessageData* msg =
136 new IdentityResultMessageData(free_identity_.release());
137 signaling_thread_->Post(this, MSG_RETURN_FREE_IDENTITY, msg);
138 }
139
140 pending_observers_.push(observer);
141 GenerateIdentity();
142 }
143
144 void DtlsIdentityStore::OnMessage(rtc::Message* msg) {
145 DCHECK(rtc::Thread::Current() == signaling_thread_);
146 switch (msg->message_id) { 152 switch (msg->message_id) {
147 case MSG_GENERATE_IDENTITY_RESULT: { 153 case MSG_GENERATE_IDENTITY_RESULT: {
148 rtc::scoped_ptr<IdentityResultMessageData> pdata( 154 rtc::scoped_ptr<IdentityResultMessageData> pdata(
149 static_cast<IdentityResultMessageData*>(msg->pdata)); 155 static_cast<IdentityResultMessageData*>(msg->pdata));
150 OnIdentityGenerated(pdata->data().Pass()); 156 OnIdentityGenerated(pdata->data()->key_type_,
151 break; 157 pdata->data()->identity_.Pass());
152 }
153 case MSG_RETURN_FREE_IDENTITY: {
154 rtc::scoped_ptr<IdentityResultMessageData> pdata(
155 static_cast<IdentityResultMessageData*>(msg->pdata));
156 ReturnIdentity(pdata->data().Pass());
157 break; 158 break;
158 } 159 }
159 } 160 }
160 } 161 }
161 162
162 bool DtlsIdentityStore::HasFreeIdentityForTesting() const { 163 bool DtlsIdentityStoreImpl::HasFreeIdentityForTesting(
163 DCHECK(rtc::Thread::Current() == signaling_thread_); 164 rtc::KeyType key_type) const {
164 return free_identity_.get() != nullptr; 165 DCHECK(signaling_thread_->IsCurrent());
166 return request_info_[key_type].free_identity_.get() != nullptr;
165 } 167 }
166 168
167 void DtlsIdentityStore::GenerateIdentity() { 169 void DtlsIdentityStoreImpl::GenerateIdentity(
168 DCHECK(rtc::Thread::Current() == signaling_thread_); 170 rtc::KeyType key_type,
169 pending_jobs_++; 171 const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>& observer) {
170 LOG(LS_VERBOSE) << "New DTLS identity generation is posted, " 172 DCHECK(signaling_thread_->IsCurrent());
171 << "pending_identities=" << pending_jobs_;
172 173
173 WorkerTask* task = new WorkerTask(this); 174 // Enqueue observer to be informed when generation of |key_type| is completed.
175 if (observer.get()) {
176 request_info_[key_type].request_observers_.push(observer);
177
178 // Already have a free identity generated?
179 if (request_info_[key_type].free_identity_.get()) {
180 // Return identity async - post even though we are on |signaling_thread_|.
181 LOG(LS_VERBOSE) << "Using a free DTLS identity.";
182 ++request_info_[key_type].gen_in_progress_counts_;
183 IdentityResultMessageData* msg = new IdentityResultMessageData(
184 new IdentityResult(key_type,
185 request_info_[key_type].free_identity_.Pass()));
186 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
187 return;
188 }
189
190 // Free identity in the process of being generated?
191 if (request_info_[key_type].gen_in_progress_counts_ ==
192 request_info_[key_type].request_observers_.size()) {
193 // No need to do anything, the free identity will be returned to the
194 // observer in a MSG_GENERATE_IDENTITY_RESULT.
195 return;
196 }
197 }
198
199 // Enqueue/Post a worker task to do the generation.
200 ++request_info_[key_type].gen_in_progress_counts_;
201 WorkerTask* task = new WorkerTask(this, key_type); // Post 1 task/request.
174 // The WorkerTask is owned by the message data to make sure it will not be 202 // The WorkerTask is owned by the message data to make sure it will not be
175 // leaked even if the task does not get run. 203 // leaked even if the task does not get run.
176 IdentityTaskMessageData* msg = new IdentityTaskMessageData(task); 204 WorkerTaskMessageData* msg = new WorkerTaskMessageData(task);
177 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg); 205 worker_thread_->Post(task, MSG_GENERATE_IDENTITY, msg);
178 } 206 }
179 207
180 void DtlsIdentityStore::OnIdentityGenerated( 208 void DtlsIdentityStoreImpl::OnIdentityGenerated(
181 rtc::scoped_ptr<rtc::SSLIdentity> identity) { 209 rtc::KeyType key_type, rtc::scoped_ptr<rtc::SSLIdentity> identity) {
182 DCHECK(rtc::Thread::Current() == signaling_thread_); 210 DCHECK(signaling_thread_->IsCurrent());
183 211
184 pending_jobs_--; 212 DCHECK(request_info_[key_type].gen_in_progress_counts_);
185 LOG(LS_VERBOSE) << "A DTLS identity generation job returned, " 213 --request_info_[key_type].gen_in_progress_counts_;
186 << "pending_identities=" << pending_jobs_;
187 214
188 if (pending_observers_.empty()) { 215 rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver> observer;
189 if (!free_identity_.get()) { 216 if (!request_info_[key_type].request_observers_.empty()) {
190 free_identity_.reset(identity.release()); 217 observer = request_info_[key_type].request_observers_.front();
191 LOG(LS_VERBOSE) << "A free DTLS identity is saved"; 218 request_info_[key_type].request_observers_.pop();
192 }
193 return;
194 }
195 ReturnIdentity(identity.Pass());
196 }
197
198 void DtlsIdentityStore::ReturnIdentity(
199 rtc::scoped_ptr<rtc::SSLIdentity> identity) {
200 DCHECK(rtc::Thread::Current() == signaling_thread_);
201 DCHECK(!free_identity_.get());
202 DCHECK(!pending_observers_.empty());
203
204 rtc::scoped_refptr<DTLSIdentityRequestObserver> observer =
205 pending_observers_.front();
206 pending_observers_.pop();
207
208 if (identity.get()) {
209 observer->OnSuccessWithIdentityObj(identity.Pass());
210 } else {
211 // Pass an arbitrary error code.
212 observer->OnFailure(0);
213 LOG(LS_WARNING) << "Failed to generate SSL identity";
214 } 219 }
215 220
216 // Do not aggressively generate the free identity if the worker thread and the 221 if (observer.get() == nullptr) {
217 // signaling thread are the same. 222 // No observer - store result in |free_identities_|.
218 if (worker_thread_ != signaling_thread_ && 223 DCHECK(!request_info_[key_type].free_identity_.get());
219 pending_observers_.empty() && 224 request_info_[key_type].free_identity_.swap(identity);
220 pending_jobs_ == 0) { 225 if (request_info_[key_type].free_identity_.get())
221 // Generate a free identity in the background. 226 LOG(LS_VERBOSE) << "A free DTLS identity was saved.";
222 GenerateIdentity(); 227 else
228 LOG(LS_WARNING) << "Failed to generate DTLS identity (preemptively).";
229 } else {
230 // Return the result to the observer.
231 if (identity.get()) {
232 LOG(LS_VERBOSE) << "A DTLS identity is returned to an observer.";
233 observer->OnSuccess(identity.Pass());
234 } else {
235 LOG(LS_WARNING) << "Failed to generate DTLS identity.";
236 observer->OnFailure(0);
237 }
238
239 // Preemptively generate another identity of the same type?
240 if (worker_thread_ != signaling_thread_ && // Only do in background thread.
241 key_type == rtc::KT_RSA && // Only necessary for RSA.
242 !request_info_[key_type].free_identity_.get() &&
243 request_info_[key_type].request_observers_.size() <=
244 request_info_[key_type].gen_in_progress_counts_) {
245 GenerateIdentity(key_type, nullptr);
246 }
223 } 247 }
224 } 248 }
225 249
226 void DtlsIdentityStore::PostGenerateIdentityResult_w(
227 rtc::scoped_ptr<rtc::SSLIdentity> identity) {
228 DCHECK(rtc::Thread::Current() == worker_thread_);
229
230 IdentityResultMessageData* msg =
231 new IdentityResultMessageData(identity.release());
232 signaling_thread_->Post(this, MSG_GENERATE_IDENTITY_RESULT, msg);
233 }
234 } // namespace webrtc 250 } // namespace webrtc
OLDNEW
« no previous file with comments | « talk/app/webrtc/dtlsidentitystore.h ('k') | talk/app/webrtc/dtlsidentitystore_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698