Coverage Report

Created: 2018-09-25 14:53

/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