blob: 4336372b5707211c5fd53beebde2f937fe6115e8 [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"
34#include "talk/app/webrtc/mediastreamsignaling.h"
35#include "talk/app/webrtc/webrtcsession.h"
Henrik Boström5e56c592015-08-11 10:33:13 +020036#include "webrtc/base/sslidentity.h"
wu@webrtc.org91053e72013-08-10 07:18:04 +000037
wu@webrtc.org364f2042013-11-20 21:49:41 +000038using cricket::MediaSessionOptions;
39
wu@webrtc.org91053e72013-08-10 07:18:04 +000040namespace webrtc {
wu@webrtc.org91053e72013-08-10 07:18:04 +000041namespace {
wu@webrtc.org91053e72013-08-10 07:18:04 +000042static const char kFailedDueToIdentityFailed[] =
43 " failed because DTLS identity request failed";
tommi0f620f42015-07-09 03:25:02 -070044static const char kFailedDueToSessionShutdown[] =
45 " failed because the session was shut down";
wu@webrtc.org91053e72013-08-10 07:18:04 +000046
wu@webrtc.org91053e72013-08-10 07:18:04 +000047static const uint64 kInitSessionVersion = 2;
48
wu@webrtc.org364f2042013-11-20 21:49:41 +000049static bool CompareStream(const MediaSessionOptions::Stream& stream1,
50 const MediaSessionOptions::Stream& stream2) {
51 return stream1.id < stream2.id;
wu@webrtc.org91053e72013-08-10 07:18:04 +000052}
53
wu@webrtc.org364f2042013-11-20 21:49:41 +000054static bool SameId(const MediaSessionOptions::Stream& stream1,
55 const MediaSessionOptions::Stream& stream2) {
56 return stream1.id == stream2.id;
wu@webrtc.org91053e72013-08-10 07:18:04 +000057}
58
59// Checks if each Stream within the |streams| has unique id.
wu@webrtc.org364f2042013-11-20 21:49:41 +000060static bool ValidStreams(const MediaSessionOptions::Streams& streams) {
61 MediaSessionOptions::Streams sorted_streams = streams;
wu@webrtc.org91053e72013-08-10 07:18:04 +000062 std::sort(sorted_streams.begin(), sorted_streams.end(), CompareStream);
wu@webrtc.org364f2042013-11-20 21:49:41 +000063 MediaSessionOptions::Streams::iterator it =
wu@webrtc.org91053e72013-08-10 07:18:04 +000064 std::adjacent_find(sorted_streams.begin(), sorted_streams.end(),
65 SameId);
wu@webrtc.org364f2042013-11-20 21:49:41 +000066 return it == sorted_streams.end();
wu@webrtc.org91053e72013-08-10 07:18:04 +000067}
68
69enum {
70 MSG_CREATE_SESSIONDESCRIPTION_SUCCESS,
Henrik Boström87713d02015-08-25 09:53:21 +020071 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
72 MSG_USE_CONSTRUCTOR_CERTIFICATE
wu@webrtc.org91053e72013-08-10 07:18:04 +000073};
74
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000075struct CreateSessionDescriptionMsg : public rtc::MessageData {
wu@webrtc.org91053e72013-08-10 07:18:04 +000076 explicit CreateSessionDescriptionMsg(
77 webrtc::CreateSessionDescriptionObserver* observer)
78 : observer(observer) {
79 }
80
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000081 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
wu@webrtc.org91053e72013-08-10 07:18:04 +000082 std::string error;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000083 rtc::scoped_ptr<webrtc::SessionDescriptionInterface> description;
wu@webrtc.org91053e72013-08-10 07:18:04 +000084};
wu@webrtc.org91053e72013-08-10 07:18:04 +000085} // namespace
86
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +000087void WebRtcIdentityRequestObserver::OnFailure(int error) {
88 SignalRequestFailed(error);
89}
90
91void WebRtcIdentityRequestObserver::OnSuccess(
92 const std::string& der_cert, const std::string& der_private_key) {
93 std::string pem_cert = rtc::SSLIdentity::DerToPem(
94 rtc::kPemTypeCertificate,
95 reinterpret_cast<const unsigned char*>(der_cert.data()),
96 der_cert.length());
97 std::string pem_key = rtc::SSLIdentity::DerToPem(
98 rtc::kPemTypeRsaPrivateKey,
99 reinterpret_cast<const unsigned char*>(der_private_key.data()),
100 der_private_key.length());
101 rtc::SSLIdentity* identity =
102 rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert);
103 SignalIdentityReady(identity);
104}
105
Henrik Boström5e56c592015-08-11 10:33:13 +0200106void WebRtcIdentityRequestObserver::OnSuccess(
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000107 rtc::scoped_ptr<rtc::SSLIdentity> identity) {
108 SignalIdentityReady(identity.release());
109}
110
wu@webrtc.org91053e72013-08-10 07:18:04 +0000111// static
112void WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
113 const SessionDescriptionInterface* source_desc,
114 SessionDescriptionInterface* dest_desc) {
115 if (!source_desc)
116 return;
117 for (size_t m = 0; m < source_desc->number_of_mediasections() &&
118 m < dest_desc->number_of_mediasections(); ++m) {
119 const IceCandidateCollection* source_candidates =
120 source_desc->candidates(m);
121 const IceCandidateCollection* dest_candidates = dest_desc->candidates(m);
122 for (size_t n = 0; n < source_candidates->count(); ++n) {
123 const IceCandidateInterface* new_candidate = source_candidates->at(n);
124 if (!dest_candidates->HasCandidate(new_candidate))
125 dest_desc->AddCandidate(source_candidates->at(n));
126 }
127 }
128}
129
Henrik Boström87713d02015-08-25 09:53:21 +0200130// Private constructor called by other constructors.
wu@webrtc.org91053e72013-08-10 07:18:04 +0000131WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000132 rtc::Thread* signaling_thread,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000133 cricket::ChannelManager* channel_manager,
134 MediaStreamSignaling* mediastream_signaling,
Henrik Boström5e56c592015-08-11 10:33:13 +0200135 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
Henrik Boström87713d02015-08-25 09:53:21 +0200136 const rtc::scoped_refptr<WebRtcIdentityRequestObserver>&
137 identity_request_observer,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000138 WebRtcSession* session,
139 const std::string& session_id,
140 cricket::DataChannelType dct,
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000141 bool dtls_enabled)
wu@webrtc.org91053e72013-08-10 07:18:04 +0000142 : signaling_thread_(signaling_thread),
143 mediastream_signaling_(mediastream_signaling),
144 session_desc_factory_(channel_manager, &transport_desc_factory_),
145 // RFC 4566 suggested a Network Time Protocol (NTP) format timestamp
146 // as the session id and session version. To simplify, it should be fine
147 // to just use a random number as session id and start version from
148 // |kInitSessionVersion|.
149 session_version_(kInitSessionVersion),
Henrik Boström5e56c592015-08-11 10:33:13 +0200150 dtls_identity_store_(dtls_identity_store.Pass()),
Henrik Boström87713d02015-08-25 09:53:21 +0200151 identity_request_observer_(identity_request_observer),
wu@webrtc.org91053e72013-08-10 07:18:04 +0000152 session_(session),
153 session_id_(session_id),
154 data_channel_type_(dct),
Henrik Boström87713d02015-08-25 09:53:21 +0200155 certificate_request_state_(CERTIFICATE_NOT_NEEDED) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000156 session_desc_factory_.set_add_legacy_streams(false);
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000157 // SRTP-SDES is disabled if DTLS is on.
158 SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED);
Henrik Boström87713d02015-08-25 09:53:21 +0200159}
wu@webrtc.org91053e72013-08-10 07:18:04 +0000160
Henrik Boström87713d02015-08-25 09:53:21 +0200161WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
162 rtc::Thread* signaling_thread,
163 cricket::ChannelManager* channel_manager,
164 MediaStreamSignaling* mediastream_signaling,
165 WebRtcSession* session,
166 const std::string& session_id,
167 cricket::DataChannelType dct)
168 : WebRtcSessionDescriptionFactory(
169 signaling_thread, channel_manager, mediastream_signaling, nullptr,
170 nullptr, session, session_id, dct, false) {
171 LOG(LS_VERBOSE) << "DTLS-SRTP disabled.";
172}
wu@webrtc.org91053e72013-08-10 07:18:04 +0000173
Henrik Boström87713d02015-08-25 09:53:21 +0200174WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
175 rtc::Thread* signaling_thread,
176 cricket::ChannelManager* channel_manager,
177 MediaStreamSignaling* mediastream_signaling,
178 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
179 WebRtcSession* session,
180 const std::string& session_id,
181 cricket::DataChannelType dct)
182 : WebRtcSessionDescriptionFactory(
183 signaling_thread,
184 channel_manager,
185 mediastream_signaling,
186 dtls_identity_store.Pass(),
187 new rtc::RefCountedObject<WebRtcIdentityRequestObserver>(),
188 session,
189 session_id,
190 dct,
191 true) {
192 DCHECK(dtls_identity_store_);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000193
Henrik Boström87713d02015-08-25 09:53:21 +0200194 certificate_request_state_ = CERTIFICATE_WAITING;
wu@webrtc.org364f2042013-11-20 21:49:41 +0000195
Henrik Boström87713d02015-08-25 09:53:21 +0200196 identity_request_observer_->SignalRequestFailed.connect(
197 this, &WebRtcSessionDescriptionFactory::OnIdentityRequestFailed);
198 identity_request_observer_->SignalIdentityReady.connect(
199 this, &WebRtcSessionDescriptionFactory::SetIdentity);
200
201 rtc::KeyType key_type = rtc::KT_DEFAULT;
202 LOG(LS_VERBOSE) << "DTLS-SRTP enabled; sending DTLS identity request (key "
203 << "type: " << key_type << ").";
204
205 // Request identity. This happens asynchronously, so the caller will have a
206 // chance to connect to SignalIdentityReady.
207 dtls_identity_store_->RequestIdentity(key_type, identity_request_observer_);
208}
209
210WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory(
211 rtc::Thread* signaling_thread,
212 cricket::ChannelManager* channel_manager,
213 MediaStreamSignaling* mediastream_signaling,
214 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate,
215 WebRtcSession* session,
216 const std::string& session_id,
217 cricket::DataChannelType dct)
218 : WebRtcSessionDescriptionFactory(
219 signaling_thread, channel_manager, mediastream_signaling, nullptr,
220 nullptr, session, session_id, dct, true) {
221 DCHECK(certificate);
222
223 certificate_request_state_ = CERTIFICATE_WAITING;
224
225 LOG(LS_VERBOSE) << "DTLS-SRTP enabled; has certificate parameter.";
226 // We already have a certificate but we wait to do SetIdentity; if we do
227 // it in the constructor then the caller has not had a chance to connect to
228 // SignalIdentityReady.
229 signaling_thread_->Post(this, MSG_USE_CONSTRUCTOR_CERTIFICATE,
230 new rtc::ScopedRefMessageData<rtc::RTCCertificate>(
231 certificate));
wu@webrtc.org91053e72013-08-10 07:18:04 +0000232}
233
234WebRtcSessionDescriptionFactory::~WebRtcSessionDescriptionFactory() {
tommi0f620f42015-07-09 03:25:02 -0700235 ASSERT(signaling_thread_->IsCurrent());
236
237 // Fail any requests that were asked for before identity generation completed.
238 FailPendingRequests(kFailedDueToSessionShutdown);
239
240 // Process all pending notifications in the message queue. If we don't do
241 // this, requests will linger and not know they succeeded or failed.
242 rtc::MessageList list;
243 signaling_thread_->Clear(this, rtc::MQID_ANY, &list);
Henrik Boström87713d02015-08-25 09:53:21 +0200244 for (auto& msg : list) {
245 if (msg.message_id != MSG_USE_CONSTRUCTOR_CERTIFICATE) {
246 OnMessage(&msg);
247 } else {
248 // Skip MSG_USE_CONSTRUCTOR_CERTIFICATE because we don't want to trigger
249 // SetIdentity-related callbacks in the destructor. This can be a problem
250 // when WebRtcSession listens to the callback but it was the WebRtcSession
251 // destructor that caused WebRtcSessionDescriptionFactory's destruction.
252 // The callback is then ignored, leaking memory allocated by OnMessage for
253 // MSG_USE_CONSTRUCTOR_CERTIFICATE.
254 delete msg.pdata;
255 }
256 }
tommi0f620f42015-07-09 03:25:02 -0700257
wu@webrtc.org91053e72013-08-10 07:18:04 +0000258 transport_desc_factory_.set_identity(NULL);
259}
260
261void WebRtcSessionDescriptionFactory::CreateOffer(
262 CreateSessionDescriptionObserver* observer,
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000263 const PeerConnectionInterface::RTCOfferAnswerOptions& options) {
264 cricket::MediaSessionOptions session_options;
265
wu@webrtc.org91053e72013-08-10 07:18:04 +0000266 std::string error = "CreateOffer";
Henrik Boström87713d02015-08-25 09:53:21 +0200267 if (certificate_request_state_ == CERTIFICATE_FAILED) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000268 error += kFailedDueToIdentityFailed;
269 LOG(LS_ERROR) << error;
270 PostCreateSessionDescriptionFailed(observer, error);
271 return;
272 }
273
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000274 if (!mediastream_signaling_->GetOptionsForOffer(options,
275 &session_options)) {
276 error += " called with invalid options.";
wu@webrtc.org91053e72013-08-10 07:18:04 +0000277 LOG(LS_ERROR) << error;
278 PostCreateSessionDescriptionFailed(observer, error);
279 return;
280 }
281
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000282 if (!ValidStreams(session_options.streams)) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000283 error += " called with invalid media streams.";
284 LOG(LS_ERROR) << error;
285 PostCreateSessionDescriptionFailed(observer, error);
286 return;
287 }
288
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000289 if (data_channel_type_ == cricket::DCT_SCTP &&
290 mediastream_signaling_->HasDataChannels()) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000291 session_options.data_channel_type = cricket::DCT_SCTP;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000292 }
293
294 CreateSessionDescriptionRequest request(
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000295 CreateSessionDescriptionRequest::kOffer, observer, session_options);
Henrik Boström87713d02015-08-25 09:53:21 +0200296 if (certificate_request_state_ == CERTIFICATE_WAITING) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000297 create_session_description_requests_.push(request);
298 } else {
Henrik Boström87713d02015-08-25 09:53:21 +0200299 ASSERT(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
300 certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000301 InternalCreateOffer(request);
302 }
303}
304
305void WebRtcSessionDescriptionFactory::CreateAnswer(
306 CreateSessionDescriptionObserver* observer,
307 const MediaConstraintsInterface* constraints) {
308 std::string error = "CreateAnswer";
Henrik Boström87713d02015-08-25 09:53:21 +0200309 if (certificate_request_state_ == CERTIFICATE_FAILED) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000310 error += kFailedDueToIdentityFailed;
311 LOG(LS_ERROR) << error;
312 PostCreateSessionDescriptionFailed(observer, error);
313 return;
314 }
315 if (!session_->remote_description()) {
316 error += " can't be called before SetRemoteDescription.";
317 LOG(LS_ERROR) << error;
318 PostCreateSessionDescriptionFailed(observer, error);
319 return;
320 }
321 if (session_->remote_description()->type() !=
322 JsepSessionDescription::kOffer) {
323 error += " failed because remote_description is not an offer.";
324 LOG(LS_ERROR) << error;
325 PostCreateSessionDescriptionFailed(observer, error);
326 return;
327 }
328
329 cricket::MediaSessionOptions options;
330 if (!mediastream_signaling_->GetOptionsForAnswer(constraints, &options)) {
331 error += " called with invalid constraints.";
332 LOG(LS_ERROR) << error;
333 PostCreateSessionDescriptionFailed(observer, error);
334 return;
335 }
336 if (!ValidStreams(options.streams)) {
337 error += " called with invalid media streams.";
338 LOG(LS_ERROR) << error;
339 PostCreateSessionDescriptionFailed(observer, error);
340 return;
341 }
mallinath@webrtc.org1112c302013-09-23 20:34:45 +0000342 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
343 // are not signaled in the SDP so does not go through that path and must be
344 // handled here.
345 if (data_channel_type_ == cricket::DCT_SCTP) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000346 options.data_channel_type = cricket::DCT_SCTP;
347 }
348
349 CreateSessionDescriptionRequest request(
350 CreateSessionDescriptionRequest::kAnswer, observer, options);
Henrik Boström87713d02015-08-25 09:53:21 +0200351 if (certificate_request_state_ == CERTIFICATE_WAITING) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000352 create_session_description_requests_.push(request);
353 } else {
Henrik Boström87713d02015-08-25 09:53:21 +0200354 ASSERT(certificate_request_state_ == CERTIFICATE_SUCCEEDED ||
355 certificate_request_state_ == CERTIFICATE_NOT_NEEDED);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000356 InternalCreateAnswer(request);
357 }
358}
359
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000360void WebRtcSessionDescriptionFactory::SetSdesPolicy(
361 cricket::SecurePolicy secure_policy) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000362 session_desc_factory_.set_secure(secure_policy);
363}
364
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000365cricket::SecurePolicy WebRtcSessionDescriptionFactory::SdesPolicy() const {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000366 return session_desc_factory_.secure();
367}
368
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000369void WebRtcSessionDescriptionFactory::OnMessage(rtc::Message* msg) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000370 switch (msg->message_id) {
371 case MSG_CREATE_SESSIONDESCRIPTION_SUCCESS: {
372 CreateSessionDescriptionMsg* param =
373 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
374 param->observer->OnSuccess(param->description.release());
375 delete param;
376 break;
377 }
378 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
379 CreateSessionDescriptionMsg* param =
380 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
381 param->observer->OnFailure(param->error);
382 delete param;
383 break;
384 }
Henrik Boström87713d02015-08-25 09:53:21 +0200385 case MSG_USE_CONSTRUCTOR_CERTIFICATE: {
386 rtc::ScopedRefMessageData<rtc::RTCCertificate>* param =
387 static_cast<rtc::ScopedRefMessageData<rtc::RTCCertificate>*>(
388 msg->pdata);
389 LOG(LS_INFO) << "Using certificate supplied to the constructor.";
390 // TODO(hbos): Pass around scoped_refptr<RTCCertificate> instead of
391 // SSLIdentity* (then there will be no need to do GetReference here).
392 SetIdentity(param->data()->identity()->GetReference());
393 delete param;
394 break;
395 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000396 default:
397 ASSERT(false);
398 break;
399 }
400}
401
402void WebRtcSessionDescriptionFactory::InternalCreateOffer(
403 CreateSessionDescriptionRequest request) {
404 cricket::SessionDescription* desc(
405 session_desc_factory_.CreateOffer(
406 request.options,
407 static_cast<cricket::BaseSession*>(session_)->local_description()));
408 // RFC 3264
409 // When issuing an offer that modifies the session,
410 // the "o=" line of the new SDP MUST be identical to that in the
411 // previous SDP, except that the version in the origin field MUST
412 // increment by one from the previous SDP.
413
414 // Just increase the version number by one each time when a new offer
415 // is created regardless if it's identical to the previous one or not.
416 // The |session_version_| is a uint64, the wrap around should not happen.
417 ASSERT(session_version_ + 1 > session_version_);
418 JsepSessionDescription* offer(new JsepSessionDescription(
419 JsepSessionDescription::kOffer));
420 if (!offer->Initialize(desc, session_id_,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000421 rtc::ToString(session_version_++))) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000422 delete offer;
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000423 PostCreateSessionDescriptionFailed(request.observer,
424 "Failed to initialize the offer.");
wu@webrtc.org91053e72013-08-10 07:18:04 +0000425 return;
426 }
427 if (session_->local_description() &&
428 !request.options.transport_options.ice_restart) {
429 // Include all local ice candidates in the SessionDescription unless
430 // the an ice restart has been requested.
431 CopyCandidatesFromSessionDescription(session_->local_description(), offer);
432 }
433 PostCreateSessionDescriptionSucceeded(request.observer, offer);
434}
435
436void WebRtcSessionDescriptionFactory::InternalCreateAnswer(
437 CreateSessionDescriptionRequest request) {
438 // According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1
439 // an answer should also contain new ice ufrag and password if an offer has
440 // been received with new ufrag and password.
441 request.options.transport_options.ice_restart = session_->IceRestartPending();
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000442 // We should pass current ssl role to the transport description factory, if
443 // there is already an existing ongoing session.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000444 rtc::SSLRole ssl_role;
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000445 if (session_->GetSslRole(&ssl_role)) {
446 request.options.transport_options.prefer_passive_role =
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000447 (rtc::SSL_SERVER == ssl_role);
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000448 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000449
450 cricket::SessionDescription* desc(session_desc_factory_.CreateAnswer(
451 static_cast<cricket::BaseSession*>(session_)->remote_description(),
452 request.options,
453 static_cast<cricket::BaseSession*>(session_)->local_description()));
454 // RFC 3264
455 // If the answer is different from the offer in any way (different IP
456 // addresses, ports, etc.), the origin line MUST be different in the answer.
457 // In that case, the version number in the "o=" line of the answer is
458 // unrelated to the version number in the o line of the offer.
459 // Get a new version number by increasing the |session_version_answer_|.
460 // The |session_version_| is a uint64, the wrap around should not happen.
461 ASSERT(session_version_ + 1 > session_version_);
462 JsepSessionDescription* answer(new JsepSessionDescription(
463 JsepSessionDescription::kAnswer));
464 if (!answer->Initialize(desc, session_id_,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000465 rtc::ToString(session_version_++))) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000466 delete answer;
467 PostCreateSessionDescriptionFailed(request.observer,
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000468 "Failed to initialize the answer.");
wu@webrtc.org91053e72013-08-10 07:18:04 +0000469 return;
470 }
471 if (session_->local_description() &&
472 !request.options.transport_options.ice_restart) {
473 // Include all local ice candidates in the SessionDescription unless
474 // the remote peer has requested an ice restart.
475 CopyCandidatesFromSessionDescription(session_->local_description(), answer);
476 }
477 session_->ResetIceRestartLatch();
478 PostCreateSessionDescriptionSucceeded(request.observer, answer);
479}
480
tommi0f620f42015-07-09 03:25:02 -0700481void WebRtcSessionDescriptionFactory::FailPendingRequests(
482 const std::string& reason) {
483 ASSERT(signaling_thread_->IsCurrent());
484 while (!create_session_description_requests_.empty()) {
485 const CreateSessionDescriptionRequest& request =
486 create_session_description_requests_.front();
487 PostCreateSessionDescriptionFailed(request.observer,
488 ((request.type == CreateSessionDescriptionRequest::kOffer) ?
489 "CreateOffer" : "CreateAnswer") + reason);
490 create_session_description_requests_.pop();
491 }
492}
493
wu@webrtc.org91053e72013-08-10 07:18:04 +0000494void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionFailed(
495 CreateSessionDescriptionObserver* observer, const std::string& error) {
496 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
497 msg->error = error;
498 signaling_thread_->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
henrike@webrtc.orgb90991d2014-03-04 19:54:57 +0000499 LOG(LS_ERROR) << "Create SDP failed: " << error;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000500}
501
502void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded(
503 CreateSessionDescriptionObserver* observer,
504 SessionDescriptionInterface* description) {
505 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
506 msg->description.reset(description);
507 signaling_thread_->Post(this, MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, msg);
508}
509
510void WebRtcSessionDescriptionFactory::OnIdentityRequestFailed(int error) {
511 ASSERT(signaling_thread_->IsCurrent());
512
513 LOG(LS_ERROR) << "Async identity request failed: error = " << error;
Henrik Boström87713d02015-08-25 09:53:21 +0200514 certificate_request_state_ = CERTIFICATE_FAILED;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000515
tommi0f620f42015-07-09 03:25:02 -0700516 FailPendingRequests(kFailedDueToIdentityFailed);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000517}
518
wu@webrtc.org91053e72013-08-10 07:18:04 +0000519void WebRtcSessionDescriptionFactory::SetIdentity(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000520 rtc::SSLIdentity* identity) {
jiayl@webrtc.org61e00b02015-03-04 22:17:38 +0000521 LOG(LS_VERBOSE) << "Setting new identity";
522
Henrik Boström87713d02015-08-25 09:53:21 +0200523 certificate_request_state_ = CERTIFICATE_SUCCEEDED;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000524 SignalIdentityReady(identity);
525
526 transport_desc_factory_.set_identity(identity);
wu@webrtc.org91053e72013-08-10 07:18:04 +0000527 transport_desc_factory_.set_secure(cricket::SEC_ENABLED);
528
529 while (!create_session_description_requests_.empty()) {
530 if (create_session_description_requests_.front().type ==
531 CreateSessionDescriptionRequest::kOffer) {
532 InternalCreateOffer(create_session_description_requests_.front());
533 } else {
534 InternalCreateAnswer(create_session_description_requests_.front());
535 }
536 create_session_description_requests_.pop();
537 }
538}
wu@webrtc.org91053e72013-08-10 07:18:04 +0000539} // namespace webrtc