diff options
Diffstat (limited to 'ipc/glue/FileDescriptorUtils.cpp')
-rw-r--r-- | ipc/glue/FileDescriptorUtils.cpp | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/ipc/glue/FileDescriptorUtils.cpp b/ipc/glue/FileDescriptorUtils.cpp new file mode 100644 index 000000000..e30bc97d8 --- /dev/null +++ b/ipc/glue/FileDescriptorUtils.cpp @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "FileDescriptorUtils.h" + +#include "nsIEventTarget.h" + +#include "nsCOMPtr.h" +#include "nsDebug.h" +#include "nsNetCID.h" +#include "nsServiceManagerUtils.h" +#include "nsThreadUtils.h" +#include "prio.h" +#include "private/pprio.h" + +#include <errno.h> +#ifdef XP_WIN +#include <io.h> +#else +#include <unistd.h> +#endif + +using mozilla::ipc::CloseFileRunnable; + +#ifdef DEBUG + +CloseFileRunnable::CloseFileRunnable(const FileDescriptor& aFileDescriptor) +: mFileDescriptor(aFileDescriptor) +{ + MOZ_ASSERT(aFileDescriptor.IsValid()); +} + +#endif // DEBUG + +CloseFileRunnable::~CloseFileRunnable() +{ + if (mFileDescriptor.IsValid()) { + // It's probably safer to take the main thread IO hit here rather than leak + // the file descriptor. + CloseFile(); + } +} + +NS_IMPL_ISUPPORTS(CloseFileRunnable, nsIRunnable) + +void +CloseFileRunnable::Dispatch() +{ + nsCOMPtr<nsIEventTarget> eventTarget = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); + NS_ENSURE_TRUE_VOID(eventTarget); + + nsresult rv = eventTarget->Dispatch(this, NS_DISPATCH_NORMAL); + NS_ENSURE_SUCCESS_VOID(rv); +} + +void +CloseFileRunnable::CloseFile() +{ + // It's possible for this to happen on the main thread if the dispatch to the + // stream service fails so we can't assert the thread on which we're running. + mFileDescriptor = FileDescriptor(); +} + +NS_IMETHODIMP +CloseFileRunnable::Run() +{ + MOZ_ASSERT(!NS_IsMainThread()); + + CloseFile(); + return NS_OK; +} + +namespace mozilla { +namespace ipc { + +FILE* +FileDescriptorToFILE(const FileDescriptor& aDesc, + const char* aOpenMode) +{ + if (!aDesc.IsValid()) { + errno = EBADF; + return nullptr; + } + auto handle = aDesc.ClonePlatformHandle(); +#ifdef XP_WIN + int fd = _open_osfhandle(static_cast<intptr_t>(handle.get()), 0); + if (fd == -1) { + return nullptr; + } + Unused << handle.release(); +#else + int fd = handle.release(); +#endif + FILE* file = fdopen(fd, aOpenMode); + if (!file) { + int saved_errno = errno; + close(fd); + errno = saved_errno; + } + return file; +} + +FileDescriptor +FILEToFileDescriptor(FILE* aStream) +{ + if (!aStream) { + errno = EBADF; + return FileDescriptor(); + } +#ifdef XP_WIN + int fd = _fileno(aStream); + if (fd == -1) { + return FileDescriptor(); + } + return FileDescriptor(reinterpret_cast<HANDLE>(_get_osfhandle(fd))); +#else + return FileDescriptor(fileno(aStream)); +#endif +} + +} // namespace ipc +} // namespace mozilla |