AltDataOutputStreamChild.cpp (5188B)
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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/net/AltDataOutputStreamChild.h" 8 #include "nsIInputStream.h" 9 #include "nsStreamUtils.h" 10 11 namespace mozilla { 12 namespace net { 13 14 NS_IMPL_ADDREF(AltDataOutputStreamChild) 15 16 NS_IMETHODIMP_(MozExternalRefCountType) AltDataOutputStreamChild::Release() { 17 MOZ_ASSERT(0 != mRefCnt, "dup release"); 18 MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); 19 --mRefCnt; 20 NS_LOG_RELEASE(this, mRefCnt, "AltDataOutputStreamChild"); 21 22 if (mRefCnt == 1 && mIPCOpen) { 23 // The only reference left is the IPDL one. After the parent replies back 24 // with a DeleteSelf message, the child will call Send__delete__(this), 25 // decrementing the ref count and triggering the destructor. 26 SendDeleteSelf(); 27 return 1; 28 } 29 30 if (mRefCnt == 0) { 31 mRefCnt = 1; /* stabilize */ 32 delete this; 33 return 0; 34 } 35 return mRefCnt; 36 } 37 38 NS_INTERFACE_MAP_BEGIN(AltDataOutputStreamChild) 39 NS_INTERFACE_MAP_ENTRY(nsIAsyncOutputStream) 40 NS_INTERFACE_MAP_ENTRY(nsIOutputStream) 41 NS_INTERFACE_MAP_ENTRY(nsISupports) 42 NS_INTERFACE_MAP_END 43 44 AltDataOutputStreamChild::AltDataOutputStreamChild() 45 : mIPCOpen(false), mError(NS_OK), mCallbackFlags(0) { 46 MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); 47 } 48 49 void AltDataOutputStreamChild::AddIPDLReference() { 50 MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference"); 51 mIPCOpen = true; 52 AddRef(); 53 } 54 55 void AltDataOutputStreamChild::ReleaseIPDLReference() { 56 MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference"); 57 mIPCOpen = false; 58 59 if (mCallback) { 60 NotifyListener(); 61 } 62 63 Release(); 64 } 65 66 bool AltDataOutputStreamChild::WriteDataInChunks( 67 const nsDependentCSubstring& data) { 68 const size_t kChunkSize = 128 * 1024; 69 size_t next = std::min(data.Length(), kChunkSize); 70 for (size_t i = 0; i < data.Length(); 71 i = next, next = std::min(data.Length(), next + kChunkSize)) { 72 nsCString chunk(Substring(data, i, kChunkSize)); 73 if (mIPCOpen && !SendWriteData(chunk)) { 74 mIPCOpen = false; 75 return false; 76 } 77 } 78 return true; 79 } 80 81 NS_IMETHODIMP 82 AltDataOutputStreamChild::Close() { return CloseWithStatus(NS_OK); } 83 84 NS_IMETHODIMP 85 AltDataOutputStreamChild::Flush() { 86 if (!mIPCOpen) { 87 return NS_ERROR_NOT_AVAILABLE; 88 } 89 if (NS_FAILED(mError)) { 90 return mError; 91 } 92 93 // This is a no-op 94 return NS_OK; 95 } 96 97 NS_IMETHODIMP 98 AltDataOutputStreamChild::StreamStatus() { 99 if (!mIPCOpen) { 100 return NS_ERROR_NOT_AVAILABLE; 101 } 102 return mError; 103 } 104 105 NS_IMETHODIMP 106 AltDataOutputStreamChild::Write(const char* aBuf, uint32_t aCount, 107 uint32_t* _retval) { 108 if (!mIPCOpen) { 109 return NS_ERROR_NOT_AVAILABLE; 110 } 111 if (NS_FAILED(mError)) { 112 return mError; 113 } 114 if (WriteDataInChunks(nsDependentCSubstring(aBuf, aCount))) { 115 *_retval = aCount; 116 return NS_OK; 117 } 118 return NS_ERROR_FAILURE; 119 } 120 121 NS_IMETHODIMP 122 AltDataOutputStreamChild::WriteFrom(nsIInputStream* aFromStream, 123 uint32_t aCount, uint32_t* _retval) { 124 return NS_ERROR_NOT_IMPLEMENTED; 125 } 126 127 NS_IMETHODIMP 128 AltDataOutputStreamChild::WriteSegments(nsReadSegmentFun aReader, 129 void* aClosure, uint32_t aCount, 130 uint32_t* _retval) { 131 return NS_ERROR_NOT_IMPLEMENTED; 132 } 133 134 NS_IMETHODIMP 135 AltDataOutputStreamChild::IsNonBlocking(bool* _retval) { 136 *_retval = false; 137 return NS_OK; 138 } 139 140 mozilla::ipc::IPCResult AltDataOutputStreamChild::RecvError( 141 const nsresult& err) { 142 mError = err; 143 return IPC_OK(); 144 } 145 146 mozilla::ipc::IPCResult AltDataOutputStreamChild::RecvDeleteSelf() { 147 PAltDataOutputStreamChild::Send__delete__(this); 148 return IPC_OK(); 149 } 150 151 // nsIAsyncOutputStream 152 153 NS_IMETHODIMP 154 AltDataOutputStreamChild::CloseWithStatus(nsresult aStatus) { 155 if (!mIPCOpen) { 156 return NS_ERROR_NOT_AVAILABLE; 157 } 158 if (NS_FAILED(mError)) { 159 return mError; 160 } 161 (void)SendClose(aStatus); 162 163 return NS_OK; 164 } 165 166 NS_IMETHODIMP 167 AltDataOutputStreamChild::AsyncWait(nsIOutputStreamCallback* aCallback, 168 uint32_t aFlags, uint32_t aRequestedCount, 169 nsIEventTarget* aEventTarget) { 170 mCallback = aCallback; 171 mCallbackFlags = aFlags; 172 mCallbackTarget = aEventTarget; 173 174 if (!mCallback) { 175 return NS_OK; 176 } 177 178 // The stream is blocking so it is writable at any time 179 if (!mIPCOpen || !(aFlags & WAIT_CLOSURE_ONLY)) { 180 NotifyListener(); 181 } 182 183 return NS_OK; 184 } 185 186 void AltDataOutputStreamChild::NotifyListener() { 187 MOZ_ASSERT(mCallback); 188 189 if (!mCallbackTarget) { 190 mCallbackTarget = GetMainThreadSerialEventTarget(); 191 } 192 193 nsCOMPtr<nsIOutputStreamCallback> asyncCallback = 194 NS_NewOutputStreamReadyEvent(mCallback, mCallbackTarget); 195 196 mCallback = nullptr; 197 mCallbackTarget = nullptr; 198 199 asyncCallback->OnOutputStreamReady(this); 200 } 201 202 } // namespace net 203 } // namespace mozilla