TCPSocketParent.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "TCPSocketParent.h"
  6. #include "TCPSocket.h"
  7. #include "jsapi.h"
  8. #include "jsfriendapi.h"
  9. #include "nsJSUtils.h"
  10. #include "mozilla/Unused.h"
  11. #include "mozilla/AppProcessChecker.h"
  12. #include "mozilla/net/NeckoCommon.h"
  13. #include "mozilla/net/PNeckoParent.h"
  14. #include "mozilla/dom/ContentParent.h"
  15. #include "mozilla/dom/ScriptSettings.h"
  16. #include "mozilla/dom/TabParent.h"
  17. #include "mozilla/HoldDropJSObjects.h"
  18. #include "nsISocketTransportService.h"
  19. #include "nsISocketTransport.h"
  20. #include "nsIScriptSecurityManager.h"
  21. #include "nsNetUtil.h"
  22. namespace IPC {
  23. //Defined in TCPSocketChild.cpp
  24. extern bool
  25. DeserializeArrayBuffer(JSContext* aCx,
  26. const InfallibleTArray<uint8_t>& aBuffer,
  27. JS::MutableHandle<JS::Value> aVal);
  28. } // namespace IPC
  29. namespace mozilla {
  30. namespace net {
  31. //
  32. // set MOZ_LOG=TCPSocket:5
  33. //
  34. extern LazyLogModule gTCPSocketLog;
  35. #define TCPSOCKET_LOG(args) MOZ_LOG(gTCPSocketLog, LogLevel::Debug, args)
  36. #define TCPSOCKET_LOG_ENABLED() MOZ_LOG_TEST(gTCPSocketLog, LogLevel::Debug)
  37. } // namespace net
  38. namespace dom {
  39. static void
  40. FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo)
  41. {
  42. mozilla::Unused <<
  43. aActor->SendCallback(NS_LITERAL_STRING("onerror"),
  44. TCPError(NS_LITERAL_STRING("InvalidStateError"), NS_LITERAL_STRING("Internal error")),
  45. static_cast<uint32_t>(TCPReadyState::Connecting));
  46. }
  47. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketParentBase)
  48. NS_INTERFACE_MAP_ENTRY(nsISupports)
  49. NS_INTERFACE_MAP_END
  50. NS_IMPL_CYCLE_COLLECTION(TCPSocketParentBase, mSocket)
  51. NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParentBase)
  52. NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParentBase)
  53. TCPSocketParentBase::TCPSocketParentBase()
  54. : mIPCOpen(false)
  55. {
  56. }
  57. TCPSocketParentBase::~TCPSocketParentBase()
  58. {
  59. }
  60. uint32_t
  61. TCPSocketParent::GetAppId()
  62. {
  63. const PContentParent *content = Manager()->Manager();
  64. if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) {
  65. TabParent *tab = TabParent::GetFrom(browser);
  66. return tab->OwnAppId();
  67. } else {
  68. return nsIScriptSecurityManager::UNKNOWN_APP_ID;
  69. }
  70. };
  71. bool
  72. TCPSocketParent::GetInIsolatedMozBrowser()
  73. {
  74. const PContentParent *content = Manager()->Manager();
  75. if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) {
  76. TabParent *tab = TabParent::GetFrom(browser);
  77. return tab->IsIsolatedMozBrowserElement();
  78. } else {
  79. return false;
  80. }
  81. }
  82. void
  83. TCPSocketParentBase::ReleaseIPDLReference()
  84. {
  85. MOZ_ASSERT(mIPCOpen);
  86. mIPCOpen = false;
  87. this->Release();
  88. }
  89. void
  90. TCPSocketParentBase::AddIPDLReference()
  91. {
  92. MOZ_ASSERT(!mIPCOpen);
  93. mIPCOpen = true;
  94. this->AddRef();
  95. }
  96. NS_IMETHODIMP_(MozExternalRefCountType) TCPSocketParent::Release(void)
  97. {
  98. nsrefcnt refcnt = TCPSocketParentBase::Release();
  99. if (refcnt == 1 && mIPCOpen) {
  100. mozilla::Unused << PTCPSocketParent::SendRequestDelete();
  101. return 1;
  102. }
  103. return refcnt;
  104. }
  105. bool
  106. TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bool& aUseSSL,
  107. const bool& aUseArrayBuffers)
  108. {
  109. // We don't have browser actors in xpcshell, and hence can't run automated
  110. // tests without this loophole.
  111. if (net::UsingNeckoIPCSecurity() &&
  112. !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) {
  113. FireInteralError(this, __LINE__);
  114. return true;
  115. }
  116. // Obtain App ID
  117. uint32_t appId = GetAppId();
  118. bool inIsolatedMozBrowser = GetInIsolatedMozBrowser();
  119. mSocket = new TCPSocket(nullptr, aHost, aPort, aUseSSL, aUseArrayBuffers);
  120. mSocket->SetAppIdAndBrowser(appId, inIsolatedMozBrowser);
  121. mSocket->SetSocketBridgeParent(this);
  122. NS_ENSURE_SUCCESS(mSocket->Init(), true);
  123. return true;
  124. }
  125. bool
  126. TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost,
  127. const uint16_t& aRemotePort,
  128. const nsCString& aLocalAddr,
  129. const uint16_t& aLocalPort,
  130. const bool& aUseSSL,
  131. const bool& aUseArrayBuffers,
  132. const nsCString& aFilter)
  133. {
  134. if (net::UsingNeckoIPCSecurity() &&
  135. !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) {
  136. FireInteralError(this, __LINE__);
  137. return true;
  138. }
  139. nsresult rv;
  140. nsCOMPtr<nsISocketTransportService> sts =
  141. do_GetService("@mozilla.org/network/socket-transport-service;1", &rv);
  142. if (NS_FAILED(rv)) {
  143. FireInteralError(this, __LINE__);
  144. return true;
  145. }
  146. nsCOMPtr<nsISocketTransport> socketTransport;
  147. rv = sts->CreateTransport(nullptr, 0,
  148. aRemoteHost, aRemotePort,
  149. nullptr, getter_AddRefs(socketTransport));
  150. if (NS_FAILED(rv)) {
  151. FireInteralError(this, __LINE__);
  152. return true;
  153. }
  154. PRNetAddr prAddr;
  155. if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr)) {
  156. FireInteralError(this, __LINE__);
  157. return true;
  158. }
  159. if (PR_SUCCESS != PR_StringToNetAddr(aLocalAddr.BeginReading(), &prAddr)) {
  160. FireInteralError(this, __LINE__);
  161. return true;
  162. }
  163. mozilla::net::NetAddr addr;
  164. PRNetAddrToNetAddr(&prAddr, &addr);
  165. rv = socketTransport->Bind(&addr);
  166. if (NS_FAILED(rv)) {
  167. FireInteralError(this, __LINE__);
  168. return true;
  169. }
  170. if (!aFilter.IsEmpty()) {
  171. nsAutoCString contractId(NS_NETWORK_TCP_SOCKET_FILTER_HANDLER_PREFIX);
  172. contractId.Append(aFilter);
  173. nsCOMPtr<nsISocketFilterHandler> filterHandler =
  174. do_GetService(contractId.get());
  175. if (!filterHandler) {
  176. NS_ERROR("Content doesn't have a valid filter");
  177. FireInteralError(this, __LINE__);
  178. return true;
  179. }
  180. rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
  181. if (NS_FAILED(rv)) {
  182. NS_ERROR("Cannot create filter that content specified");
  183. FireInteralError(this, __LINE__);
  184. return true;
  185. }
  186. }
  187. // Obtain App ID
  188. uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
  189. bool inIsolatedMozBrowser = false;
  190. const PContentParent *content = Manager()->Manager();
  191. if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) {
  192. // appId's are for B2G only currently, where managees.Count() == 1
  193. // This is not guaranteed currently in Desktop, so skip this there.
  194. TabParent *tab = TabParent::GetFrom(browser);
  195. appId = tab->OwnAppId();
  196. inIsolatedMozBrowser = tab->IsIsolatedMozBrowserElement();
  197. }
  198. mSocket = new TCPSocket(nullptr, NS_ConvertUTF8toUTF16(aRemoteHost), aRemotePort, aUseSSL, aUseArrayBuffers);
  199. mSocket->SetAppIdAndBrowser(appId, inIsolatedMozBrowser);
  200. mSocket->SetSocketBridgeParent(this);
  201. rv = mSocket->InitWithUnconnectedTransport(socketTransport);
  202. NS_ENSURE_SUCCESS(rv, true);
  203. return true;
  204. }
  205. bool
  206. TCPSocketParent::RecvStartTLS()
  207. {
  208. NS_ENSURE_TRUE(mSocket, true);
  209. ErrorResult rv;
  210. mSocket->UpgradeToSecure(rv);
  211. if (NS_WARN_IF(rv.Failed())) {
  212. rv.SuppressException();
  213. }
  214. return true;
  215. }
  216. bool
  217. TCPSocketParent::RecvSuspend()
  218. {
  219. NS_ENSURE_TRUE(mSocket, true);
  220. mSocket->Suspend();
  221. return true;
  222. }
  223. bool
  224. TCPSocketParent::RecvResume()
  225. {
  226. NS_ENSURE_TRUE(mSocket, true);
  227. ErrorResult rv;
  228. mSocket->Resume(rv);
  229. if (NS_WARN_IF(rv.Failed())) {
  230. rv.SuppressException();
  231. }
  232. return true;
  233. }
  234. bool
  235. TCPSocketParent::RecvData(const SendableData& aData,
  236. const uint32_t& aTrackingNumber)
  237. {
  238. ErrorResult rv;
  239. if (mFilter) {
  240. mozilla::net::NetAddr addr; // dummy value
  241. bool allowed;
  242. MOZ_ASSERT(aData.type() == SendableData::TArrayOfuint8_t,
  243. "Unsupported data type for filtering");
  244. const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
  245. nsresult nsrv = mFilter->FilterPacket(&addr, data.Elements(),
  246. data.Length(),
  247. nsISocketFilter::SF_OUTGOING,
  248. &allowed);
  249. // Reject sending of unallowed data
  250. if (NS_WARN_IF(NS_FAILED(nsrv)) || !allowed) {
  251. TCPSOCKET_LOG(("%s: Dropping outgoing TCP packet", __FUNCTION__));
  252. return false;
  253. }
  254. }
  255. switch (aData.type()) {
  256. case SendableData::TArrayOfuint8_t: {
  257. AutoSafeJSContext autoCx;
  258. JS::Rooted<JS::Value> val(autoCx);
  259. const nsTArray<uint8_t>& buffer = aData.get_ArrayOfuint8_t();
  260. bool ok = IPC::DeserializeArrayBuffer(autoCx, buffer, &val);
  261. NS_ENSURE_TRUE(ok, true);
  262. RootedTypedArray<ArrayBuffer> data(autoCx);
  263. data.Init(&val.toObject());
  264. Optional<uint32_t> byteLength(buffer.Length());
  265. mSocket->SendWithTrackingNumber(autoCx, data, 0, byteLength, aTrackingNumber, rv);
  266. break;
  267. }
  268. case SendableData::TnsCString: {
  269. const nsCString& strData = aData.get_nsCString();
  270. mSocket->SendWithTrackingNumber(strData, aTrackingNumber, rv);
  271. break;
  272. }
  273. default:
  274. MOZ_CRASH("unexpected SendableData type");
  275. }
  276. NS_ENSURE_SUCCESS(rv.StealNSResult(), true);
  277. return true;
  278. }
  279. bool
  280. TCPSocketParent::RecvClose()
  281. {
  282. NS_ENSURE_TRUE(mSocket, true);
  283. mSocket->Close();
  284. return true;
  285. }
  286. void
  287. TCPSocketParent::FireErrorEvent(const nsAString& aName, const nsAString& aType, TCPReadyState aReadyState)
  288. {
  289. SendEvent(NS_LITERAL_STRING("error"), TCPError(nsString(aName), nsString(aType)), aReadyState);
  290. }
  291. void
  292. TCPSocketParent::FireEvent(const nsAString& aType, TCPReadyState aReadyState)
  293. {
  294. return SendEvent(aType, mozilla::void_t(), aReadyState);
  295. }
  296. void
  297. TCPSocketParent::FireArrayBufferDataEvent(nsTArray<uint8_t>& aBuffer, TCPReadyState aReadyState)
  298. {
  299. InfallibleTArray<uint8_t> arr;
  300. arr.SwapElements(aBuffer);
  301. if (mFilter) {
  302. bool allowed;
  303. mozilla::net::NetAddr addr;
  304. nsresult nsrv = mFilter->FilterPacket(&addr, arr.Elements(), arr.Length(),
  305. nsISocketFilter::SF_INCOMING,
  306. &allowed);
  307. // receiving unallowed data, drop it.
  308. if (NS_WARN_IF(NS_FAILED(nsrv)) || !allowed) {
  309. TCPSOCKET_LOG(("%s: Dropping incoming TCP packet", __FUNCTION__));
  310. return;
  311. }
  312. }
  313. SendableData data(arr);
  314. SendEvent(NS_LITERAL_STRING("data"), data, aReadyState);
  315. }
  316. void
  317. TCPSocketParent::FireStringDataEvent(const nsACString& aData, TCPReadyState aReadyState)
  318. {
  319. SendableData data((nsCString(aData)));
  320. MOZ_ASSERT(!mFilter, "Socket filtering doesn't support nsCString");
  321. SendEvent(NS_LITERAL_STRING("data"), data, aReadyState);
  322. }
  323. void
  324. TCPSocketParent::SendEvent(const nsAString& aType, CallbackData aData, TCPReadyState aReadyState)
  325. {
  326. if (mIPCOpen) {
  327. mozilla::Unused << PTCPSocketParent::SendCallback(nsString(aType),
  328. aData,
  329. static_cast<uint32_t>(aReadyState));
  330. }
  331. }
  332. void
  333. TCPSocketParent::SetSocket(TCPSocket *socket)
  334. {
  335. mSocket = socket;
  336. }
  337. nsresult
  338. TCPSocketParent::GetHost(nsAString& aHost)
  339. {
  340. if (!mSocket) {
  341. NS_ERROR("No internal socket instance mSocket!");
  342. return NS_ERROR_FAILURE;
  343. }
  344. mSocket->GetHost(aHost);
  345. return NS_OK;
  346. }
  347. nsresult
  348. TCPSocketParent::GetPort(uint16_t* aPort)
  349. {
  350. if (!mSocket) {
  351. NS_ERROR("No internal socket instance mSocket!");
  352. return NS_ERROR_FAILURE;
  353. }
  354. *aPort = mSocket->Port();
  355. return NS_OK;
  356. }
  357. void
  358. TCPSocketParent::ActorDestroy(ActorDestroyReason why)
  359. {
  360. if (mSocket) {
  361. mSocket->Close();
  362. }
  363. mSocket = nullptr;
  364. }
  365. bool
  366. TCPSocketParent::RecvRequestDelete()
  367. {
  368. mozilla::Unused << Send__delete__(this);
  369. return true;
  370. }
  371. } // namespace dom
  372. } // namespace mozilla