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 file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_dom_TCPSocket_h
8 #define mozilla_dom_TCPSocket_h
9 
10 #include "mozilla/dom/TCPSocketBinding.h"
11 #include "mozilla/dom/TypedArray.h"
12 #include "mozilla/DOMEventTargetHelper.h"
13 #include "nsIProxyInfo.h"
14 #include "nsITransport.h"
15 #include "nsIStreamListener.h"
16 #include "nsIAsyncInputStream.h"
17 #include "nsISupportsImpl.h"
18 #include "nsIObserver.h"
19 #include "nsWeakReference.h"
20 #include "nsITCPSocketCallback.h"
21 #include "nsIProtocolProxyCallback.h"
22 #include "js/RootingAPI.h"
23 
24 class nsISocketTransport;
25 class nsIInputStreamPump;
26 class nsIScriptableInputStream;
27 class nsIBinaryInputStream;
28 class nsIMultiplexInputStream;
29 class nsIAsyncStreamCopier;
30 class nsIInputStream;
31 class nsINetworkInfo;
32 
33 namespace mozilla {
34 class ErrorResult;
35 namespace dom {
36 
37 struct ServerSocketOptions;
38 class TCPServerSocket;
39 class TCPSocketChild;
40 class TCPSocketParent;
41 
42 // This interface is only used for legacy navigator.mozTCPSocket API
43 // compatibility.
44 class LegacyMozTCPSocket : public nsISupports {
45  public:
46   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
47   NS_DECL_CYCLE_COLLECTION_CLASS(LegacyMozTCPSocket)
48 
49   explicit LegacyMozTCPSocket(nsPIDOMWindowInner* aWindow);
50 
51   already_AddRefed<TCPServerSocket> Listen(uint16_t aPort,
52                                            const ServerSocketOptions& aOptions,
53                                            uint16_t aBacklog, ErrorResult& aRv);
54 
55   already_AddRefed<TCPSocket> Open(const nsAString& aHost, uint16_t aPort,
56                                    const SocketOptions& aOptions,
57                                    ErrorResult& aRv);
58 
59   bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
60                   JS::MutableHandle<JSObject*> aReflector);
61 
62  private:
63   virtual ~LegacyMozTCPSocket();
64 
65   nsCOMPtr<nsIGlobalObject> mGlobal;
66 };
67 
68 class TCPSocket final : public DOMEventTargetHelper,
69                         public nsIStreamListener,
70                         public nsITransportEventSink,
71                         public nsIInputStreamCallback,
72                         public nsIObserver,
73                         public nsSupportsWeakReference,
74                         public nsITCPSocketCallback,
75                         public nsIProtocolProxyCallback {
76  public:
77   TCPSocket(nsIGlobalObject* aGlobal, const nsAString& aHost, uint16_t aPort,
78             bool aSsl, bool aUseArrayBuffers);
79 
80   NS_DECL_ISUPPORTS_INHERITED
81   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(TCPSocket,
82                                                          DOMEventTargetHelper)
83   NS_DECL_NSIREQUESTOBSERVER
84   NS_DECL_NSISTREAMLISTENER
85   NS_DECL_NSITRANSPORTEVENTSINK
86   NS_DECL_NSIINPUTSTREAMCALLBACK
87   NS_DECL_NSIOBSERVER
88   NS_DECL_NSITCPSOCKETCALLBACK
89   NS_DECL_NSIPROTOCOLPROXYCALLBACK
90 
91   virtual JSObject* WrapObject(JSContext* aCx,
92                                JS::Handle<JSObject*> aGivenProto) override;
93 
94   static bool ShouldTCPSocketExist(JSContext* aCx, JSObject* aGlobal);
95 
GetTransport()96   nsISocketTransport* GetTransport() const { return mTransport.get(); }
97 
98   void GetHost(nsAString& aHost);
99   uint32_t Port();
100   bool Ssl();
BufferedAmount()101   uint64_t BufferedAmount() const { return mBufferedAmount; }
102   void Suspend();
103   void Resume(ErrorResult& aRv);
104   void Close();
105   void CloseImmediately();
106   bool Send(const nsACString& aData, ErrorResult& aRv);
107   bool Send(const ArrayBuffer& aData, uint32_t aByteOffset,
108             const Optional<uint32_t>& aByteLength, ErrorResult& aRv);
109   TCPReadyState ReadyState();
110   TCPSocketBinaryType BinaryType();
111   void UpgradeToSecure(ErrorResult& aRv);
112 
113   static already_AddRefed<TCPSocket> Constructor(const GlobalObject& aGlobal,
114                                                  const nsAString& aHost,
115                                                  uint16_t aPort,
116                                                  const SocketOptions& aOptions,
117                                                  ErrorResult& aRv);
118 
119   // Create a TCPSocket object from an existing low-level socket connection.
120   // Used by the TCPServerSocket implementation when a new connection is
121   // accepted.
122   static already_AddRefed<TCPSocket> CreateAcceptedSocket(
123       nsIGlobalObject* aGlobal, nsISocketTransport* aTransport,
124       bool aUseArrayBuffers);
125   // Create a TCPSocket object from an existing child-side IPC actor.
126   // Used by the TCPServerSocketChild implementation when a new connection is
127   // accepted.
128   static already_AddRefed<TCPSocket> CreateAcceptedSocket(
129       nsIGlobalObject* aGlobal, TCPSocketChild* aBridge, bool aUseArrayBuffers);
130 
131   // Initialize this socket's associated IPC actor in the parent process.
132   void SetSocketBridgeParent(TCPSocketParent* aBridgeParent);
133 
134   static bool SocketEnabled();
135 
136   IMPL_EVENT_HANDLER(open);
137   IMPL_EVENT_HANDLER(drain);
138   IMPL_EVENT_HANDLER(data);
139   IMPL_EVENT_HANDLER(error);
140   IMPL_EVENT_HANDLER(close);
141 
142   nsresult Init(nsIProxyInfo* aProxyInfo);
143 
144   // Inform this socket that a buffered send() has completed sending.
145   void NotifyCopyComplete(nsresult aStatus);
146 
147   // Initialize this socket from a low-level connection that hasn't connected
148   // yet (called from RecvOpenBind() in TCPSocketParent).
149   nsresult InitWithUnconnectedTransport(nsISocketTransport* aTransport);
150 
151  private:
152   ~TCPSocket();
153 
154   // Initialize this socket with an existing IPC actor.
155   void InitWithSocketChild(TCPSocketChild* aSocketBridge);
156   // Initialize this socket from an existing low-level connection.
157   nsresult InitWithTransport(nsISocketTransport* aTransport);
158   // Initialize the input/output streams for this socket object.
159   nsresult CreateStream();
160   // Initialize the asynchronous read operation from this socket's input stream.
161   nsresult CreateInputStreamPump();
162   // Send the contents of the provided input stream, which is assumed to be the
163   // given length for reporting and buffering purposes.
164   bool Send(nsIInputStream* aStream, uint32_t aByteLength);
165   // Begin an asynchronous copy operation if one is not already in progress.
166   nsresult EnsureCopying();
167   // Re-calculate buffered amount.
168   void CalculateBufferedAmount();
169   // Enable TLS on this socket.
170   void ActivateTLS();
171   // Dispatch an error event if necessary, then dispatch a "close" event.
172   nsresult MaybeReportErrorAndCloseIfOpen(nsresult status);
173 
174   // Helper for FireDataStringEvent/FireDataArrayEvent.
175   nsresult FireDataEvent(JSContext* aCx, const nsAString& aType,
176                          JS::Handle<JS::Value> aData);
177   // Helper for Close/CloseImmediately
178   void CloseHelper(bool waitForUnsentData);
179 
180   nsresult ResolveProxy();
181 
182   TCPReadyState mReadyState;
183   // Whether to use strings or array buffers for the "data" event.
184   bool mUseArrayBuffers;
185   nsString mHost;
186   uint16_t mPort;
187   // Whether this socket is using a secure transport.
188   bool mSsl;
189 
190   // The associated IPC actor in a child process.
191   RefPtr<TCPSocketChild> mSocketBridgeChild;
192   // The associated IPC actor in a parent process.
193   RefPtr<TCPSocketParent> mSocketBridgeParent;
194 
195   // Raw socket streams
196   nsCOMPtr<nsISocketTransport> mTransport;
197   nsCOMPtr<nsIInputStream> mSocketInputStream;
198   nsCOMPtr<nsIOutputStream> mSocketOutputStream;
199 
200   nsCOMPtr<nsICancelable> mProxyRequest;
201 
202   // Input stream machinery
203   nsCOMPtr<nsIInputStreamPump> mInputStreamPump;
204   nsCOMPtr<nsIScriptableInputStream> mInputStreamScriptable;
205   nsCOMPtr<nsIBinaryInputStream> mInputStreamBinary;
206 
207   // Is there an async copy operation in progress?
208   bool mAsyncCopierActive;
209   // True if the buffer is full and a "drain" event is expected by the client.
210   bool mWaitingForDrain;
211 
212   // The id of the window that created this socket.
213   uint64_t mInnerWindowID;
214 
215   // The current number of buffered bytes. Only used in content processes when
216   // IPC is enabled.
217   uint64_t mBufferedAmount;
218 
219   // The number of times this socket has had `Suspend` called without a
220   // corresponding `Resume`.
221   uint32_t mSuspendCount;
222 
223   // The current sequence number (ie. number of send operations) that have been
224   // processed. This is used in the IPC scenario by the child process to filter
225   // out outdated notifications about the amount of buffered data present in the
226   // parent process.
227   uint32_t mTrackingNumber;
228 
229   // True if this socket has been upgraded to secure after the initial
230   // connection, but the actual upgrade is waiting for an in-progress copy
231   // operation to complete.
232   bool mWaitingForStartTLS;
233   // The buffered data awaiting the TLS upgrade to finish.
234   nsTArray<nsCOMPtr<nsIInputStream>> mPendingDataAfterStartTLS;
235 
236   // The data to be sent.
237   nsTArray<nsCOMPtr<nsIInputStream>> mPendingData;
238 
239   bool mObserversActive;
240 };
241 
242 }  // namespace dom
243 }  // namespace mozilla
244 
245 #endif  // mozilla_dom_TCPSocket_h
246