Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et ft=cpp : */
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 file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/dom/ContentChild.h"
8 : #include "mozilla/dom/PermissionMessageUtils.h"
9 : #include "mozilla/dom/PPresentation.h"
10 : #include "mozilla/dom/TabParent.h"
11 : #include "mozilla/ipc/InputStreamUtils.h"
12 : #include "mozilla/ipc/URIUtils.h"
13 : #include "nsGlobalWindow.h"
14 : #include "nsIPresentationListener.h"
15 : #include "PresentationCallbacks.h"
16 : #include "PresentationChild.h"
17 : #include "PresentationContentSessionInfo.h"
18 : #include "PresentationIPCService.h"
19 : #include "PresentationLog.h"
20 :
21 : using namespace mozilla;
22 : using namespace mozilla::dom;
23 : using namespace mozilla::ipc;
24 :
25 : namespace {
26 :
27 : PresentationChild* sPresentationChild;
28 :
29 : } // anonymous
30 :
31 0 : NS_IMPL_ISUPPORTS(PresentationIPCService,
32 : nsIPresentationService,
33 : nsIPresentationAvailabilityListener)
34 :
35 0 : PresentationIPCService::PresentationIPCService()
36 : {
37 0 : ContentChild* contentChild = ContentChild::GetSingleton();
38 0 : if (NS_WARN_IF(!contentChild || contentChild->IsShuttingDown())) {
39 0 : return;
40 : }
41 0 : sPresentationChild = new PresentationChild(this);
42 : Unused <<
43 0 : NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild));
44 : }
45 :
46 : /* virtual */
47 0 : PresentationIPCService::~PresentationIPCService()
48 : {
49 0 : Shutdown();
50 :
51 0 : mSessionListeners.Clear();
52 0 : mSessionInfoAtController.Clear();
53 0 : mSessionInfoAtReceiver.Clear();
54 0 : sPresentationChild = nullptr;
55 0 : }
56 :
57 : NS_IMETHODIMP
58 0 : PresentationIPCService::StartSession(
59 : const nsTArray<nsString>& aUrls,
60 : const nsAString& aSessionId,
61 : const nsAString& aOrigin,
62 : const nsAString& aDeviceId,
63 : uint64_t aWindowId,
64 : nsIDOMEventTarget* aEventTarget,
65 : nsIPrincipal* aPrincipal,
66 : nsIPresentationServiceCallback* aCallback,
67 : nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
68 : {
69 0 : if (aWindowId != 0) {
70 0 : AddRespondingSessionId(aWindowId,
71 : aSessionId,
72 0 : nsIPresentationService::ROLE_CONTROLLER);
73 : }
74 :
75 : nsPIDOMWindowInner* window =
76 0 : nsGlobalWindow::GetInnerWindowWithId(aWindowId)->AsInner();
77 0 : TabId tabId = TabParent::GetTabIdFrom(window->GetDocShell());
78 :
79 0 : return SendRequest(aCallback, StartSessionRequest(aUrls,
80 0 : nsString(aSessionId),
81 0 : nsString(aOrigin),
82 0 : nsString(aDeviceId),
83 : aWindowId,
84 : tabId,
85 0 : IPC::Principal(aPrincipal)));
86 : }
87 :
88 : NS_IMETHODIMP
89 0 : PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
90 : uint8_t aRole,
91 : const nsAString& aData)
92 : {
93 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
94 0 : MOZ_ASSERT(!aData.IsEmpty());
95 :
96 : RefPtr<PresentationContentSessionInfo> info =
97 0 : GetSessionInfo(aSessionId, aRole);
98 : // data channel session transport is maintained by content process
99 0 : if (info) {
100 0 : return info->Send(aData);
101 : }
102 :
103 0 : return SendRequest(nullptr, SendSessionMessageRequest(nsString(aSessionId),
104 : aRole,
105 0 : nsString(aData)));
106 : }
107 :
108 : NS_IMETHODIMP
109 0 : PresentationIPCService::SendSessionBinaryMsg(const nsAString& aSessionId,
110 : uint8_t aRole,
111 : const nsACString &aData)
112 : {
113 0 : MOZ_ASSERT(NS_IsMainThread());
114 0 : MOZ_ASSERT(!aData.IsEmpty());
115 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
116 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
117 : aRole == nsIPresentationService::ROLE_RECEIVER);
118 :
119 : RefPtr<PresentationContentSessionInfo> info =
120 0 : GetSessionInfo(aSessionId, aRole);
121 : // data channel session transport is maintained by content process
122 0 : if (info) {
123 0 : return info->SendBinaryMsg(aData);
124 : }
125 :
126 0 : return NS_ERROR_NOT_AVAILABLE;
127 : }
128 :
129 : NS_IMETHODIMP
130 0 : PresentationIPCService::SendSessionBlob(const nsAString& aSessionId,
131 : uint8_t aRole,
132 : nsIDOMBlob* aBlob)
133 : {
134 0 : MOZ_ASSERT(NS_IsMainThread());
135 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
136 0 : MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
137 : aRole == nsIPresentationService::ROLE_RECEIVER);
138 0 : MOZ_ASSERT(aBlob);
139 :
140 : RefPtr<PresentationContentSessionInfo> info =
141 0 : GetSessionInfo(aSessionId, aRole);
142 : // data channel session transport is maintained by content process
143 0 : if (info) {
144 0 : return info->SendBlob(aBlob);
145 : }
146 :
147 0 : return NS_ERROR_NOT_AVAILABLE;
148 : }
149 :
150 : NS_IMETHODIMP
151 0 : PresentationIPCService::CloseSession(const nsAString& aSessionId,
152 : uint8_t aRole,
153 : uint8_t aClosedReason)
154 : {
155 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
156 :
157 0 : nsresult rv = SendRequest(nullptr, CloseSessionRequest(nsString(aSessionId),
158 : aRole,
159 0 : aClosedReason));
160 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
161 0 : return rv;
162 : }
163 :
164 : RefPtr<PresentationContentSessionInfo> info =
165 0 : GetSessionInfo(aSessionId, aRole);
166 0 : if (info) {
167 0 : return info->Close(NS_OK);
168 : }
169 :
170 0 : return NS_OK;
171 : }
172 :
173 : NS_IMETHODIMP
174 0 : PresentationIPCService::TerminateSession(const nsAString& aSessionId,
175 : uint8_t aRole)
176 : {
177 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
178 :
179 0 : nsresult rv = SendRequest(nullptr, TerminateSessionRequest(nsString(aSessionId), aRole));
180 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
181 0 : return rv;
182 : }
183 :
184 : RefPtr<PresentationContentSessionInfo> info =
185 0 : GetSessionInfo(aSessionId, aRole);
186 0 : if (info) {
187 0 : return info->Close(NS_OK);
188 : }
189 :
190 0 : return NS_OK;
191 : }
192 :
193 : NS_IMETHODIMP
194 0 : PresentationIPCService::ReconnectSession(const nsTArray<nsString>& aUrls,
195 : const nsAString& aSessionId,
196 : uint8_t aRole,
197 : nsIPresentationServiceCallback* aCallback)
198 : {
199 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
200 :
201 0 : if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
202 0 : MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
203 : return NS_ERROR_INVALID_ARG;
204 : }
205 :
206 0 : return SendRequest(aCallback, ReconnectSessionRequest(aUrls,
207 0 : nsString(aSessionId),
208 0 : aRole));
209 : }
210 :
211 : NS_IMETHODIMP
212 0 : PresentationIPCService::BuildTransport(const nsAString& aSessionId,
213 : uint8_t aRole)
214 : {
215 0 : MOZ_ASSERT(!aSessionId.IsEmpty());
216 :
217 0 : if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
218 0 : MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
219 : return NS_ERROR_INVALID_ARG;
220 : }
221 :
222 0 : return SendRequest(nullptr, BuildTransportRequest(nsString(aSessionId),
223 0 : aRole));
224 : }
225 :
226 : nsresult
227 0 : PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback,
228 : const PresentationIPCRequest& aRequest)
229 : {
230 0 : if (sPresentationChild) {
231 0 : PresentationRequestChild* actor = new PresentationRequestChild(aCallback);
232 0 : Unused << NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest));
233 : }
234 0 : return NS_OK;
235 : }
236 :
237 : NS_IMETHODIMP
238 0 : PresentationIPCService::RegisterAvailabilityListener(
239 : const nsTArray<nsString>& aAvailabilityUrls,
240 : nsIPresentationAvailabilityListener* aListener)
241 : {
242 0 : MOZ_ASSERT(NS_IsMainThread());
243 0 : MOZ_ASSERT(!aAvailabilityUrls.IsEmpty());
244 0 : MOZ_ASSERT(aListener);
245 :
246 0 : nsTArray<nsString> addedUrls;
247 0 : mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls,
248 : aListener,
249 0 : addedUrls);
250 :
251 0 : if (sPresentationChild && !addedUrls.IsEmpty()) {
252 : Unused <<
253 0 : NS_WARN_IF(
254 : !sPresentationChild->SendRegisterAvailabilityHandler(addedUrls));
255 : }
256 0 : return NS_OK;
257 : }
258 :
259 : NS_IMETHODIMP
260 0 : PresentationIPCService::UnregisterAvailabilityListener(
261 : const nsTArray<nsString>& aAvailabilityUrls,
262 : nsIPresentationAvailabilityListener* aListener)
263 : {
264 0 : MOZ_ASSERT(NS_IsMainThread());
265 :
266 0 : nsTArray<nsString> removedUrls;
267 0 : mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls,
268 : aListener,
269 0 : removedUrls);
270 :
271 0 : if (sPresentationChild && !removedUrls.IsEmpty()) {
272 : Unused <<
273 0 : NS_WARN_IF(
274 : !sPresentationChild->SendUnregisterAvailabilityHandler(removedUrls));
275 : }
276 0 : return NS_OK;
277 : }
278 :
279 : NS_IMETHODIMP
280 0 : PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
281 : uint8_t aRole,
282 : nsIPresentationSessionListener* aListener)
283 : {
284 0 : MOZ_ASSERT(NS_IsMainThread());
285 0 : MOZ_ASSERT(aListener);
286 :
287 0 : nsCOMPtr<nsIPresentationSessionListener> listener;
288 0 : if (mSessionListeners.Get(aSessionId, getter_AddRefs(listener))) {
289 0 : mSessionListeners.Put(aSessionId, aListener);
290 0 : return NS_OK;
291 : }
292 :
293 0 : mSessionListeners.Put(aSessionId, aListener);
294 0 : if (sPresentationChild) {
295 : Unused <<
296 0 : NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(
297 : nsString(aSessionId), aRole));
298 : }
299 0 : return NS_OK;
300 : }
301 :
302 : NS_IMETHODIMP
303 0 : PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId,
304 : uint8_t aRole)
305 : {
306 0 : MOZ_ASSERT(NS_IsMainThread());
307 :
308 0 : UntrackSessionInfo(aSessionId, aRole);
309 :
310 0 : mSessionListeners.Remove(aSessionId);
311 0 : if (sPresentationChild) {
312 : Unused <<
313 0 : NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(
314 : nsString(aSessionId), aRole));
315 : }
316 0 : return NS_OK;
317 : }
318 :
319 : NS_IMETHODIMP
320 0 : PresentationIPCService::RegisterRespondingListener(uint64_t aWindowId,
321 : nsIPresentationRespondingListener* aListener)
322 : {
323 0 : MOZ_ASSERT(NS_IsMainThread());
324 :
325 0 : mRespondingListeners.Put(aWindowId, aListener);
326 0 : if (sPresentationChild) {
327 : Unused <<
328 0 : NS_WARN_IF(!sPresentationChild->SendRegisterRespondingHandler(aWindowId));
329 : }
330 0 : return NS_OK;
331 : }
332 :
333 : NS_IMETHODIMP
334 0 : PresentationIPCService::UnregisterRespondingListener(uint64_t aWindowId)
335 : {
336 0 : MOZ_ASSERT(NS_IsMainThread());
337 :
338 0 : mRespondingListeners.Remove(aWindowId);
339 0 : if (sPresentationChild) {
340 : Unused <<
341 0 : NS_WARN_IF(!sPresentationChild->SendUnregisterRespondingHandler(
342 : aWindowId));
343 : }
344 0 : return NS_OK;
345 : }
346 :
347 : nsresult
348 0 : PresentationIPCService::NotifySessionTransport(const nsString& aSessionId,
349 : const uint8_t& aRole,
350 : nsIPresentationSessionTransport* aTransport)
351 : {
352 : RefPtr<PresentationContentSessionInfo> info =
353 0 : new PresentationContentSessionInfo(aSessionId, aRole, aTransport);
354 :
355 0 : if (NS_WARN_IF(NS_FAILED(info->Init()))) {
356 0 : return NS_ERROR_NOT_AVAILABLE;
357 : }
358 :
359 0 : if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
360 0 : mSessionInfoAtController.Put(aSessionId, info);
361 : } else {
362 0 : mSessionInfoAtReceiver.Put(aSessionId, info);
363 : }
364 0 : return NS_OK;
365 : }
366 :
367 : NS_IMETHODIMP
368 0 : PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId,
369 : uint8_t aRole,
370 : uint64_t* aWindowId)
371 : {
372 0 : return GetWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
373 : }
374 :
375 : NS_IMETHODIMP
376 0 : PresentationIPCService::UpdateWindowIdBySessionId(const nsAString& aSessionId,
377 : uint8_t aRole,
378 : const uint64_t aWindowId)
379 : {
380 0 : return UpdateWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId);
381 : }
382 :
383 : nsresult
384 0 : PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
385 : uint16_t aState,
386 : nsresult aReason)
387 : {
388 0 : nsCOMPtr<nsIPresentationSessionListener> listener;
389 0 : if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
390 0 : return NS_OK;
391 : }
392 :
393 0 : return listener->NotifyStateChange(aSessionId, aState, aReason);
394 : }
395 :
396 : // Only used for OOP RTCDataChannel session transport case.
397 : nsresult
398 0 : PresentationIPCService::NotifyMessage(const nsAString& aSessionId,
399 : const nsACString& aData,
400 : const bool& aIsBinary)
401 : {
402 0 : nsCOMPtr<nsIPresentationSessionListener> listener;
403 0 : if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
404 0 : return NS_OK;
405 : }
406 :
407 0 : return listener->NotifyMessage(aSessionId, aData, aIsBinary);
408 : }
409 :
410 : // Only used for OOP RTCDataChannel session transport case.
411 : nsresult
412 0 : PresentationIPCService::NotifyTransportClosed(const nsAString& aSessionId,
413 : uint8_t aRole,
414 : nsresult aReason)
415 : {
416 : RefPtr<PresentationContentSessionInfo> info =
417 0 : GetSessionInfo(aSessionId, aRole);
418 0 : if (NS_WARN_IF(!info)) {
419 0 : return NS_ERROR_NOT_AVAILABLE;
420 : }
421 0 : Unused << NS_WARN_IF(!sPresentationChild->SendNotifyTransportClosed(nsString(aSessionId), aRole, aReason));
422 0 : return NS_OK;
423 : }
424 :
425 : nsresult
426 0 : PresentationIPCService::NotifySessionConnect(uint64_t aWindowId,
427 : const nsAString& aSessionId)
428 : {
429 0 : nsCOMPtr<nsIPresentationRespondingListener> listener;
430 0 : if (NS_WARN_IF(!mRespondingListeners.Get(aWindowId, getter_AddRefs(listener)))) {
431 0 : return NS_OK;
432 : }
433 :
434 0 : return listener->NotifySessionConnect(aWindowId, aSessionId);
435 : }
436 :
437 : NS_IMETHODIMP
438 0 : PresentationIPCService::NotifyAvailableChange(
439 : const nsTArray<nsString>& aAvailabilityUrls,
440 : bool aAvailable)
441 : {
442 0 : return mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls,
443 0 : aAvailable);
444 : }
445 :
446 : NS_IMETHODIMP
447 0 : PresentationIPCService::NotifyReceiverReady(
448 : const nsAString& aSessionId,
449 : uint64_t aWindowId,
450 : bool aIsLoading,
451 : nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
452 : {
453 0 : MOZ_ASSERT(NS_IsMainThread());
454 :
455 : // No actual window uses 0 as its ID.
456 0 : if (NS_WARN_IF(aWindowId == 0)) {
457 0 : return NS_ERROR_NOT_AVAILABLE;
458 : }
459 :
460 : // Track the responding info for an OOP receiver page.
461 0 : AddRespondingSessionId(aWindowId,
462 : aSessionId,
463 0 : nsIPresentationService::ROLE_RECEIVER);
464 :
465 0 : Unused << NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId),
466 : aWindowId,
467 : aIsLoading));
468 :
469 : // Release mCallback after using aSessionId
470 : // because aSessionId is held by mCallback.
471 0 : mCallback = nullptr;
472 0 : return NS_OK;
473 : }
474 :
475 : NS_IMETHODIMP
476 0 : PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId,
477 : uint8_t aRole)
478 : {
479 0 : PRES_DEBUG("content %s:id[%s], role[%d]\n", __func__,
480 : NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);
481 :
482 0 : if (nsIPresentationService::ROLE_RECEIVER == aRole) {
483 : // Terminate receiver page.
484 : uint64_t windowId;
485 0 : if (NS_SUCCEEDED(GetWindowIdBySessionIdInternal(aSessionId,
486 : aRole,
487 : &windowId))) {
488 0 : NS_DispatchToMainThread(NS_NewRunnableFunction(
489 : "dom::PresentationIPCService::UntrackSessionInfo",
490 0 : [windowId]() -> void {
491 0 : PRES_DEBUG("Attempt to close window[%" PRIu64 "]\n", windowId);
492 :
493 0 : if (auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId)) {
494 0 : window->Close();
495 : }
496 0 : }));
497 : }
498 : }
499 :
500 : // Remove the OOP responding info (if it has never been used).
501 0 : RemoveRespondingSessionId(aSessionId, aRole);
502 :
503 0 : if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
504 0 : mSessionInfoAtController.Remove(aSessionId);
505 : } else {
506 0 : mSessionInfoAtReceiver.Remove(aSessionId);
507 : }
508 :
509 0 : return NS_OK;
510 : }
511 :
512 : void
513 0 : PresentationIPCService::NotifyPresentationChildDestroyed()
514 : {
515 0 : sPresentationChild = nullptr;
516 0 : }
517 :
518 : nsresult
519 0 : PresentationIPCService::MonitorResponderLoading(const nsAString& aSessionId,
520 : nsIDocShell* aDocShell)
521 : {
522 0 : MOZ_ASSERT(NS_IsMainThread());
523 :
524 0 : mCallback = new PresentationResponderLoadingCallback(aSessionId);
525 0 : return mCallback->Init(aDocShell);
526 : }
527 :
528 : nsresult
529 0 : PresentationIPCService::CloseContentSessionTransport(const nsString& aSessionId,
530 : uint8_t aRole,
531 : nsresult aReason)
532 : {
533 : RefPtr<PresentationContentSessionInfo> info =
534 0 : GetSessionInfo(aSessionId, aRole);
535 0 : if (NS_WARN_IF(!info)) {
536 0 : return NS_ERROR_NOT_AVAILABLE;
537 : }
538 :
539 0 : return info->Close(aReason);
540 : }
|