/* -*- 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 "nsITransport.h" #include "nsIStreamListener.h" #include "nsIAsyncInputStream.h" #include "nsISupportsImpl.h" #include "nsIObserver.h" #include "nsWeakReference.h" #include "nsITCPSocketCallback.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 Listen(uint16_t aPort, const ServerSocketOptions& aOptions, uint16_t aBacklog, ErrorResult& aRv); already_AddRefed Open(const nsAString& aHost, uint16_t aPort, const SocketOptions& aOptions, ErrorResult& aRv); bool WrapObject(JSContext* aCx, JS::Handle aGivenProto, JS::MutableHandle aReflector); private: virtual ~LegacyMozTCPSocket(); nsCOMPtr mGlobal; }; class TCPSocket final : public DOMEventTargetHelper, public nsIStreamListener, public nsITransportEventSink, public nsIInputStreamCallback, public nsIObserver, public nsSupportsWeakReference, public nsITCPSocketCallback { 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 virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; static bool ShouldTCPSocketExist(JSContext* aCx, JSObject* aGlobal); void GetHost(nsAString& aHost); uint32_t Port(); bool Ssl(); 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& aByteLength, ErrorResult& aRv); TCPReadyState ReadyState(); TCPSocketBinaryType BinaryType(); void UpgradeToSecure(ErrorResult& aRv); static already_AddRefed 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 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 CreateAcceptedSocket( nsIGlobalObject* aGlobal, TCPSocketChild* aSocketBridge, 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(); // 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* aBridge); // 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(); // Enable TLS on this socket. 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 aData); // Helper for Close/CloseImmediately void CloseHelper(bool waitForUnsentData); 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 mSocketBridgeChild; // The associated IPC actor in a parent process. RefPtr mSocketBridgeParent; // Raw socket streams nsCOMPtr mTransport; nsCOMPtr mSocketInputStream; nsCOMPtr mSocketOutputStream; // Input stream machinery nsCOMPtr mInputStreamPump; nsCOMPtr mInputStreamScriptable; nsCOMPtr 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> mPendingDataAfterStartTLS; // The data to be sent. nsTArray> mPendingData; bool mObserversActive; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_TCPSocket_h