summaryrefslogtreecommitdiffstats
path: root/dom/network/TCPSocketChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/network/TCPSocketChild.cpp')
-rw-r--r--dom/network/TCPSocketChild.cpp177
1 files changed, 177 insertions, 0 deletions
diff --git a/dom/network/TCPSocketChild.cpp b/dom/network/TCPSocketChild.cpp
new file mode 100644
index 0000000000..b6ccba021d
--- /dev/null
+++ b/dom/network/TCPSocketChild.cpp
@@ -0,0 +1,177 @@
+/* -*- 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/. */
+
+#include <algorithm>
+#include "TCPSocketChild.h"
+#include "mozilla/HoldDropJSObjects.h"
+#include "mozilla/Unused.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/net/NeckoChild.h"
+#include "mozilla/dom/PBrowserChild.h"
+#include "mozilla/dom/BrowserChild.h"
+#include "nsITCPSocketCallback.h"
+#include "TCPSocket.h"
+#include "nsContentUtils.h"
+#include "js/ArrayBuffer.h" // JS::NewArrayBufferWithContents
+#include "js/RootingAPI.h" // JS::MutableHandle
+#include "js/Utility.h" // js::ArrayBufferContentsArena, JS::FreePolicy, js_pod_arena_malloc
+#include "js/Value.h" // JS::Value
+
+using mozilla::net::gNeckoChild;
+
+namespace IPC {
+
+bool DeserializeArrayBuffer(JSContext* cx, const nsTArray<uint8_t>& aBuffer,
+ JS::MutableHandle<JS::Value> aVal) {
+ mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(
+ js_pod_arena_malloc<uint8_t>(js::ArrayBufferContentsArena,
+ aBuffer.Length()));
+ if (!data) return false;
+ memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());
+
+ JSObject* obj =
+ JS::NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
+ if (!obj) return false;
+ // If JS::NewArrayBufferWithContents returns non-null, the ownership of
+ // the data is transfered to obj, so we release the ownership here.
+ mozilla::Unused << data.release();
+
+ aVal.setObject(*obj);
+ return true;
+}
+
+} // namespace IPC
+
+namespace mozilla::dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(TCPSocketChildBase)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TCPSocketChildBase)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocket)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TCPSocketChildBase)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocket)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TCPSocketChildBase)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketChildBase)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketChildBase)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketChildBase)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+TCPSocketChildBase::TCPSocketChildBase() : mIPCOpen(false) {
+ mozilla::HoldJSObjects(this);
+}
+
+TCPSocketChildBase::~TCPSocketChildBase() { mozilla::DropJSObjects(this); }
+
+NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketChild::Release(void) {
+ nsrefcnt refcnt = TCPSocketChildBase::Release();
+ if (refcnt == 1 && mIPCOpen) {
+ PTCPSocketChild::SendRequestDelete();
+ return 1;
+ }
+ return refcnt;
+}
+
+TCPSocketChild::TCPSocketChild(const nsAString& aHost, const uint16_t& aPort,
+ nsISerialEventTarget* aTarget)
+ : mHost(aHost), mPort(aPort), mIPCEventTarget(aTarget) {}
+
+void TCPSocketChild::SendOpen(nsITCPSocketCallback* aSocket, bool aUseSSL,
+ bool aUseArrayBuffers) {
+ mSocket = aSocket;
+
+ AddIPDLReference();
+ gNeckoChild->SendPTCPSocketConstructor(this, mHost, mPort);
+ PTCPSocketChild::SendOpen(mHost, mPort, aUseSSL, aUseArrayBuffers);
+}
+
+void TCPSocketChildBase::ReleaseIPDLReference() {
+ MOZ_ASSERT(mIPCOpen);
+ mIPCOpen = false;
+ mSocket = nullptr;
+ this->Release();
+}
+
+void TCPSocketChildBase::AddIPDLReference() {
+ MOZ_ASSERT(!mIPCOpen);
+ mIPCOpen = true;
+ this->AddRef();
+}
+
+TCPSocketChild::~TCPSocketChild() = default;
+
+mozilla::ipc::IPCResult TCPSocketChild::RecvUpdateBufferedAmount(
+ const uint32_t& aBuffered, const uint32_t& aTrackingNumber) {
+ mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TCPSocketChild::RecvCallback(
+ const nsString& aType, const CallbackData& aData,
+ const uint32_t& aReadyState) {
+ mSocket->UpdateReadyState(aReadyState);
+
+ if (aData.type() == CallbackData::Tvoid_t) {
+ mSocket->FireEvent(aType);
+
+ } else if (aData.type() == CallbackData::TTCPError) {
+ const TCPError& err(aData.get_TCPError());
+ mSocket->FireErrorEvent(err.name(), err.message(), err.errorCode());
+
+ } else if (aData.type() == CallbackData::TSendableData) {
+ const SendableData& data = aData.get_SendableData();
+
+ if (data.type() == SendableData::TArrayOfuint8_t) {
+ mSocket->FireDataArrayEvent(aType, data.get_ArrayOfuint8_t());
+ } else if (data.type() == SendableData::TnsCString) {
+ mSocket->FireDataStringEvent(aType, data.get_nsCString());
+ } else {
+ MOZ_CRASH("Invalid callback data type!");
+ }
+ } else {
+ MOZ_CRASH("Invalid callback type!");
+ }
+ return IPC_OK();
+}
+
+void TCPSocketChild::SendSend(const nsACString& aData) {
+ SendData(nsCString(aData));
+}
+
+nsresult TCPSocketChild::SendSend(const ArrayBuffer& aData,
+ uint32_t aByteOffset, uint32_t aByteLength) {
+ uint32_t buflen = aData.Length();
+ uint32_t offset = std::min(buflen, aByteOffset);
+ uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
+ FallibleTArray<uint8_t> fallibleArr;
+ if (!fallibleArr.InsertElementsAt(0, aData.Data() + offset, nbytes,
+ fallible)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ SendData(SendableData{std::move(fallibleArr)});
+ return NS_OK;
+}
+
+void TCPSocketChild::SetSocket(TCPSocket* aSocket) { mSocket = aSocket; }
+
+void TCPSocketChild::GetHost(nsAString& aHost) { aHost = mHost; }
+
+void TCPSocketChild::GetPort(uint16_t* aPort) const { *aPort = mPort; }
+
+mozilla::ipc::IPCResult TCPSocketChild::RecvRequestDelete() {
+ mozilla::Unused << Send__delete__(this);
+ return IPC_OK();
+}
+
+} // namespace mozilla::dom