|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #ifndef mozilla_ipc_FileDescriptor_h |
|
6 #define mozilla_ipc_FileDescriptor_h |
|
7 |
|
8 #include "base/basictypes.h" |
|
9 #include "base/process.h" |
|
10 #include "mozilla/DebugOnly.h" |
|
11 #include "nscore.h" |
|
12 |
|
13 #ifdef XP_WIN |
|
14 // Need the HANDLE typedef. |
|
15 #include <winnt.h> |
|
16 #else |
|
17 #include "base/file_descriptor_posix.h" |
|
18 #endif |
|
19 |
|
20 namespace mozilla { |
|
21 namespace ipc { |
|
22 |
|
23 // This class is used by IPDL to share file descriptors across processes. When |
|
24 // sending a FileDescriptor IPDL will first duplicate a platform-specific file |
|
25 // handle type ('PlatformHandleType') into a handle that is valid in the other |
|
26 // process. Then IPDL will convert the duplicated handle into a type suitable |
|
27 // for pickling ('PickleType') and then send that through the IPC pipe. In the |
|
28 // receiving process the pickled data is converted into a platform-specific file |
|
29 // handle and then returned to the receiver. |
|
30 // |
|
31 // To use this class add 'FileDescriptor' as an argument in the IPDL protocol |
|
32 // and then pass a file descriptor from C++ to the Call/Send method. The |
|
33 // Answer/Recv method will receive a FileDescriptor& on which PlatformHandle() |
|
34 // can be called to return the platform file handle. |
|
35 class FileDescriptor |
|
36 { |
|
37 public: |
|
38 typedef base::ProcessHandle ProcessHandle; |
|
39 |
|
40 #ifdef XP_WIN |
|
41 typedef HANDLE PlatformHandleType; |
|
42 typedef HANDLE PickleType; |
|
43 #else |
|
44 typedef int PlatformHandleType; |
|
45 typedef base::FileDescriptor PickleType; |
|
46 #endif |
|
47 |
|
48 // This should only ever be created by IPDL. |
|
49 struct IPDLPrivate |
|
50 {}; |
|
51 |
|
52 FileDescriptor(); |
|
53 |
|
54 FileDescriptor(const FileDescriptor& aOther) |
|
55 : mHandleCreatedByOtherProcess(false), |
|
56 mHandleCreatedByOtherProcessWasUsed(false) |
|
57 { |
|
58 // Don't use operator= here because that will call |
|
59 // CloseCurrentProcessHandle() on this (uninitialized) object. |
|
60 Assign(aOther); |
|
61 } |
|
62 |
|
63 FileDescriptor(PlatformHandleType aHandle); |
|
64 |
|
65 FileDescriptor(const IPDLPrivate&, const PickleType& aPickle) |
|
66 #ifdef XP_WIN |
|
67 : mHandle(aPickle) |
|
68 #else |
|
69 : mHandle(aPickle.fd) |
|
70 #endif |
|
71 , mHandleCreatedByOtherProcess(true) |
|
72 , mHandleCreatedByOtherProcessWasUsed(false) |
|
73 { } |
|
74 |
|
75 ~FileDescriptor() |
|
76 { |
|
77 CloseCurrentProcessHandle(); |
|
78 } |
|
79 |
|
80 FileDescriptor& |
|
81 operator=(const FileDescriptor& aOther) |
|
82 { |
|
83 CloseCurrentProcessHandle(); |
|
84 Assign(aOther); |
|
85 return *this; |
|
86 } |
|
87 |
|
88 // Performs platform-specific actions to duplicate mHandle in the other |
|
89 // process (e.g. dup() on POSIX, DuplicateHandle() on Windows). Returns a |
|
90 // pickled value that can be passed to the other process via IPC. |
|
91 PickleType |
|
92 ShareTo(const IPDLPrivate&, ProcessHandle aOtherProcess) const; |
|
93 |
|
94 // Tests mHandle against a well-known invalid platform-specific file handle |
|
95 // (e.g. -1 on POSIX, INVALID_HANDLE_VALUE on Windows). |
|
96 bool |
|
97 IsValid() const |
|
98 { |
|
99 return IsValid(mHandle); |
|
100 } |
|
101 |
|
102 PlatformHandleType |
|
103 PlatformHandle() const |
|
104 { |
|
105 if (mHandleCreatedByOtherProcess) { |
|
106 mHandleCreatedByOtherProcessWasUsed = true; |
|
107 } |
|
108 return mHandle; |
|
109 } |
|
110 |
|
111 bool |
|
112 operator==(const FileDescriptor& aOther) const |
|
113 { |
|
114 return mHandle == aOther.mHandle; |
|
115 } |
|
116 |
|
117 private: |
|
118 void |
|
119 Assign(const FileDescriptor& aOther) |
|
120 { |
|
121 if (aOther.mHandleCreatedByOtherProcess) { |
|
122 mHandleCreatedByOtherProcess = true; |
|
123 mHandleCreatedByOtherProcessWasUsed = |
|
124 aOther.mHandleCreatedByOtherProcessWasUsed; |
|
125 mHandle = aOther.PlatformHandle(); |
|
126 } else { |
|
127 DuplicateInCurrentProcess(aOther.PlatformHandle()); |
|
128 mHandleCreatedByOtherProcess = false; |
|
129 mHandleCreatedByOtherProcessWasUsed = false; |
|
130 } |
|
131 } |
|
132 |
|
133 static bool |
|
134 IsValid(PlatformHandleType aHandle); |
|
135 |
|
136 void |
|
137 DuplicateInCurrentProcess(PlatformHandleType aHandle); |
|
138 |
|
139 void |
|
140 CloseCurrentProcessHandle(); |
|
141 |
|
142 PlatformHandleType mHandle; |
|
143 |
|
144 // If this is true then this instance is created by IPDL to ferry a handle to |
|
145 // its eventual consumer and we never close the handle. If this is false then |
|
146 // we are a RAII wrapper around the handle and we close the handle on |
|
147 // destruction. |
|
148 bool mHandleCreatedByOtherProcess; |
|
149 |
|
150 // This is to ensure that we don't leak the handle (which is only possible |
|
151 // when we're in the receiving process). |
|
152 mutable DebugOnly<bool> mHandleCreatedByOtherProcessWasUsed; |
|
153 }; |
|
154 |
|
155 } // namespace ipc |
|
156 } // namespace mozilla |
|
157 |
|
158 #endif // mozilla_ipc_FileDescriptor_h |