summaryrefslogtreecommitdiffstats
path: root/ipc/glue/DataPipe.h
blob: f339b1c72d223baf36e53b0e4fd46f2c36403b22 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* -*- 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 https://mozilla.org/MPL/2.0/. */

#ifndef mozilla_ipc_DataPipe_h
#define mozilla_ipc_DataPipe_h

#include "mozilla/ipc/SharedMemoryBasic.h"
#include "mozilla/ipc/NodeController.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsISupports.h"

namespace mozilla {
namespace ipc {

namespace data_pipe_detail {

class DataPipeAutoLock;
class DataPipeLink;

class DataPipeBase {
 public:
  DataPipeBase(const DataPipeBase&) = delete;
  DataPipeBase& operator=(const DataPipeBase&) = delete;

 protected:
  explicit DataPipeBase(bool aReceiverSide, nsresult aError);
  DataPipeBase(bool aReceiverSide, ScopedPort aPort,
               SharedMemoryBasic::Handle aShmemHandle, SharedMemory* aShmem,
               uint32_t aCapacity, nsresult aPeerStatus, uint32_t aOffset,
               uint32_t aAvailable);

  void CloseInternal(DataPipeAutoLock&, nsresult aStatus) MOZ_REQUIRES(*mMutex);

  void AsyncWaitInternal(already_AddRefed<nsIRunnable> aCallback,
                         already_AddRefed<nsIEventTarget> aTarget,
                         bool aClosureOnly) MOZ_EXCLUDES(*mMutex);

  // Like `nsWriteSegmentFun` or `nsReadSegmentFun`.
  using ProcessSegmentFun =
      FunctionRef<nsresult(Span<char> aSpan, uint32_t aProcessedThisCall,
                           uint32_t* aProcessedCount)>;
  nsresult ProcessSegmentsInternal(uint32_t aCount,
                                   ProcessSegmentFun aProcessSegment,
                                   uint32_t* aProcessedCount)
      MOZ_EXCLUDES(*mMutex);

  nsresult CheckStatus(DataPipeAutoLock&) MOZ_REQUIRES(*mMutex);

  nsCString Describe(DataPipeAutoLock&) MOZ_REQUIRES(*mMutex);

  // Thread safety helper to tell the analysis that `mLink->mMutex` is held when
  // `mMutex` is held.
  void AssertSameMutex(const std::shared_ptr<Mutex>& aMutex)
      MOZ_REQUIRES(*mMutex) MOZ_ASSERT_CAPABILITY(*aMutex) {
    MOZ_ASSERT(mMutex == aMutex);
  }

  virtual ~DataPipeBase();

  const std::shared_ptr<Mutex> mMutex;
  nsresult mStatus MOZ_GUARDED_BY(*mMutex) = NS_OK;
  RefPtr<DataPipeLink> mLink MOZ_GUARDED_BY(*mMutex);
};

template <typename T>
void DataPipeWrite(IPC::MessageWriter* aWriter, T* aParam);

template <typename T>
bool DataPipeRead(IPC::MessageReader* aReader, RefPtr<T>* aResult);

}  // namespace data_pipe_detail

class DataPipeSender;
class DataPipeReceiver;

#define NS_DATAPIPESENDER_IID                        \
  {                                                  \
    0x6698ed77, 0x9fff, 0x425d, {                    \
      0xb0, 0xa6, 0x1d, 0x30, 0x66, 0xee, 0xb8, 0x16 \
    }                                                \
  }

// Helper class for streaming data to another process.
class DataPipeSender final : public nsIAsyncOutputStream,
                             public data_pipe_detail::DataPipeBase {
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DATAPIPESENDER_IID)
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIOUTPUTSTREAM
  NS_DECL_NSIASYNCOUTPUTSTREAM

 private:
  friend nsresult NewDataPipe(uint32_t, DataPipeSender**, DataPipeReceiver**);
  friend void data_pipe_detail::DataPipeWrite<DataPipeSender>(
      IPC::MessageWriter* aWriter, DataPipeSender* aParam);
  friend bool data_pipe_detail::DataPipeRead<DataPipeSender>(
      IPC::MessageReader* aReader, RefPtr<DataPipeSender>* aResult);

  explicit DataPipeSender(nsresult aError)
      : data_pipe_detail::DataPipeBase(/* aReceiverSide */ false, aError) {}
  DataPipeSender(ScopedPort aPort, SharedMemoryBasic::Handle aShmemHandle,
                 SharedMemory* aShmem, uint32_t aCapacity, nsresult aPeerStatus,
                 uint32_t aOffset, uint32_t aAvailable)
      : data_pipe_detail::DataPipeBase(
            /* aReceiverSide */ false, std::move(aPort),
            std::move(aShmemHandle), aShmem, aCapacity, aPeerStatus, aOffset,
            aAvailable) {}

  ~DataPipeSender() = default;
};

NS_DEFINE_STATIC_IID_ACCESSOR(DataPipeSender, NS_DATAPIPESENDER_IID)

#define NS_DATAPIPERECEIVER_IID                      \
  {                                                  \
    0x0a185f83, 0x499e, 0x450c, {                    \
      0x95, 0x82, 0x27, 0x67, 0xad, 0x6d, 0x64, 0xb5 \
    }                                                \
  }

// Helper class for streaming data from another process.
class DataPipeReceiver final : public nsIAsyncInputStream,
                               public nsIIPCSerializableInputStream,
                               public data_pipe_detail::DataPipeBase {
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DATAPIPERECEIVER_IID)
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIINPUTSTREAM
  NS_DECL_NSIASYNCINPUTSTREAM
  NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM

 private:
  friend nsresult NewDataPipe(uint32_t, DataPipeSender**, DataPipeReceiver**);
  friend void data_pipe_detail::DataPipeWrite<DataPipeReceiver>(
      IPC::MessageWriter* aWriter, DataPipeReceiver* aParam);
  friend bool data_pipe_detail::DataPipeRead<DataPipeReceiver>(
      IPC::MessageReader* aReader, RefPtr<DataPipeReceiver>* aResult);

  explicit DataPipeReceiver(nsresult aError)
      : data_pipe_detail::DataPipeBase(/* aReceiverSide */ true, aError) {}
  DataPipeReceiver(ScopedPort aPort, SharedMemoryBasic::Handle aShmemHandle,
                   SharedMemory* aShmem, uint32_t aCapacity,
                   nsresult aPeerStatus, uint32_t aOffset, uint32_t aAvailable)
      : data_pipe_detail::DataPipeBase(
            /* aReceiverSide */ true, std::move(aPort), std::move(aShmemHandle),
            aShmem, aCapacity, aPeerStatus, aOffset, aAvailable) {}

  ~DataPipeReceiver() = default;
};

NS_DEFINE_STATIC_IID_ACCESSOR(DataPipeReceiver, NS_DATAPIPERECEIVER_IID)

constexpr uint32_t kDefaultDataPipeCapacity = 64 * 1024;

/**
 * Create a new DataPipe pair. The sender and receiver ends of the pipe may be
 * used to transfer data between processes. |aCapacity| is the capacity of the
 * underlying ring buffer. If `0` is passed, `kDefaultDataPipeCapacity` will be
 * used.
 */
nsresult NewDataPipe(uint32_t aCapacity, DataPipeSender** aSender,
                     DataPipeReceiver** aReceiver);

}  // namespace ipc
}  // namespace mozilla

namespace IPC {

template <>
struct ParamTraits<mozilla::ipc::DataPipeSender*> {
  static void Write(MessageWriter* aWriter,
                    mozilla::ipc::DataPipeSender* aParam);
  static bool Read(MessageReader* aReader,
                   RefPtr<mozilla::ipc::DataPipeSender>* aResult);
};

template <>
struct ParamTraits<mozilla::ipc::DataPipeReceiver*> {
  static void Write(MessageWriter* aWriter,
                    mozilla::ipc::DataPipeReceiver* aParam);
  static bool Read(MessageReader* aReader,
                   RefPtr<mozilla::ipc::DataPipeReceiver>* aResult);
};

}  // namespace IPC

#endif  // mozilla_ipc_DataPipe_h