1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/network/src/TCPSocketChild.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,257 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include <algorithm> 1.9 +#include "TCPSocketChild.h" 1.10 +#include "mozilla/unused.h" 1.11 +#include "mozilla/net/NeckoChild.h" 1.12 +#include "mozilla/dom/PBrowserChild.h" 1.13 +#include "mozilla/dom/TabChild.h" 1.14 +#include "nsIDOMTCPSocket.h" 1.15 +#include "nsJSUtils.h" 1.16 +#include "nsContentUtils.h" 1.17 +#include "jsapi.h" 1.18 +#include "jsfriendapi.h" 1.19 +#include "jswrapper.h" 1.20 + 1.21 +using mozilla::net::gNeckoChild; 1.22 + 1.23 +namespace IPC { 1.24 + 1.25 +bool 1.26 +DeserializeArrayBuffer(JS::Handle<JSObject*> aObj, 1.27 + const InfallibleTArray<uint8_t>& aBuffer, 1.28 + JS::MutableHandle<JS::Value> aVal) 1.29 +{ 1.30 + mozilla::AutoSafeJSContext cx; 1.31 + JSAutoCompartment ac(cx, aObj); 1.32 + 1.33 + JS::Rooted<JSObject*> obj(cx, JS_NewArrayBuffer(cx, aBuffer.Length())); 1.34 + if (!obj) 1.35 + return false; 1.36 + uint8_t* data = JS_GetArrayBufferData(obj); 1.37 + if (!data) 1.38 + return false; 1.39 + memcpy(data, aBuffer.Elements(), aBuffer.Length()); 1.40 + aVal.set(OBJECT_TO_JSVAL(obj)); 1.41 + return true; 1.42 +} 1.43 + 1.44 +} // namespace IPC 1.45 + 1.46 +namespace mozilla { 1.47 +namespace dom { 1.48 + 1.49 +NS_IMPL_CYCLE_COLLECTION(TCPSocketChildBase, mSocket) 1.50 +NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketChildBase) 1.51 +NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketChildBase) 1.52 + 1.53 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketChildBase) 1.54 + NS_INTERFACE_MAP_ENTRY(nsITCPSocketChild) 1.55 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.56 +NS_INTERFACE_MAP_END 1.57 + 1.58 +TCPSocketChildBase::TCPSocketChildBase() 1.59 +: mIPCOpen(false) 1.60 +{ 1.61 +} 1.62 + 1.63 +TCPSocketChildBase::~TCPSocketChildBase() 1.64 +{ 1.65 +} 1.66 + 1.67 +NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketChild::Release(void) 1.68 +{ 1.69 + nsrefcnt refcnt = TCPSocketChildBase::Release(); 1.70 + if (refcnt == 1 && mIPCOpen) { 1.71 + PTCPSocketChild::SendRequestDelete(); 1.72 + return 1; 1.73 + } 1.74 + return refcnt; 1.75 +} 1.76 + 1.77 +TCPSocketChild::TCPSocketChild() 1.78 +: mWindowObj(nullptr) 1.79 +{ 1.80 +} 1.81 + 1.82 +NS_IMETHODIMP 1.83 +TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket, 1.84 + const nsAString& aHost, uint16_t aPort, 1.85 + bool aUseSSL, const nsAString& aBinaryType, 1.86 + nsIDOMWindow* aWindow, JS::Handle<JS::Value> aWindowObj, 1.87 + JSContext* aCx) 1.88 +{ 1.89 + mSocket = aSocket; 1.90 + 1.91 + MOZ_ASSERT(aWindowObj.isObject()); 1.92 + mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject()); 1.93 + if (!mWindowObj) { 1.94 + return NS_ERROR_FAILURE; 1.95 + } 1.96 + AddIPDLReference(); 1.97 + gNeckoChild->SendPTCPSocketConstructor(this); 1.98 + PTCPSocketChild::SendOpen(nsString(aHost), aPort, 1.99 + aUseSSL, nsString(aBinaryType)); 1.100 + return NS_OK; 1.101 +} 1.102 + 1.103 +void 1.104 +TCPSocketChildBase::ReleaseIPDLReference() 1.105 +{ 1.106 + MOZ_ASSERT(mIPCOpen); 1.107 + mIPCOpen = false; 1.108 + this->Release(); 1.109 +} 1.110 + 1.111 +void 1.112 +TCPSocketChildBase::AddIPDLReference() 1.113 +{ 1.114 + MOZ_ASSERT(!mIPCOpen); 1.115 + mIPCOpen = true; 1.116 + this->AddRef(); 1.117 +} 1.118 + 1.119 +TCPSocketChild::~TCPSocketChild() 1.120 +{ 1.121 +} 1.122 + 1.123 +bool 1.124 +TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered, 1.125 + const uint32_t& aTrackingNumber) 1.126 +{ 1.127 + if (NS_FAILED(mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber))) { 1.128 + NS_ERROR("Shouldn't fail!"); 1.129 + } 1.130 + return true; 1.131 +} 1.132 + 1.133 +bool 1.134 +TCPSocketChild::RecvCallback(const nsString& aType, 1.135 + const CallbackData& aData, 1.136 + const nsString& aReadyState) 1.137 +{ 1.138 + if (NS_FAILED(mSocket->UpdateReadyState(aReadyState))) 1.139 + NS_ERROR("Shouldn't fail!"); 1.140 + 1.141 + nsresult rv = NS_ERROR_FAILURE; 1.142 + if (aData.type() == CallbackData::Tvoid_t) { 1.143 + rv = mSocket->CallListenerVoid(aType); 1.144 + 1.145 + } else if (aData.type() == CallbackData::TTCPError) { 1.146 + const TCPError& err(aData.get_TCPError()); 1.147 + rv = mSocket->CallListenerError(aType, err.name()); 1.148 + 1.149 + } else if (aData.type() == CallbackData::TSendableData) { 1.150 + const SendableData& data = aData.get_SendableData(); 1.151 + 1.152 + if (data.type() == SendableData::TArrayOfuint8_t) { 1.153 + JSContext* cx = nsContentUtils::GetSafeJSContext(); 1.154 + JSAutoRequest ar(cx); 1.155 + JS::Rooted<JS::Value> val(cx); 1.156 + JS::Rooted<JSObject*> window(cx, mWindowObj); 1.157 + bool ok = IPC::DeserializeArrayBuffer(window, data.get_ArrayOfuint8_t(), &val); 1.158 + NS_ENSURE_TRUE(ok, true); 1.159 + rv = mSocket->CallListenerArrayBuffer(aType, val); 1.160 + 1.161 + } else if (data.type() == SendableData::TnsString) { 1.162 + rv = mSocket->CallListenerData(aType, data.get_nsString()); 1.163 + 1.164 + } else { 1.165 + MOZ_CRASH("Invalid callback data type!"); 1.166 + } 1.167 + 1.168 + } else { 1.169 + MOZ_CRASH("Invalid callback type!"); 1.170 + } 1.171 + NS_ENSURE_SUCCESS(rv, true); 1.172 + return true; 1.173 +} 1.174 + 1.175 +NS_IMETHODIMP 1.176 +TCPSocketChild::SendStartTLS() 1.177 +{ 1.178 + PTCPSocketChild::SendStartTLS(); 1.179 + return NS_OK; 1.180 +} 1.181 + 1.182 +NS_IMETHODIMP 1.183 +TCPSocketChild::SendSuspend() 1.184 +{ 1.185 + PTCPSocketChild::SendSuspend(); 1.186 + return NS_OK; 1.187 +} 1.188 + 1.189 +NS_IMETHODIMP 1.190 +TCPSocketChild::SendResume() 1.191 +{ 1.192 + PTCPSocketChild::SendResume(); 1.193 + return NS_OK; 1.194 +} 1.195 + 1.196 +NS_IMETHODIMP 1.197 +TCPSocketChild::SendClose() 1.198 +{ 1.199 + PTCPSocketChild::SendClose(); 1.200 + return NS_OK; 1.201 +} 1.202 + 1.203 +NS_IMETHODIMP 1.204 +TCPSocketChild::SendSend(JS::Handle<JS::Value> aData, 1.205 + uint32_t aByteOffset, 1.206 + uint32_t aByteLength, 1.207 + uint32_t aTrackingNumber, 1.208 + JSContext* aCx) 1.209 +{ 1.210 + if (aData.isString()) { 1.211 + JSString* jsstr = aData.toString(); 1.212 + nsDependentJSString str; 1.213 + bool ok = str.init(aCx, jsstr); 1.214 + NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); 1.215 + SendData(str, aTrackingNumber); 1.216 + } else { 1.217 + NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE); 1.218 + JS::Rooted<JSObject*> obj(aCx, &aData.toObject()); 1.219 + NS_ENSURE_TRUE(JS_IsArrayBufferObject(obj), NS_ERROR_FAILURE); 1.220 + uint32_t buflen = JS_GetArrayBufferByteLength(obj); 1.221 + aByteOffset = std::min(buflen, aByteOffset); 1.222 + uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength); 1.223 + uint8_t* data = JS_GetArrayBufferData(obj); 1.224 + if (!data) { 1.225 + return NS_ERROR_OUT_OF_MEMORY; 1.226 + } 1.227 + FallibleTArray<uint8_t> fallibleArr; 1.228 + if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) { 1.229 + return NS_ERROR_OUT_OF_MEMORY; 1.230 + } 1.231 + InfallibleTArray<uint8_t> arr; 1.232 + arr.SwapElements(fallibleArr); 1.233 + SendData(arr, aTrackingNumber); 1.234 + } 1.235 + return NS_OK; 1.236 +} 1.237 + 1.238 +NS_IMETHODIMP 1.239 +TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket, 1.240 + JS::Handle<JS::Value> aWindowObj, 1.241 + JSContext* aCx) 1.242 +{ 1.243 + mSocket = aSocket; 1.244 + MOZ_ASSERT(aWindowObj.isObject()); 1.245 + mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject()); 1.246 + if (!mWindowObj) { 1.247 + return NS_ERROR_FAILURE; 1.248 + } 1.249 + return NS_OK; 1.250 +} 1.251 + 1.252 +bool 1.253 +TCPSocketChild::RecvRequestDelete() 1.254 +{ 1.255 + mozilla::unused << Send__delete__(this); 1.256 + return true; 1.257 +} 1.258 + 1.259 +} // namespace dom 1.260 +} // namespace mozilla