/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SerialPortPumps.h" #include "SerialLogging.h" namespace mozilla::dom::webserial { NS_IMPL_ISUPPORTS(SerialPortWritePump, nsIInputStreamCallback) SerialPortWritePump::SerialPortWritePump(const nsString& aPortId, nsIAsyncInputStream* aInput) : mPortId(aPortId), mInput(aInput) {} void SerialPortWritePump::Start() { RefPtr service = SerialPlatformService::GetInstance(); if (service && mInput) { mInput->AsyncWait(this, 0, 0, service->IOThread()); } } void SerialPortWritePump::Stop() { MOZ_LOG(gWebSerialLog, LogLevel::Debug, ("SerialPortWritePump::Stop for port '%s'", NS_ConvertUTF16toUTF8(mPortId).get())); mStopped = true; } NS_IMETHODIMP SerialPortWritePump::OnInputStreamReady( nsIAsyncInputStream* aStream) { if (mStopped) { return NS_OK; } RefPtr service = SerialPlatformService::GetInstance(); if (!service) { return NS_OK; } service->AssertIsOnIOThread(); // Read available data from the DataPipeReceiver. char buf[4096]; uint32_t bytesRead = 0; nsresult rv = mInput->Read(buf, sizeof(buf), &bytesRead); if (rv == NS_BASE_STREAM_WOULD_BLOCK) { // No data yet, wait again. mInput->AsyncWait(this, 0, 0, service->IOThread()); return NS_OK; } // NS_OK with 0 bytes is the nsIInputStream EOF convention. DataPipe // returns this when the peer (sender) has closed and no data remains. if (NS_FAILED(rv) || (NS_SUCCEEDED(rv) && bytesRead == 0)) { MOZ_LOG(gWebSerialLog, LogLevel::Debug, ("SerialPortWritePump pipe closed/error for port '%s': 0x%08x", NS_ConvertUTF16toUTF8(mPortId).get(), static_cast(rv))); mPipeClosed = true; if (nsCOMPtr cb = mClosedCallback.forget()) { cb->Run(); } return NS_OK; } if (bytesRead > 0) { MOZ_LOG(gWebSerialLog, LogLevel::Verbose, ("SerialPortWritePump writing %u bytes to port '%s'", bytesRead, NS_ConvertUTF16toUTF8(mPortId).get())); nsTArray data; data.AppendElements(reinterpret_cast(buf), bytesRead); rv = service->Write(mPortId, data); if (NS_FAILED(rv)) { MOZ_LOG( gWebSerialLog, LogLevel::Error, ("SerialPortWritePump device write failed for port '%s': 0x%08x", NS_ConvertUTF16toUTF8(mPortId).get(), static_cast(rv))); // Close the pipe to signal the error back to the child. mInput->CloseWithStatus(rv); return NS_OK; } } // Wait for more data. if (!mStopped) { mInput->AsyncWait(this, 0, 0, service->IOThread()); } return NS_OK; } void SerialPortWritePump::OnPipeClosed(nsCOMPtr&& aCallback) { RefPtr service = SerialPlatformService::GetInstance(); MOZ_DIAGNOSTIC_ASSERT(service && service->IOThread()->IsOnCurrentThread()); if (mPipeClosed) { aCallback->Run(); return; } mClosedCallback = std::move(aCallback); } } // namespace mozilla::dom::webserial