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 "FileDescriptorUtils.h"
8 
9 #include "nsIEventTarget.h"
10 
11 #include "nsCOMPtr.h"
12 #include "nsDebug.h"
13 #include "nsNetCID.h"
14 #include "nsServiceManagerUtils.h"
15 #include "nsThreadUtils.h"
16 #include "prio.h"
17 #include "private/pprio.h"
18 
19 #include <errno.h>
20 #ifdef XP_WIN
21 #include <io.h>
22 #else
23 #include <unistd.h>
24 #endif
25 
26 using mozilla::ipc::CloseFileRunnable;
27 
28 #ifdef DEBUG
29 
CloseFileRunnable(const FileDescriptor & aFileDescriptor)30 CloseFileRunnable::CloseFileRunnable(const FileDescriptor& aFileDescriptor)
31     : mFileDescriptor(aFileDescriptor) {
32   MOZ_ASSERT(aFileDescriptor.IsValid());
33 }
34 
35 #endif  // DEBUG
36 
~CloseFileRunnable()37 CloseFileRunnable::~CloseFileRunnable() {
38   if (mFileDescriptor.IsValid()) {
39     // It's probably safer to take the main thread IO hit here rather than leak
40     // the file descriptor.
41     CloseFile();
42   }
43 }
44 
NS_IMPL_ISUPPORTS(CloseFileRunnable,nsIRunnable)45 NS_IMPL_ISUPPORTS(CloseFileRunnable, nsIRunnable)
46 
47 void CloseFileRunnable::Dispatch() {
48   nsCOMPtr<nsIEventTarget> eventTarget =
49       do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
50   NS_ENSURE_TRUE_VOID(eventTarget);
51 
52   nsresult rv = eventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
53   NS_ENSURE_SUCCESS_VOID(rv);
54 }
55 
CloseFile()56 void CloseFileRunnable::CloseFile() {
57   // It's possible for this to happen on the main thread if the dispatch to the
58   // stream service fails so we can't assert the thread on which we're running.
59   mFileDescriptor = FileDescriptor();
60 }
61 
62 NS_IMETHODIMP
Run()63 CloseFileRunnable::Run() {
64   MOZ_ASSERT(!NS_IsMainThread());
65 
66   CloseFile();
67   return NS_OK;
68 }
69 
70 namespace mozilla {
71 namespace ipc {
72 
FileDescriptorToFILE(const FileDescriptor & aDesc,const char * aOpenMode)73 FILE* FileDescriptorToFILE(const FileDescriptor& aDesc, const char* aOpenMode) {
74   if (!aDesc.IsValid()) {
75     errno = EBADF;
76     return nullptr;
77   }
78   auto handle = aDesc.ClonePlatformHandle();
79 #ifdef XP_WIN
80   int fd = _open_osfhandle(static_cast<intptr_t>(handle.get()), 0);
81   if (fd == -1) {
82     return nullptr;
83   }
84   Unused << handle.release();
85 #else
86   int fd = handle.release();
87 #endif
88   FILE* file = fdopen(fd, aOpenMode);
89   if (!file) {
90     int saved_errno = errno;
91     close(fd);
92     errno = saved_errno;
93   }
94   return file;
95 }
96 
FILEToFileDescriptor(FILE * aStream)97 FileDescriptor FILEToFileDescriptor(FILE* aStream) {
98   if (!aStream) {
99     errno = EBADF;
100     return FileDescriptor();
101   }
102 #ifdef XP_WIN
103   int fd = _fileno(aStream);
104   if (fd == -1) {
105     return FileDescriptor();
106   }
107   return FileDescriptor(reinterpret_cast<HANDLE>(_get_osfhandle(fd)));
108 #else
109   return FileDescriptor(fileno(aStream));
110 #endif
111 }
112 
113 }  // namespace ipc
114 }  // namespace mozilla
115