Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/ipc/glue/IPCStreamUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 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 "IPCStreamUtils.h"
8
9
#include "nsIIPCSerializableInputStream.h"
10
11
#include "mozilla/Assertions.h"
12
#include "mozilla/InputStreamLengthHelper.h"
13
#include "mozilla/dom/ContentChild.h"
14
#include "mozilla/dom/ContentParent.h"
15
#include "mozilla/dom/File.h"
16
#include "mozilla/ipc/FileDescriptorSetChild.h"
17
#include "mozilla/ipc/FileDescriptorSetParent.h"
18
#include "mozilla/ipc/InputStreamUtils.h"
19
#include "mozilla/ipc/IPCStreamDestination.h"
20
#include "mozilla/ipc/IPCStreamSource.h"
21
#include "mozilla/ipc/PBackgroundChild.h"
22
#include "mozilla/ipc/PBackgroundParent.h"
23
#include "mozilla/Unused.h"
24
#include "nsIAsyncInputStream.h"
25
#include "nsIAsyncOutputStream.h"
26
#include "nsIPipe.h"
27
#include "nsNetCID.h"
28
#include "nsStreamUtils.h"
29
30
using namespace mozilla::dom;
31
32
namespace mozilla {
33
namespace ipc {
34
35
namespace {
36
37
void
38
AssertValidValueToTake(const IPCStream& aVal)
39
0
{
40
0
  MOZ_ASSERT(aVal.type() == IPCStream::TIPCRemoteStream ||
41
0
             aVal.type() == IPCStream::TInputStreamParamsWithFds);
42
0
}
43
44
void
45
AssertValidValueToTake(const OptionalIPCStream& aVal)
46
0
{
47
0
  MOZ_ASSERT(aVal.type() == OptionalIPCStream::Tvoid_t ||
48
0
             aVal.type() == OptionalIPCStream::TIPCStream);
49
0
  if (aVal.type() == OptionalIPCStream::TIPCStream) {
50
0
    AssertValidValueToTake(aVal.get_IPCStream());
51
0
  }
52
0
}
53
54
// These serialization and cleanup functions could be externally exposed.  For
55
// now, though, keep them private to encourage use of the safer RAII
56
// AutoIPCStream class.
57
58
template<typename M>
59
bool
60
SerializeInputStreamWithFdsChild(nsIIPCSerializableInputStream* aStream,
61
                                 IPCStream& aValue,
62
                                 M* aManager)
63
0
{
64
0
  MOZ_RELEASE_ASSERT(aStream);
65
0
  MOZ_ASSERT(aManager);
66
0
67
0
  aValue = InputStreamParamsWithFds();
68
0
  InputStreamParamsWithFds& streamWithFds =
69
0
    aValue.get_InputStreamParamsWithFds();
70
0
71
0
  AutoTArray<FileDescriptor, 4> fds;
72
0
  aStream->Serialize(streamWithFds.stream(), fds);
73
0
74
0
  if (streamWithFds.stream().type() == InputStreamParams::T__None) {
75
0
    MOZ_CRASH("Serialize failed!");
76
0
  }
77
0
78
0
  if (fds.IsEmpty()) {
79
0
    streamWithFds.optionalFds() = void_t();
80
0
  } else {
81
0
    PFileDescriptorSetChild* fdSet =
82
0
      aManager->SendPFileDescriptorSetConstructor(fds[0]);
83
0
    for (uint32_t i = 1; i < fds.Length(); ++i) {
84
0
      Unused << fdSet->SendAddFileDescriptor(fds[i]);
85
0
    }
86
0
87
0
    streamWithFds.optionalFds() = fdSet;
88
0
  }
89
0
90
0
  return true;
91
0
}
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStreamWithFdsChild<mozilla::dom::nsIContentChild>(nsIIPCSerializableInputStream*, mozilla::ipc::IPCStream&, mozilla::dom::nsIContentChild*)
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStreamWithFdsChild<mozilla::ipc::PBackgroundChild>(nsIIPCSerializableInputStream*, mozilla::ipc::IPCStream&, mozilla::ipc::PBackgroundChild*)
92
93
template<typename M>
94
bool
95
SerializeInputStreamWithFdsParent(nsIIPCSerializableInputStream* aStream,
96
                                  IPCStream& aValue,
97
                                  M* aManager)
98
0
{
99
0
  MOZ_RELEASE_ASSERT(aStream);
100
0
  MOZ_ASSERT(aManager);
101
0
102
0
  aValue = InputStreamParamsWithFds();
103
0
  InputStreamParamsWithFds& streamWithFds =
104
0
    aValue.get_InputStreamParamsWithFds();
105
0
106
0
  AutoTArray<FileDescriptor, 4> fds;
107
0
  aStream->Serialize(streamWithFds.stream(), fds);
108
0
109
0
  if (streamWithFds.stream().type() == InputStreamParams::T__None) {
110
0
    MOZ_CRASH("Serialize failed!");
111
0
  }
112
0
113
0
  streamWithFds.optionalFds() = void_t();
114
0
  if (!fds.IsEmpty()) {
115
0
    PFileDescriptorSetParent* fdSet =
116
0
      aManager->SendPFileDescriptorSetConstructor(fds[0]);
117
0
    for (uint32_t i = 1; i < fds.Length(); ++i) {
118
0
      if (NS_WARN_IF(!fdSet->SendAddFileDescriptor(fds[i]))) {
119
0
        Unused << PFileDescriptorSetParent::Send__delete__(fdSet);
120
0
        fdSet = nullptr;
121
0
        break;
122
0
      }
123
0
    }
124
0
125
0
    if (fdSet) {
126
0
      streamWithFds.optionalFds() = fdSet;
127
0
    }
128
0
  }
129
0
130
0
  return true;
131
0
}
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStreamWithFdsParent<mozilla::dom::nsIContentParent>(nsIIPCSerializableInputStream*, mozilla::ipc::IPCStream&, mozilla::dom::nsIContentParent*)
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStreamWithFdsParent<mozilla::ipc::PBackgroundParent>(nsIIPCSerializableInputStream*, mozilla::ipc::IPCStream&, mozilla::ipc::PBackgroundParent*)
132
133
template<typename M>
134
bool
135
SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue, M* aManager,
136
                     bool aDelayedStart)
137
0
{
138
0
  MOZ_ASSERT(aStream);
139
0
  MOZ_ASSERT(aManager);
140
0
141
0
  // Let's try to take the length using InputStreamLengthHelper. If the length
142
0
  // cannot be taken synchronously, and its length is needed, the stream needs
143
0
  // to be fully copied in memory on the deserialization side.
144
0
  int64_t length;
145
0
  if (!InputStreamLengthHelper::GetSyncLength(aStream, &length)) {
146
0
    length = -1;
147
0
  }
148
0
149
0
  // As a fallback, attempt to stream the data across using a IPCStream
150
0
  // actor. For blocking streams, create a nonblocking pipe instead,
151
0
  nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
152
0
  if (!asyncStream) {
153
0
    const uint32_t kBufferSize = 32768; // matches IPCStream buffer size.
154
0
    nsCOMPtr<nsIAsyncOutputStream> sink;
155
0
    nsresult rv = NS_NewPipe2(getter_AddRefs(asyncStream),
156
0
                              getter_AddRefs(sink),
157
0
                              true,
158
0
                              false,
159
0
                              kBufferSize,
160
0
                              UINT32_MAX);
161
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
162
0
      return false;
163
0
    }
164
0
165
0
    nsCOMPtr<nsIEventTarget> target =
166
0
      do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
167
0
168
0
    rv = NS_AsyncCopy(aStream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
169
0
                      kBufferSize);
170
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
171
0
      return false;
172
0
    }
173
0
  }
174
0
175
0
  MOZ_ASSERT(asyncStream);
176
0
177
0
  IPCRemoteStream remoteStream;
178
0
  remoteStream.delayedStart() = aDelayedStart;
179
0
  remoteStream.stream() = IPCStreamSource::Create(asyncStream, aManager);
180
0
  remoteStream.length() = length;
181
0
  aValue = remoteStream;
182
0
183
0
  return true;
184
0
}
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStream<mozilla::dom::nsIContentChild>(nsIInputStream*, mozilla::ipc::IPCStream&, mozilla::dom::nsIContentChild*, bool)
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStream<mozilla::ipc::PBackgroundChild>(nsIInputStream*, mozilla::ipc::IPCStream&, mozilla::ipc::PBackgroundChild*, bool)
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStream<mozilla::dom::nsIContentParent>(nsIInputStream*, mozilla::ipc::IPCStream&, mozilla::dom::nsIContentParent*, bool)
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStream<mozilla::ipc::PBackgroundParent>(nsIInputStream*, mozilla::ipc::IPCStream&, mozilla::ipc::PBackgroundParent*, bool)
185
186
template<typename M>
187
bool
188
SerializeInputStreamChild(nsIInputStream* aStream, M* aManager,
189
                          IPCStream* aValue,
190
                          OptionalIPCStream* aOptionalValue,
191
                          bool aDelayedStart)
192
0
{
193
0
  MOZ_ASSERT(aStream);
194
0
  MOZ_ASSERT(aManager);
195
0
  MOZ_ASSERT(aValue || aOptionalValue);
196
0
197
0
  // If a stream is known to be larger than 1MB, prefer sending it in chunks.
198
0
  const uint64_t kTooLargeStream = 1024 * 1024;
199
0
200
0
  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
201
0
    do_QueryInterface(aStream);
202
0
203
0
  // ExpectedSerializedLength() returns the length of the stream if serialized.
204
0
  // This is useful to decide if we want to continue using the serialization
205
0
  // directly, or if it's better to use IPCStream.
206
0
  uint64_t expectedLength =
207
0
    serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
208
0
  if (serializable && expectedLength < kTooLargeStream) {
209
0
    if (aValue) {
210
0
      return SerializeInputStreamWithFdsChild(serializable, *aValue, aManager);
211
0
    }
212
0
213
0
    return SerializeInputStreamWithFdsChild(serializable, *aOptionalValue,
214
0
                                            aManager);
215
0
  }
216
0
217
0
  if (aValue) {
218
0
    return SerializeInputStream(aStream, *aValue, aManager, aDelayedStart);
219
0
  }
220
0
221
0
  return SerializeInputStream(aStream, *aOptionalValue, aManager, aDelayedStart);
222
0
}
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStreamChild<mozilla::dom::nsIContentChild>(nsIInputStream*, mozilla::dom::nsIContentChild*, mozilla::ipc::IPCStream*, mozilla::ipc::OptionalIPCStream*, bool)
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStreamChild<mozilla::ipc::PBackgroundChild>(nsIInputStream*, mozilla::ipc::PBackgroundChild*, mozilla::ipc::IPCStream*, mozilla::ipc::OptionalIPCStream*, bool)
223
224
template<typename M>
225
bool
226
SerializeInputStreamParent(nsIInputStream* aStream, M* aManager,
227
                           IPCStream* aValue,
228
                           OptionalIPCStream* aOptionalValue,
229
                           bool aDelayedStart)
230
0
{
231
0
  MOZ_ASSERT(aStream);
232
0
  MOZ_ASSERT(aManager);
233
0
  MOZ_ASSERT(aValue || aOptionalValue);
234
0
235
0
  // If a stream is known to be larger than 1MB, prefer sending it in chunks.
236
0
  const uint64_t kTooLargeStream = 1024 * 1024;
237
0
238
0
  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
239
0
    do_QueryInterface(aStream);
240
0
  uint64_t expectedLength =
241
0
    serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
242
0
243
0
  if (serializable && expectedLength < kTooLargeStream) {
244
0
    if (aValue) {
245
0
      return SerializeInputStreamWithFdsParent(serializable, *aValue, aManager);
246
0
    }
247
0
248
0
    return SerializeInputStreamWithFdsParent(serializable, *aOptionalValue,
249
0
                                             aManager);
250
0
  }
251
0
252
0
  if (aValue) {
253
0
    return SerializeInputStream(aStream, *aValue, aManager, aDelayedStart);
254
0
  }
255
0
256
0
  return SerializeInputStream(aStream, *aOptionalValue, aManager, aDelayedStart);
257
0
}
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStreamParent<mozilla::dom::nsIContentParent>(nsIInputStream*, mozilla::dom::nsIContentParent*, mozilla::ipc::IPCStream*, mozilla::ipc::OptionalIPCStream*, bool)
Unexecuted instantiation: Unified_cpp_ipc_glue1.cpp:bool mozilla::ipc::(anonymous namespace)::SerializeInputStreamParent<mozilla::ipc::PBackgroundParent>(nsIInputStream*, mozilla::ipc::PBackgroundParent*, mozilla::ipc::IPCStream*, mozilla::ipc::OptionalIPCStream*, bool)
258
259
void
260
CleanupIPCStream(IPCStream& aValue, bool aConsumedByIPC, bool aDelayedStart)
261
0
{
262
0
  if (aValue.type() == IPCStream::T__None) {
263
0
    return;
264
0
  }
265
0
266
0
  if (aValue.type() == IPCStream::TInputStreamParamsWithFds) {
267
0
268
0
    InputStreamParamsWithFds& streamWithFds =
269
0
      aValue.get_InputStreamParamsWithFds();
270
0
271
0
    // Cleanup file descriptors if necessary
272
0
    if (streamWithFds.optionalFds().type() ==
273
0
        OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
274
0
275
0
      AutoTArray<FileDescriptor, 4> fds;
276
0
277
0
      auto fdSetActor = static_cast<FileDescriptorSetChild*>(
278
0
        streamWithFds.optionalFds().get_PFileDescriptorSetChild());
279
0
      MOZ_ASSERT(fdSetActor);
280
0
281
0
      // FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
282
0
      // unconditionally forget them here.  The fds themselves are auto-closed in
283
0
      // ~FileDescriptor since they originated in this process.
284
0
      fdSetActor->ForgetFileDescriptors(fds);
285
0
286
0
      if (!aConsumedByIPC) {
287
0
        Unused << FileDescriptorSetChild::Send__delete__(fdSetActor);
288
0
      }
289
0
290
0
    } else if (streamWithFds.optionalFds().type() ==
291
0
               OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
292
0
293
0
      AutoTArray<FileDescriptor, 4> fds;
294
0
295
0
      auto fdSetActor = static_cast<FileDescriptorSetParent*>(
296
0
        streamWithFds.optionalFds().get_PFileDescriptorSetParent());
297
0
      MOZ_ASSERT(fdSetActor);
298
0
299
0
      // FileDescriptorSet doesn't clear its fds in its ActorDestroy, so we
300
0
      // unconditionally forget them here.  The fds themselves are auto-closed in
301
0
      // ~FileDescriptor since they originated in this process.
302
0
      fdSetActor->ForgetFileDescriptors(fds);
303
0
304
0
      if (!aConsumedByIPC) {
305
0
        Unused << FileDescriptorSetParent::Send__delete__(fdSetActor);
306
0
      }
307
0
    }
308
0
309
0
    return;
310
0
  }
311
0
312
0
  MOZ_ASSERT(aValue.type() == IPCStream::TIPCRemoteStream);
313
0
  IPCRemoteStreamType& remoteInputStream =
314
0
    aValue.get_IPCRemoteStream().stream();
315
0
316
0
  IPCStreamSource* source = nullptr;
317
0
  if (remoteInputStream.type() == IPCRemoteStreamType::TPChildToParentStreamChild) {
318
0
    source = IPCStreamSource::Cast(remoteInputStream.get_PChildToParentStreamChild());
319
0
  } else {
320
0
    MOZ_ASSERT(remoteInputStream.type() == IPCRemoteStreamType::TPParentToChildStreamParent);
321
0
    source = IPCStreamSource::Cast(remoteInputStream.get_PParentToChildStreamParent());
322
0
  }
323
0
324
0
  MOZ_ASSERT(source);
325
0
326
0
  // If the source stream has not been taken to be sent to the other side, we
327
0
  // can destroy it.
328
0
  if (!aConsumedByIPC) {
329
0
    source->StartDestroy();
330
0
    return;
331
0
  }
332
0
333
0
  if (!aDelayedStart) {
334
0
    // If we don't need to do a delayedStart, we start it now. Otherwise, the
335
0
    // Start() will be called at the first use by the
336
0
    // IPCStreamDestination::DelayedStartInputStream.
337
0
    source->Start();
338
0
  }
339
0
}
340
341
void
342
CleanupIPCStream(OptionalIPCStream& aValue, bool aConsumedByIPC, bool aDelayedStart)
343
0
{
344
0
  if (aValue.type() == OptionalIPCStream::Tvoid_t) {
345
0
    return;
346
0
  }
347
0
348
0
  CleanupIPCStream(aValue.get_IPCStream(), aConsumedByIPC, aDelayedStart);
349
0
}
350
351
// Returns false if the serialization should not proceed. This means that the
352
// inputStream is null.
353
bool
354
NormalizeOptionalValue(nsIInputStream* aStream,
355
                       IPCStream* aValue,
356
                       OptionalIPCStream* aOptionalValue)
357
0
{
358
0
  if (aValue) {
359
0
    // if aStream is null, we will crash when serializing.
360
0
    return true;
361
0
  }
362
0
363
0
  if (!aStream) {
364
0
    *aOptionalValue = void_t();
365
0
    return false;
366
0
  }
367
0
368
0
  *aOptionalValue = IPCStream();
369
0
  return true;
370
0
}
371
372
} // anonymous namespace
373
374
already_AddRefed<nsIInputStream>
375
DeserializeIPCStream(const IPCStream& aValue)
376
0
{
377
0
  if (aValue.type() == IPCStream::TIPCRemoteStream) {
378
0
    const IPCRemoteStream& remoteStream = aValue.get_IPCRemoteStream();
379
0
    const IPCRemoteStreamType& remoteStreamType = remoteStream.stream();
380
0
    IPCStreamDestination* destinationStream;
381
0
382
0
    if (remoteStreamType.type() == IPCRemoteStreamType::TPChildToParentStreamParent) {
383
0
      destinationStream =
384
0
        IPCStreamDestination::Cast(remoteStreamType.get_PChildToParentStreamParent());
385
0
    } else {
386
0
      MOZ_ASSERT(remoteStreamType.type() == IPCRemoteStreamType::TPParentToChildStreamChild);
387
0
      destinationStream =
388
0
        IPCStreamDestination::Cast(remoteStreamType.get_PParentToChildStreamChild());
389
0
    }
390
0
391
0
    destinationStream->SetDelayedStart(remoteStream.delayedStart());
392
0
    destinationStream->SetLength(remoteStream.length());
393
0
    return destinationStream->TakeReader();
394
0
  }
395
0
396
0
  // Note, we explicitly do not support deserializing the PChildToParentStream actor on
397
0
  // the child side nor the PParentToChildStream actor on the parent side.
398
0
  MOZ_ASSERT(aValue.type() == IPCStream::TInputStreamParamsWithFds);
399
0
400
0
  const InputStreamParamsWithFds& streamWithFds =
401
0
    aValue.get_InputStreamParamsWithFds();
402
0
403
0
  AutoTArray<FileDescriptor, 4> fds;
404
0
  if (streamWithFds.optionalFds().type() ==
405
0
      OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
406
0
407
0
    auto fdSetActor = static_cast<FileDescriptorSetParent*>(
408
0
      streamWithFds.optionalFds().get_PFileDescriptorSetParent());
409
0
    MOZ_ASSERT(fdSetActor);
410
0
411
0
    fdSetActor->ForgetFileDescriptors(fds);
412
0
    MOZ_ASSERT(!fds.IsEmpty());
413
0
414
0
    if (!FileDescriptorSetParent::Send__delete__(fdSetActor)) {
415
0
      // child process is gone, warn and allow actor to clean up normally
416
0
      NS_WARNING("Failed to delete fd set actor.");
417
0
    }
418
0
  } else if (streamWithFds.optionalFds().type() ==
419
0
             OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
420
0
421
0
    auto fdSetActor = static_cast<FileDescriptorSetChild*>(
422
0
      streamWithFds.optionalFds().get_PFileDescriptorSetChild());
423
0
    MOZ_ASSERT(fdSetActor);
424
0
425
0
    fdSetActor->ForgetFileDescriptors(fds);
426
0
    MOZ_ASSERT(!fds.IsEmpty());
427
0
428
0
    Unused << FileDescriptorSetChild::Send__delete__(fdSetActor);
429
0
  }
430
0
431
0
  return InputStreamHelper::DeserializeInputStream(streamWithFds.stream(), fds);
432
0
}
433
434
already_AddRefed<nsIInputStream>
435
DeserializeIPCStream(const OptionalIPCStream& aValue)
436
0
{
437
0
  if (aValue.type() == OptionalIPCStream::Tvoid_t) {
438
0
    return nullptr;
439
0
  }
440
0
441
0
  return DeserializeIPCStream(aValue.get_IPCStream());
442
0
}
443
444
AutoIPCStream::AutoIPCStream(bool aDelayedStart)
445
  : mInlineValue(void_t())
446
  , mValue(nullptr)
447
  , mOptionalValue(&mInlineValue)
448
  , mTaken(false)
449
  , mDelayedStart(aDelayedStart)
450
0
{
451
0
}
452
453
AutoIPCStream::AutoIPCStream(IPCStream& aTarget, bool aDelayedStart)
454
  : mInlineValue(void_t())
455
  , mValue(&aTarget)
456
  , mOptionalValue(nullptr)
457
  , mTaken(false)
458
  , mDelayedStart(aDelayedStart)
459
0
{
460
0
}
461
462
AutoIPCStream::AutoIPCStream(OptionalIPCStream& aTarget, bool aDelayedStart)
463
  : mInlineValue(void_t())
464
  , mValue(nullptr)
465
  , mOptionalValue(&aTarget)
466
  , mTaken(false)
467
  , mDelayedStart(aDelayedStart)
468
0
{
469
0
  *mOptionalValue = void_t();
470
0
}
471
472
AutoIPCStream::~AutoIPCStream()
473
0
{
474
0
  MOZ_ASSERT(mValue || mOptionalValue);
475
0
  if (mValue && IsSet()) {
476
0
    CleanupIPCStream(*mValue, mTaken, mDelayedStart);
477
0
  } else {
478
0
    CleanupIPCStream(*mOptionalValue, mTaken, mDelayedStart);
479
0
  }
480
0
}
481
482
bool
483
AutoIPCStream::Serialize(nsIInputStream* aStream, dom::nsIContentChild* aManager)
484
0
{
485
0
  MOZ_ASSERT(aStream || !mValue);
486
0
  MOZ_ASSERT(aManager);
487
0
  MOZ_ASSERT(mValue || mOptionalValue);
488
0
  MOZ_ASSERT(!mTaken);
489
0
  MOZ_ASSERT(!IsSet());
490
0
491
0
  // If NormalizeOptionalValue returns false, we don't have to proceed.
492
0
  if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
493
0
    return true;
494
0
  }
495
0
496
0
  if (!SerializeInputStreamChild(aStream, aManager, mValue, mOptionalValue,
497
0
                                 mDelayedStart)) {
498
0
    MOZ_CRASH("IPCStream creation failed!");
499
0
  }
500
0
501
0
  if (mValue) {
502
0
    AssertValidValueToTake(*mValue);
503
0
  } else {
504
0
    AssertValidValueToTake(*mOptionalValue);
505
0
  }
506
0
507
0
  return true;
508
0
}
509
510
bool
511
AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundChild* aManager)
512
0
{
513
0
  MOZ_ASSERT(aStream || !mValue);
514
0
  MOZ_ASSERT(aManager);
515
0
  MOZ_ASSERT(mValue || mOptionalValue);
516
0
  MOZ_ASSERT(!mTaken);
517
0
  MOZ_ASSERT(!IsSet());
518
0
519
0
  // If NormalizeOptionalValue returns false, we don't have to proceed.
520
0
  if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
521
0
    return true;
522
0
  }
523
0
524
0
  if (!SerializeInputStreamChild(aStream, aManager, mValue, mOptionalValue,
525
0
                                 mDelayedStart)) {
526
0
    MOZ_CRASH("IPCStream creation failed!");
527
0
  }
528
0
529
0
  if (mValue) {
530
0
    AssertValidValueToTake(*mValue);
531
0
  } else {
532
0
    AssertValidValueToTake(*mOptionalValue);
533
0
  }
534
0
535
0
  return true;
536
0
}
537
538
bool
539
AutoIPCStream::Serialize(nsIInputStream* aStream,
540
                         dom::nsIContentParent* aManager)
541
0
{
542
0
  MOZ_ASSERT(aStream || !mValue);
543
0
  MOZ_ASSERT(aManager);
544
0
  MOZ_ASSERT(mValue || mOptionalValue);
545
0
  MOZ_ASSERT(!mTaken);
546
0
  MOZ_ASSERT(!IsSet());
547
0
548
0
  // If NormalizeOptionalValue returns false, we don't have to proceed.
549
0
  if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
550
0
    return true;
551
0
  }
552
0
553
0
  if (!SerializeInputStreamParent(aStream, aManager, mValue, mOptionalValue,
554
0
                                  mDelayedStart)) {
555
0
    return false;
556
0
  }
557
0
558
0
  if (mValue) {
559
0
    AssertValidValueToTake(*mValue);
560
0
  } else {
561
0
    AssertValidValueToTake(*mOptionalValue);
562
0
  }
563
0
564
0
  return true;
565
0
}
566
567
bool
568
AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundParent* aManager)
569
0
{
570
0
  MOZ_ASSERT(aStream || !mValue);
571
0
  MOZ_ASSERT(aManager);
572
0
  MOZ_ASSERT(mValue || mOptionalValue);
573
0
  MOZ_ASSERT(!mTaken);
574
0
  MOZ_ASSERT(!IsSet());
575
0
576
0
  // If NormalizeOptionalValue returns false, we don't have to proceed.
577
0
  if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
578
0
    return true;
579
0
  }
580
0
581
0
  if (!SerializeInputStreamParent(aStream, aManager, mValue, mOptionalValue,
582
0
                                  mDelayedStart)) {
583
0
    return false;
584
0
  }
585
0
586
0
  if (mValue) {
587
0
    AssertValidValueToTake(*mValue);
588
0
  } else {
589
0
    AssertValidValueToTake(*mOptionalValue);
590
0
  }
591
0
592
0
  return true;
593
0
}
594
595
bool
596
AutoIPCStream::IsSet() const
597
0
{
598
0
  MOZ_ASSERT(mValue || mOptionalValue);
599
0
  if (mValue) {
600
0
    return mValue->type() != IPCStream::T__None;
601
0
  } else {
602
0
    return mOptionalValue->type() != OptionalIPCStream::Tvoid_t &&
603
0
           mOptionalValue->get_IPCStream().type() != IPCStream::T__None;
604
0
  }
605
0
}
606
607
IPCStream&
608
AutoIPCStream::TakeValue()
609
0
{
610
0
  MOZ_ASSERT(mValue || mOptionalValue);
611
0
  MOZ_ASSERT(!mTaken);
612
0
  MOZ_ASSERT(IsSet());
613
0
614
0
  mTaken = true;
615
0
616
0
  if (mValue) {
617
0
    AssertValidValueToTake(*mValue);
618
0
    return *mValue;
619
0
  }
620
0
621
0
  IPCStream& value =
622
0
    mOptionalValue->get_IPCStream();
623
0
624
0
  AssertValidValueToTake(value);
625
0
  return value;
626
0
}
627
628
OptionalIPCStream&
629
AutoIPCStream::TakeOptionalValue()
630
0
{
631
0
  MOZ_ASSERT(!mTaken);
632
0
  MOZ_ASSERT(!mValue);
633
0
  MOZ_ASSERT(mOptionalValue);
634
0
  mTaken = true;
635
0
  AssertValidValueToTake(*mOptionalValue);
636
0
  return *mOptionalValue;
637
0
}
638
639
void
640
IPDLParamTraits<nsIInputStream>::Write(IPC::Message* aMsg,
641
                                       IProtocol* aActor,
642
                                       nsIInputStream* aParam)
643
0
{
644
0
  mozilla::ipc::AutoIPCStream autoStream;
645
0
  bool ok = false;
646
0
  bool found = false;
647
0
648
0
  // We can only serialize our nsIInputStream if it's going to be sent over one
649
0
  // of the protocols we support, or a protocol which is managed by one of the
650
0
  // protocols we support.
651
0
  IProtocol* actor = aActor;
652
0
  while (!found && actor) {
653
0
    switch (actor->GetProtocolTypeId()) {
654
0
      case PContentMsgStart:
655
0
        if (actor->GetSide() == mozilla::ipc::ParentSide) {
656
0
          ok = autoStream.Serialize(
657
0
            aParam, static_cast<mozilla::dom::ContentParent*>(actor));
658
0
        } else {
659
0
          MOZ_RELEASE_ASSERT(actor->GetSide() == mozilla::ipc::ChildSide);
660
0
          ok = autoStream.Serialize(
661
0
            aParam, static_cast<mozilla::dom::ContentChild*>(actor));
662
0
        }
663
0
        found = true;
664
0
        break;
665
0
      case PBackgroundMsgStart:
666
0
        if (actor->GetSide() == mozilla::ipc::ParentSide) {
667
0
          ok = autoStream.Serialize(
668
0
            aParam, static_cast<mozilla::ipc::PBackgroundParent*>(actor));
669
0
        } else {
670
0
          MOZ_RELEASE_ASSERT(actor->GetSide() == mozilla::ipc::ChildSide);
671
0
          ok = autoStream.Serialize(
672
0
            aParam, static_cast<mozilla::ipc::PBackgroundChild*>(actor));
673
0
        }
674
0
        found = true;
675
0
        break;
676
0
    }
677
0
678
0
    // Try the actor's manager.
679
0
    actor = actor->Manager();
680
0
  }
681
0
682
0
  if (!found) {
683
0
    aActor->FatalError("Attempt to send nsIInputStream over an unsupported ipdl protocol");
684
0
  }
685
0
  MOZ_RELEASE_ASSERT(ok, "Failed to serialize nsIInputStream");
686
0
687
0
  WriteIPDLParam(aMsg, aActor, autoStream.TakeOptionalValue());
688
0
}
689
690
bool
691
IPDLParamTraits<nsIInputStream>::Read(const IPC::Message* aMsg, PickleIterator* aIter,
692
                                      IProtocol* aActor, RefPtr<nsIInputStream>* aResult)
693
0
{
694
0
  mozilla::ipc::OptionalIPCStream ipcStream;
695
0
  if (!ReadIPDLParam(aMsg, aIter, aActor, &ipcStream)) {
696
0
    return false;
697
0
  }
698
0
699
0
  *aResult = mozilla::ipc::DeserializeIPCStream(ipcStream);
700
0
  return true;
701
0
}
702
703
} // namespace ipc
704
} // namespace mozilla