/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/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 { class DOMError; 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: 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<JSObject*> aGivenProto) override; static bool ShouldTCPSocketExist(JSContext* aCx, JSObject* aGlobal); void GetHost(nsAString& aHost); uint32_t Port(); bool Ssl(); uint64_t BufferedAmount(); void Suspend(); void Resume(ErrorResult& aRv); void Close(); void CloseImmediately(); bool Send(JSContext* aCx, const nsACString& aData, ErrorResult& aRv); bool Send(JSContext* aCx, const ArrayBuffer& aData, uint32_t aByteOffset, const Optional<uint32_t>& aByteLength, ErrorResult& aRv); TCPReadyState ReadyState(); TCPSocketBinaryType BinaryType(); void UpgradeToSecure(ErrorResult& aRv); static already_AddRefed<TCPSocket> Constructor(const GlobalObject& aGlobal, const nsAString& aHost, uint16_t aPort, const SocketOptions& aOptions, ErrorResult& aRv); // Perform a send operation that's asssociated with a sequence number. Used in // IPC scenarios to track the number of bytes buffered at any given time. void SendWithTrackingNumber(const nsACString& aData, const uint32_t& aTrackingNumber, ErrorResult& aRv); void SendWithTrackingNumber(JSContext* aCx, const ArrayBuffer& aData, uint32_t aByteOffset, const Optional<uint32_t>& aByteLength, const uint32_t& aTrackingNumber, 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* aSocketBridge, bool aUseArrayBuffers); // Initialize this socket's associated app and browser information. void SetAppIdAndBrowser(uint32_t aAppId, bool aInBrowser); // 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<JS::Value> 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<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; // Input stream machinery nsCOMPtr<nsIInputStreamPump> mInputStreamPump; nsCOMPtr<nsIScriptableInputStream> mInputStreamScriptable; nsCOMPtr<nsIBinaryInputStream> mInputStreamBinary; // Output stream machinery nsCOMPtr<nsIMultiplexInputStream> mMultiplexStream; nsCOMPtr<nsIAsyncStreamCopier> mMultiplexStreamCopier; // 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 while AsyncCopier is still active. nsTArray<nsCOMPtr<nsIInputStream>> mPendingDataWhileCopierActive; bool mObserversActive; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_TCPSocket_h