WebSocketConnectionParent.cpp (6093B)
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 "WebSocketConnectionParent.h" 9 10 #include "nsIHttpChannelInternal.h" 11 #include "nsITransportSecurityInfo.h" 12 #include "nsSerializationHelper.h" 13 #include "nsThreadUtils.h" 14 #include "WebSocketConnectionListener.h" 15 16 namespace mozilla { 17 namespace net { 18 19 NS_IMPL_ISUPPORTS0(WebSocketConnectionParent) 20 21 WebSocketConnectionParent::WebSocketConnectionParent( 22 nsIHttpUpgradeListener* aListener) 23 : mUpgradeListener(aListener), 24 mBackgroundThread(GetCurrentSerialEventTarget()) { 25 LOG(("WebSocketConnectionParent ctor %p\n", this)); 26 MOZ_ASSERT(mUpgradeListener); 27 } 28 29 WebSocketConnectionParent::~WebSocketConnectionParent() { 30 LOG(("WebSocketConnectionParent dtor %p\n", this)); 31 } 32 33 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnTransportAvailable( 34 nsITransportSecurityInfo* aSecurityInfo) { 35 LOG(("WebSocketConnectionParent::RecvOnTransportAvailable %p\n", this)); 36 MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread()); 37 38 if (aSecurityInfo) { 39 MutexAutoLock lock(mMutex); 40 mSecurityInfo = aSecurityInfo; 41 } 42 43 if (mUpgradeListener) { 44 (void)mUpgradeListener->OnWebSocketConnectionAvailable(this); 45 mUpgradeListener = nullptr; 46 } 47 return IPC_OK(); 48 } 49 50 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnError( 51 const nsresult& aStatus) { 52 LOG(("WebSocketConnectionParent::RecvOnError %p\n", this)); 53 MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread()); 54 55 MOZ_ASSERT(mListener); 56 mListener->OnError(aStatus); 57 return IPC_OK(); 58 } 59 60 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnUpgradeFailed( 61 const nsresult& aReason) { 62 MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread()); 63 64 if (mUpgradeListener) { 65 (void)mUpgradeListener->OnUpgradeFailed(aReason); 66 mUpgradeListener = nullptr; 67 } 68 return IPC_OK(); 69 } 70 71 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnTCPClosed() { 72 LOG(("WebSocketConnectionParent::RecvOnTCPClosed %p\n", this)); 73 MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread()); 74 75 MOZ_ASSERT(mListener); 76 mListener->OnTCPClosed(); 77 return IPC_OK(); 78 } 79 80 mozilla::ipc::IPCResult WebSocketConnectionParent::RecvOnDataReceived( 81 nsTArray<uint8_t>&& aData) { 82 LOG(("WebSocketConnectionParent::RecvOnDataReceived %p\n", this)); 83 MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread()); 84 85 MOZ_ASSERT(mListener); 86 uint8_t* buffer = const_cast<uint8_t*>(aData.Elements()); 87 nsresult rv = mListener->OnDataReceived(buffer, aData.Length()); 88 if (NS_FAILED(rv)) { 89 mListener->OnError(rv); 90 } 91 92 return IPC_OK(); 93 } 94 95 void WebSocketConnectionParent::ActorDestroy(ActorDestroyReason aWhy) { 96 LOG(("WebSocketConnectionParent::ActorDestroy %p aWhy=%d\n", this, aWhy)); 97 if (!mClosed) { 98 // Treat this as an error when IPC is closed before 99 // WebSocketConnectionParent::Close() is called. 100 RefPtr<WebSocketConnectionListener> listener; 101 listener.swap(mListener); 102 if (listener) { 103 listener->OnError(NS_ERROR_FAILURE); 104 } 105 } 106 mBackgroundThread->Dispatch(NS_NewRunnableFunction( 107 "WebSocketConnectionParent::DefereredDestroy", [self = RefPtr{this}]() { 108 LOG(("WebSocketConnectionParent::DefereredDestroy")); 109 })); 110 }; 111 112 nsresult WebSocketConnectionParent::Init( 113 WebSocketConnectionListener* aListener) { 114 NS_ENSURE_ARG_POINTER(aListener); 115 116 mListener = aListener; 117 return NS_OK; 118 } 119 120 void WebSocketConnectionParent::GetIoTarget(nsIEventTarget** aTarget) { 121 nsCOMPtr<nsIEventTarget> target = mBackgroundThread; 122 return target.forget(aTarget); 123 } 124 125 void WebSocketConnectionParent::Close() { 126 LOG(("WebSocketConnectionParent::Close %p\n", this)); 127 128 mClosed = true; 129 130 auto task = [self = RefPtr{this}]() { 131 self->PWebSocketConnectionParent::Close(); 132 }; 133 134 if (mBackgroundThread->IsOnCurrentThread()) { 135 task(); 136 } else { 137 mBackgroundThread->Dispatch(NS_NewRunnableFunction( 138 "WebSocketConnectionParent::Close", std::move(task))); 139 } 140 } 141 142 nsresult WebSocketConnectionParent::WriteOutputData( 143 const uint8_t* aHdrBuf, uint32_t aHdrBufLength, const uint8_t* aPayloadBuf, 144 uint32_t aPayloadBufLength) { 145 LOG(("WebSocketConnectionParent::WriteOutputData %p", this)); 146 MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread()); 147 148 if (!CanSend()) { 149 return NS_ERROR_NOT_AVAILABLE; 150 } 151 152 nsTArray<uint8_t> data; 153 data.AppendElements(aHdrBuf, aHdrBufLength); 154 data.AppendElements(aPayloadBuf, aPayloadBufLength); 155 return SendWriteOutputData(data) ? NS_OK : NS_ERROR_FAILURE; 156 } 157 158 nsresult WebSocketConnectionParent::StartReading() { 159 LOG(("WebSocketConnectionParent::StartReading %p\n", this)); 160 161 RefPtr<WebSocketConnectionParent> self = this; 162 auto task = [self{std::move(self)}]() { 163 if (!self->CanSend()) { 164 if (self->mListener) { 165 self->mListener->OnError(NS_ERROR_NOT_AVAILABLE); 166 } 167 return; 168 } 169 170 (void)self->SendStartReading(); 171 }; 172 173 if (mBackgroundThread->IsOnCurrentThread()) { 174 task(); 175 } else { 176 mBackgroundThread->Dispatch(NS_NewRunnableFunction( 177 "WebSocketConnectionParent::SendStartReading", std::move(task))); 178 } 179 180 return NS_OK; 181 } 182 183 void WebSocketConnectionParent::DrainSocketData() { 184 LOG(("WebSocketConnectionParent::DrainSocketData %p\n", this)); 185 MOZ_ASSERT(mBackgroundThread->IsOnCurrentThread()); 186 187 if (!CanSend()) { 188 MOZ_ASSERT(mListener); 189 mListener->OnError(NS_ERROR_NOT_AVAILABLE); 190 191 return; 192 } 193 194 (void)SendDrainSocketData(); 195 } 196 197 nsresult WebSocketConnectionParent::GetSecurityInfo( 198 nsITransportSecurityInfo** aSecurityInfo) { 199 LOG(("WebSocketConnectionParent::GetSecurityInfo() %p\n", this)); 200 MOZ_ASSERT(NS_IsMainThread()); 201 202 NS_ENSURE_ARG_POINTER(aSecurityInfo); 203 204 MutexAutoLock lock(mMutex); 205 NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo); 206 return NS_OK; 207 } 208 209 } // namespace net 210 } // namespace mozilla