WebSocketConnectionChild.cpp (6516B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set sw=2 ts=8 et ft=cpp : */ 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 "WebSocketLog.h" 8 #include "WebSocketConnectionChild.h" 9 10 #include "WebSocketConnection.h" 11 #include "mozilla/ipc/Endpoint.h" 12 #include "mozilla/net/SocketProcessBackgroundChild.h" 13 #include "mozilla/Components.h" 14 #include "nsISerializable.h" 15 #include "nsITLSSocketControl.h" 16 #include "nsITransportSecurityInfo.h" 17 #include "nsNetCID.h" 18 #include "nsSerializationHelper.h" 19 #include "nsSocketTransportService2.h" 20 #include "nsThreadUtils.h" 21 22 namespace mozilla { 23 namespace net { 24 25 NS_IMPL_ISUPPORTS(WebSocketConnectionChild, nsIHttpUpgradeListener) 26 27 WebSocketConnectionChild::WebSocketConnectionChild() { 28 LOG(("WebSocketConnectionChild ctor %p\n", this)); 29 } 30 31 WebSocketConnectionChild::~WebSocketConnectionChild() { 32 LOG(("WebSocketConnectionChild dtor %p\n", this)); 33 } 34 35 void WebSocketConnectionChild::Init(uint32_t aListenerId) { 36 MOZ_ASSERT(NS_IsMainThread()); 37 38 nsresult rv; 39 mSocketThread = mozilla::components::SocketTransport::Service(&rv); 40 MOZ_ASSERT(NS_SUCCEEDED(rv)); 41 if (!mSocketThread) { 42 return; 43 } 44 45 ipc::Endpoint<PWebSocketConnectionParent> parentEndpoint; 46 ipc::Endpoint<PWebSocketConnectionChild> childEndpoint; 47 PWebSocketConnection::CreateEndpoints(&parentEndpoint, &childEndpoint); 48 49 if (NS_FAILED(SocketProcessBackgroundChild::WithActor( 50 "SendInitWebSocketConnection", 51 [aListenerId, endpoint = std::move(parentEndpoint)]( 52 SocketProcessBackgroundChild* aActor) mutable { 53 (void)aActor->SendInitWebSocketConnection(std::move(endpoint), 54 aListenerId); 55 }))) { 56 return; 57 } 58 59 mSocketThread->Dispatch(NS_NewRunnableFunction( 60 "BindWebSocketConnectionChild", 61 [self = RefPtr{this}, endpoint = std::move(childEndpoint)]() mutable { 62 endpoint.Bind(self); 63 })); 64 } 65 66 // nsIHttpUpgradeListener 67 NS_IMETHODIMP 68 WebSocketConnectionChild::OnTransportAvailable( 69 nsISocketTransport* aTransport, nsIAsyncInputStream* aSocketIn, 70 nsIAsyncOutputStream* aSocketOut) { 71 LOG(("WebSocketConnectionChild::OnTransportAvailable %p\n", this)); 72 if (!OnSocketThread()) { 73 nsCOMPtr<nsISocketTransport> transport = aTransport; 74 nsCOMPtr<nsIAsyncInputStream> inputStream = aSocketIn; 75 nsCOMPtr<nsIAsyncOutputStream> outputStream = aSocketOut; 76 RefPtr<WebSocketConnectionChild> self = this; 77 return mSocketThread->Dispatch( 78 NS_NewRunnableFunction("WebSocketConnectionChild::OnTransportAvailable", 79 [self, transport, inputStream, outputStream]() { 80 (void)self->OnTransportAvailable( 81 transport, inputStream, outputStream); 82 }), 83 NS_DISPATCH_NORMAL); 84 } 85 86 LOG(("WebSocketConnectionChild::OnTransportAvailable %p\n", this)); 87 MOZ_ASSERT(OnSocketThread()); 88 MOZ_ASSERT(!mConnection, "already called"); 89 MOZ_ASSERT(aTransport); 90 91 if (!CanSend()) { 92 return NS_ERROR_NOT_AVAILABLE; 93 } 94 95 nsCOMPtr<nsITLSSocketControl> tlsSocketControl; 96 aTransport->GetTlsSocketControl(getter_AddRefs(tlsSocketControl)); 97 nsCOMPtr<nsITransportSecurityInfo> securityInfo( 98 do_QueryInterface(tlsSocketControl)); 99 100 RefPtr<WebSocketConnection> connection = 101 new WebSocketConnection(aTransport, aSocketIn, aSocketOut); 102 nsresult rv = connection->Init(this); 103 if (NS_FAILED(rv)) { 104 (void)OnUpgradeFailed(rv); 105 return NS_OK; 106 } 107 108 mConnection = std::move(connection); 109 110 (void)SendOnTransportAvailable(securityInfo); 111 return NS_OK; 112 } 113 114 NS_IMETHODIMP 115 WebSocketConnectionChild::OnUpgradeFailed(nsresult aReason) { 116 if (!OnSocketThread()) { 117 return mSocketThread->Dispatch(NewRunnableMethod<nsresult>( 118 "WebSocketConnectionChild::OnUpgradeFailed", this, 119 &WebSocketConnectionChild::OnUpgradeFailed, aReason)); 120 } 121 122 if (CanSend()) { 123 (void)SendOnUpgradeFailed(aReason); 124 } 125 return NS_OK; 126 } 127 128 NS_IMETHODIMP 129 WebSocketConnectionChild::OnWebSocketConnectionAvailable( 130 WebSocketConnectionBase* aConnection) { 131 return NS_ERROR_NOT_IMPLEMENTED; 132 } 133 134 mozilla::ipc::IPCResult WebSocketConnectionChild::RecvWriteOutputData( 135 nsTArray<uint8_t>&& aData) { 136 LOG(("WebSocketConnectionChild::RecvWriteOutputData %p\n", this)); 137 138 if (!mConnection) { 139 OnError(NS_ERROR_NOT_AVAILABLE); 140 return IPC_OK(); 141 } 142 143 mConnection->WriteOutputData(std::move(aData)); 144 return IPC_OK(); 145 } 146 147 mozilla::ipc::IPCResult WebSocketConnectionChild::RecvStartReading() { 148 LOG(("WebSocketConnectionChild::RecvStartReading %p\n", this)); 149 150 if (!mConnection) { 151 OnError(NS_ERROR_NOT_AVAILABLE); 152 return IPC_OK(); 153 } 154 155 mConnection->StartReading(); 156 return IPC_OK(); 157 } 158 159 mozilla::ipc::IPCResult WebSocketConnectionChild::RecvDrainSocketData() { 160 LOG(("WebSocketConnectionChild::RecvDrainSocketData %p\n", this)); 161 162 if (!mConnection) { 163 OnError(NS_ERROR_NOT_AVAILABLE); 164 return IPC_OK(); 165 } 166 167 mConnection->DrainSocketData(); 168 return IPC_OK(); 169 } 170 171 mozilla::ipc::IPCResult WebSocketConnectionChild::Recv__delete__() { 172 LOG(("WebSocketConnectionChild::Recv__delete__ %p\n", this)); 173 174 if (!mConnection) { 175 OnError(NS_ERROR_NOT_AVAILABLE); 176 return IPC_OK(); 177 } 178 179 mConnection->Close(); 180 mConnection = nullptr; 181 return IPC_OK(); 182 } 183 184 void WebSocketConnectionChild::OnError(nsresult aStatus) { 185 LOG(("WebSocketConnectionChild::OnError %p\n", this)); 186 187 if (CanSend()) { 188 (void)SendOnError(aStatus); 189 } 190 } 191 192 void WebSocketConnectionChild::OnTCPClosed() { 193 LOG(("WebSocketConnectionChild::OnTCPClosed %p\n", this)); 194 195 if (CanSend()) { 196 (void)SendOnTCPClosed(); 197 } 198 } 199 200 nsresult WebSocketConnectionChild::OnDataReceived(uint8_t* aData, 201 uint32_t aCount) { 202 LOG(("WebSocketConnectionChild::OnDataReceived %p\n", this)); 203 204 if (CanSend()) { 205 nsTArray<uint8_t> data; 206 data.AppendElements(aData, aCount); 207 (void)SendOnDataReceived(data); 208 } 209 210 return NS_OK; 211 } 212 213 void WebSocketConnectionChild::ActorDestroy(ActorDestroyReason aWhy) { 214 LOG(("WebSocketConnectionChild::ActorDestroy %p\n", this)); 215 if (mConnection) { 216 mConnection->Close(); 217 mConnection = nullptr; 218 } 219 } 220 221 } // namespace net 222 } // namespace mozilla