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