Line data Source code
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/. */
6 :
7 : #include <algorithm>
8 : #include "TCPSocketChild.h"
9 : #include "mozilla/Unused.h"
10 : #include "mozilla/UniquePtr.h"
11 : #include "mozilla/net/NeckoChild.h"
12 : #include "mozilla/dom/PBrowserChild.h"
13 : #include "mozilla/dom/TabChild.h"
14 : #include "nsITCPSocketCallback.h"
15 : #include "TCPSocket.h"
16 : #include "nsContentUtils.h"
17 : #include "jsapi.h"
18 : #include "jsfriendapi.h"
19 :
20 : using mozilla::net::gNeckoChild;
21 :
22 : namespace IPC {
23 :
24 : bool
25 0 : DeserializeArrayBuffer(JSContext* cx,
26 : const InfallibleTArray<uint8_t>& aBuffer,
27 : JS::MutableHandle<JS::Value> aVal)
28 : {
29 0 : mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(js_pod_malloc<uint8_t>(aBuffer.Length()));
30 0 : if (!data)
31 0 : return false;
32 0 : memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());
33 :
34 0 : JSObject* obj = JS_NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
35 0 : if (!obj)
36 0 : return false;
37 : // If JS_NewArrayBufferWithContents returns non-null, the ownership of
38 : // the data is transfered to obj, so we release the ownership here.
39 0 : mozilla::Unused << data.release();
40 :
41 0 : aVal.setObject(*obj);
42 0 : return true;
43 : }
44 :
45 : } // namespace IPC
46 :
47 : namespace mozilla {
48 : namespace dom {
49 :
50 : NS_IMPL_CYCLE_COLLECTION_CLASS(TCPSocketChildBase)
51 :
52 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TCPSocketChildBase)
53 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSocket)
54 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
55 :
56 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TCPSocketChildBase)
57 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mSocket)
58 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
59 :
60 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TCPSocketChildBase)
61 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
62 :
63 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketChildBase)
64 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketChildBase)
65 :
66 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketChildBase)
67 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
68 0 : NS_INTERFACE_MAP_END
69 :
70 0 : TCPSocketChildBase::TCPSocketChildBase()
71 0 : : mIPCOpen(false)
72 : {
73 0 : mozilla::HoldJSObjects(this);
74 0 : }
75 :
76 0 : TCPSocketChildBase::~TCPSocketChildBase()
77 : {
78 0 : mozilla::DropJSObjects(this);
79 0 : }
80 :
81 0 : NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketChild::Release(void)
82 : {
83 0 : nsrefcnt refcnt = TCPSocketChildBase::Release();
84 0 : if (refcnt == 1 && mIPCOpen) {
85 0 : PTCPSocketChild::SendRequestDelete();
86 0 : return 1;
87 : }
88 0 : return refcnt;
89 : }
90 :
91 0 : TCPSocketChild::TCPSocketChild(const nsAString& aHost,
92 : const uint16_t& aPort,
93 0 : nsIEventTarget* aTarget)
94 : : mHost(aHost)
95 0 : , mPort(aPort)
96 0 : , mIPCEventTarget(aTarget)
97 : {
98 0 : }
99 :
100 : void
101 0 : TCPSocketChild::SendOpen(nsITCPSocketCallback* aSocket, bool aUseSSL, bool aUseArrayBuffers)
102 : {
103 0 : mSocket = aSocket;
104 :
105 0 : if (mIPCEventTarget) {
106 0 : gNeckoChild->SetEventTargetForActor(this, mIPCEventTarget);
107 : }
108 :
109 0 : AddIPDLReference();
110 0 : gNeckoChild->SendPTCPSocketConstructor(this, mHost, mPort);
111 0 : MOZ_ASSERT(mFilterName.IsEmpty()); // Currently nobody should use this
112 0 : PTCPSocketChild::SendOpen(mHost, mPort, aUseSSL, aUseArrayBuffers);
113 0 : }
114 :
115 : void
116 0 : TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketCallback* aSocket,
117 : const nsACString& aRemoteHost, uint16_t aRemotePort,
118 : const nsACString& aLocalHost, uint16_t aLocalPort,
119 : bool aUseSSL, bool aReuseAddrPort)
120 : {
121 0 : mSocket = aSocket;
122 :
123 0 : if (mIPCEventTarget) {
124 0 : gNeckoChild->SetEventTargetForActor(this, mIPCEventTarget);
125 : }
126 :
127 0 : AddIPDLReference();
128 0 : gNeckoChild->SendPTCPSocketConstructor(this,
129 0 : NS_ConvertUTF8toUTF16(aRemoteHost),
130 0 : aRemotePort);
131 0 : PTCPSocketChild::SendOpenBind(nsCString(aRemoteHost), aRemotePort,
132 0 : nsCString(aLocalHost), aLocalPort,
133 : aUseSSL, aReuseAddrPort,
134 0 : true, mFilterName);
135 0 : }
136 :
137 : void
138 0 : TCPSocketChildBase::ReleaseIPDLReference()
139 : {
140 0 : MOZ_ASSERT(mIPCOpen);
141 0 : mIPCOpen = false;
142 0 : mSocket = nullptr;
143 0 : this->Release();
144 0 : }
145 :
146 : void
147 0 : TCPSocketChildBase::AddIPDLReference()
148 : {
149 0 : MOZ_ASSERT(!mIPCOpen);
150 0 : mIPCOpen = true;
151 0 : this->AddRef();
152 0 : }
153 :
154 0 : TCPSocketChild::~TCPSocketChild()
155 : {
156 0 : }
157 :
158 : mozilla::ipc::IPCResult
159 0 : TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered,
160 : const uint32_t& aTrackingNumber)
161 : {
162 0 : mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber);
163 0 : return IPC_OK();
164 : }
165 :
166 : mozilla::ipc::IPCResult
167 0 : TCPSocketChild::RecvCallback(const nsString& aType,
168 : const CallbackData& aData,
169 : const uint32_t& aReadyState)
170 : {
171 0 : mSocket->UpdateReadyState(aReadyState);
172 :
173 0 : if (aData.type() == CallbackData::Tvoid_t) {
174 0 : mSocket->FireEvent(aType);
175 :
176 0 : } else if (aData.type() == CallbackData::TTCPError) {
177 0 : const TCPError& err(aData.get_TCPError());
178 0 : mSocket->FireErrorEvent(err.name(), err.message());
179 :
180 0 : } else if (aData.type() == CallbackData::TSendableData) {
181 0 : const SendableData& data = aData.get_SendableData();
182 :
183 0 : if (data.type() == SendableData::TArrayOfuint8_t) {
184 0 : mSocket->FireDataArrayEvent(aType, data.get_ArrayOfuint8_t());
185 0 : } else if (data.type() == SendableData::TnsCString) {
186 0 : mSocket->FireDataStringEvent(aType, data.get_nsCString());
187 : } else {
188 0 : MOZ_CRASH("Invalid callback data type!");
189 : }
190 : } else {
191 0 : MOZ_CRASH("Invalid callback type!");
192 : }
193 0 : return IPC_OK();
194 : }
195 :
196 : void
197 0 : TCPSocketChild::SendSend(const nsACString& aData, uint32_t aTrackingNumber)
198 : {
199 0 : SendData(nsCString(aData), aTrackingNumber);
200 0 : }
201 :
202 : nsresult
203 0 : TCPSocketChild::SendSend(const ArrayBuffer& aData,
204 : uint32_t aByteOffset,
205 : uint32_t aByteLength,
206 : uint32_t aTrackingNumber)
207 : {
208 0 : uint32_t buflen = aData.Length();
209 0 : uint32_t offset = std::min(buflen, aByteOffset);
210 0 : uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
211 0 : FallibleTArray<uint8_t> fallibleArr;
212 0 : if (!fallibleArr.InsertElementsAt(0, aData.Data() + offset, nbytes, fallible)) {
213 0 : return NS_ERROR_OUT_OF_MEMORY;
214 : }
215 :
216 0 : InfallibleTArray<uint8_t> arr;
217 0 : arr.SwapElements(fallibleArr);
218 0 : SendData(arr, aTrackingNumber);
219 0 : return NS_OK;
220 : }
221 :
222 : NS_IMETHODIMP
223 0 : TCPSocketChild::SendSendArray(nsTArray<uint8_t>& aArray, uint32_t aTrackingNumber)
224 : {
225 0 : SendData(aArray, aTrackingNumber);
226 0 : return NS_OK;
227 : }
228 :
229 : void
230 0 : TCPSocketChild::SetSocket(TCPSocket* aSocket)
231 : {
232 0 : mSocket = aSocket;
233 0 : }
234 :
235 : void
236 0 : TCPSocketChild::GetHost(nsAString& aHost)
237 : {
238 0 : aHost = mHost;
239 0 : }
240 :
241 : void
242 0 : TCPSocketChild::GetPort(uint16_t* aPort)
243 : {
244 0 : *aPort = mPort;
245 0 : }
246 :
247 : nsresult
248 0 : TCPSocketChild::SetFilterName(const nsACString& aFilterName)
249 : {
250 0 : if (!mFilterName.IsEmpty()) {
251 : // filter name can only be set once.
252 0 : return NS_ERROR_FAILURE;
253 : }
254 0 : mFilterName = aFilterName;
255 0 : return NS_OK;
256 : }
257 :
258 : mozilla::ipc::IPCResult
259 0 : TCPSocketChild::RecvRequestDelete()
260 : {
261 0 : mozilla::Unused << Send__delete__(this);
262 0 : return IPC_OK();
263 : }
264 :
265 : } // namespace dom
266 : } // namespace mozilla
|