summaryrefslogtreecommitdiff
path: root/ipc/glue/SendStreamParent.cpp
blob: 3ed2d1b2bb9ab94a01b1437d5622793fe470c63d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/ipc/SendStream.h"

#include "mozilla/Unused.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsIPipe.h"

namespace mozilla {
namespace ipc {

namespace {

class SendStreamParentImpl final : public SendStreamParent
{
public:
  SendStreamParentImpl(nsIAsyncInputStream* aReader,
                        nsIAsyncOutputStream* aWriter);
  ~SendStreamParentImpl();

private:
  // PSendStreamParentImpl methods
  virtual void
  ActorDestroy(ActorDestroyReason aReason) override;

  // SendStreamparent methods
  already_AddRefed<nsIInputStream>
  TakeReader() override;

  virtual bool
  RecvBuffer(const nsCString& aBuffer) override;

  virtual bool
  RecvClose(const nsresult& aRv) override;

  nsCOMPtr<nsIAsyncInputStream> mReader;
  nsCOMPtr<nsIAsyncOutputStream> mWriter;

  NS_DECL_OWNINGTHREAD
};

SendStreamParentImpl::~SendStreamParentImpl()
{
}

already_AddRefed<nsIInputStream>
SendStreamParentImpl::TakeReader()
{
  MOZ_ASSERT(mReader);
  return mReader.forget();
}

void
SendStreamParentImpl::ActorDestroy(ActorDestroyReason aReason)
{
  // If we were gracefully closed we should have gotten RecvClose().  In
  // that case, the writer will already be closed and this will have no
  // effect.  This just aborts the writer in the case where the child process
  // crashes.
  mWriter->CloseWithStatus(NS_ERROR_ABORT);
}

bool
SendStreamParentImpl::RecvBuffer(const nsCString& aBuffer)
{
  uint32_t numWritten = 0;

  // This should only fail if we hit an OOM condition.
  nsresult rv = mWriter->Write(aBuffer.get(), aBuffer.Length(), &numWritten);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    Unused << SendRequestClose(rv);
  }

  return true;
}

bool
SendStreamParentImpl::RecvClose(const nsresult& aRv)
{
  mWriter->CloseWithStatus(aRv);
  Unused << Send__delete__(this);
  return true;
}

SendStreamParentImpl::SendStreamParentImpl(nsIAsyncInputStream* aReader,
                                             nsIAsyncOutputStream* aWriter)
  : mReader(aReader)
  , mWriter(aWriter)
{
  MOZ_ASSERT(mReader);
  MOZ_ASSERT(mWriter);
}

} // anonymous namespace

SendStreamParent::~SendStreamParent()
{
}

PSendStreamParent*
AllocPSendStreamParent()
{
  // use async versions for both reader and writer even though we are
  // opening the writer as an infinite stream.  We want to be able to
  // use CloseWithStatus() to communicate errors through the pipe.
  nsCOMPtr<nsIAsyncInputStream> reader;
  nsCOMPtr<nsIAsyncOutputStream> writer;

  // Use an "infinite" pipe because we cannot apply back-pressure through
  // the async IPC layer at the moment.  Blocking the IPC worker thread
  // is not desirable, either.
  nsresult rv = NS_NewPipe2(getter_AddRefs(reader),
                            getter_AddRefs(writer),
                            true, true,   // non-blocking
                            0,            // segment size
                            UINT32_MAX);  // "infinite" pipe
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return nullptr;
  }

  return new SendStreamParentImpl(reader, writer);
}

void
DeallocPSendStreamParent(PSendStreamParent* aActor)
{
  delete aActor;
}

} // namespace ipc
} // namespace mozilla