1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "TCPSocketChild.h"
9 #include "mozilla/HoldDropJSObjects.h"
10 #include "mozilla/Unused.h"
11 #include "mozilla/UniquePtr.h"
12 #include "mozilla/net/NeckoChild.h"
13 #include "mozilla/dom/PBrowserChild.h"
14 #include "mozilla/dom/BrowserChild.h"
15 #include "nsITCPSocketCallback.h"
16 #include "TCPSocket.h"
17 #include "nsContentUtils.h"
18 #include "js/ArrayBuffer.h" // JS::NewArrayBufferWithContents
19 #include "js/RootingAPI.h" // JS::MutableHandle
20 #include "js/Utility.h" // js::ArrayBufferContentsArena, JS::FreePolicy, js_pod_arena_malloc
21 #include "js/Value.h" // JS::Value
23 using mozilla::net::gNeckoChild
;
27 bool DeserializeArrayBuffer(JSContext
* cx
, const nsTArray
<uint8_t>& aBuffer
,
28 JS::MutableHandle
<JS::Value
> aVal
) {
29 mozilla::UniquePtr
<uint8_t[], JS::FreePolicy
> data(
30 js_pod_arena_malloc
<uint8_t>(js::ArrayBufferContentsArena
,
32 if (!data
) return false;
33 memcpy(data
.get(), aBuffer
.Elements(), aBuffer
.Length());
36 JS::NewArrayBufferWithContents(cx
, aBuffer
.Length(), data
.get());
37 if (!obj
) return false;
38 // If JS::NewArrayBufferWithContents returns non-null, the ownership of
39 // the data is transfered to obj, so we release the ownership here.
40 mozilla::Unused
<< data
.release();
48 namespace mozilla::dom
{
50 NS_IMPL_CYCLE_COLLECTION_CLASS(TCPSocketChildBase
)
52 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TCPSocketChildBase
)
53 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocket
)
54 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
56 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TCPSocketChildBase
)
57 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocket
)
58 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
60 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TCPSocketChildBase
)
61 NS_IMPL_CYCLE_COLLECTION_TRACE_END
63 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketChildBase
)
64 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketChildBase
)
66 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketChildBase
)
67 NS_INTERFACE_MAP_ENTRY(nsISupports
)
70 TCPSocketChildBase::TCPSocketChildBase() : mIPCOpen(false) {
71 mozilla::HoldJSObjects(this);
74 TCPSocketChildBase::~TCPSocketChildBase() { mozilla::DropJSObjects(this); }
76 NS_IMETHODIMP_(MozExternalRefCountType
) TCPSocketChild::Release(void) {
77 nsrefcnt refcnt
= TCPSocketChildBase::Release();
78 if (refcnt
== 1 && mIPCOpen
) {
79 PTCPSocketChild::SendRequestDelete();
85 TCPSocketChild::TCPSocketChild(const nsAString
& aHost
, const uint16_t& aPort
,
86 nsISerialEventTarget
* aTarget
)
87 : mHost(aHost
), mPort(aPort
), mIPCEventTarget(aTarget
) {}
89 void TCPSocketChild::SendOpen(nsITCPSocketCallback
* aSocket
, bool aUseSSL
,
90 bool aUseArrayBuffers
) {
94 gNeckoChild
->SendPTCPSocketConstructor(this, mHost
, mPort
);
95 PTCPSocketChild::SendOpen(mHost
, mPort
, aUseSSL
, aUseArrayBuffers
);
98 void TCPSocketChildBase::ReleaseIPDLReference() {
105 void TCPSocketChildBase::AddIPDLReference() {
106 MOZ_ASSERT(!mIPCOpen
);
111 TCPSocketChild::~TCPSocketChild() = default;
113 mozilla::ipc::IPCResult
TCPSocketChild::RecvUpdateBufferedAmount(
114 const uint32_t& aBuffered
, const uint32_t& aTrackingNumber
) {
115 mSocket
->UpdateBufferedAmount(aBuffered
, aTrackingNumber
);
119 mozilla::ipc::IPCResult
TCPSocketChild::RecvCallback(
120 const nsString
& aType
, const CallbackData
& aData
,
121 const uint32_t& aReadyState
) {
122 mSocket
->UpdateReadyState(aReadyState
);
124 if (aData
.type() == CallbackData::Tvoid_t
) {
125 mSocket
->FireEvent(aType
);
127 } else if (aData
.type() == CallbackData::TTCPError
) {
128 const TCPError
& err(aData
.get_TCPError());
129 mSocket
->FireErrorEvent(err
.name(), err
.message(), err
.errorCode());
131 } else if (aData
.type() == CallbackData::TSendableData
) {
132 const SendableData
& data
= aData
.get_SendableData();
134 if (data
.type() == SendableData::TArrayOfuint8_t
) {
135 mSocket
->FireDataArrayEvent(aType
, data
.get_ArrayOfuint8_t());
136 } else if (data
.type() == SendableData::TnsCString
) {
137 mSocket
->FireDataStringEvent(aType
, data
.get_nsCString());
139 MOZ_CRASH("Invalid callback data type!");
142 MOZ_CRASH("Invalid callback type!");
147 void TCPSocketChild::SendSend(const nsACString
& aData
) {
148 SendData(nsCString(aData
));
151 nsresult
TCPSocketChild::SendSend(const ArrayBuffer
& aData
,
152 uint32_t aByteOffset
, uint32_t aByteLength
) {
153 uint32_t buflen
= aData
.Length();
154 uint32_t offset
= std::min(buflen
, aByteOffset
);
155 uint32_t nbytes
= std::min(buflen
- aByteOffset
, aByteLength
);
156 FallibleTArray
<uint8_t> fallibleArr
;
157 if (!fallibleArr
.InsertElementsAt(0, aData
.Data() + offset
, nbytes
,
159 return NS_ERROR_OUT_OF_MEMORY
;
162 SendData(SendableData
{std::move(fallibleArr
)});
166 void TCPSocketChild::SetSocket(TCPSocket
* aSocket
) { mSocket
= aSocket
; }
168 void TCPSocketChild::GetHost(nsAString
& aHost
) { aHost
= mHost
; }
170 void TCPSocketChild::GetPort(uint16_t* aPort
) const { *aPort
= mPort
; }
172 mozilla::ipc::IPCResult
TCPSocketChild::RecvRequestDelete() {
173 mozilla::Unused
<< Send__delete__(this);
177 } // namespace mozilla::dom