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 https://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_ipc_DataPipe_h
8 #define mozilla_ipc_DataPipe_h
9 
10 #include "mozilla/ipc/SharedMemoryBasic.h"
11 #include "mozilla/ipc/NodeController.h"
12 #include "nsIAsyncInputStream.h"
13 #include "nsIAsyncOutputStream.h"
14 #include "nsIIPCSerializableInputStream.h"
15 #include "nsISupports.h"
16 
17 namespace mozilla {
18 namespace ipc {
19 
20 namespace data_pipe_detail {
21 
22 class DataPipeAutoLock;
23 class DataPipeLink;
24 
25 class DataPipeBase {
26  public:
27   DataPipeBase(const DataPipeBase&) = delete;
28   DataPipeBase& operator=(const DataPipeBase&) = delete;
29 
30  protected:
31   explicit DataPipeBase(bool aReceiverSide, nsresult aError);
32   DataPipeBase(bool aReceiverSide, ScopedPort aPort, SharedMemory* aShmem,
33                uint32_t aCapacity, nsresult aPeerStatus, uint32_t aOffset,
34                uint32_t aAvailable);
35 
36   void CloseInternal(DataPipeAutoLock&, nsresult aStatus);
37 
38   void AsyncWaitInternal(already_AddRefed<nsIRunnable> aCallback,
39                          already_AddRefed<nsIEventTarget> aTarget,
40                          bool aClosureOnly);
41 
42   // Like `nsWriteSegmentFun` or `nsReadSegmentFun`.
43   using ProcessSegmentFun =
44       FunctionRef<nsresult(Span<char> aSpan, uint32_t aProcessedThisCall,
45                            uint32_t* aProcessedCount)>;
46   nsresult ProcessSegmentsInternal(uint32_t aCount,
47                                    ProcessSegmentFun aProcessSegment,
48                                    uint32_t* aProcessedCount);
49 
50   nsresult CheckStatus(DataPipeAutoLock&);
51 
52   nsCString Describe(DataPipeAutoLock&);
53 
54   virtual ~DataPipeBase();
55 
56   const std::shared_ptr<Mutex> mMutex;
57   nsresult mStatus = NS_OK;
58   RefPtr<DataPipeLink> mLink;
59 };
60 
61 template <typename T>
62 void DataPipeWrite(IPC::MessageWriter* aWriter, T* aParam);
63 
64 template <typename T>
65 bool DataPipeRead(IPC::MessageReader* aReader, RefPtr<T>* aResult);
66 
67 }  // namespace data_pipe_detail
68 
69 class DataPipeSender;
70 class DataPipeReceiver;
71 
72 #define NS_DATAPIPESENDER_IID                        \
73   {                                                  \
74     0x6698ed77, 0x9fff, 0x425d, {                    \
75       0xb0, 0xa6, 0x1d, 0x30, 0x66, 0xee, 0xb8, 0x16 \
76     }                                                \
77   }
78 
79 // Helper class for streaming data to another process.
80 class DataPipeSender final : public nsIAsyncOutputStream,
81                              public data_pipe_detail::DataPipeBase {
82  public:
83   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DATAPIPESENDER_IID)
84   NS_DECL_THREADSAFE_ISUPPORTS
85   NS_DECL_NSIOUTPUTSTREAM
86   NS_DECL_NSIASYNCOUTPUTSTREAM
87 
88  private:
89   friend nsresult NewDataPipe(uint32_t, DataPipeSender**, DataPipeReceiver**);
90   friend void data_pipe_detail::DataPipeWrite<DataPipeSender>(
91       IPC::MessageWriter* aWriter, DataPipeSender* aParam);
92   friend bool data_pipe_detail::DataPipeRead<DataPipeSender>(
93       IPC::MessageReader* aReader, RefPtr<DataPipeSender>* aResult);
94 
DataPipeSender(nsresult aError)95   explicit DataPipeSender(nsresult aError)
96       : data_pipe_detail::DataPipeBase(/* aReceiverSide */ false, aError) {}
DataPipeSender(ScopedPort aPort,SharedMemory * aShmem,uint32_t aCapacity,nsresult aPeerStatus,uint32_t aOffset,uint32_t aAvailable)97   DataPipeSender(ScopedPort aPort, SharedMemory* aShmem, uint32_t aCapacity,
98                  nsresult aPeerStatus, uint32_t aOffset, uint32_t aAvailable)
99       : data_pipe_detail::DataPipeBase(/* aReceiverSide */ false,
100                                        std::move(aPort), aShmem, aCapacity,
101                                        aPeerStatus, aOffset, aAvailable) {}
102 
103   ~DataPipeSender() = default;
104 };
105 
NS_DEFINE_STATIC_IID_ACCESSOR(DataPipeSender,NS_DATAPIPESENDER_IID)106 NS_DEFINE_STATIC_IID_ACCESSOR(DataPipeSender, NS_DATAPIPESENDER_IID)
107 
108 #define NS_DATAPIPERECEIVER_IID                      \
109   {                                                  \
110     0x0a185f83, 0x499e, 0x450c, {                    \
111       0x95, 0x82, 0x27, 0x67, 0xad, 0x6d, 0x64, 0xb5 \
112     }                                                \
113   }
114 
115 // Helper class for streaming data from another process.
116 class DataPipeReceiver final : public nsIAsyncInputStream,
117                                public nsIIPCSerializableInputStream,
118                                public data_pipe_detail::DataPipeBase {
119  public:
120   NS_DECLARE_STATIC_IID_ACCESSOR(NS_DATAPIPERECEIVER_IID)
121   NS_DECL_THREADSAFE_ISUPPORTS
122   NS_DECL_NSIINPUTSTREAM
123   NS_DECL_NSIASYNCINPUTSTREAM
124   NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
125 
126  private:
127   friend nsresult NewDataPipe(uint32_t, DataPipeSender**, DataPipeReceiver**);
128   friend void data_pipe_detail::DataPipeWrite<DataPipeReceiver>(
129       IPC::MessageWriter* aWriter, DataPipeReceiver* aParam);
130   friend bool data_pipe_detail::DataPipeRead<DataPipeReceiver>(
131       IPC::MessageReader* aReader, RefPtr<DataPipeReceiver>* aResult);
132 
133   explicit DataPipeReceiver(nsresult aError)
134       : data_pipe_detail::DataPipeBase(/* aReceiverSide */ true, aError) {}
135   DataPipeReceiver(ScopedPort aPort, SharedMemory* aShmem, uint32_t aCapacity,
136                    nsresult aPeerStatus, uint32_t aOffset, uint32_t aAvailable)
137       : data_pipe_detail::DataPipeBase(/* aReceiverSide */ true,
138                                        std::move(aPort), aShmem, aCapacity,
139                                        aPeerStatus, aOffset, aAvailable) {}
140 
141   ~DataPipeReceiver() = default;
142 };
143 
144 NS_DEFINE_STATIC_IID_ACCESSOR(DataPipeReceiver, NS_DATAPIPERECEIVER_IID)
145 
146 constexpr uint32_t kDefaultDataPipeCapacity = 64 * 1024;
147 
148 /**
149  * Create a new DataPipe pair. The sender and receiver ends of the pipe may be
150  * used to transfer data between processes. |aCapacity| is the capacity of the
151  * underlying ring buffer. If `0` is passed, `kDefaultDataPipeCapacity` will be
152  * used.
153  */
154 nsresult NewDataPipe(uint32_t aCapacity, DataPipeSender** aSender,
155                      DataPipeReceiver** aReceiver);
156 
157 }  // namespace ipc
158 }  // namespace mozilla
159 
160 namespace IPC {
161 
162 template <>
163 struct ParamTraits<mozilla::ipc::DataPipeSender*> {
164   static void Write(MessageWriter* aWriter,
165                     mozilla::ipc::DataPipeSender* aParam);
166   static bool Read(MessageReader* aReader,
167                    RefPtr<mozilla::ipc::DataPipeSender>* aResult);
168 };
169 
170 template <>
171 struct ParamTraits<mozilla::ipc::DataPipeReceiver*> {
172   static void Write(MessageWriter* aWriter,
173                     mozilla::ipc::DataPipeReceiver* aParam);
174   static bool Read(MessageReader* aReader,
175                    RefPtr<mozilla::ipc::DataPipeReceiver>* aResult);
176 };
177 
178 }  // namespace IPC
179 
180 #endif  // mozilla_ipc_DataPipe_h
181