diff options
Diffstat (limited to 'dom/network/TCPServerSocket.cpp')
-rw-r--r-- | dom/network/TCPServerSocket.cpp | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/dom/network/TCPServerSocket.cpp b/dom/network/TCPServerSocket.cpp new file mode 100644 index 000000000..5e6f778a3 --- /dev/null +++ b/dom/network/TCPServerSocket.cpp @@ -0,0 +1,192 @@ +/* -*- 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/. */ + +#include "mozilla/dom/TCPServerSocketBinding.h" +#include "mozilla/dom/TCPServerSocketEvent.h" +#include "mozilla/dom/TCPSocketBinding.h" +#include "TCPServerSocketParent.h" +#include "TCPServerSocketChild.h" +#include "mozilla/dom/Event.h" +#include "mozilla/ErrorResult.h" +#include "TCPServerSocket.h" +#include "TCPSocket.h" + +using namespace mozilla::dom; + +NS_IMPL_CYCLE_COLLECTION_CLASS(TCPServerSocket) + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(TCPServerSocket, + DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TCPServerSocket, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerSocket) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerBridgeChild) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerBridgeParent) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TCPServerSocket, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerSocket) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerBridgeChild) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerBridgeParent) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_ADDREF_INHERITED(TCPServerSocket, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(TCPServerSocket, DOMEventTargetHelper) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TCPServerSocket) + NS_INTERFACE_MAP_ENTRY(nsIServerSocketListener) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +TCPServerSocket::TCPServerSocket(nsIGlobalObject* aGlobal, uint16_t aPort, + bool aUseArrayBuffers, uint16_t aBacklog) + : DOMEventTargetHelper(aGlobal) + , mPort(aPort) + , mBacklog(aBacklog) + , mUseArrayBuffers(aUseArrayBuffers) +{ +} + +TCPServerSocket::~TCPServerSocket() +{ +} + +nsresult +TCPServerSocket::Init() +{ + if (mServerSocket || mServerBridgeChild) { + NS_WARNING("Child TCPServerSocket is already listening."); + return NS_ERROR_FAILURE; + } + + if (XRE_GetProcessType() == GeckoProcessType_Content) { + mServerBridgeChild = new TCPServerSocketChild(this, mPort, mBacklog, mUseArrayBuffers); + return NS_OK; + } + + nsresult rv; + mServerSocket = do_CreateInstance("@mozilla.org/network/server-socket;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = mServerSocket->Init(mPort, false, mBacklog); + NS_ENSURE_SUCCESS(rv, rv); + rv = mServerSocket->GetPort(&mPort); + NS_ENSURE_SUCCESS(rv, rv); + rv = mServerSocket->AsyncListen(this); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; +} + +already_AddRefed<TCPServerSocket> +TCPServerSocket::Constructor(const GlobalObject& aGlobal, + uint16_t aPort, + const ServerSocketOptions& aOptions, + uint16_t aBacklog, + mozilla::ErrorResult& aRv) +{ + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); + if (!global) { + aRv = NS_ERROR_FAILURE; + return nullptr; + } + bool useArrayBuffers = aOptions.mBinaryType == TCPSocketBinaryType::Arraybuffer; + RefPtr<TCPServerSocket> socket = new TCPServerSocket(global, aPort, useArrayBuffers, aBacklog); + nsresult rv = socket->Init(); + if (NS_WARN_IF(NS_FAILED(rv))) { + aRv = NS_ERROR_FAILURE; + return nullptr; + } + return socket.forget(); +} + +uint16_t +TCPServerSocket::LocalPort() +{ + return mPort; +} + +void +TCPServerSocket::Close() +{ + if (mServerBridgeChild) { + mServerBridgeChild->Close(); + } + if (mServerSocket) { + mServerSocket->Close(); + } +} + +void +TCPServerSocket::FireEvent(const nsAString& aType, TCPSocket* aSocket) +{ + TCPServerSocketEventInit init; + init.mBubbles = false; + init.mCancelable = false; + init.mSocket = aSocket; + + RefPtr<TCPServerSocketEvent> event = + TCPServerSocketEvent::Constructor(this, aType, init); + event->SetTrusted(true); + bool dummy; + DispatchEvent(event, &dummy); + + if (mServerBridgeParent) { + mServerBridgeParent->OnConnect(event); + } +} + +NS_IMETHODIMP +TCPServerSocket::OnSocketAccepted(nsIServerSocket* aServer, nsISocketTransport* aTransport) +{ + nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal(); + RefPtr<TCPSocket> socket = TCPSocket::CreateAcceptedSocket(global, aTransport, mUseArrayBuffers); + if (mServerBridgeParent) { + socket->SetAppIdAndBrowser(mServerBridgeParent->GetAppId(), + mServerBridgeParent->GetInIsolatedMozBrowser()); + } + FireEvent(NS_LITERAL_STRING("connect"), socket); + return NS_OK; +} + +NS_IMETHODIMP +TCPServerSocket::OnStopListening(nsIServerSocket* aServer, nsresult aStatus) +{ + if (aStatus != NS_BINDING_ABORTED) { + RefPtr<Event> event = new Event(GetOwner()); + event->InitEvent(NS_LITERAL_STRING("error"), false, false); + event->SetTrusted(true); + bool dummy; + DispatchEvent(event, &dummy); + + NS_WARNING("Server socket was closed by unexpected reason."); + return NS_ERROR_FAILURE; + } + mServerSocket = nullptr; + return NS_OK; +} + +nsresult +TCPServerSocket::AcceptChildSocket(TCPSocketChild* aSocketChild) +{ + nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal(); + NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); + RefPtr<TCPSocket> socket = TCPSocket::CreateAcceptedSocket(global, aSocketChild, mUseArrayBuffers); + NS_ENSURE_TRUE(socket, NS_ERROR_FAILURE); + FireEvent(NS_LITERAL_STRING("connect"), socket); + return NS_OK; +} + +void +TCPServerSocket::SetServerBridgeParent(TCPServerSocketParent* aBridgeParent) +{ + mServerBridgeParent = aBridgeParent; +} + +JSObject* +TCPServerSocket::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + return TCPServerSocketBinding::Wrap(aCx, this, aGivenProto); +} |