Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include <algorithm>
6 #include "TCPSocketChild.h"
7 #include "mozilla/unused.h"
8 #include "mozilla/net/NeckoChild.h"
9 #include "mozilla/dom/PBrowserChild.h"
10 #include "mozilla/dom/TabChild.h"
11 #include "nsIDOMTCPSocket.h"
12 #include "nsJSUtils.h"
13 #include "nsContentUtils.h"
14 #include "jsapi.h"
15 #include "jsfriendapi.h"
16 #include "jswrapper.h"
18 using mozilla::net::gNeckoChild;
20 namespace IPC {
22 bool
23 DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
24 const InfallibleTArray<uint8_t>& aBuffer,
25 JS::MutableHandle<JS::Value> aVal)
26 {
27 mozilla::AutoSafeJSContext cx;
28 JSAutoCompartment ac(cx, aObj);
30 JS::Rooted<JSObject*> obj(cx, JS_NewArrayBuffer(cx, aBuffer.Length()));
31 if (!obj)
32 return false;
33 uint8_t* data = JS_GetArrayBufferData(obj);
34 if (!data)
35 return false;
36 memcpy(data, aBuffer.Elements(), aBuffer.Length());
37 aVal.set(OBJECT_TO_JSVAL(obj));
38 return true;
39 }
41 } // namespace IPC
43 namespace mozilla {
44 namespace dom {
46 NS_IMPL_CYCLE_COLLECTION(TCPSocketChildBase, mSocket)
47 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketChildBase)
48 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketChildBase)
50 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketChildBase)
51 NS_INTERFACE_MAP_ENTRY(nsITCPSocketChild)
52 NS_INTERFACE_MAP_ENTRY(nsISupports)
53 NS_INTERFACE_MAP_END
55 TCPSocketChildBase::TCPSocketChildBase()
56 : mIPCOpen(false)
57 {
58 }
60 TCPSocketChildBase::~TCPSocketChildBase()
61 {
62 }
64 NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketChild::Release(void)
65 {
66 nsrefcnt refcnt = TCPSocketChildBase::Release();
67 if (refcnt == 1 && mIPCOpen) {
68 PTCPSocketChild::SendRequestDelete();
69 return 1;
70 }
71 return refcnt;
72 }
74 TCPSocketChild::TCPSocketChild()
75 : mWindowObj(nullptr)
76 {
77 }
79 NS_IMETHODIMP
80 TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
81 const nsAString& aHost, uint16_t aPort,
82 bool aUseSSL, const nsAString& aBinaryType,
83 nsIDOMWindow* aWindow, JS::Handle<JS::Value> aWindowObj,
84 JSContext* aCx)
85 {
86 mSocket = aSocket;
88 MOZ_ASSERT(aWindowObj.isObject());
89 mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
90 if (!mWindowObj) {
91 return NS_ERROR_FAILURE;
92 }
93 AddIPDLReference();
94 gNeckoChild->SendPTCPSocketConstructor(this);
95 PTCPSocketChild::SendOpen(nsString(aHost), aPort,
96 aUseSSL, nsString(aBinaryType));
97 return NS_OK;
98 }
100 void
101 TCPSocketChildBase::ReleaseIPDLReference()
102 {
103 MOZ_ASSERT(mIPCOpen);
104 mIPCOpen = false;
105 this->Release();
106 }
108 void
109 TCPSocketChildBase::AddIPDLReference()
110 {
111 MOZ_ASSERT(!mIPCOpen);
112 mIPCOpen = true;
113 this->AddRef();
114 }
116 TCPSocketChild::~TCPSocketChild()
117 {
118 }
120 bool
121 TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered,
122 const uint32_t& aTrackingNumber)
123 {
124 if (NS_FAILED(mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber))) {
125 NS_ERROR("Shouldn't fail!");
126 }
127 return true;
128 }
130 bool
131 TCPSocketChild::RecvCallback(const nsString& aType,
132 const CallbackData& aData,
133 const nsString& aReadyState)
134 {
135 if (NS_FAILED(mSocket->UpdateReadyState(aReadyState)))
136 NS_ERROR("Shouldn't fail!");
138 nsresult rv = NS_ERROR_FAILURE;
139 if (aData.type() == CallbackData::Tvoid_t) {
140 rv = mSocket->CallListenerVoid(aType);
142 } else if (aData.type() == CallbackData::TTCPError) {
143 const TCPError& err(aData.get_TCPError());
144 rv = mSocket->CallListenerError(aType, err.name());
146 } else if (aData.type() == CallbackData::TSendableData) {
147 const SendableData& data = aData.get_SendableData();
149 if (data.type() == SendableData::TArrayOfuint8_t) {
150 JSContext* cx = nsContentUtils::GetSafeJSContext();
151 JSAutoRequest ar(cx);
152 JS::Rooted<JS::Value> val(cx);
153 JS::Rooted<JSObject*> window(cx, mWindowObj);
154 bool ok = IPC::DeserializeArrayBuffer(window, data.get_ArrayOfuint8_t(), &val);
155 NS_ENSURE_TRUE(ok, true);
156 rv = mSocket->CallListenerArrayBuffer(aType, val);
158 } else if (data.type() == SendableData::TnsString) {
159 rv = mSocket->CallListenerData(aType, data.get_nsString());
161 } else {
162 MOZ_CRASH("Invalid callback data type!");
163 }
165 } else {
166 MOZ_CRASH("Invalid callback type!");
167 }
168 NS_ENSURE_SUCCESS(rv, true);
169 return true;
170 }
172 NS_IMETHODIMP
173 TCPSocketChild::SendStartTLS()
174 {
175 PTCPSocketChild::SendStartTLS();
176 return NS_OK;
177 }
179 NS_IMETHODIMP
180 TCPSocketChild::SendSuspend()
181 {
182 PTCPSocketChild::SendSuspend();
183 return NS_OK;
184 }
186 NS_IMETHODIMP
187 TCPSocketChild::SendResume()
188 {
189 PTCPSocketChild::SendResume();
190 return NS_OK;
191 }
193 NS_IMETHODIMP
194 TCPSocketChild::SendClose()
195 {
196 PTCPSocketChild::SendClose();
197 return NS_OK;
198 }
200 NS_IMETHODIMP
201 TCPSocketChild::SendSend(JS::Handle<JS::Value> aData,
202 uint32_t aByteOffset,
203 uint32_t aByteLength,
204 uint32_t aTrackingNumber,
205 JSContext* aCx)
206 {
207 if (aData.isString()) {
208 JSString* jsstr = aData.toString();
209 nsDependentJSString str;
210 bool ok = str.init(aCx, jsstr);
211 NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
212 SendData(str, aTrackingNumber);
213 } else {
214 NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
215 JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
216 NS_ENSURE_TRUE(JS_IsArrayBufferObject(obj), NS_ERROR_FAILURE);
217 uint32_t buflen = JS_GetArrayBufferByteLength(obj);
218 aByteOffset = std::min(buflen, aByteOffset);
219 uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
220 uint8_t* data = JS_GetArrayBufferData(obj);
221 if (!data) {
222 return NS_ERROR_OUT_OF_MEMORY;
223 }
224 FallibleTArray<uint8_t> fallibleArr;
225 if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) {
226 return NS_ERROR_OUT_OF_MEMORY;
227 }
228 InfallibleTArray<uint8_t> arr;
229 arr.SwapElements(fallibleArr);
230 SendData(arr, aTrackingNumber);
231 }
232 return NS_OK;
233 }
235 NS_IMETHODIMP
236 TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket,
237 JS::Handle<JS::Value> aWindowObj,
238 JSContext* aCx)
239 {
240 mSocket = aSocket;
241 MOZ_ASSERT(aWindowObj.isObject());
242 mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
243 if (!mWindowObj) {
244 return NS_ERROR_FAILURE;
245 }
246 return NS_OK;
247 }
249 bool
250 TCPSocketChild::RecvRequestDelete()
251 {
252 mozilla::unused << Send__delete__(this);
253 return true;
254 }
256 } // namespace dom
257 } // namespace mozilla