summaryrefslogtreecommitdiffstats
path: root/dom/network/TCPSocket.h
blob: a6d807ef54d582844b03fe97cafc0ec03788904e (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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/* -*- 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/. */

#ifndef mozilla_dom_TCPSocket_h
#define mozilla_dom_TCPSocket_h

#include "mozilla/dom/TCPSocketBinding.h"
#include "mozilla/dom/TypedArray.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "nsIProxyInfo.h"
#include "nsITransport.h"
#include "nsIStreamListener.h"
#include "nsIAsyncInputStream.h"
#include "nsISupportsImpl.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsITCPSocketCallback.h"
#include "nsIProtocolProxyCallback.h"
#include "js/RootingAPI.h"

class nsISocketTransport;
class nsIInputStreamPump;
class nsIScriptableInputStream;
class nsIBinaryInputStream;
class nsIMultiplexInputStream;
class nsIAsyncStreamCopier;
class nsIInputStream;
class nsINetworkInfo;

namespace mozilla {
class ErrorResult;
namespace dom {

struct ServerSocketOptions;
class TCPServerSocket;
class TCPSocketChild;
class TCPSocketParent;

// This interface is only used for legacy navigator.mozTCPSocket API
// compatibility.
class LegacyMozTCPSocket : public nsISupports {
 public:
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_CLASS(LegacyMozTCPSocket)

  explicit LegacyMozTCPSocket(nsPIDOMWindowInner* aWindow);

  already_AddRefed<TCPServerSocket> Listen(uint16_t aPort,
                                           const ServerSocketOptions& aOptions,
                                           uint16_t aBacklog, ErrorResult& aRv);

  already_AddRefed<TCPSocket> Open(const nsAString& aHost, uint16_t aPort,
                                   const SocketOptions& aOptions,
                                   ErrorResult& aRv);

  bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
                  JS::MutableHandle<JSObject*> aReflector);

 private:
  virtual ~LegacyMozTCPSocket();

  nsCOMPtr<nsIGlobalObject> mGlobal;
};

class TCPSocket final : public DOMEventTargetHelper,
                        public nsIStreamListener,
                        public nsITransportEventSink,
                        public nsIInputStreamCallback,
                        public nsIObserver,
                        public nsSupportsWeakReference,
                        public nsITCPSocketCallback,
                        public nsIProtocolProxyCallback {
 public:
  TCPSocket(nsIGlobalObject* aGlobal, const nsAString& aHost, uint16_t aPort,
            bool aSsl, bool aUseArrayBuffers);

  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(TCPSocket,
                                                         DOMEventTargetHelper)
  NS_DECL_NSIREQUESTOBSERVER
  NS_DECL_NSISTREAMLISTENER
  NS_DECL_NSITRANSPORTEVENTSINK
  NS_DECL_NSIINPUTSTREAMCALLBACK
  NS_DECL_NSIOBSERVER
  NS_DECL_NSITCPSOCKETCALLBACK
  NS_DECL_NSIPROTOCOLPROXYCALLBACK

  virtual JSObject* WrapObject(JSContext* aCx,
                               JS::Handle<JSObject*> aGivenProto) override;

  static bool ShouldTCPSocketExist(JSContext* aCx, JSObject* aGlobal);

  nsISocketTransport* GetTransport() const { return mTransport.get(); }

  void GetHost(nsAString& aHost);
  uint32_t Port() const;
  bool Ssl() const;
  uint64_t BufferedAmount() const { return mBufferedAmount; }
  void Suspend();
  void Resume(ErrorResult& aRv);
  void Close();
  void CloseImmediately();
  bool Send(const nsACString& aData, ErrorResult& aRv);
  bool Send(const ArrayBuffer& aData, uint32_t aByteOffset,
            const Optional<uint32_t>& aByteLength, ErrorResult& aRv);
  TCPReadyState ReadyState();
  TCPSocketBinaryType BinaryType() const;
  void UpgradeToSecure(ErrorResult& aRv);

  static already_AddRefed<TCPSocket> Constructor(const GlobalObject& aGlobal,
                                                 const nsAString& aHost,
                                                 uint16_t aPort,
                                                 const SocketOptions& aOptions,
                                                 ErrorResult& aRv);

  // Create a TCPSocket object from an existing low-level socket connection.
  // Used by the TCPServerSocket implementation when a new connection is
  // accepted.
  static already_AddRefed<TCPSocket> CreateAcceptedSocket(
      nsIGlobalObject* aGlobal, nsISocketTransport* aTransport,
      bool aUseArrayBuffers);
  // Create a TCPSocket object from an existing child-side IPC actor.
  // Used by the TCPServerSocketChild implementation when a new connection is
  // accepted.
  static already_AddRefed<TCPSocket> CreateAcceptedSocket(
      nsIGlobalObject* aGlobal, TCPSocketChild* aBridge, bool aUseArrayBuffers);

  // Initialize this socket's associated IPC actor in the parent process.
  void SetSocketBridgeParent(TCPSocketParent* aBridgeParent);

  static bool SocketEnabled();

  IMPL_EVENT_HANDLER(open);
  IMPL_EVENT_HANDLER(drain);
  IMPL_EVENT_HANDLER(data);
  IMPL_EVENT_HANDLER(error);
  IMPL_EVENT_HANDLER(close);

  nsresult Init(nsIProxyInfo* aProxyInfo);

  // Inform this socket that a buffered send() has completed sending.
  void NotifyCopyComplete(nsresult aStatus);

  // Initialize this socket from a low-level connection that hasn't connected
  // yet (called from RecvOpenBind() in TCPSocketParent).
  nsresult InitWithUnconnectedTransport(nsISocketTransport* aTransport);

 private:
  ~TCPSocket();

  // Initialize this socket with an existing IPC actor.
  void InitWithSocketChild(TCPSocketChild* aSocketBridge);
  // Initialize this socket from an existing low-level connection.
  nsresult InitWithTransport(nsISocketTransport* aTransport);
  // Initialize the input/output streams for this socket object.
  nsresult CreateStream();
  // Initialize the asynchronous read operation from this socket's input stream.
  nsresult CreateInputStreamPump();
  // Send the contents of the provided input stream, which is assumed to be the
  // given length for reporting and buffering purposes.
  bool Send(nsIInputStream* aStream, uint32_t aByteLength);
  // Begin an asynchronous copy operation if one is not already in progress.
  nsresult EnsureCopying();
  // Re-calculate buffered amount.
  void CalculateBufferedAmount();
  // Helper function, should be called by ActivateTLS(), only.
  void ActivateTLSHelper();
  // Enable TLS on this socket, dispatch to STSThread if necessary.
  void ActivateTLS();
  // Dispatch an error event if necessary, then dispatch a "close" event.
  nsresult MaybeReportErrorAndCloseIfOpen(nsresult status);

  // Helper for FireDataStringEvent/FireDataArrayEvent.
  nsresult FireDataEvent(JSContext* aCx, const nsAString& aType,
                         JS::Handle<JS::Value> aData);
  // Helper for Close/CloseImmediately
  void CloseHelper(bool waitForUnsentData);

  nsresult ResolveProxy();

  TCPReadyState mReadyState;
  // Whether to use strings or array buffers for the "data" event.
  bool mUseArrayBuffers;
  nsString mHost;
  uint16_t mPort;
  // Whether this socket is using a secure transport.
  bool mSsl;

  // The associated IPC actor in a child process.
  RefPtr<TCPSocketChild> mSocketBridgeChild;
  // The associated IPC actor in a parent process.
  RefPtr<TCPSocketParent> mSocketBridgeParent;

  // Raw socket streams
  nsCOMPtr<nsISocketTransport> mTransport;
  nsCOMPtr<nsIInputStream> mSocketInputStream;
  nsCOMPtr<nsIOutputStream> mSocketOutputStream;

  nsCOMPtr<nsICancelable> mProxyRequest;

  // Input stream machinery
  nsCOMPtr<nsIInputStreamPump> mInputStreamPump;
  nsCOMPtr<nsIScriptableInputStream> mInputStreamScriptable;
  nsCOMPtr<nsIBinaryInputStream> mInputStreamBinary;

  // Is there an async copy operation in progress?
  bool mAsyncCopierActive;
  // True if the buffer is full and a "drain" event is expected by the client.
  bool mWaitingForDrain;

  // The id of the window that created this socket.
  uint64_t mInnerWindowID;

  // The current number of buffered bytes. Only used in content processes when
  // IPC is enabled.
  uint64_t mBufferedAmount;

  // The number of times this socket has had `Suspend` called without a
  // corresponding `Resume`.
  uint32_t mSuspendCount;

  // The current sequence number (ie. number of send operations) that have been
  // processed. This is used in the IPC scenario by the child process to filter
  // out outdated notifications about the amount of buffered data present in the
  // parent process.
  uint32_t mTrackingNumber;

  // True if this socket has been upgraded to secure after the initial
  // connection, but the actual upgrade is waiting for an in-progress copy
  // operation to complete.
  bool mWaitingForStartTLS;
  // The buffered data awaiting the TLS upgrade to finish.
  nsTArray<nsCOMPtr<nsIInputStream>> mPendingDataAfterStartTLS;

  // The data to be sent.
  nsTArray<nsCOMPtr<nsIInputStream>> mPendingData;

  bool mObserversActive;
};

}  // namespace dom
}  // namespace mozilla

#endif  // mozilla_dom_TCPSocket_h