OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2013 Google Inc. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright notice, | |
9 * this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 * this list of conditions and the following disclaimer in the documentation | |
12 * and/or other materials provided with the distribution. | |
13 * 3. The name of the author may not be used to endorse or promote products | |
14 * derived from this software without specific prior written permission. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
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 | |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 #include "talk/app/webrtc/webrtcsessiondescriptionfactory.h" | |
29 | |
30 #include <utility> | |
31 | |
32 #include "talk/app/webrtc/dtlsidentitystore.h" | |
33 #include "talk/app/webrtc/jsep.h" | |
34 #include "talk/app/webrtc/jsepsessiondescription.h" | |
35 #include "talk/app/webrtc/mediaconstraintsinterface.h" | |
36 #include "talk/app/webrtc/webrtcsession.h" | |
37 #include "webrtc/base/sslidentity.h" | |
38 | |
39 using cricket::MediaSessionOptions; | |
40 | |
41 namespace webrtc { | |
42 namespace { | |
43 static const char kFailedDueToIdentityFailed[] = | |
44 " failed because DTLS identity request failed"; | |
45 static const char kFailedDueToSessionShutdown[] = | |
46 " failed because the session was shut down"; | |
47 | |
48 static const uint64_t kInitSessionVersion = 2; | |
49 | |
50 static bool CompareStream(const MediaSessionOptions::Stream& stream1, | |
51 const MediaSessionOptions::Stream& stream2) { | |
52 return stream1.id < stream2.id; | |
53 } | |
54 | |
55 static bool SameId(const MediaSessionOptions::Stream& stream1, | |
56 const MediaSessionOptions::Stream& stream2) { | |
57 return stream1.id == stream2.id; | |
58 } | |
59 | |
60 // Checks if each Stream within the |streams| has unique id. | |
61 static bool ValidStreams(const MediaSessionOptions::Streams& streams) { | |
62 MediaSessionOptions::Streams sorted_streams = streams; | |
63 std::sort(sorted_streams.begin(), sorted_streams.end(), CompareStream); | |
64 MediaSessionOptions::Streams::iterator it = | |
65 std::adjacent_find(sorted_streams.begin(), sorted_streams.end(), | |
66 SameId); | |
67 return it == sorted_streams.end(); | |
68 } | |
69 | |
70 enum { | |
71 MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, | |
72 MSG_CREATE_SESSIONDESCRIPTION_FAILED, | |
73 MSG_USE_CONSTRUCTOR_CERTIFICATE | |
74 }; | |
75 | |
76 struct CreateSessionDescriptionMsg : public rtc::MessageData { | |
77 explicit CreateSessionDescriptionMsg( | |
78 webrtc::CreateSessionDescriptionObserver* observer) | |
79 : observer(observer) { | |
80 } | |
81 | |
82 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer; | |
83 std::string error; | |
84 rtc::scoped_ptr<webrtc::SessionDescriptionInterface> description; | |
85 }; | |
86 } // namespace | |
87 | |
88 void WebRtcIdentityRequestObserver::OnFailure(int error) { | |
89 SignalRequestFailed(error); | |
90 } | |
91 | |
92 void WebRtcIdentityRequestObserver::OnSuccess( | |
93 const std::string& der_cert, const std::string& der_private_key) { | |
94 std::string pem_cert = rtc::SSLIdentity::DerToPem( | |
95 rtc::kPemTypeCertificate, | |
96 reinterpret_cast<const unsigned char*>(der_cert.data()), | |
97 der_cert.length()); | |
98 std::string pem_key = rtc::SSLIdentity::DerToPem( | |
99 rtc::kPemTypeRsaPrivateKey, | |
100 reinterpret_cast<const unsigned char*>(der_private_key.data()), | |
101 der_private_key.length()); | |
102 rtc::scoped_ptr<rtc::SSLIdentity> identity( | |
103 rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert)); | |
104 SignalCertificateReady(rtc::RTCCertificate::Create(std::move(identity))); | |
105 } | |
106 | |
107 void WebRtcIdentityRequestObserver::OnSuccess( | |
108 rtc::scoped_ptr<rtc::SSLIdentity> identity) { | |
109 SignalCertificateReady(rtc::RTCCertificate::Create(std::move(identity))); | |
110 } | |
111 | |
112 // static | |
113 void WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription( | |
114 const SessionDescriptionInterface* source_desc, | |
115 SessionDescriptionInterface* dest_desc) { | |
116 if (!source_desc) | |
117 return; | |
118 for (size_t m = 0; m < source_desc->number_of_mediasections() && | |
119 m < dest_desc->number_of_mediasections(); ++m) { | |
120 const IceCandidateCollection* source_candidates = | |
121 source_desc->candidates(m); | |
122 const IceCandidateCollection* dest_candidates = dest_desc->candidates(m); | |
123 for (size_t n = 0; n < source_candidates->count(); ++n) { | |
124 const IceCandidateInterface* new_candidate = source_candidates->at(n); | |
125 if (!dest_candidates->HasCandidate(new_candidate)) | |
126 dest_desc->AddCandidate(source_candidates->at(n)); | |
127 } | |
128 } | |
129 } | |
130 | |
131 // Private constructor called by other constructors. | |
132 WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory( | |
133 rtc::Thread* signaling_thread, | |
134 cricket::ChannelManager* channel_manager, | |
135 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, | |
136 const rtc::scoped_refptr<WebRtcIdentityRequestObserver>& | |
137 identity_request_observer, | |
138 WebRtcSession* session, | |
139 const std::string& session_id, | |
140 bool dtls_enabled) | |
141 : signaling_thread_(signaling_thread), | |
142 session_desc_factory_(channel_manager, &transport_desc_factory_), | |
143 // RFC 4566 suggested a Network Time Protocol (NTP) format timestamp | |
144 // as the session id and session version. To simplify, it should be fine | |
145 // to just use a random number as session id and start version from | |
146 // |kInitSessionVersion|. | |
147 session_version_(kInitSessionVersion), | |
148 dtls_identity_store_(std::move(dtls_identity_store)), | |
149 identity_request_observer_(identity_request_observer), | |
150 session_(session), | |
151 session_id_(session_id), | |
152 certificate_request_state_(CERTIFICATE_NOT_NEEDED) { | |
153 session_desc_factory_.set_add_legacy_streams(false); | |
154 // SRTP-SDES is disabled if DTLS is on. | |
155 SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED); | |
156 } | |
157 | |
158 WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory( | |
159 rtc::Thread* signaling_thread, | |
160 cricket::ChannelManager* channel_manager, | |
161 WebRtcSession* session, | |
162 const std::string& session_id) | |
163 : WebRtcSessionDescriptionFactory(signaling_thread, | |
164 channel_manager, | |
165 nullptr, | |
166 nullptr, | |
167 session, | |
168 session_id, | |
169 false) { | |
170 LOG(LS_VERBOSE) << "DTLS-SRTP disabled."; | |
171 } | |
172 | |
173 WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory( | |
174 rtc::Thread* signaling_thread, | |
175 cricket::ChannelManager* channel_manager, | |
176 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store, | |
177 WebRtcSession* session, | |
178 const std::string& session_id) | |
179 : WebRtcSessionDescriptionFactory( | |
180 signaling_thread, | |
181 channel_manager, | |
182 std::move(dtls_identity_store), | |
183 new rtc::RefCountedObject<WebRtcIdentityRequestObserver>(), | |
184 session, | |
185 session_id, | |
186 true) { | |
187 RTC_DCHECK(dtls_identity_store_); | |
188 | |
189 certificate_request_state_ = CERTIFICATE_WAITING; | |
190 | |
191 identity_request_observer_->SignalRequestFailed.connect( | |
192 this, &WebRtcSessionDescriptionFactory::OnIdentityRequestFailed); | |
193 identity_request_observer_->SignalCertificateReady.connect( | |
194 this, &WebRtcSessionDescriptionFactory::SetCertificate); | |
195 | |
196 rtc::KeyType key_type = rtc::KT_DEFAULT; | |
197 LOG(LS_VERBOSE) << "DTLS-SRTP enabled; sending DTLS identity request (key " | |
198 << "type: " << key_type << ")."; | |
199 | |
200 // Request identity. This happens asynchronously, so the caller will have a | |
201 // chance to connect to SignalIdentityReady. | |
202 dtls_identity_store_->RequestIdentity(key_type, identity_request_observer_); | |
203 } | |
204 | |
205 WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory( | |
206 rtc::Thread* signaling_thread, | |
207 cricket::ChannelManager* channel_manager, | |
208 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate, | |
209 WebRtcSession* session, | |
210 const std::string& session_id) | |
211 : WebRtcSessionDescriptionFactory(signaling_thread, | |
212 channel_manager, | |
213 nullptr, | |
214 nullptr, | |
215 session, | |
216 session_id, | |
217 true) { | |
218 RTC_DCHECK(certificate); | |
219 | |
220 certificate_request_state_ = CERTIFICATE_WAITING; | |
221 | |
222 LOG(LS_VERBOSE) << "DTLS-SRTP enabled; has certificate parameter."; | |
223 // We already have a certificate but we wait to do SetIdentity; if we do | |
224 // it in the constructor then the caller has not had a chance to connect to | |
225 // SignalIdentityReady. | |
226 signaling_thread_->Post( | |
227 this, MSG_USE_CONSTRUCTOR_CERTIFICATE, | |
228 new rtc::ScopedRefMessageData<rtc::RTCCertificate>(certificate)); | |
229 } | |
230 | |
231 WebRtcSessionDescriptionFactory::~WebRtcSessionDescriptionFactory() { | |
232 ASSERT(signaling_thread_->IsCurrent()); | |
233 | |
234 // Fail any requests that were asked for before identity generation completed. | |
235 FailPendingRequests(kFailedDueToSessionShutdown); | |
236 | |
237 // Process all pending notifications in the message queue. If we don't do | |
238 // this, requests will linger and not know they succeeded or failed. | |
239 rtc::MessageList list; | |
240 signaling_thread_->Clear(this, rtc::MQID_ANY, &list); | |
241 for (auto& msg : list) { | |
242 if (msg.message_id != MSG_USE_CONSTRUCTOR_CERTIFICATE) { | |
243 OnMessage(&msg); | |
244 } else { | |
245 // Skip MSG_USE_CONSTRUCTOR_CERTIFICATE because we don't want to trigger | |
246 // SetIdentity-related callbacks in the destructor. This can be a problem | |
247 // when WebRtcSession listens to the callback but it was the WebRtcSession | |
248 // destructor that caused WebRtcSessionDescriptionFactory's destruction. | |
249 // The callback is then ignored, leaking memory allocated by OnMessage for | |
250 // MSG_USE_CONSTRUCTOR_CERTIFICATE. | |
251 delete msg.pdata; | |
252 } | |
253 } | |
254 } | |
255 | |
256 void WebRtcSessionDescriptionFactory::CreateOffer( | |
257 CreateSessionDescriptionObserver* observer, | |
258 const PeerConnectionInterface::RTCOfferAnswerOptions& options, | |
259 const cricket::MediaSessionOptions& session_options) { | |
260 std::string error = "CreateOffer"; | |
261 if (certificate_request_state_ == CERTIFICATE_FAILED) { | |
262 error += kFailedDueToIdentityFailed; | |
263 LOG(LS_ERROR) << error; | |
264 PostCreateSessionDescriptionFailed(observer, error); | |
265 return; | |
266 } | |
267 | |
268 if (!ValidStreams(session_options.streams)) { | |
269 error += " called with invalid media streams."; | |
270 LOG(LS_ERROR) << error; | |
271 PostCreateSessionDescriptionFailed(observer, error); | |
272 return; | |
273 } | |
274 | |
275 CreateSessionDescriptionRequest request( | |
276 CreateSessionDescriptionRequest::kOffer, observer, session_options); | |
277 if (certificate_request_state_ == CERTIFICATE_WAITING) { | |
278 create_session_description_requests_.push(request); | |
279 } else { | |
280 ASSERT(certificate_request_state_ == CERTIFICATE_SUCCEEDED || | |
281 certificate_request_state_ == CERTIFICATE_NOT_NEEDED); | |
282 InternalCreateOffer(request); | |
283 } | |
284 } | |
285 | |
286 void WebRtcSessionDescriptionFactory::CreateAnswer( | |
287 CreateSessionDescriptionObserver* observer, | |
288 const MediaConstraintsInterface* constraints, | |
289 const cricket::MediaSessionOptions& session_options) { | |
290 std::string error = "CreateAnswer"; | |
291 if (certificate_request_state_ == CERTIFICATE_FAILED) { | |
292 error += kFailedDueToIdentityFailed; | |
293 LOG(LS_ERROR) << error; | |
294 PostCreateSessionDescriptionFailed(observer, error); | |
295 return; | |
296 } | |
297 if (!session_->remote_description()) { | |
298 error += " can't be called before SetRemoteDescription."; | |
299 LOG(LS_ERROR) << error; | |
300 PostCreateSessionDescriptionFailed(observer, error); | |
301 return; | |
302 } | |
303 if (session_->remote_description()->type() != | |
304 JsepSessionDescription::kOffer) { | |
305 error += " failed because remote_description is not an offer."; | |
306 LOG(LS_ERROR) << error; | |
307 PostCreateSessionDescriptionFailed(observer, error); | |
308 return; | |
309 } | |
310 | |
311 if (!ValidStreams(session_options.streams)) { | |
312 error += " called with invalid media streams."; | |
313 LOG(LS_ERROR) << error; | |
314 PostCreateSessionDescriptionFailed(observer, error); | |
315 return; | |
316 } | |
317 | |
318 CreateSessionDescriptionRequest request( | |
319 CreateSessionDescriptionRequest::kAnswer, observer, session_options); | |
320 if (certificate_request_state_ == CERTIFICATE_WAITING) { | |
321 create_session_description_requests_.push(request); | |
322 } else { | |
323 ASSERT(certificate_request_state_ == CERTIFICATE_SUCCEEDED || | |
324 certificate_request_state_ == CERTIFICATE_NOT_NEEDED); | |
325 InternalCreateAnswer(request); | |
326 } | |
327 } | |
328 | |
329 void WebRtcSessionDescriptionFactory::SetSdesPolicy( | |
330 cricket::SecurePolicy secure_policy) { | |
331 session_desc_factory_.set_secure(secure_policy); | |
332 } | |
333 | |
334 cricket::SecurePolicy WebRtcSessionDescriptionFactory::SdesPolicy() const { | |
335 return session_desc_factory_.secure(); | |
336 } | |
337 | |
338 void WebRtcSessionDescriptionFactory::OnMessage(rtc::Message* msg) { | |
339 switch (msg->message_id) { | |
340 case MSG_CREATE_SESSIONDESCRIPTION_SUCCESS: { | |
341 CreateSessionDescriptionMsg* param = | |
342 static_cast<CreateSessionDescriptionMsg*>(msg->pdata); | |
343 param->observer->OnSuccess(param->description.release()); | |
344 delete param; | |
345 break; | |
346 } | |
347 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: { | |
348 CreateSessionDescriptionMsg* param = | |
349 static_cast<CreateSessionDescriptionMsg*>(msg->pdata); | |
350 param->observer->OnFailure(param->error); | |
351 delete param; | |
352 break; | |
353 } | |
354 case MSG_USE_CONSTRUCTOR_CERTIFICATE: { | |
355 rtc::ScopedRefMessageData<rtc::RTCCertificate>* param = | |
356 static_cast<rtc::ScopedRefMessageData<rtc::RTCCertificate>*>( | |
357 msg->pdata); | |
358 LOG(LS_INFO) << "Using certificate supplied to the constructor."; | |
359 SetCertificate(param->data()); | |
360 delete param; | |
361 break; | |
362 } | |
363 default: | |
364 ASSERT(false); | |
365 break; | |
366 } | |
367 } | |
368 | |
369 void WebRtcSessionDescriptionFactory::InternalCreateOffer( | |
370 CreateSessionDescriptionRequest request) { | |
371 cricket::SessionDescription* desc(session_desc_factory_.CreateOffer( | |
372 request.options, session_->local_description() | |
373 ? session_->local_description()->description() | |
374 : nullptr)); | |
375 // RFC 3264 | |
376 // When issuing an offer that modifies the session, | |
377 // the "o=" line of the new SDP MUST be identical to that in the | |
378 // previous SDP, except that the version in the origin field MUST | |
379 // increment by one from the previous SDP. | |
380 | |
381 // Just increase the version number by one each time when a new offer | |
382 // is created regardless if it's identical to the previous one or not. | |
383 // The |session_version_| is a uint64_t, the wrap around should not happen. | |
384 ASSERT(session_version_ + 1 > session_version_); | |
385 JsepSessionDescription* offer(new JsepSessionDescription( | |
386 JsepSessionDescription::kOffer)); | |
387 if (!offer->Initialize(desc, session_id_, | |
388 rtc::ToString(session_version_++))) { | |
389 delete offer; | |
390 PostCreateSessionDescriptionFailed(request.observer, | |
391 "Failed to initialize the offer."); | |
392 return; | |
393 } | |
394 if (session_->local_description() && | |
395 !request.options.audio_transport_options.ice_restart && | |
396 !request.options.video_transport_options.ice_restart && | |
397 !request.options.data_transport_options.ice_restart) { | |
398 // Include all local ice candidates in the SessionDescription unless | |
399 // the an ice restart has been requested. | |
400 CopyCandidatesFromSessionDescription(session_->local_description(), offer); | |
401 } | |
402 PostCreateSessionDescriptionSucceeded(request.observer, offer); | |
403 } | |
404 | |
405 void WebRtcSessionDescriptionFactory::InternalCreateAnswer( | |
406 CreateSessionDescriptionRequest request) { | |
407 // According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1 | |
408 // an answer should also contain new ice ufrag and password if an offer has | |
409 // been received with new ufrag and password. | |
410 request.options.audio_transport_options.ice_restart = | |
411 session_->IceRestartPending(); | |
412 request.options.video_transport_options.ice_restart = | |
413 session_->IceRestartPending(); | |
414 request.options.data_transport_options.ice_restart = | |
415 session_->IceRestartPending(); | |
416 // We should pass current ssl role to the transport description factory, if | |
417 // there is already an existing ongoing session. | |
418 rtc::SSLRole ssl_role; | |
419 if (session_->GetSslRole(session_->voice_channel(), &ssl_role)) { | |
420 request.options.audio_transport_options.prefer_passive_role = | |
421 (rtc::SSL_SERVER == ssl_role); | |
422 } | |
423 if (session_->GetSslRole(session_->video_channel(), &ssl_role)) { | |
424 request.options.video_transport_options.prefer_passive_role = | |
425 (rtc::SSL_SERVER == ssl_role); | |
426 } | |
427 if (session_->GetSslRole(session_->data_channel(), &ssl_role)) { | |
428 request.options.data_transport_options.prefer_passive_role = | |
429 (rtc::SSL_SERVER == ssl_role); | |
430 } | |
431 | |
432 cricket::SessionDescription* desc(session_desc_factory_.CreateAnswer( | |
433 session_->remote_description() | |
434 ? session_->remote_description()->description() | |
435 : nullptr, | |
436 request.options, session_->local_description() | |
437 ? session_->local_description()->description() | |
438 : nullptr)); | |
439 // RFC 3264 | |
440 // If the answer is different from the offer in any way (different IP | |
441 // addresses, ports, etc.), the origin line MUST be different in the answer. | |
442 // In that case, the version number in the "o=" line of the answer is | |
443 // unrelated to the version number in the o line of the offer. | |
444 // Get a new version number by increasing the |session_version_answer_|. | |
445 // The |session_version_| is a uint64_t, the wrap around should not happen. | |
446 ASSERT(session_version_ + 1 > session_version_); | |
447 JsepSessionDescription* answer(new JsepSessionDescription( | |
448 JsepSessionDescription::kAnswer)); | |
449 if (!answer->Initialize(desc, session_id_, | |
450 rtc::ToString(session_version_++))) { | |
451 delete answer; | |
452 PostCreateSessionDescriptionFailed(request.observer, | |
453 "Failed to initialize the answer."); | |
454 return; | |
455 } | |
456 if (session_->local_description() && | |
457 !request.options.audio_transport_options.ice_restart && | |
458 !request.options.video_transport_options.ice_restart && | |
459 !request.options.data_transport_options.ice_restart) { | |
460 // Include all local ice candidates in the SessionDescription unless | |
461 // the remote peer has requested an ice restart. | |
462 CopyCandidatesFromSessionDescription(session_->local_description(), answer); | |
463 } | |
464 session_->ResetIceRestartLatch(); | |
465 PostCreateSessionDescriptionSucceeded(request.observer, answer); | |
466 } | |
467 | |
468 void WebRtcSessionDescriptionFactory::FailPendingRequests( | |
469 const std::string& reason) { | |
470 ASSERT(signaling_thread_->IsCurrent()); | |
471 while (!create_session_description_requests_.empty()) { | |
472 const CreateSessionDescriptionRequest& request = | |
473 create_session_description_requests_.front(); | |
474 PostCreateSessionDescriptionFailed(request.observer, | |
475 ((request.type == CreateSessionDescriptionRequest::kOffer) ? | |
476 "CreateOffer" : "CreateAnswer") + reason); | |
477 create_session_description_requests_.pop(); | |
478 } | |
479 } | |
480 | |
481 void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionFailed( | |
482 CreateSessionDescriptionObserver* observer, const std::string& error) { | |
483 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer); | |
484 msg->error = error; | |
485 signaling_thread_->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg); | |
486 LOG(LS_ERROR) << "Create SDP failed: " << error; | |
487 } | |
488 | |
489 void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded( | |
490 CreateSessionDescriptionObserver* observer, | |
491 SessionDescriptionInterface* description) { | |
492 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer); | |
493 msg->description.reset(description); | |
494 signaling_thread_->Post(this, MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, msg); | |
495 } | |
496 | |
497 void WebRtcSessionDescriptionFactory::OnIdentityRequestFailed(int error) { | |
498 ASSERT(signaling_thread_->IsCurrent()); | |
499 | |
500 LOG(LS_ERROR) << "Async identity request failed: error = " << error; | |
501 certificate_request_state_ = CERTIFICATE_FAILED; | |
502 | |
503 FailPendingRequests(kFailedDueToIdentityFailed); | |
504 } | |
505 | |
506 void WebRtcSessionDescriptionFactory::SetCertificate( | |
507 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { | |
508 RTC_DCHECK(certificate); | |
509 LOG(LS_VERBOSE) << "Setting new certificate"; | |
510 | |
511 certificate_request_state_ = CERTIFICATE_SUCCEEDED; | |
512 SignalCertificateReady(certificate); | |
513 | |
514 transport_desc_factory_.set_certificate(certificate); | |
515 transport_desc_factory_.set_secure(cricket::SEC_ENABLED); | |
516 | |
517 while (!create_session_description_requests_.empty()) { | |
518 if (create_session_description_requests_.front().type == | |
519 CreateSessionDescriptionRequest::kOffer) { | |
520 InternalCreateOffer(create_session_description_requests_.front()); | |
521 } else { | |
522 InternalCreateAnswer(create_session_description_requests_.front()); | |
523 } | |
524 create_session_description_requests_.pop(); | |
525 } | |
526 } | |
527 } // namespace webrtc | |
OLD | NEW |