TCPServerSocket.cpp (5828B)
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 "TCPServerSocket.h" 8 9 #include "TCPServerSocketChild.h" 10 #include "TCPServerSocketParent.h" 11 #include "TCPSocket.h" 12 #include "mozilla/ErrorResult.h" 13 #include "mozilla/dom/Event.h" 14 #include "mozilla/dom/TCPServerSocketBinding.h" 15 #include "mozilla/dom/TCPServerSocketEvent.h" 16 #include "mozilla/dom/TCPSocketBinding.h" 17 #include "nsComponentManagerUtils.h" 18 #include "nsGlobalWindowInner.h" 19 20 using namespace mozilla::dom; 21 22 NS_IMPL_CYCLE_COLLECTION_CLASS(TCPServerSocket) 23 24 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(TCPServerSocket, 25 DOMEventTargetHelper) 26 NS_IMPL_CYCLE_COLLECTION_TRACE_END 27 28 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TCPServerSocket, 29 DOMEventTargetHelper) 30 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerSocket) 31 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerBridgeChild) 32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServerBridgeParent) 33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 34 35 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TCPServerSocket, 36 DOMEventTargetHelper) 37 NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerSocket) 38 NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerBridgeChild) 39 NS_IMPL_CYCLE_COLLECTION_UNLINK(mServerBridgeParent) 40 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 41 42 NS_IMPL_ADDREF_INHERITED(TCPServerSocket, DOMEventTargetHelper) 43 NS_IMPL_RELEASE_INHERITED(TCPServerSocket, DOMEventTargetHelper) 44 45 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPServerSocket) 46 NS_INTERFACE_MAP_ENTRY(nsIServerSocketListener) 47 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 48 49 TCPServerSocket::TCPServerSocket(nsIGlobalObject* aGlobal, uint16_t aPort, 50 bool aUseArrayBuffers, uint16_t aBacklog) 51 : DOMEventTargetHelper(aGlobal), 52 mPort(aPort), 53 mBacklog(aBacklog), 54 mUseArrayBuffers(aUseArrayBuffers) {} 55 56 TCPServerSocket::~TCPServerSocket() = default; 57 58 nsresult TCPServerSocket::Init() { 59 if (mServerSocket || mServerBridgeChild) { 60 NS_WARNING("Child TCPServerSocket is already listening."); 61 return NS_ERROR_FAILURE; 62 } 63 64 if (XRE_GetProcessType() == GeckoProcessType_Content) { 65 mServerBridgeChild = 66 new TCPServerSocketChild(this, mPort, mBacklog, mUseArrayBuffers); 67 return NS_OK; 68 } 69 70 nsresult rv; 71 mServerSocket = 72 do_CreateInstance("@mozilla.org/network/server-socket;1", &rv); 73 NS_ENSURE_SUCCESS(rv, rv); 74 rv = mServerSocket->Init(mPort, false, mBacklog); 75 NS_ENSURE_SUCCESS(rv, rv); 76 rv = mServerSocket->GetPort(&mPort); 77 NS_ENSURE_SUCCESS(rv, rv); 78 rv = mServerSocket->AsyncListen(this); 79 NS_ENSURE_SUCCESS(rv, rv); 80 return NS_OK; 81 } 82 83 already_AddRefed<TCPServerSocket> TCPServerSocket::Constructor( 84 const GlobalObject& aGlobal, uint16_t aPort, 85 const ServerSocketOptions& aOptions, uint16_t aBacklog, 86 mozilla::ErrorResult& aRv) { 87 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); 88 if (!global) { 89 aRv = NS_ERROR_FAILURE; 90 return nullptr; 91 } 92 bool useArrayBuffers = 93 aOptions.mBinaryType == TCPSocketBinaryType::Arraybuffer; 94 RefPtr<TCPServerSocket> socket = 95 new TCPServerSocket(global, aPort, useArrayBuffers, aBacklog); 96 nsresult rv = socket->Init(); 97 if (NS_WARN_IF(NS_FAILED(rv))) { 98 aRv = NS_ERROR_FAILURE; 99 return nullptr; 100 } 101 return socket.forget(); 102 } 103 104 uint16_t TCPServerSocket::LocalPort() const { return mPort; } 105 106 void TCPServerSocket::Close() { 107 if (mServerBridgeChild) { 108 mServerBridgeChild->Close(); 109 } 110 if (mServerSocket) { 111 mServerSocket->Close(); 112 } 113 } 114 115 void TCPServerSocket::FireEvent(const nsAString& aType, TCPSocket* aSocket) { 116 TCPServerSocketEventInit init; 117 init.mBubbles = false; 118 init.mCancelable = false; 119 init.mSocket = aSocket; 120 121 RefPtr<TCPServerSocketEvent> event = 122 TCPServerSocketEvent::Constructor(this, aType, init); 123 event->SetTrusted(true); 124 DispatchEvent(*event); 125 126 if (mServerBridgeParent) { 127 mServerBridgeParent->OnConnect(event); 128 } 129 } 130 131 NS_IMETHODIMP 132 TCPServerSocket::OnSocketAccepted(nsIServerSocket* aServer, 133 nsISocketTransport* aTransport) { 134 nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal(); 135 RefPtr<TCPSocket> socket = 136 TCPSocket::CreateAcceptedSocket(global, aTransport, mUseArrayBuffers); 137 FireEvent(u"connect"_ns, socket); 138 return NS_OK; 139 } 140 141 NS_IMETHODIMP 142 TCPServerSocket::OnStopListening(nsIServerSocket* aServer, nsresult aStatus) { 143 if (aStatus != NS_BINDING_ABORTED) { 144 RefPtr<Event> event = new Event(GetOwnerWindow()); 145 event->InitEvent(u"error"_ns, false, false); 146 event->SetTrusted(true); 147 DispatchEvent(*event); 148 149 NS_WARNING("Server socket was closed by unexpected reason."); 150 return NS_ERROR_FAILURE; 151 } 152 mServerSocket = nullptr; 153 return NS_OK; 154 } 155 156 nsresult TCPServerSocket::AcceptChildSocket(TCPSocketChild* aSocketChild) { 157 nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal(); 158 NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); 159 RefPtr<TCPSocket> socket = 160 TCPSocket::CreateAcceptedSocket(global, aSocketChild, mUseArrayBuffers); 161 NS_ENSURE_TRUE(socket, NS_ERROR_FAILURE); 162 FireEvent(u"connect"_ns, socket); 163 return NS_OK; 164 } 165 166 void TCPServerSocket::SetServerBridgeParent( 167 TCPServerSocketParent* aBridgeParent) { 168 mServerBridgeParent = aBridgeParent; 169 } 170 171 JSObject* TCPServerSocket::WrapObject(JSContext* aCx, 172 JS::Handle<JSObject*> aGivenProto) { 173 return TCPServerSocket_Binding::Wrap(aCx, this, aGivenProto); 174 }