Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "PresentationService.h"
8 :
9 : #include "ipc/PresentationIPCService.h"
10 : #include "mozilla/Services.h"
11 : #include "nsGlobalWindow.h"
12 : #include "nsIMutableArray.h"
13 : #include "nsIObserverService.h"
14 : #include "nsIPresentationControlChannel.h"
15 : #include "nsIPresentationDeviceManager.h"
16 : #include "nsIPresentationDevicePrompt.h"
17 : #include "nsIPresentationListener.h"
18 : #include "nsIPresentationRequestUIGlue.h"
19 : #include "nsIPresentationSessionRequest.h"
20 : #include "nsIPresentationTerminateRequest.h"
21 : #include "nsISupportsPrimitives.h"
22 : #include "nsNetUtil.h"
23 : #include "nsServiceManagerUtils.h"
24 : #include "nsThreadUtils.h"
25 : #include "nsXPCOMCID.h"
26 : #include "nsXULAppAPI.h"
27 : #include "PresentationLog.h"
28 :
29 : namespace mozilla {
30 : namespace dom {
31 :
32 : static bool
33 0 : IsSameDevice(nsIPresentationDevice* aDevice, nsIPresentationDevice* aDeviceAnother) {
34 0 : if (!aDevice || !aDeviceAnother) {
35 0 : return false;
36 : }
37 :
38 0 : nsAutoCString deviceId;
39 0 : aDevice->GetId(deviceId);
40 0 : nsAutoCString anotherId;
41 0 : aDeviceAnother->GetId(anotherId);
42 0 : if (!deviceId.Equals(anotherId)) {
43 0 : return false;
44 : }
45 :
46 0 : nsAutoCString deviceType;
47 0 : aDevice->GetType(deviceType);
48 0 : nsAutoCString anotherType;
49 0 : aDeviceAnother->GetType(anotherType);
50 0 : if (!deviceType.Equals(anotherType)) {
51 0 : return false;
52 : }
53 :
54 0 : return true;
55 : }
56 :
57 : static nsresult
58 0 : ConvertURLArrayHelper(const nsTArray<nsString>& aUrls, nsIArray** aResult)
59 : {
60 0 : if (!aResult) {
61 0 : return NS_ERROR_INVALID_POINTER;
62 : }
63 :
64 0 : *aResult = nullptr;
65 :
66 : nsresult rv;
67 : nsCOMPtr<nsIMutableArray> urls =
68 0 : do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
69 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
70 0 : return rv;
71 : }
72 :
73 0 : for (const auto& url : aUrls) {
74 : nsCOMPtr<nsISupportsString> isupportsString =
75 0 : do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
76 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
77 0 : return rv;
78 : }
79 :
80 0 : rv = isupportsString->SetData(url);
81 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
82 0 : return rv;
83 : }
84 :
85 0 : rv = urls->AppendElement(isupportsString, false);
86 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
87 0 : return rv;
88 : }
89 : }
90 :
91 0 : urls.forget(aResult);
92 0 : return NS_OK;
93 : }
94 :
95 : /*
96 : * Implementation of PresentationDeviceRequest
97 : */
98 :
99 : class PresentationDeviceRequest final : public nsIPresentationDeviceRequest
100 : {
101 : public:
102 : NS_DECL_ISUPPORTS
103 : NS_DECL_NSIPRESENTATIONDEVICEREQUEST
104 :
105 : PresentationDeviceRequest(
106 : const nsTArray<nsString>& aUrls,
107 : const nsAString& aId,
108 : const nsAString& aOrigin,
109 : uint64_t aWindowId,
110 : nsIDOMEventTarget* aEventTarget,
111 : nsIPrincipal* aPrincipal,
112 : nsIPresentationServiceCallback* aCallback,
113 : nsIPresentationTransportBuilderConstructor* aBuilderConstructor);
114 :
115 : private:
116 0 : virtual ~PresentationDeviceRequest() = default;
117 : nsresult CreateSessionInfo(nsIPresentationDevice* aDevice,
118 : const nsAString& aSelectedRequestUrl);
119 :
120 : nsTArray<nsString> mRequestUrls;
121 : nsString mId;
122 : nsString mOrigin;
123 : uint64_t mWindowId;
124 : nsWeakPtr mChromeEventHandler;
125 : nsCOMPtr<nsIPrincipal> mPrincipal;
126 : nsCOMPtr<nsIPresentationServiceCallback> mCallback;
127 : nsCOMPtr<nsIPresentationTransportBuilderConstructor> mBuilderConstructor;
128 : };
129 :
130 : LazyLogModule gPresentationLog("Presentation");
131 :
132 0 : NS_IMPL_ISUPPORTS(PresentationDeviceRequest, nsIPresentationDeviceRequest)
133 :
134 0 : PresentationDeviceRequest::PresentationDeviceRequest(
135 : const nsTArray<nsString>& aUrls,
136 : const nsAString& aId,
137 : const nsAString& aOrigin,
138 : uint64_t aWindowId,
139 : nsIDOMEventTarget* aEventTarget,
140 : nsIPrincipal* aPrincipal,
141 : nsIPresentationServiceCallback* aCallback,
142 0 : nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
143 : : mRequestUrls(aUrls)
144 : , mId(aId)
145 : , mOrigin(aOrigin)
146 : , mWindowId(aWindowId)
147 0 : , mChromeEventHandler(do_GetWeakReference(aEventTarget))
148 : , mPrincipal(aPrincipal)
149 : , mCallback(aCallback)
150 0 : , mBuilderConstructor(aBuilderConstructor)
151 : {
152 0 : MOZ_ASSERT(!mRequestUrls.IsEmpty());
153 0 : MOZ_ASSERT(!mId.IsEmpty());
154 0 : MOZ_ASSERT(!mOrigin.IsEmpty());
155 0 : MOZ_ASSERT(mCallback);
156 0 : MOZ_ASSERT(mBuilderConstructor);
157 0 : }
158 :
159 : NS_IMETHODIMP
160 0 : PresentationDeviceRequest::GetOrigin(nsAString& aOrigin)
161 : {
162 0 : aOrigin = mOrigin;
163 0 : return NS_OK;
164 : }
165 :
166 : NS_IMETHODIMP
167 0 : PresentationDeviceRequest::GetRequestURLs(nsIArray** aUrls)
168 : {
169 0 : return ConvertURLArrayHelper(mRequestUrls, aUrls);
170 : }
171 :
172 : NS_IMETHODIMP
173 0 : PresentationDeviceRequest::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
174 : {
175 0 : nsCOMPtr<nsIDOMEventTarget> handler(do_QueryReferent(mChromeEventHandler));
176 0 : handler.forget(aChromeEventHandler);
177 0 : return NS_OK;
178 : }
179 :
180 : NS_IMETHODIMP
181 0 : PresentationDeviceRequest::GetPrincipal(nsIPrincipal** aPrincipal)
182 : {
183 0 : nsCOMPtr<nsIPrincipal> principal(mPrincipal);
184 0 : principal.forget(aPrincipal);
185 0 : return NS_OK;
186 : }
187 :
188 : NS_IMETHODIMP
189 0 : PresentationDeviceRequest::Select(nsIPresentationDevice* aDevice)
190 : {
191 0 : MOZ_ASSERT(NS_IsMainThread());
192 0 : if (NS_WARN_IF(!aDevice)) {
193 0 : MOZ_ASSERT(false, "|aDevice| should noe be null.");
194 : mCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
195 : return NS_ERROR_INVALID_ARG;
196 : }
197 :
198 : // Select the most suitable URL for starting the presentation.
199 0 : nsAutoString selectedRequestUrl;
200 0 : for (const auto& url : mRequestUrls) {
201 : bool isSupported;
202 0 : if (NS_SUCCEEDED(aDevice->IsRequestedUrlSupported(url, &isSupported)) &&
203 : isSupported) {
204 0 : selectedRequestUrl.Assign(url);
205 0 : break;
206 : }
207 : }
208 :
209 0 : if (selectedRequestUrl.IsEmpty()) {
210 0 : return mCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
211 : }
212 :
213 0 : if (NS_WARN_IF(NS_FAILED(CreateSessionInfo(aDevice, selectedRequestUrl)))) {
214 0 : return mCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
215 : }
216 :
217 0 : return mCallback->NotifySuccess(selectedRequestUrl);
218 : }
219 :
220 : nsresult
221 0 : PresentationDeviceRequest::CreateSessionInfo(
222 : nsIPresentationDevice* aDevice,
223 : const nsAString& aSelectedRequestUrl)
224 : {
225 : nsCOMPtr<nsIPresentationService> service =
226 0 : do_GetService(PRESENTATION_SERVICE_CONTRACTID);
227 0 : if (NS_WARN_IF(!service)) {
228 0 : return NS_ERROR_NOT_AVAILABLE;
229 : }
230 :
231 : // Create the controlling session info
232 : RefPtr<PresentationSessionInfo> info =
233 0 : static_cast<PresentationService*>(service.get())->
234 0 : CreateControllingSessionInfo(aSelectedRequestUrl, mId, mWindowId);
235 0 : if (NS_WARN_IF(!info)) {
236 0 : return NS_ERROR_NOT_AVAILABLE;
237 : }
238 0 : info->SetDevice(aDevice);
239 :
240 : // Establish a control channel. If we failed to do so, the callback is called
241 : // with an error message.
242 0 : nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
243 0 : nsresult rv = aDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel));
244 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
245 0 : return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
246 : }
247 :
248 : // Initialize the session info with the control channel.
249 0 : rv = info->Init(ctrlChannel);
250 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
251 0 : return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
252 : }
253 :
254 0 : info->SetTransportBuilderConstructor(mBuilderConstructor);
255 0 : return NS_OK;
256 : }
257 :
258 : NS_IMETHODIMP
259 0 : PresentationDeviceRequest::Cancel(nsresult aReason)
260 : {
261 0 : return mCallback->NotifyError(aReason);
262 : }
263 :
264 : /*
265 : * Implementation of PresentationService
266 : */
267 :
268 23 : NS_IMPL_ISUPPORTS(PresentationService,
269 : nsIPresentationService,
270 : nsIObserver)
271 :
272 1 : PresentationService::PresentationService()
273 : {
274 1 : }
275 :
276 0 : PresentationService::~PresentationService()
277 : {
278 0 : HandleShutdown();
279 0 : }
280 :
281 : bool
282 1 : PresentationService::Init()
283 : {
284 1 : MOZ_ASSERT(NS_IsMainThread());
285 :
286 2 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
287 1 : if (NS_WARN_IF(!obs)) {
288 0 : return false;
289 : }
290 :
291 1 : nsresult rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
292 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
293 0 : return false;
294 : }
295 1 : rv = obs->AddObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC, false);
296 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
297 0 : return false;
298 : }
299 1 : rv = obs->AddObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC, false);
300 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
301 0 : return false;
302 : }
303 1 : rv = obs->AddObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC, false);
304 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
305 0 : return false;
306 : }
307 1 : rv = obs->AddObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC, false);
308 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
309 0 : return false;
310 : }
311 :
312 1 : return !NS_WARN_IF(NS_FAILED(rv));
313 : }
314 :
315 : NS_IMETHODIMP
316 1 : PresentationService::Observe(nsISupports* aSubject,
317 : const char* aTopic,
318 : const char16_t* aData)
319 : {
320 1 : if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
321 0 : HandleShutdown();
322 0 : return NS_OK;
323 1 : } else if (!strcmp(aTopic, PRESENTATION_DEVICE_CHANGE_TOPIC)) {
324 : // Ignore the "update" case here, since we only care about the arrival and
325 : // removal of the device.
326 0 : if (!NS_strcmp(aData, u"add")) {
327 0 : nsCOMPtr<nsIPresentationDevice> device = do_QueryInterface(aSubject);
328 0 : if (NS_WARN_IF(!device)) {
329 0 : return NS_ERROR_FAILURE;
330 : }
331 :
332 0 : return HandleDeviceAdded(device);
333 0 : } else if(!NS_strcmp(aData, u"remove")) {
334 0 : return HandleDeviceRemoved();
335 : }
336 :
337 0 : return NS_OK;
338 1 : } else if (!strcmp(aTopic, PRESENTATION_SESSION_REQUEST_TOPIC)) {
339 0 : nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject));
340 0 : if (NS_WARN_IF(!request)) {
341 0 : return NS_ERROR_FAILURE;
342 : }
343 :
344 0 : return HandleSessionRequest(request);
345 1 : } else if (!strcmp(aTopic, PRESENTATION_TERMINATE_REQUEST_TOPIC)) {
346 0 : nsCOMPtr<nsIPresentationTerminateRequest> request(do_QueryInterface(aSubject));
347 0 : if (NS_WARN_IF(!request)) {
348 0 : return NS_ERROR_FAILURE;
349 : }
350 :
351 0 : return HandleTerminateRequest(request);
352 1 : } else if (!strcmp(aTopic, PRESENTATION_RECONNECT_REQUEST_TOPIC)) {
353 0 : nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject));
354 0 : if (NS_WARN_IF(!request)) {
355 0 : return NS_ERROR_FAILURE;
356 : }
357 :
358 0 : return HandleReconnectRequest(request);
359 1 : } else if (!strcmp(aTopic, "profile-after-change")) {
360 : // It's expected since we add and entry to |kLayoutCategories| in
361 : // |nsLayoutModule.cpp| to launch this service earlier.
362 1 : return NS_OK;
363 : }
364 :
365 0 : MOZ_ASSERT(false, "Unexpected topic for PresentationService");
366 : return NS_ERROR_UNEXPECTED;
367 : }
368 :
369 : void
370 0 : PresentationService::HandleShutdown()
371 : {
372 0 : MOZ_ASSERT(NS_IsMainThread());
373 :
374 0 : Shutdown();
375 :
376 0 : mAvailabilityManager.Clear();
377 0 : mSessionInfoAtController.Clear();
378 0 : mSessionInfoAtReceiver.Clear();
379 :
380 0 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
381 0 : if (obs) {
382 0 : obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
383 0 : obs->RemoveObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC);
384 0 : obs->RemoveObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC);
385 0 : obs->RemoveObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC);
386 0 : obs->RemoveObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC);
387 : }
388 0 : }
389 :
390 : nsresult
391 0 : PresentationService::HandleDeviceAdded(nsIPresentationDevice* aDevice)
392 : {
393 0 : PRES_DEBUG("%s\n", __func__);
394 0 : if (!aDevice) {
395 0 : MOZ_ASSERT(false, "aDevice shoud no be null.");
396 : return NS_ERROR_INVALID_ARG;
397 : }
398 :
399 : // Query for only unavailable URLs while device added.
400 0 : nsTArray<nsString> unavailableUrls;
401 0 : mAvailabilityManager.GetAvailbilityUrlByAvailability(unavailableUrls, false);
402 :
403 0 : nsTArray<nsString> supportedAvailabilityUrl;
404 0 : for (const auto& url : unavailableUrls) {
405 : bool isSupported;
406 0 : if (NS_SUCCEEDED(aDevice->IsRequestedUrlSupported(url, &isSupported)) &&
407 : isSupported) {
408 0 : supportedAvailabilityUrl.AppendElement(url);
409 : }
410 : }
411 :
412 0 : if (!supportedAvailabilityUrl.IsEmpty()) {
413 0 : return mAvailabilityManager.DoNotifyAvailableChange(supportedAvailabilityUrl,
414 0 : true);
415 : }
416 :
417 0 : return NS_OK;
418 : }
419 :
420 : nsresult
421 0 : PresentationService::HandleDeviceRemoved()
422 : {
423 0 : PRES_DEBUG("%s\n", __func__);
424 :
425 : // Query for only available URLs while device removed.
426 0 : nsTArray<nsString> availabilityUrls;
427 0 : mAvailabilityManager.GetAvailbilityUrlByAvailability(availabilityUrls, true);
428 :
429 0 : return UpdateAvailabilityUrlChange(availabilityUrls);
430 : }
431 :
432 : nsresult
433 0 : PresentationService::UpdateAvailabilityUrlChange(
434 : const nsTArray<nsString>& aAvailabilityUrls)
435 : {
436 : nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
437 0 : do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
438 0 : if (NS_WARN_IF(!deviceManager)) {
439 0 : return NS_ERROR_NOT_AVAILABLE;
440 : }
441 :
442 0 : nsCOMPtr<nsIArray> devices;
443 0 : nsresult rv = deviceManager->GetAvailableDevices(nullptr,
444 0 : getter_AddRefs(devices));
445 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
446 0 : return rv;
447 : }
448 :
449 : uint32_t numOfDevices;
450 0 : devices->GetLength(&numOfDevices);
451 :
452 0 : nsTArray<nsString> supportedAvailabilityUrl;
453 0 : for (const auto& url : aAvailabilityUrls) {
454 0 : for (uint32_t i = 0; i < numOfDevices; ++i) {
455 0 : nsCOMPtr<nsIPresentationDevice> device = do_QueryElementAt(devices, i);
456 0 : if (device) {
457 : bool isSupported;
458 0 : if (NS_SUCCEEDED(device->IsRequestedUrlSupported(url, &isSupported)) &&
459 : isSupported) {
460 0 : supportedAvailabilityUrl.AppendElement(url);
461 0 : break;
462 : }
463 : }
464 : }
465 : }
466 :
467 0 : if (supportedAvailabilityUrl.IsEmpty()) {
468 0 : return mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls,
469 0 : false);
470 : }
471 :
472 0 : return mAvailabilityManager.DoNotifyAvailableChange(supportedAvailabilityUrl,
473 0 : true);
474 : }
475 :
476 : nsresult
477 0 : PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aRequest)
478 : {
479 0 : nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
480 0 : nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
481 0 : if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
482 0 : return rv;
483 : }
484 :
485 0 : nsAutoString url;
486 0 : rv = aRequest->GetUrl(url);
487 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
488 0 : ctrlChannel->Disconnect(rv);
489 0 : return rv;
490 : }
491 :
492 0 : nsAutoString sessionId;
493 0 : rv = aRequest->GetPresentationId(sessionId);
494 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
495 0 : ctrlChannel->Disconnect(rv);
496 0 : return rv;
497 : }
498 :
499 0 : nsCOMPtr<nsIPresentationDevice> device;
500 0 : rv = aRequest->GetDevice(getter_AddRefs(device));
501 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
502 0 : ctrlChannel->Disconnect(rv);
503 0 : return rv;
504 : }
505 :
506 : // Create or reuse session info.
507 : RefPtr<PresentationSessionInfo> info =
508 0 : GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
509 :
510 : // This is the case for reconnecting a session.
511 : // Update the control channel and device of the session info.
512 : // Call |NotifyResponderReady| to indicate the receiver page is already there.
513 0 : if (info) {
514 0 : PRES_DEBUG("handle reconnection:id[%s]\n",
515 : NS_ConvertUTF16toUTF8(sessionId).get());
516 :
517 0 : info->SetControlChannel(ctrlChannel);
518 0 : info->SetDevice(device);
519 : return static_cast<PresentationPresentingInfo*>(
520 0 : info.get())->DoReconnect();
521 : }
522 :
523 : // This is the case for a new session.
524 0 : PRES_DEBUG("handle new session:url[%s], id[%s]\n",
525 : NS_ConvertUTF16toUTF8(url).get(),
526 : NS_ConvertUTF16toUTF8(sessionId).get());
527 :
528 0 : info = new PresentationPresentingInfo(url, sessionId, device);
529 0 : rv = info->Init(ctrlChannel);
530 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
531 0 : ctrlChannel->Disconnect(rv);
532 0 : return rv;
533 : }
534 :
535 0 : mSessionInfoAtReceiver.Put(sessionId, info);
536 :
537 : // Notify the receiver to launch.
538 : nsCOMPtr<nsIPresentationRequestUIGlue> glue =
539 0 : do_CreateInstance(PRESENTATION_REQUEST_UI_GLUE_CONTRACTID);
540 0 : if (NS_WARN_IF(!glue)) {
541 0 : ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
542 0 : return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
543 : }
544 0 : nsCOMPtr<nsISupports> promise;
545 0 : rv = glue->SendRequest(url, sessionId, device, getter_AddRefs(promise));
546 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
547 0 : ctrlChannel->Disconnect(rv);
548 0 : return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
549 : }
550 0 : nsCOMPtr<Promise> realPromise = do_QueryInterface(promise);
551 0 : static_cast<PresentationPresentingInfo*>(info.get())->SetPromise(realPromise);
552 :
553 0 : return NS_OK;
554 : }
555 :
556 : nsresult
557 0 : PresentationService::HandleTerminateRequest(nsIPresentationTerminateRequest* aRequest)
558 : {
559 0 : nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
560 0 : nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
561 0 : if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
562 0 : return rv;
563 : }
564 :
565 0 : nsAutoString sessionId;
566 0 : rv = aRequest->GetPresentationId(sessionId);
567 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
568 0 : ctrlChannel->Disconnect(rv);
569 0 : return rv;
570 : }
571 :
572 0 : nsCOMPtr<nsIPresentationDevice> device;
573 0 : rv = aRequest->GetDevice(getter_AddRefs(device));
574 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
575 0 : ctrlChannel->Disconnect(rv);
576 0 : return rv;
577 : }
578 :
579 : bool isFromReceiver;
580 0 : rv = aRequest->GetIsFromReceiver(&isFromReceiver);
581 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
582 0 : ctrlChannel->Disconnect(rv);
583 0 : return rv;
584 : }
585 :
586 0 : RefPtr<PresentationSessionInfo> info;
587 0 : if (!isFromReceiver) {
588 0 : info = GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
589 : } else {
590 0 : info = GetSessionInfo(sessionId, nsIPresentationService::ROLE_CONTROLLER);
591 : }
592 0 : if (NS_WARN_IF(!info)) {
593 : // Cannot terminate non-existed session.
594 0 : ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
595 0 : return NS_ERROR_DOM_ABORT_ERR;
596 : }
597 :
598 : // Check if terminate request comes from known device.
599 0 : RefPtr<nsIPresentationDevice> knownDevice = info->GetDevice();
600 0 : if (NS_WARN_IF(!IsSameDevice(device, knownDevice))) {
601 0 : ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
602 0 : return NS_ERROR_DOM_ABORT_ERR;
603 : }
604 :
605 0 : PRES_DEBUG("%s:handle termination:id[%s], receiver[%d]\n", __func__,
606 : NS_ConvertUTF16toUTF8(sessionId).get(), isFromReceiver);
607 :
608 0 : return info->OnTerminate(ctrlChannel);
609 : }
610 :
611 : nsresult
612 0 : PresentationService::HandleReconnectRequest(nsIPresentationSessionRequest* aRequest)
613 : {
614 0 : nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
615 0 : nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
616 0 : if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
617 0 : return rv;
618 : }
619 :
620 0 : nsAutoString sessionId;
621 0 : rv = aRequest->GetPresentationId(sessionId);
622 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
623 0 : ctrlChannel->Disconnect(rv);
624 0 : return rv;
625 : }
626 :
627 : uint64_t windowId;
628 0 : rv = GetWindowIdBySessionIdInternal(sessionId,
629 : nsIPresentationService::ROLE_RECEIVER,
630 0 : &windowId);
631 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
632 0 : ctrlChannel->Disconnect(rv);
633 0 : return rv;
634 : }
635 :
636 : RefPtr<PresentationSessionInfo> info =
637 0 : GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
638 0 : if (NS_WARN_IF(!info)) {
639 : // Cannot reconnect non-existed session
640 0 : ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
641 0 : return NS_ERROR_DOM_ABORT_ERR;
642 : }
643 :
644 0 : nsAutoString url;
645 0 : rv = aRequest->GetUrl(url);
646 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
647 0 : ctrlChannel->Disconnect(rv);
648 0 : return rv;
649 : }
650 :
651 : // Make sure the url is the same as the previous one.
652 0 : if (NS_WARN_IF(!info->GetUrl().Equals(url))) {
653 0 : ctrlChannel->Disconnect(rv);
654 0 : return rv;
655 : }
656 :
657 0 : return HandleSessionRequest(aRequest);
658 : }
659 :
660 : NS_IMETHODIMP
661 0 : PresentationService::StartSession(
662 : const nsTArray<nsString>& aUrls,
663 : const nsAString& aSessionId,
664 : const nsAString& aOrigin,
665 : const nsAString& aDeviceId,
666 : uint64_t aWindowId,
667 : nsIDOMEventTarget* aEventTarget,
668 : nsIPrincipal* aPrincipal,
669 : nsIPresentationServiceCallback* aCallback,
670 : nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
671 : {
672 0 : PRES_DEBUG("%s:id[%s]\n", __func__, NS_ConvertUTF16toUTF8(aSessionId).get());
673 :
674 0 : MOZ_ASSERT(NS_IsMainThread());
675 0 : MOZ_ASSERT(aCallback);
676 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
677 0 : MOZ_ASSERT(!aUrls.IsEmpty());
678 :
679 : nsCOMPtr<nsIPresentationDeviceRequest> request =
680 : new PresentationDeviceRequest(aUrls,
681 : aSessionId,
682 : aOrigin,
683 : aWindowId,
684 : aEventTarget,
685 : aPrincipal,
686 : aCallback,
687 0 : aBuilderConstructor);
688 :
689 0 : if (aDeviceId.IsVoid()) {
690 : // Pop up a prompt and ask user to select a device.
691 : nsCOMPtr<nsIPresentationDevicePrompt> prompt =
692 0 : do_GetService(PRESENTATION_DEVICE_PROMPT_CONTRACTID);
693 0 : if (NS_WARN_IF(!prompt)) {
694 0 : return aCallback->NotifyError(NS_ERROR_DOM_INVALID_ACCESS_ERR);
695 : }
696 :
697 0 : nsresult rv = prompt->PromptDeviceSelection(request);
698 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
699 0 : return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
700 : }
701 :
702 0 : return NS_OK;
703 : }
704 :
705 : // Find the designated device from available device list.
706 : nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
707 0 : do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
708 0 : if (NS_WARN_IF(!deviceManager)) {
709 0 : return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
710 : }
711 :
712 0 : nsCOMPtr<nsIArray> presentationUrls;
713 0 : if (NS_WARN_IF(NS_FAILED(
714 : ConvertURLArrayHelper(aUrls, getter_AddRefs(presentationUrls))))) {
715 0 : return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
716 : }
717 :
718 0 : nsCOMPtr<nsIArray> devices;
719 0 : nsresult rv = deviceManager->GetAvailableDevices(presentationUrls, getter_AddRefs(devices));
720 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
721 0 : return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
722 : }
723 :
724 0 : nsCOMPtr<nsISimpleEnumerator> enumerator;
725 0 : rv = devices->Enumerate(getter_AddRefs(enumerator));
726 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
727 0 : return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
728 : }
729 :
730 0 : NS_ConvertUTF16toUTF8 utf8DeviceId(aDeviceId);
731 : bool hasMore;
732 0 : while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
733 0 : nsCOMPtr<nsISupports> isupports;
734 0 : rv = enumerator->GetNext(getter_AddRefs(isupports));
735 :
736 0 : nsCOMPtr<nsIPresentationDevice> device(do_QueryInterface(isupports));
737 0 : MOZ_ASSERT(device);
738 :
739 0 : nsAutoCString id;
740 0 : if (NS_SUCCEEDED(device->GetId(id)) && id.Equals(utf8DeviceId)) {
741 0 : request->Select(device);
742 0 : return NS_OK;
743 : }
744 : }
745 :
746 : // Reject if designated device is not available.
747 0 : return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
748 : }
749 :
750 : already_AddRefed<PresentationSessionInfo>
751 0 : PresentationService::CreateControllingSessionInfo(const nsAString& aUrl,
752 : const nsAString& aSessionId,
753 : uint64_t aWindowId)
754 : {
755 0 : MOZ_ASSERT(NS_IsMainThread());
756 :
757 0 : if (aSessionId.IsEmpty()) {
758 0 : return nullptr;
759 : }
760 :
761 : RefPtr<PresentationSessionInfo> info =
762 0 : new PresentationControllingInfo(aUrl, aSessionId);
763 :
764 0 : mSessionInfoAtController.Put(aSessionId, info);
765 0 : AddRespondingSessionId(aWindowId,
766 : aSessionId,
767 0 : nsIPresentationService::ROLE_CONTROLLER);
768 0 : return info.forget();
769 : }
770 :
771 : NS_IMETHODIMP
772 0 : PresentationService::SendSessionMessage(const nsAString& aSessionId,
773 : uint8_t aRole,
774 : const nsAString& aData)
775 : {
776 0 : MOZ_ASSERT(NS_IsMainThread());
777 0 : MOZ_ASSERT(!aData.IsEmpty());
778 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
779 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
780 : aRole == nsIPresentationService::ROLE_RECEIVER);
781 :
782 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
783 0 : if (NS_WARN_IF(!info)) {
784 0 : return NS_ERROR_NOT_AVAILABLE;
785 : }
786 :
787 0 : return info->Send(aData);
788 : }
789 :
790 : NS_IMETHODIMP
791 0 : PresentationService::SendSessionBinaryMsg(const nsAString& aSessionId,
792 : uint8_t aRole,
793 : const nsACString &aData)
794 : {
795 0 : MOZ_ASSERT(NS_IsMainThread());
796 0 : MOZ_ASSERT(!aData.IsEmpty());
797 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
798 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
799 : aRole == nsIPresentationService::ROLE_RECEIVER);
800 :
801 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
802 0 : if (NS_WARN_IF(!info)) {
803 0 : return NS_ERROR_NOT_AVAILABLE;
804 : }
805 :
806 0 : return info->SendBinaryMsg(aData);
807 : }
808 :
809 : NS_IMETHODIMP
810 0 : PresentationService::SendSessionBlob(const nsAString& aSessionId,
811 : uint8_t aRole,
812 : nsIDOMBlob* aBlob)
813 : {
814 0 : MOZ_ASSERT(NS_IsMainThread());
815 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
816 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
817 : aRole == nsIPresentationService::ROLE_RECEIVER);
818 0 : MOZ_ASSERT(aBlob);
819 :
820 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
821 0 : if (NS_WARN_IF(!info)) {
822 0 : return NS_ERROR_NOT_AVAILABLE;
823 : }
824 :
825 0 : return info->SendBlob(aBlob);
826 : }
827 :
828 : NS_IMETHODIMP
829 0 : PresentationService::CloseSession(const nsAString& aSessionId,
830 : uint8_t aRole,
831 : uint8_t aClosedReason)
832 : {
833 0 : PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
834 : NS_ConvertUTF16toUTF8(aSessionId).get(), aClosedReason, aRole);
835 :
836 0 : MOZ_ASSERT(NS_IsMainThread());
837 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
838 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
839 : aRole == nsIPresentationService::ROLE_RECEIVER);
840 :
841 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
842 0 : if (NS_WARN_IF(!info)) {
843 0 : return NS_ERROR_NOT_AVAILABLE;
844 : }
845 :
846 0 : if (aClosedReason == nsIPresentationService::CLOSED_REASON_WENTAWAY) {
847 : // Remove nsIPresentationSessionListener since we don't want to dispatch
848 : // PresentationConnectionCloseEvent if the page is went away.
849 0 : info->SetListener(nullptr);
850 : }
851 :
852 0 : return info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED);
853 : }
854 :
855 : NS_IMETHODIMP
856 0 : PresentationService::TerminateSession(const nsAString& aSessionId,
857 : uint8_t aRole)
858 : {
859 0 : PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
860 : NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
861 :
862 0 : MOZ_ASSERT(NS_IsMainThread());
863 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
864 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
865 : aRole == nsIPresentationService::ROLE_RECEIVER);
866 :
867 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
868 0 : if (NS_WARN_IF(!info)) {
869 0 : return NS_ERROR_NOT_AVAILABLE;
870 : }
871 :
872 0 : return info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED);
873 : }
874 :
875 : NS_IMETHODIMP
876 0 : PresentationService::ReconnectSession(const nsTArray<nsString>& aUrls,
877 : const nsAString& aSessionId,
878 : uint8_t aRole,
879 : nsIPresentationServiceCallback* aCallback)
880 : {
881 0 : PRES_DEBUG("%s:id[%s]\n", __func__, NS_ConvertUTF16toUTF8(aSessionId).get());
882 :
883 0 : MOZ_ASSERT(NS_IsMainThread());
884 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
885 0 : MOZ_ASSERT(aCallback);
886 0 : MOZ_ASSERT(!aUrls.IsEmpty());
887 :
888 0 : if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
889 0 : MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
890 : return NS_ERROR_INVALID_ARG;
891 : }
892 :
893 0 : if (NS_WARN_IF(!aCallback)) {
894 0 : return NS_ERROR_INVALID_ARG;
895 : }
896 :
897 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
898 0 : if (NS_WARN_IF(!info)) {
899 0 : return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
900 : }
901 :
902 0 : if (NS_WARN_IF(!aUrls.Contains(info->GetUrl()))) {
903 0 : return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
904 : }
905 :
906 0 : return static_cast<PresentationControllingInfo*>(info.get())->Reconnect(aCallback);
907 : }
908 :
909 : NS_IMETHODIMP
910 0 : PresentationService::BuildTransport(const nsAString& aSessionId,
911 : uint8_t aRole)
912 : {
913 0 : MOZ_ASSERT(NS_IsMainThread());
914 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
915 :
916 0 : if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
917 0 : MOZ_ASSERT(false, "Only controller can call BuildTransport.");
918 : return NS_ERROR_INVALID_ARG;
919 : }
920 :
921 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
922 0 : if (NS_WARN_IF(!info)) {
923 0 : return NS_ERROR_NOT_AVAILABLE;
924 : }
925 :
926 0 : return static_cast<PresentationControllingInfo*>(info.get())->BuildTransport();
927 : }
928 :
929 : NS_IMETHODIMP
930 0 : PresentationService::RegisterAvailabilityListener(
931 : const nsTArray<nsString>& aAvailabilityUrls,
932 : nsIPresentationAvailabilityListener* aListener)
933 : {
934 0 : MOZ_ASSERT(NS_IsMainThread());
935 0 : MOZ_ASSERT(!aAvailabilityUrls.IsEmpty());
936 0 : MOZ_ASSERT(aListener);
937 :
938 0 : mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls, aListener);
939 0 : return UpdateAvailabilityUrlChange(aAvailabilityUrls);
940 : }
941 :
942 : NS_IMETHODIMP
943 0 : PresentationService::UnregisterAvailabilityListener(
944 : const nsTArray<nsString>& aAvailabilityUrls,
945 : nsIPresentationAvailabilityListener* aListener)
946 : {
947 0 : MOZ_ASSERT(NS_IsMainThread());
948 :
949 0 : mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls, aListener);
950 0 : return NS_OK;
951 : }
952 :
953 : NS_IMETHODIMP
954 0 : PresentationService::RegisterSessionListener(const nsAString& aSessionId,
955 : uint8_t aRole,
956 : nsIPresentationSessionListener* aListener)
957 : {
958 0 : PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
959 : NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
960 :
961 0 : MOZ_ASSERT(NS_IsMainThread());
962 0 : MOZ_ASSERT(aListener);
963 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
964 : aRole == nsIPresentationService::ROLE_RECEIVER);
965 :
966 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
967 0 : if (NS_WARN_IF(!info)) {
968 : // Notify the listener of TERMINATED since no correspondent session info is
969 : // available possibly due to establishment failure. This would be useful at
970 : // the receiver side, since a presentation session is created at beginning
971 : // and here is the place to realize the underlying establishment fails.
972 : nsresult rv = aListener->NotifyStateChange(aSessionId,
973 : nsIPresentationSessionListener::STATE_TERMINATED,
974 0 : NS_ERROR_NOT_AVAILABLE);
975 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
976 0 : return rv;
977 : }
978 0 : return NS_ERROR_NOT_AVAILABLE;
979 : }
980 :
981 0 : return info->SetListener(aListener);
982 : }
983 :
984 : NS_IMETHODIMP
985 0 : PresentationService::UnregisterSessionListener(const nsAString& aSessionId,
986 : uint8_t aRole)
987 : {
988 0 : PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
989 : NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
990 :
991 0 : MOZ_ASSERT(NS_IsMainThread());
992 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
993 : aRole == nsIPresentationService::ROLE_RECEIVER);
994 :
995 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
996 0 : if (info) {
997 : // When content side decide not handling this session anymore, simply
998 : // close the connection. Session info is kept for reconnection.
999 0 : Unused << NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED)));
1000 0 : return info->SetListener(nullptr);
1001 : }
1002 0 : return NS_OK;
1003 : }
1004 :
1005 : NS_IMETHODIMP
1006 0 : PresentationService::RegisterRespondingListener(
1007 : uint64_t aWindowId,
1008 : nsIPresentationRespondingListener* aListener)
1009 : {
1010 0 : PRES_DEBUG("%s:windowId[%" PRIu64 "]\n", __func__, aWindowId);
1011 :
1012 0 : MOZ_ASSERT(NS_IsMainThread());
1013 0 : MOZ_ASSERT(aListener);
1014 :
1015 0 : nsCOMPtr<nsIPresentationRespondingListener> listener;
1016 0 : if (mRespondingListeners.Get(aWindowId, getter_AddRefs(listener))) {
1017 0 : return (listener == aListener) ? NS_OK : NS_ERROR_DOM_INVALID_STATE_ERR;
1018 : }
1019 :
1020 0 : nsTArray<nsString> sessionIdArray;
1021 0 : nsresult rv = mReceiverSessionIdManager.GetSessionIds(aWindowId,
1022 0 : sessionIdArray);
1023 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1024 0 : return rv;
1025 : }
1026 :
1027 0 : for (const auto& id : sessionIdArray) {
1028 0 : aListener->NotifySessionConnect(aWindowId, id);
1029 : }
1030 :
1031 0 : mRespondingListeners.Put(aWindowId, aListener);
1032 0 : return NS_OK;
1033 : }
1034 :
1035 : NS_IMETHODIMP
1036 0 : PresentationService::UnregisterRespondingListener(uint64_t aWindowId)
1037 : {
1038 0 : PRES_DEBUG("%s:windowId[%" PRIu64 "]\n", __func__, aWindowId);
1039 :
1040 0 : MOZ_ASSERT(NS_IsMainThread());
1041 :
1042 0 : mRespondingListeners.Remove(aWindowId);
1043 0 : return NS_OK;
1044 : }
1045 :
1046 : NS_IMETHODIMP
1047 0 : PresentationService::NotifyReceiverReady(
1048 : const nsAString& aSessionId,
1049 : uint64_t aWindowId,
1050 : bool aIsLoading,
1051 : nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
1052 : {
1053 0 : PRES_DEBUG("%s:id[%s], windowId[%" PRIu64 "], loading[%d]\n", __func__,
1054 : NS_ConvertUTF16toUTF8(aSessionId).get(), aWindowId, aIsLoading);
1055 :
1056 : RefPtr<PresentationSessionInfo> info =
1057 0 : GetSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER);
1058 0 : if (NS_WARN_IF(!info)) {
1059 0 : return NS_ERROR_NOT_AVAILABLE;
1060 : }
1061 :
1062 0 : AddRespondingSessionId(aWindowId,
1063 : aSessionId,
1064 0 : nsIPresentationService::ROLE_RECEIVER);
1065 :
1066 0 : if (!aIsLoading) {
1067 : return static_cast<PresentationPresentingInfo*>(
1068 0 : info.get())->NotifyResponderFailure();
1069 : }
1070 :
1071 0 : nsCOMPtr<nsIPresentationRespondingListener> listener;
1072 0 : if (mRespondingListeners.Get(aWindowId, getter_AddRefs(listener))) {
1073 0 : nsresult rv = listener->NotifySessionConnect(aWindowId, aSessionId);
1074 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1075 0 : return rv;
1076 : }
1077 : }
1078 :
1079 0 : info->SetTransportBuilderConstructor(aBuilderConstructor);
1080 0 : return static_cast<PresentationPresentingInfo*>(info.get())->NotifyResponderReady();
1081 : }
1082 :
1083 : nsresult
1084 0 : PresentationService::NotifyTransportClosed(const nsAString& aSessionId,
1085 : uint8_t aRole,
1086 : nsresult aReason)
1087 : {
1088 0 : PRES_DEBUG("%s:id[%s], reason[%" PRIx32 "], role[%d]\n", __func__,
1089 : NS_ConvertUTF16toUTF8(aSessionId).get(), static_cast<uint32_t>(aReason),
1090 : aRole);
1091 :
1092 0 : MOZ_ASSERT(NS_IsMainThread());
1093 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
1094 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
1095 : aRole == nsIPresentationService::ROLE_RECEIVER);
1096 :
1097 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
1098 0 : if (NS_WARN_IF(!info)) {
1099 0 : return NS_ERROR_NOT_AVAILABLE;
1100 : }
1101 :
1102 0 : return info->NotifyTransportClosed(aReason);
1103 : }
1104 :
1105 : NS_IMETHODIMP
1106 0 : PresentationService::UntrackSessionInfo(const nsAString& aSessionId,
1107 : uint8_t aRole)
1108 : {
1109 0 : PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
1110 : NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
1111 :
1112 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
1113 : aRole == nsIPresentationService::ROLE_RECEIVER);
1114 : // Remove the session info.
1115 0 : if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
1116 0 : mSessionInfoAtController.Remove(aSessionId);
1117 : } else {
1118 : // Terminate receiver page.
1119 : uint64_t windowId;
1120 0 : nsresult rv = GetWindowIdBySessionIdInternal(aSessionId, aRole, &windowId);
1121 0 : if (NS_SUCCEEDED(rv)) {
1122 0 : NS_DispatchToMainThread(NS_NewRunnableFunction(
1123 0 : "dom::PresentationService::UntrackSessionInfo", [windowId]() -> void {
1124 0 : PRES_DEBUG("Attempt to close window[%" PRIu64 "]\n", windowId);
1125 :
1126 0 : if (auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId)) {
1127 0 : window->Close();
1128 : }
1129 0 : }));
1130 : }
1131 :
1132 0 : mSessionInfoAtReceiver.Remove(aSessionId);
1133 : }
1134 :
1135 : // Remove the in-process responding info if there's still any.
1136 0 : RemoveRespondingSessionId(aSessionId, aRole);
1137 :
1138 0 : return NS_OK;
1139 : }
1140 :
1141 : NS_IMETHODIMP
1142 0 : PresentationService::GetWindowIdBySessionId(const nsAString& aSessionId,
1143 : uint8_t aRole,
1144 : uint64_t* aWindowId)
1145 : {
1146 0 : return GetWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
1147 : }
1148 :
1149 : NS_IMETHODIMP
1150 0 : PresentationService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
1151 : uint8_t aRole,
1152 : const uint64_t aWindowId)
1153 : {
1154 0 : return UpdateWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
1155 : }
1156 :
1157 : bool
1158 0 : PresentationService::IsSessionAccessible(const nsAString& aSessionId,
1159 : const uint8_t aRole,
1160 : base::ProcessId aProcessId)
1161 : {
1162 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
1163 : aRole == nsIPresentationService::ROLE_RECEIVER);
1164 0 : RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
1165 0 : if (NS_WARN_IF(!info)) {
1166 0 : return false;
1167 : }
1168 0 : return info->IsAccessible(aProcessId);
1169 : }
1170 :
1171 : } // namespace dom
1172 : } // namespace mozilla
1173 :
1174 : already_AddRefed<nsIPresentationService>
1175 1 : NS_CreatePresentationService()
1176 : {
1177 1 : MOZ_ASSERT(NS_IsMainThread());
1178 :
1179 2 : nsCOMPtr<nsIPresentationService> service;
1180 1 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
1181 0 : service = new mozilla::dom::PresentationIPCService();
1182 : } else {
1183 1 : service = new PresentationService();
1184 1 : if (NS_WARN_IF(!static_cast<PresentationService*>(service.get())->Init())) {
1185 0 : return nullptr;
1186 : }
1187 : }
1188 :
1189 1 : return service.forget();
1190 : }
|