blob: 25965af79d30f92cddd20b999436d67d4a95f601 [file] [log] [blame]
wu@webrtc.org91053e72013-08-10 07:18:04 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +00003 * Copyright 2013 Google Inc.
wu@webrtc.org91053e72013-08-10 07:18:04 +00004 *
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
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000030#include "talk/app/webrtc/dtlsidentitystore.h"
wu@webrtc.org91053e72013-08-10 07:18:04 +000031#include "talk/app/webrtc/jsep.h"
32#include "talk/app/webrtc/jsepsessiondescription.h"
33#include "talk/app/webrtc/mediaconstraintsinterface.h"
wu@webrtc.org91053e72013-08-10 07:18:04 +000034#include "talk/app/webrtc/webrtcsession.h"
Henrik Boström5e56c592015-08-11 10:33:13 +020035#include "webrtc/base/sslidentity.h"
wu@webrtc.org91053e72013-08-10 07:18:04 +000036
wu@webrtc.org364f2042013-11-20 21:49:41 +000037using cricket::MediaSessionOptions;
38
wu@webrtc.org91053e72013-08-10 07:18:04 +000039namespace webrtc {
wu@webrtc.org91053e72013-08-10 07:18:04 +000040namespace {
wu@webrtc.org91053e72013-08-10 07:18:04 +000041static const char kFailedDueToIdentityFailed[] =
42 " failed because DTLS identity request failed";
tommi0f620f42015-07-09 03:25:02 -070043static const char kFailedDueToSessionShutdown[] =
44 " failed because the session was shut down";
wu@webrtc.org91053e72013-08-10 07:18:04 +000045
Peter Boström0c4e06b2015-10-07 12:23:21 +020046static const uint64_t kInitSessionVersion = 2;
wu@webrtc.org91053e72013-08-10 07:18:04 +000047
wu@webrtc.org364f2042013-11-20 21:49:41 +000048static bool CompareStream(const MediaSessionOptions::Stream& stream1,
49 const MediaSessionOptions::Stream& stream2) {
50 return stream1.id < stream2.id;
wu@webrtc.org91053e72013-08-10 07:18:04 +000051}
52
wu@webrtc.org364f2042013-11-20 21:49:41 +000053static bool SameId(const MediaSessionOptions::Stream& stream1,
54 const MediaSessionOptions::Stream& stream2) {
55 return stream1.id == stream2.id;
wu@webrtc.org91053e72013-08-10 07:18:04 +000056}
57
58// Checks if each Stream within the |streams| has unique id.
wu@webrtc.org364f2042013-11-20 21:49:41 +000059static bool ValidStreams(const MediaSessionOptions::Streams& streams) {
60 MediaSessionOptions::Streams sorted_streams = streams;
wu@webrtc.org91053e72013-08-10 07:18:04 +000061 std::sort(sorted_streams.begin(), sorted_streams.end(), CompareStream);
wu@webrtc.org364f2042013-11-20 21:49:41 +000062 MediaSessionOptions::Streams::iterator it =
wu@webrtc.org91053e72013-08-10 07:18:04 +000063 std::adjacent_find(sorted_streams.begin(), sorted_streams.end(),
64 SameId);
wu@webrtc.org364f2042013-11-20 21:49:41 +000065 return it == sorted_streams.end();
wu@webrtc.org91053e72013-08-10 07:18:04 +000066}
67
68enum {
69 MSG_CREATE_SESSIONDESCRIPTION_SUCCESS,
Henrik Boström87713d02015-08-25 09:53:21 +020070 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
71 MSG_USE_CONSTRUCTOR_CERTIFICATE
wu@webrtc.org91053e72013-08-10 07:18:04 +000072};
73
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000074struct CreateSessionDescriptionMsg : public rtc::MessageData {
wu@webrtc.org91053e72013-08-10 07:18:04 +000075 explicit CreateSessionDescriptionMsg(
76 webrtc::CreateSessionDescriptionObserver* observer)
77 : observer(observer) {
78 }
79
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000080 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
wu@webrtc.org91053e72013-08-10 07:18:04 +000081 std::string error;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000082 rtc::scoped_ptr<webrtc::SessionDescriptionInterface> description;
wu@webrtc.org91053e72013-08-10 07:18:04 +000083};
wu@webrtc.org91053e72013-08-10 07:18:04 +000084} // namespace
85
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000086void WebRtcIdentityRequestObserver::OnFailure(int error) {
87 SignalRequestFailed(error);
88}
89
90void WebRtcIdentityRequestObserver::OnSuccess(
91 const std::string& der_cert, const std::string& der_private_key) {
92 std::string pem_cert = rtc::SSLIdentity::DerToPem(
93 rtc::kPemTypeCertificate,
94 reinterpret_cast<const unsigned char*>(der_cert.data()),
95 der_cert.length());
96 std::string pem_key = rtc::SSLIdentity::DerToPem(
97 rtc::kPemTypeRsaPrivateKey,
98 reinterpret_cast<const unsigned char*>(der_private_key.data()),
99 der_private_key.length());
Henrik Boströmd8281982015-08-27 10:12:24 +0200100 rtc::scoped_ptr<rtc::SSLIdentity> identity(
101 rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert));
102 SignalCertificateReady(rtc::RTCCertificate::Create(identity.Pass()));
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000103}
104
Henrik Boström5e56c592015-08-11 10:33:13 +0200105void WebRtcIdentityRequestObserver::OnSuccess(
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000106 rtc::scoped_ptr<rtc::SSLIdentity> identity) {
Henrik Boströmd8281982015-08-27 10:12:24 +0200107 SignalCertificateReady(rtc::RTCCertificate::Create(identity.Pass()));
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000108}
109
wu@webrtc.org91053e72013-08-10 07:18:04 +0000110// static
111void WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
112 const SessionDescriptionInterface* source_desc,
113 SessionDescriptionInterface* dest_desc) {
114 if (!source_desc)
115 return;
116 for (size_t m = 0; m < source_desc->number_of_mediasections() &&
117 m < dest_desc->number_of_mediasections(); ++m) {
118 const IceCandidateCollection* source_candidates =
119 source_desc->candidates(m);
120 const IceCandidateCollection* dest_candidates = dest_desc->candidates(m);
121 for (size_t n = 0; n < source_candidates->count(); ++n) {
122 const IceCandidateInterface* new_candidate = source_candidates->at(n);
123 if (!dest_candidates->HasCandidate(new_candidate))
124 dest_desc->AddCandidate(source_candidates->at(n));
125 }
126 }
127}
128
Henrik Boström87713d02015-08-25 09:53:21 +0200129// Private constructor called by other constructors.
wu@webrtc.org91053e72013-08-10 07:18:04 +0000130WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000131 rtc::Thread* signaling_thread,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000132 cricket::ChannelManager* channel_manager,
Henrik Boström5e56c592015-08-11 10:33:13 +0200133 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
Henrik Boström87713d02015-08-25 09:53:21 +0200134 const rtc::scoped_refptr<WebRtcIdentityRequestObserver>&
135 identity_request_observer,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000136 WebRtcSession* session,
137 const std::string& session_id,
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000138 bool dtls_enabled)
wu@webrtc.org91053e72013-08-10 07:18:04 +0000139 : signaling_thread_(signaling_thread),
wu@webrtc.org91053e72013-08-10 07:18:04 +0000140 session_desc_factory_(channel_manager, &transport_desc_factory_),
141 // RFC 4566 suggested a Network Time Protocol (NTP) format timestamp
142 // as the session id and session version. To simplify, it should be fine
143 // to just use a random number as session id and start version from
144 // |kInitSessionVersion|.
145 session_version_(kInitSessionVersion),
Henrik Boström5e56c592015-08-11 10:33:13 +0200146 dtls_identity_store_(dtls_identity_store.Pass()),
Henrik Boström87713d02015-08-25 09:53:21 +0200147 identity_request_observer_(identity_request_observer),
wu@webrtc.org91053e72013-08-10 07:18:04 +0000148 session_(session),
149 session_id_(session_id),
Henrik Boström87713d02015-08-25 09:53:21 +0200150 certificate_request_state_(CERTIFICATE_NOT_NEEDED) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000151 session_desc_factory_.set_add_legacy_streams(false);
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000152 // SRTP-SDES is disabled if DTLS is on.
153 SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED);
Henrik Boström87713d02015-08-25 09:53:21 +0200154}
wu@webrtc.org91053e72013-08-10 07:18:04 +0000155
Henrik Boström87713d02015-08-25 09:53:21 +0200156WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
157 rtc::Thread* signaling_thread,
158 cricket::ChannelManager* channel_manager,
Henrik Boström87713d02015-08-25 09:53:21 +0200159 WebRtcSession* session,
deadbeefab9b2d12015-10-14 11:33:11 -0700160 const std::string& session_id)
deadbeefcbecd352015-09-23 11:50:27 -0700161 : WebRtcSessionDescriptionFactory(signaling_thread,
162 channel_manager,
deadbeefcbecd352015-09-23 11:50:27 -0700163 nullptr,
164 nullptr,
165 session,
166 session_id,
deadbeefcbecd352015-09-23 11:50:27 -0700167 false) {
Henrik Boström87713d02015-08-25 09:53:21 +0200168 LOG(LS_VERBOSE) << "DTLS-SRTP disabled.";
169}
wu@webrtc.org91053e72013-08-10 07:18:04 +0000170
Henrik Boström87713d02015-08-25 09:53:21 +0200171WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
172 rtc::Thread* signaling_thread,
173 cricket::ChannelManager* channel_manager,
Henrik Boström87713d02015-08-25 09:53:21 +0200174 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
175 WebRtcSession* session,
deadbeefab9b2d12015-10-14 11:33:11 -0700176 const std::string& session_id)
Henrik Boström87713d02015-08-25 09:53:21 +0200177 : WebRtcSessionDescriptionFactory(
deadbeefab9b2d12015-10-14 11:33:11 -0700178 signaling_thread,
179 channel_manager,
180 dtls_identity_store.Pass(),
181 new rtc::RefCountedObject<WebRtcIdentityRequestObserver>(),
182 session,
183 session_id,
184 true) {
henrikg91d6ede2015-09-17 00:24:34 -0700185 RTC_DCHECK(dtls_identity_store_);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000186
Henrik Boström87713d02015-08-25 09:53:21 +0200187 certificate_request_state_ = CERTIFICATE_WAITING;
wu@webrtc.org364f2042013-11-20 21:49:41 +0000188
Henrik Boström87713d02015-08-25 09:53:21 +0200189 identity_request_observer_->SignalRequestFailed.connect(
190 this, &WebRtcSessionDescriptionFactory::OnIdentityRequestFailed);
Henrik Boströmd8281982015-08-27 10:12:24 +0200191 identity_request_observer_->SignalCertificateReady.connect(
192 this, &WebRtcSessionDescriptionFactory::SetCertificate);
Henrik Boström87713d02015-08-25 09:53:21 +0200193
194 rtc::KeyType key_type = rtc::KT_DEFAULT;
195 LOG(LS_VERBOSE) << "DTLS-SRTP enabled; sending DTLS identity request (key "
196 << "type: " << key_type << ").";
197
198 // Request identity. This happens asynchronously, so the caller will have a
199 // chance to connect to SignalIdentityReady.
200 dtls_identity_store_->RequestIdentity(key_type, identity_request_observer_);
201}
202
203WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
204 rtc::Thread* signaling_thread,
205 cricket::ChannelManager* channel_manager,
Henrik Boström87713d02015-08-25 09:53:21 +0200206 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate,
207 WebRtcSession* session,
deadbeefab9b2d12015-10-14 11:33:11 -0700208 const std::string& session_id)
209 : WebRtcSessionDescriptionFactory(signaling_thread,
210 channel_manager,
211 nullptr,
212 nullptr,
213 session,
214 session_id,
215 true) {
henrikg91d6ede2015-09-17 00:24:34 -0700216 RTC_DCHECK(certificate);
Henrik Boström87713d02015-08-25 09:53:21 +0200217
218 certificate_request_state_ = CERTIFICATE_WAITING;
219
220 LOG(LS_VERBOSE) << "DTLS-SRTP enabled; has certificate parameter.";
221 // We already have a certificate but we wait to do SetIdentity; if we do
222 // it in the constructor then the caller has not had a chance to connect to
223 // SignalIdentityReady.
deadbeefcbecd352015-09-23 11:50:27 -0700224 signaling_thread_->Post(
225 this, MSG_USE_CONSTRUCTOR_CERTIFICATE,
226 new rtc::ScopedRefMessageData<rtc::RTCCertificate>(certificate));
wu@webrtc.org91053e72013-08-10 07:18:04 +0000227}
228
229WebRtcSessionDescriptionFactory::~WebRtcSessionDescriptionFactory() {
tommi0f620f42015-07-09 03:25:02 -0700230 ASSERT(signaling_thread_->IsCurrent());
231
232 // Fail any requests that were asked for before identity generation completed.
233 FailPendingRequests(kFailedDueToSessionShutdown);
234
235 // Process all pending notifications in the message queue. If we don't do
236 // this, requests will linger and not know they succeeded or failed.
237 rtc::MessageList list;
238 signaling_thread_->Clear(this, rtc::MQID_ANY, &list);
Henrik Boström87713d02015-08-25 09:53:21 +0200239 for (auto& msg : list) {
240 if (msg.message_id != MSG_USE_CONSTRUCTOR_CERTIFICATE) {
241 OnMessage(&msg);
242 } else {
243 // Skip MSG_USE_CONSTRUCTOR_CERTIFICATE because we don't want to trigger
244 // SetIdentity-related callbacks in the destructor. This can be a problem
245 // when WebRtcSession listens to the callback but it was the WebRtcSession
246 // destructor that caused WebRtcSessionDescriptionFactory's destruction.
247 // The callback is then ignored, leaking memory allocated by OnMessage for
248 // MSG_USE_CONSTRUCTOR_CERTIFICATE.
249 delete msg.pdata;
250 }
251 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000252}
253
254void WebRtcSessionDescriptionFactory::CreateOffer(
255 CreateSessionDescriptionObserver* observer,
deadbeefab9b2d12015-10-14 11:33:11 -0700256 const PeerConnectionInterface::RTCOfferAnswerOptions& options,
257 const cricket::MediaSessionOptions& session_options) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000258 std::string error = "CreateOffer";
Henrik Boström87713d02015-08-25 09:53:21 +0200259 if (certificate_request_state_ == CERTIFICATE_FAILED) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000260 error += kFailedDueToIdentityFailed;
261 LOG(LS_ERROR) << error;
262 PostCreateSessionDescriptionFailed(observer, error);
263 return;
264 }
265
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000266 if (!ValidStreams(session_options.streams)) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000267 error += " called with invalid media streams.";
268 LOG(LS_ERROR) << error;
269 PostCreateSessionDescriptionFailed(observer, error);
270 return;
271 }
272
wu@webrtc.org91053e72013-08-10 07:18:04 +0000273 CreateSessionDescriptionRequest request(
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000274 CreateSessionDescriptionRequest::kOffer, observer, session_options);
Henrik Boström87713d02015-08-25 09:53:21 +0200275 if (certificate_request_state_ == CERTIFICATE_WAITING) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000276 create_session_description_requests_.push(request);
277 } else {
Henrik Boström87713d02015-08-25 09:53:21 +0200278 ASSERT(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
279 certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000280 InternalCreateOffer(request);
281 }
282}
283
284void WebRtcSessionDescriptionFactory::CreateAnswer(
285 CreateSessionDescriptionObserver* observer,
deadbeefab9b2d12015-10-14 11:33:11 -0700286 const MediaConstraintsInterface* constraints,
287 const cricket::MediaSessionOptions& session_options) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000288 std::string error = "CreateAnswer";
Henrik Boström87713d02015-08-25 09:53:21 +0200289 if (certificate_request_state_ == CERTIFICATE_FAILED) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000290 error += kFailedDueToIdentityFailed;
291 LOG(LS_ERROR) << error;
292 PostCreateSessionDescriptionFailed(observer, error);
293 return;
294 }
295 if (!session_->remote_description()) {
296 error += " can't be called before SetRemoteDescription.";
297 LOG(LS_ERROR) << error;
298 PostCreateSessionDescriptionFailed(observer, error);
299 return;
300 }
301 if (session_->remote_description()->type() !=
302 JsepSessionDescription::kOffer) {
303 error += " failed because remote_description is not an offer.";
304 LOG(LS_ERROR) << error;
305 PostCreateSessionDescriptionFailed(observer, error);
306 return;
307 }
308
deadbeefab9b2d12015-10-14 11:33:11 -0700309 if (!ValidStreams(session_options.streams)) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000310 error += " called with invalid media streams.";
311 LOG(LS_ERROR) << error;
312 PostCreateSessionDescriptionFailed(observer, error);
313 return;
314 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000315
316 CreateSessionDescriptionRequest request(
deadbeefab9b2d12015-10-14 11:33:11 -0700317 CreateSessionDescriptionRequest::kAnswer, observer, session_options);
Henrik Boström87713d02015-08-25 09:53:21 +0200318 if (certificate_request_state_ == CERTIFICATE_WAITING) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000319 create_session_description_requests_.push(request);
320 } else {
Henrik Boström87713d02015-08-25 09:53:21 +0200321 ASSERT(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
322 certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000323 InternalCreateAnswer(request);
324 }
325}
326
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000327void WebRtcSessionDescriptionFactory::SetSdesPolicy(
328 cricket::SecurePolicy secure_policy) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000329 session_desc_factory_.set_secure(secure_policy);
330}
331
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000332cricket::SecurePolicy WebRtcSessionDescriptionFactory::SdesPolicy() const {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000333 return session_desc_factory_.secure();
334}
335
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000336void WebRtcSessionDescriptionFactory::OnMessage(rtc::Message* msg) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000337 switch (msg->message_id) {
338 case MSG_CREATE_SESSIONDESCRIPTION_SUCCESS: {
339 CreateSessionDescriptionMsg* param =
340 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
341 param->observer->OnSuccess(param->description.release());
342 delete param;
343 break;
344 }
345 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
346 CreateSessionDescriptionMsg* param =
347 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
348 param->observer->OnFailure(param->error);
349 delete param;
350 break;
351 }
Henrik Boström87713d02015-08-25 09:53:21 +0200352 case MSG_USE_CONSTRUCTOR_CERTIFICATE: {
353 rtc::ScopedRefMessageData<rtc::RTCCertificate>* param =
354 static_cast<rtc::ScopedRefMessageData<rtc::RTCCertificate>*>(
355 msg->pdata);
356 LOG(LS_INFO) << "Using certificate supplied to the constructor.";
Henrik Boströmd8281982015-08-27 10:12:24 +0200357 SetCertificate(param->data());
Henrik Boström87713d02015-08-25 09:53:21 +0200358 delete param;
359 break;
360 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000361 default:
362 ASSERT(false);
363 break;
364 }
365}
366
367void WebRtcSessionDescriptionFactory::InternalCreateOffer(
368 CreateSessionDescriptionRequest request) {
deadbeefd59daf82015-10-14 15:02:44 -0700369 cricket::SessionDescription* desc(session_desc_factory_.CreateOffer(
370 request.options, session_->local_description()
371 ? session_->local_description()->description()
372 : nullptr));
wu@webrtc.org91053e72013-08-10 07:18:04 +0000373 // RFC 3264
374 // When issuing an offer that modifies the session,
375 // the "o=" line of the new SDP MUST be identical to that in the
376 // previous SDP, except that the version in the origin field MUST
377 // increment by one from the previous SDP.
378
379 // Just increase the version number by one each time when a new offer
380 // is created regardless if it's identical to the previous one or not.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200381 // The |session_version_| is a uint64_t, the wrap around should not happen.
wu@webrtc.org91053e72013-08-10 07:18:04 +0000382 ASSERT(session_version_ + 1 > session_version_);
383 JsepSessionDescription* offer(new JsepSessionDescription(
384 JsepSessionDescription::kOffer));
385 if (!offer->Initialize(desc, session_id_,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000386 rtc::ToString(session_version_++))) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000387 delete offer;
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000388 PostCreateSessionDescriptionFailed(request.observer,
389 "Failed to initialize the offer.");
wu@webrtc.org91053e72013-08-10 07:18:04 +0000390 return;
391 }
392 if (session_->local_description() &&
393 !request.options.transport_options.ice_restart) {
394 // Include all local ice candidates in the SessionDescription unless
395 // the an ice restart has been requested.
396 CopyCandidatesFromSessionDescription(session_->local_description(), offer);
397 }
398 PostCreateSessionDescriptionSucceeded(request.observer, offer);
399}
400
401void WebRtcSessionDescriptionFactory::InternalCreateAnswer(
402 CreateSessionDescriptionRequest request) {
403 // According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1
404 // an answer should also contain new ice ufrag and password if an offer has
405 // been received with new ufrag and password.
406 request.options.transport_options.ice_restart = session_->IceRestartPending();
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000407 // We should pass current ssl role to the transport description factory, if
408 // there is already an existing ongoing session.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000409 rtc::SSLRole ssl_role;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000410 if (session_->GetSslRole(&ssl_role)) {
411 request.options.transport_options.prefer_passive_role =
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000412 (rtc::SSL_SERVER == ssl_role);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000413 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000414
415 cricket::SessionDescription* desc(session_desc_factory_.CreateAnswer(
deadbeefd59daf82015-10-14 15:02:44 -0700416 session_->remote_description()
417 ? session_->remote_description()->description()
418 : nullptr,
419 request.options, session_->local_description()
420 ? session_->local_description()->description()
421 : nullptr));
wu@webrtc.org91053e72013-08-10 07:18:04 +0000422 // RFC 3264
423 // If the answer is different from the offer in any way (different IP
424 // addresses, ports, etc.), the origin line MUST be different in the answer.
425 // In that case, the version number in the "o=" line of the answer is
426 // unrelated to the version number in the o line of the offer.
427 // Get a new version number by increasing the |session_version_answer_|.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200428 // The |session_version_| is a uint64_t, the wrap around should not happen.
wu@webrtc.org91053e72013-08-10 07:18:04 +0000429 ASSERT(session_version_ + 1 > session_version_);
430 JsepSessionDescription* answer(new JsepSessionDescription(
431 JsepSessionDescription::kAnswer));
432 if (!answer->Initialize(desc, session_id_,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000433 rtc::ToString(session_version_++))) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000434 delete answer;
435 PostCreateSessionDescriptionFailed(request.observer,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000436 "Failed to initialize the answer.");
wu@webrtc.org91053e72013-08-10 07:18:04 +0000437 return;
438 }
439 if (session_->local_description() &&
440 !request.options.transport_options.ice_restart) {
441 // Include all local ice candidates in the SessionDescription unless
442 // the remote peer has requested an ice restart.
443 CopyCandidatesFromSessionDescription(session_->local_description(), answer);
444 }
445 session_->ResetIceRestartLatch();
446 PostCreateSessionDescriptionSucceeded(request.observer, answer);
447}
448
tommi0f620f42015-07-09 03:25:02 -0700449void WebRtcSessionDescriptionFactory::FailPendingRequests(
450 const std::string& reason) {
451 ASSERT(signaling_thread_->IsCurrent());
452 while (!create_session_description_requests_.empty()) {
453 const CreateSessionDescriptionRequest& request =
454 create_session_description_requests_.front();
455 PostCreateSessionDescriptionFailed(request.observer,
456 ((request.type == CreateSessionDescriptionRequest::kOffer) ?
457 "CreateOffer" : "CreateAnswer") + reason);
458 create_session_description_requests_.pop();
459 }
460}
461
wu@webrtc.org91053e72013-08-10 07:18:04 +0000462void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionFailed(
463 CreateSessionDescriptionObserver* observer, const std::string& error) {
464 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
465 msg->error = error;
466 signaling_thread_->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000467 LOG(LS_ERROR) << "Create SDP failed: " << error;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000468}
469
470void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded(
471 CreateSessionDescriptionObserver* observer,
472 SessionDescriptionInterface* description) {
473 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
474 msg->description.reset(description);
475 signaling_thread_->Post(this, MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, msg);
476}
477
478void WebRtcSessionDescriptionFactory::OnIdentityRequestFailed(int error) {
479 ASSERT(signaling_thread_->IsCurrent());
480
481 LOG(LS_ERROR) << "Async identity request failed: error = " << error;
Henrik Boström87713d02015-08-25 09:53:21 +0200482 certificate_request_state_ = CERTIFICATE_FAILED;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000483
tommi0f620f42015-07-09 03:25:02 -0700484 FailPendingRequests(kFailedDueToIdentityFailed);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000485}
486
Henrik Boströmd8281982015-08-27 10:12:24 +0200487void WebRtcSessionDescriptionFactory::SetCertificate(
488 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
henrikg91d6ede2015-09-17 00:24:34 -0700489 RTC_DCHECK(certificate);
Henrik Boströmd8281982015-08-27 10:12:24 +0200490 LOG(LS_VERBOSE) << "Setting new certificate";
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000491
Henrik Boström87713d02015-08-25 09:53:21 +0200492 certificate_request_state_ = CERTIFICATE_SUCCEEDED;
Henrik Boströmd8281982015-08-27 10:12:24 +0200493 SignalCertificateReady(certificate);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000494
Henrik Boström3a14bf32015-08-31 09:27:58 +0200495 transport_desc_factory_.set_certificate(certificate);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000496 transport_desc_factory_.set_secure(cricket::SEC_ENABLED);
497
498 while (!create_session_description_requests_.empty()) {
499 if (create_session_description_requests_.front().type ==
500 CreateSessionDescriptionRequest::kOffer) {
501 InternalCreateOffer(create_session_description_requests_.front());
502 } else {
503 InternalCreateAnswer(create_session_description_requests_.front());
504 }
505 create_session_description_requests_.pop();
506 }
507}
wu@webrtc.org91053e72013-08-10 07:18:04 +0000508} // namespace webrtc