1 // Copyright © 2017 Mozilla Foundation
2 //
3 // This program is made available under an ISC-style license. See the
4 // accompanying file LICENSE for details
5
6 #![warn(unused_extern_crates)]
7 #![recursion_limit = "1024"]
8 #[macro_use]
9 extern crate error_chain;
10 #[macro_use]
11 extern crate log;
12
13 pub mod codec;
14 #[allow(deprecated)]
15 pub mod errors;
16 pub mod messages;
17 pub mod shm;
18
19 pub mod ipccore;
20 pub mod rpccore;
21 pub mod sys;
22
23 pub use crate::messages::{ClientMessage, ServerMessage};
24
25 #[cfg(unix)]
26 use std::os::unix::io::IntoRawFd;
27 #[cfg(windows)]
28 use std::os::windows::io::IntoRawHandle;
29
30 // This must match the definition of
31 // ipc::FileDescriptor::PlatformHandleType in Gecko.
32 #[cfg(windows)]
33 pub type PlatformHandleType = std::os::windows::raw::HANDLE;
34 #[cfg(unix)]
35 pub type PlatformHandleType = libc::c_int;
36
37 // This stands in for RawFd/RawHandle.
38 #[derive(Debug)]
39 pub struct PlatformHandle(PlatformHandleType);
40
41 #[cfg(unix)]
42 pub const INVALID_HANDLE_VALUE: PlatformHandleType = -1isize as PlatformHandleType;
43
44 #[cfg(windows)]
45 pub const INVALID_HANDLE_VALUE: PlatformHandleType = winapi::um::handleapi::INVALID_HANDLE_VALUE;
46
47 #[cfg(unix)]
valid_handle(handle: PlatformHandleType) -> bool48 fn valid_handle(handle: PlatformHandleType) -> bool {
49 handle >= 0
50 }
51
52 #[cfg(windows)]
valid_handle(handle: PlatformHandleType) -> bool53 fn valid_handle(handle: PlatformHandleType) -> bool {
54 handle != INVALID_HANDLE_VALUE && !handle.is_null()
55 }
56
57 impl PlatformHandle {
new(raw: PlatformHandleType) -> PlatformHandle58 pub fn new(raw: PlatformHandleType) -> PlatformHandle {
59 assert!(valid_handle(raw));
60 PlatformHandle(raw)
61 }
62
63 #[cfg(windows)]
from<T: IntoRawHandle>(from: T) -> PlatformHandle64 pub fn from<T: IntoRawHandle>(from: T) -> PlatformHandle {
65 PlatformHandle::new(from.into_raw_handle())
66 }
67
68 #[cfg(unix)]
from<T: IntoRawFd>(from: T) -> PlatformHandle69 pub fn from<T: IntoRawFd>(from: T) -> PlatformHandle {
70 PlatformHandle::new(from.into_raw_fd())
71 }
72
73 #[allow(clippy::missing_safety_doc)]
into_raw(self) -> PlatformHandleType74 pub unsafe fn into_raw(self) -> PlatformHandleType {
75 let handle = self.0;
76 std::mem::forget(self);
77 handle
78 }
79
80 #[cfg(unix)]
duplicate(h: PlatformHandleType) -> Result<PlatformHandle, std::io::Error>81 pub fn duplicate(h: PlatformHandleType) -> Result<PlatformHandle, std::io::Error> {
82 unsafe {
83 let newfd = libc::dup(h);
84 if !valid_handle(newfd) {
85 return Err(std::io::Error::last_os_error());
86 }
87 Ok(PlatformHandle::from(newfd))
88 }
89 }
90
91 #[allow(clippy::missing_safety_doc)]
92 #[cfg(windows)]
duplicate(h: PlatformHandleType) -> Result<PlatformHandle, std::io::Error>93 pub unsafe fn duplicate(h: PlatformHandleType) -> Result<PlatformHandle, std::io::Error> {
94 let dup = duplicate_platform_handle(h, None)?;
95 Ok(PlatformHandle::new(dup))
96 }
97 }
98
99 impl Drop for PlatformHandle {
drop(&mut self)100 fn drop(&mut self) {
101 unsafe { close_platform_handle(self.0) }
102 }
103 }
104
105 #[cfg(unix)]
close_platform_handle(handle: PlatformHandleType)106 unsafe fn close_platform_handle(handle: PlatformHandleType) {
107 libc::close(handle);
108 }
109
110 #[cfg(windows)]
close_platform_handle(handle: PlatformHandleType)111 unsafe fn close_platform_handle(handle: PlatformHandleType) {
112 winapi::um::handleapi::CloseHandle(handle);
113 }
114
115 #[cfg(windows)]
116 use winapi::shared::minwindef::DWORD;
117
118 // Duplicate `source_handle`.
119 // - If `target_pid` is `Some(...)`, `source_handle` is closed.
120 // - If `target_pid` is `None`, `source_handle` is not closed.
121 #[cfg(windows)]
duplicate_platform_handle( source_handle: PlatformHandleType, target_pid: Option<DWORD>, ) -> Result<PlatformHandleType, std::io::Error>122 pub(crate) unsafe fn duplicate_platform_handle(
123 source_handle: PlatformHandleType,
124 target_pid: Option<DWORD>,
125 ) -> Result<PlatformHandleType, std::io::Error> {
126 use winapi::shared::minwindef::FALSE;
127 use winapi::um::{handleapi, processthreadsapi, winnt};
128
129 let source = processthreadsapi::GetCurrentProcess();
130 let (target, close_source) = if let Some(pid) = target_pid {
131 let target = processthreadsapi::OpenProcess(winnt::PROCESS_DUP_HANDLE, FALSE, pid);
132 if !valid_handle(target) {
133 return Err(std::io::Error::new(
134 std::io::ErrorKind::Other,
135 "invalid target process",
136 ));
137 }
138 (target, true)
139 } else {
140 (source, false)
141 };
142
143 let mut target_handle = std::ptr::null_mut();
144 let mut options = winnt::DUPLICATE_SAME_ACCESS;
145 if close_source {
146 options |= winnt::DUPLICATE_CLOSE_SOURCE;
147 }
148 let ok = handleapi::DuplicateHandle(
149 source,
150 source_handle,
151 target,
152 &mut target_handle,
153 0,
154 FALSE,
155 options,
156 );
157 handleapi::CloseHandle(target);
158 if ok == FALSE {
159 return Err(std::io::Error::new(
160 std::io::ErrorKind::Other,
161 "DuplicateHandle failed",
162 ));
163 }
164 Ok(target_handle)
165 }
166
167 #[cfg(windows)]
server_platform_init()168 pub fn server_platform_init() {
169 use winapi::shared::winerror;
170 use winapi::um::combaseapi;
171 use winapi::um::objbase;
172
173 unsafe {
174 let r = combaseapi::CoInitializeEx(std::ptr::null_mut(), objbase::COINIT_MULTITHREADED);
175 assert!(winerror::SUCCEEDED(r));
176 }
177 }
178
179 #[cfg(unix)]
server_platform_init()180 pub fn server_platform_init() {}
181