1use self::mach_sys::mach_port_deallocate;
11use self::mach_sys::{kern_return_t, mach_msg_body_t, mach_msg_header_t, mach_msg_return_t};
12use self::mach_sys::{mach_msg_ool_descriptor_t, mach_msg_port_descriptor_t, mach_msg_type_name_t};
13use self::mach_sys::{mach_msg_timeout_t, mach_port_limits_t, mach_port_msgcount_t};
14use self::mach_sys::{mach_port_right_t, mach_port_t, mach_task_self_, vm_inherit_t};
15use crate::ipc::{self, IpcMessage};
16
17use bincode;
18use lazy_static::lazy_static;
19use libc::{self, c_char, c_uint, c_void, size_t};
20use rand::{self, Rng};
21use std::cell::Cell;
22use std::convert::TryInto;
23use std::error::Error as StdError;
24use std::ffi::CString;
25use std::fmt::{self, Debug, Formatter};
26use std::io;
27use std::marker::PhantomData;
28use std::mem;
29use std::ops::Deref;
30use std::ptr;
31use std::slice;
32use std::sync::RwLock;
33use std::time::Duration;
34
35mod mach_sys;
36
37const SMALL_MESSAGE_SIZE: usize = 4096;
40
41static BOOTSTRAP_PREFIX: &str = "org.rust-lang.ipc-channel.";
43
44const BOOTSTRAP_NAME_IN_USE: kern_return_t = 1101;
45const BOOTSTRAP_SUCCESS: kern_return_t = 0;
46const KERN_NOT_IN_SET: kern_return_t = 12;
47const KERN_INVALID_NAME: kern_return_t = 15;
48const KERN_INVALID_RIGHT: kern_return_t = 17;
49const KERN_INVALID_VALUE: kern_return_t = 18;
50const KERN_UREFS_OVERFLOW: kern_return_t = 19;
51const KERN_INVALID_CAPABILITY: kern_return_t = 20;
52const KERN_SUCCESS: kern_return_t = 0;
53const KERN_NO_SPACE: kern_return_t = 3;
54const MACH_MSGH_BITS_COMPLEX: u32 = 0x80000000;
55const MACH_MSG_IPC_KERNEL: kern_return_t = 0x00000800;
56const MACH_MSG_IPC_SPACE: kern_return_t = 0x00002000;
57const MACH_MSG_OOL_DESCRIPTOR: u32 = 1;
58const MACH_MSG_PORT_DESCRIPTOR: u32 = 0;
59const MACH_MSG_SUCCESS: kern_return_t = 0;
60const MACH_MSG_TIMEOUT_NONE: mach_msg_timeout_t = 0;
61const MACH_MSG_TYPE_COPY_SEND: u8 = 19;
62const MACH_MSG_TYPE_MAKE_SEND: u8 = 20;
63const MACH_MSG_TYPE_MAKE_SEND_ONCE: u8 = 21;
64const MACH_MSG_TYPE_MOVE_RECEIVE: u32 = 16;
65const MACH_MSG_TYPE_MOVE_SEND: u32 = 17;
66const MACH_MSG_TYPE_PORT_SEND: u32 = MACH_MSG_TYPE_MOVE_SEND;
67const MACH_MSG_VIRTUAL_COPY: c_uint = 1;
68const MACH_MSG_VM_KERNEL: kern_return_t = 0x00000400;
69const MACH_MSG_VM_SPACE: kern_return_t = 0x00001000;
70const MACH_NOTIFY_FIRST: i32 = 64;
71const MACH_NOTIFY_NO_SENDERS: i32 = MACH_NOTIFY_FIRST + 6;
72const MACH_PORT_LIMITS_INFO: i32 = 1;
73const MACH_PORT_NULL: mach_port_t = 0;
74const MACH_PORT_QLIMIT_LARGE: mach_port_msgcount_t = 1024;
75const MACH_PORT_QLIMIT_MAX: mach_port_msgcount_t = MACH_PORT_QLIMIT_LARGE;
76const MACH_PORT_RIGHT_PORT_SET: mach_port_right_t = 3;
77const MACH_PORT_RIGHT_RECEIVE: mach_port_right_t = 1;
78const MACH_PORT_RIGHT_SEND: mach_port_right_t = 0;
79const MACH_RCV_BODY_ERROR: kern_return_t = 0x1000400c;
80const MACH_RCV_HEADER_ERROR: kern_return_t = 0x1000400b;
81const MACH_RCV_INTERRUPTED: kern_return_t = 0x10004005;
82const MACH_RCV_INVALID_DATA: kern_return_t = 0x10004008;
83const MACH_RCV_INVALID_NAME: kern_return_t = 0x10004002;
84const MACH_RCV_INVALID_NOTIFY: kern_return_t = 0x10004007;
85const MACH_RCV_INVALID_TRAILER: kern_return_t = 0x1000400f;
86const MACH_RCV_INVALID_TYPE: kern_return_t = 0x1000400d;
87const MACH_RCV_IN_PROGRESS: kern_return_t = 0x10004001;
88const MACH_RCV_IN_PROGRESS_TIMED: kern_return_t = 0x10004011;
89const MACH_RCV_IN_SET: kern_return_t = 0x1000400a;
90const MACH_RCV_LARGE: i32 = 4;
91const MACH_RCV_MSG: i32 = 2;
92const MACH_RCV_PORT_CHANGED: kern_return_t = 0x10004006;
93const MACH_RCV_PORT_DIED: kern_return_t = 0x10004009;
94const MACH_RCV_SCATTER_SMALL: kern_return_t = 0x1000400e;
95const MACH_RCV_TIMED_OUT: kern_return_t = 0x10004003;
96const MACH_RCV_TIMEOUT: i32 = 0x100;
97const MACH_RCV_TOO_LARGE: kern_return_t = 0x10004004;
98const MACH_SEND_INTERRUPTED: kern_return_t = 0x10000007;
99const MACH_SEND_INVALID_DATA: kern_return_t = 0x10000002;
100const MACH_SEND_INVALID_DEST: kern_return_t = 0x10000003;
101const MACH_SEND_INVALID_HEADER: kern_return_t = 0x10000010;
102const MACH_SEND_INVALID_MEMORY: kern_return_t = 0x1000000c;
103const MACH_SEND_INVALID_NOTIFY: kern_return_t = 0x1000000b;
104const MACH_SEND_INVALID_REPLY: kern_return_t = 0x10000009;
105const MACH_SEND_INVALID_RIGHT: kern_return_t = 0x1000000a;
106const MACH_SEND_INVALID_RT_OOL_SIZE: kern_return_t = 0x10000015;
107const MACH_SEND_INVALID_TRAILER: kern_return_t = 0x10000011;
108const MACH_SEND_INVALID_TYPE: kern_return_t = 0x1000000f;
109const MACH_SEND_INVALID_VOUCHER: kern_return_t = 0x10000005;
110const MACH_SEND_IN_PROGRESS: kern_return_t = 0x10000001;
111const MACH_SEND_MSG: i32 = 1;
112const MACH_SEND_MSG_TOO_SMALL: kern_return_t = 0x10000008;
113const MACH_SEND_NO_BUFFER: kern_return_t = 0x1000000d;
114const MACH_SEND_TIMED_OUT: kern_return_t = 0x10000004;
115const MACH_SEND_TOO_LARGE: kern_return_t = 0x1000000e;
116const TASK_BOOTSTRAP_PORT: i32 = 4;
117const VM_INHERIT_SHARE: vm_inherit_t = 0;
118
119#[allow(non_camel_case_types)]
120type name_t = *const c_char;
121
122pub fn channel() -> Result<(OsIpcSender, OsIpcReceiver), MachError> {
123 let receiver = OsIpcReceiver::new()?;
124 let sender = receiver.sender()?;
125 receiver.request_no_senders_notification()?;
126 Ok((sender, receiver))
127}
128
129#[derive(PartialEq, Debug)]
130pub struct OsIpcReceiver {
131 port: Cell<mach_port_t>,
132}
133
134impl Drop for OsIpcReceiver {
135 fn drop(&mut self) {
136 let port = self.port.get();
137 if port != MACH_PORT_NULL {
138 mach_port_mod_release(port, MACH_PORT_RIGHT_RECEIVE).unwrap();
139 }
140 }
141}
142
143fn mach_port_allocate(right: mach_port_right_t) -> Result<mach_port_t, KernelError> {
144 let mut port: mach_port_t = 0;
145 let os_result = unsafe { mach_sys::mach_port_allocate(mach_task_self(), right, &mut port) };
146 if os_result == KERN_SUCCESS {
147 return Ok(port);
148 }
149 Err(os_result.into())
150}
151
152fn mach_port_mod_addref(port: mach_port_t, right: mach_port_right_t) -> Result<(), KernelError> {
153 let err = unsafe { mach_sys::mach_port_mod_refs(mach_task_self(), port, right, 1) };
154 if err == KERN_SUCCESS {
155 return Ok(());
156 }
157 Err(err.into())
158}
159
160fn mach_port_mod_release(port: mach_port_t, right: mach_port_right_t) -> Result<(), KernelError> {
161 let err = unsafe { mach_sys::mach_port_mod_refs(mach_task_self(), port, right, -1) };
162 if err == KERN_SUCCESS {
163 return Ok(());
164 }
165 Err(err.into())
166}
167
168fn mach_port_move_member(port: mach_port_t, set: mach_port_t) -> Result<(), KernelError> {
169 let error = unsafe { mach_sys::mach_port_move_member(mach_task_self(), port, set) };
170 if error == KERN_SUCCESS {
171 return Ok(());
172 }
173 Err(error.into())
174}
175
176fn mach_port_extract_right(
177 port: mach_port_t,
178 message_type: mach_msg_type_name_t,
179) -> Result<(mach_port_t, mach_msg_type_name_t), KernelError> {
180 let (mut right, mut acquired_right) = (0, 0);
181 let error = unsafe {
182 mach_sys::mach_port_extract_right(
183 mach_task_self(),
184 port,
185 message_type,
186 &mut right,
187 &mut acquired_right,
188 )
189 };
190 if error == KERN_SUCCESS {
191 return Ok((right, acquired_right));
192 }
193 Err(error.into())
194}
195
196impl OsIpcReceiver {
197 fn new() -> Result<OsIpcReceiver, MachError> {
198 let port = mach_port_allocate(MACH_PORT_RIGHT_RECEIVE)?;
199 let limits = mach_port_limits_t {
200 mpl_qlimit: MACH_PORT_QLIMIT_MAX,
201 };
202 let os_result = unsafe {
203 mach_sys::mach_port_set_attributes(
204 mach_task_self(),
205 port,
206 MACH_PORT_LIMITS_INFO,
207 &limits as *const mach_port_limits_t as *mut i32,
208 1,
209 )
210 };
211 if os_result == KERN_SUCCESS {
212 Ok(OsIpcReceiver::from_name(port))
213 } else {
214 Err(KernelError::from(os_result).into())
215 }
216 }
217
218 fn from_name(port: mach_port_t) -> OsIpcReceiver {
219 OsIpcReceiver {
220 port: Cell::new(port),
221 }
222 }
223
224 fn extract_port(&self) -> mach_port_t {
225 let port = self.port.get();
226 debug_assert!(port != MACH_PORT_NULL);
227 port
228 }
229
230 fn consume_port(&self) -> mach_port_t {
231 let port = self.extract_port();
232 self.port.set(MACH_PORT_NULL);
233 port
234 }
235
236 pub fn consume(&self) -> OsIpcReceiver {
237 OsIpcReceiver::from_name(self.consume_port())
238 }
239
240 fn sender(&self) -> Result<OsIpcSender, MachError> {
241 let port = self.port.get();
242 debug_assert!(port != MACH_PORT_NULL);
243 let (right, acquired_right) =
244 mach_port_extract_right(port, MACH_MSG_TYPE_MAKE_SEND as u32)?;
245 debug_assert!(acquired_right == MACH_MSG_TYPE_PORT_SEND);
246 Ok(OsIpcSender::from_name(right))
247 }
248
249 fn register_bootstrap_name(&self) -> Result<(u32, String), MachError> {
250 let port = self.port.get();
251 debug_assert!(port != MACH_PORT_NULL);
252 unsafe {
253 let mut bootstrap_port = 0;
254 let os_result = mach_sys::task_get_special_port(
255 mach_task_self(),
256 TASK_BOOTSTRAP_PORT,
257 &mut bootstrap_port,
258 );
259 if os_result != KERN_SUCCESS {
260 return Err(KernelError::from(os_result).into());
261 }
262
263 let (right, acquired_right) =
264 mach_port_extract_right(port, MACH_MSG_TYPE_MAKE_SEND as u32)?;
265 debug_assert!(acquired_right == MACH_MSG_TYPE_PORT_SEND);
266
267 let mut os_result;
268 let mut name;
269 loop {
270 name = format!("{}{}", BOOTSTRAP_PREFIX, rand::thread_rng().gen::<i64>());
271 let c_name = CString::new(name.clone()).unwrap();
272 os_result = bootstrap_register2(bootstrap_port, c_name.as_ptr(), right, 0);
273 if os_result == BOOTSTRAP_NAME_IN_USE {
274 continue;
275 }
276 if os_result != BOOTSTRAP_SUCCESS {
277 return Err(MachError::from(os_result));
278 }
279 break;
280 }
281 Ok((right, name))
282 }
283 }
284
285 fn unregister_global_name(name: String) -> Result<(), MachError> {
286 unsafe {
287 let mut bootstrap_port = 0;
288 let os_result = mach_sys::task_get_special_port(
289 mach_task_self(),
290 TASK_BOOTSTRAP_PORT,
291 &mut bootstrap_port,
292 );
293 if os_result != KERN_SUCCESS {
294 return Err(KernelError::from(os_result).into());
295 }
296
297 let c_name = CString::new(name).unwrap();
298 let os_result = bootstrap_register2(bootstrap_port, c_name.as_ptr(), MACH_PORT_NULL, 0);
299 if os_result == BOOTSTRAP_SUCCESS {
300 Ok(())
301 } else {
302 Err(MachError::from(os_result))
303 }
304 }
305 }
306
307 fn request_no_senders_notification(&self) -> Result<(), MachError> {
308 let port = self.port.get();
309 debug_assert!(port != MACH_PORT_NULL);
310 unsafe {
311 let os_result = mach_sys::mach_port_request_notification(
312 mach_task_self(),
313 port,
314 MACH_NOTIFY_NO_SENDERS,
315 0,
316 port,
317 MACH_MSG_TYPE_MAKE_SEND_ONCE as u32,
318 &mut 0,
319 );
320 if os_result != KERN_SUCCESS {
321 return Err(KernelError::from(os_result).into());
322 }
323 }
324 Ok(())
325 }
326
327 fn recv_with_blocking_mode(
328 &self,
329 blocking_mode: BlockingMode,
330 ) -> Result<IpcMessage, MachError> {
331 select(self.port.get(), blocking_mode).and_then(|result| match result {
332 OsIpcSelectionResult::DataReceived(_, ipc_message) => Ok(ipc_message),
333 OsIpcSelectionResult::ChannelClosed(_) => Err(MachError::from(MACH_NOTIFY_NO_SENDERS)),
334 })
335 }
336
337 pub fn recv(&self) -> Result<IpcMessage, MachError> {
338 self.recv_with_blocking_mode(BlockingMode::Blocking)
339 }
340
341 pub fn try_recv(&self) -> Result<IpcMessage, MachError> {
342 self.recv_with_blocking_mode(BlockingMode::Nonblocking)
343 }
344
345 pub fn try_recv_timeout(&self, duration: Duration) -> Result<IpcMessage, MachError> {
346 self.recv_with_blocking_mode(BlockingMode::Timeout(duration))
347 }
348}
349
350enum SendData<'a> {
351 Inline(&'a [u8]),
352 OutOfLine(Option<OsIpcSharedMemory>),
353}
354
355lazy_static! {
356 static ref MAX_INLINE_SIZE: RwLock<usize> = RwLock::new(usize::MAX);
357}
358
359impl<'a> From<&'a [u8]> for SendData<'a> {
360 fn from(data: &'a [u8]) -> SendData<'a> {
361 let max_inline_size = *MAX_INLINE_SIZE.read().unwrap();
362 if data.len() >= max_inline_size {
363 SendData::OutOfLine(Some(OsIpcSharedMemory::from_bytes(data)))
366 } else {
367 SendData::Inline(data)
368 }
369 }
370}
371
372impl<'a> SendData<'a> {
373 fn take_shared_memory(&mut self) -> Option<OsIpcSharedMemory> {
374 match *self {
375 SendData::Inline(_) => None,
376 SendData::OutOfLine(ref mut data) => data.take(),
377 }
378 }
379
380 fn is_inline(&self) -> bool {
381 match *self {
382 SendData::Inline(_) => true,
383 SendData::OutOfLine(_) => false,
384 }
385 }
386
387 fn inline_data(&self) -> &[u8] {
388 match *self {
389 SendData::Inline(data) => data,
390 SendData::OutOfLine(_) => &[],
391 }
392 }
393}
394
395#[derive(PartialEq, Debug)]
396pub struct OsIpcSender {
397 port: mach_port_t,
398 nosync_marker: PhantomData<Cell<()>>,
404}
405
406impl Drop for OsIpcSender {
407 fn drop(&mut self) {
408 if self.port == MACH_PORT_NULL {
409 return;
410 }
411 deallocate_mach_port(self.port);
412 }
413}
414
415impl Clone for OsIpcSender {
416 fn clone(&self) -> OsIpcSender {
417 let mut cloned_port = self.port;
418 if cloned_port != MACH_PORT_NULL {
419 match mach_port_mod_addref(cloned_port, MACH_PORT_RIGHT_SEND) {
420 Ok(()) => (),
421 Err(KernelError::InvalidRight) => cloned_port = MACH_PORT_NULL,
422 Err(error) => panic!("mach_port_mod_refs(1, {}) failed: {:?}", cloned_port, error),
423 }
424 }
425 OsIpcSender {
426 port: cloned_port,
427 nosync_marker: PhantomData,
428 }
429 }
430}
431
432impl OsIpcSender {
433 fn from_name(port: mach_port_t) -> OsIpcSender {
434 OsIpcSender {
435 port,
436 nosync_marker: PhantomData,
437 }
438 }
439
440 pub fn connect(name: String) -> Result<OsIpcSender, MachError> {
441 unsafe {
442 let mut bootstrap_port = 0;
443 let os_result = mach_sys::task_get_special_port(
444 mach_task_self(),
445 TASK_BOOTSTRAP_PORT,
446 &mut bootstrap_port,
447 );
448 if os_result != KERN_SUCCESS {
449 return Err(KernelError::from(os_result).into());
450 }
451
452 let mut port = 0;
453 let c_name = CString::new(name).unwrap();
454 let os_result = bootstrap_look_up(bootstrap_port, c_name.as_ptr(), &mut port);
455 if os_result == BOOTSTRAP_SUCCESS {
456 Ok(OsIpcSender::from_name(port))
457 } else {
458 Err(MachError::from(os_result))
459 }
460 }
461 }
462
463 pub fn get_max_fragment_size() -> usize {
464 usize::MAX
465 }
466
467 pub fn send(
468 &self,
469 data: &[u8],
470 ports: Vec<OsIpcChannel>,
471 mut shared_memory_regions: Vec<OsIpcSharedMemory>,
472 ) -> Result<(), MachError> {
473 let mut data = SendData::from(data);
474 if let Some(data) = data.take_shared_memory() {
475 shared_memory_regions.push(data);
476 }
477
478 unsafe {
479 let size = Message::size_of(&data, ports.len(), shared_memory_regions.len());
480 let message = libc::malloc(size as size_t) as *mut Message;
481 (*message).header.msgh_bits = (MACH_MSG_TYPE_COPY_SEND as u32) | MACH_MSGH_BITS_COMPLEX;
482 (*message).header.msgh_size = size as u32;
483 (*message).header.msgh_local_port = MACH_PORT_NULL;
484 (*message).header.msgh_remote_port = self.port;
485 (*message).header.msgh_id = 0;
486 (*message).body.msgh_descriptor_count =
487 (ports.len() + shared_memory_regions.len()) as u32;
488
489 let mut port_descriptor_dest = message.offset(1) as *mut mach_msg_port_descriptor_t;
490 for outgoing_port in &ports {
491 (*port_descriptor_dest).name = outgoing_port.port();
492 (*port_descriptor_dest).pad1 = 0;
493
494 (*port_descriptor_dest).set_disposition(match *outgoing_port {
495 OsIpcChannel::Sender(_) => MACH_MSG_TYPE_MOVE_SEND,
496 OsIpcChannel::Receiver(_) => MACH_MSG_TYPE_MOVE_RECEIVE,
497 });
498
499 (*port_descriptor_dest).set_type(MACH_MSG_PORT_DESCRIPTOR);
500 port_descriptor_dest = port_descriptor_dest.offset(1);
501 }
502
503 let mut shared_memory_descriptor_dest =
504 port_descriptor_dest as *mut mach_msg_ool_descriptor_t;
505 for shared_memory_region in &shared_memory_regions {
506 (*shared_memory_descriptor_dest).address =
507 shared_memory_region.as_ptr() as *const c_void as *mut c_void;
508 (*shared_memory_descriptor_dest).size = shared_memory_region.len() as u32;
509 (*shared_memory_descriptor_dest).set_deallocate(1);
510 (*shared_memory_descriptor_dest).set_copy(MACH_MSG_VIRTUAL_COPY);
511 (*shared_memory_descriptor_dest).set_type(MACH_MSG_OOL_DESCRIPTOR);
512 shared_memory_descriptor_dest = shared_memory_descriptor_dest.offset(1);
513 }
514
515 let is_inline_dest = shared_memory_descriptor_dest as *mut bool;
516 *is_inline_dest = data.is_inline();
517 if data.is_inline() {
518 *((message as *mut u8).offset(size as isize - 4) as *mut u32) = 0;
520
521 let data = data.inline_data();
522 let data_size = data.len();
523 let padding_start = is_inline_dest.offset(1) as *mut u8;
524 let padding_count = Message::payload_padding(padding_start as usize);
525 padding_start.write_bytes(0, padding_count);
527 let data_size_dest = padding_start.add(padding_count) as *mut usize;
528 *data_size_dest = data_size;
529
530 let data_dest = data_size_dest.offset(1) as *mut u8;
531 ptr::copy_nonoverlapping(data.as_ptr(), data_dest, data_size);
532 }
533
534 let os_result = mach_sys::mach_msg(
535 message as *mut _,
536 MACH_SEND_MSG,
537 (*message).header.msgh_size,
538 0,
539 MACH_PORT_NULL,
540 MACH_MSG_TIMEOUT_NONE,
541 MACH_PORT_NULL,
542 );
543 libc::free(message as *mut _);
544 if os_result == MACH_SEND_TOO_LARGE && data.is_inline() {
545 let inline_data = data.inline_data();
546 {
547 let mut max_inline_size = MAX_INLINE_SIZE.write().unwrap();
548 let inline_len = inline_data.len();
549 if inline_len < *max_inline_size {
550 *max_inline_size = inline_len;
551 }
552 }
553 return self.send(inline_data, ports, shared_memory_regions);
554 }
555 if os_result != MACH_MSG_SUCCESS {
556 return Err(MachError::from(os_result));
557 }
558 for outgoing_port in ports {
559 mem::forget(outgoing_port);
560 }
561 for shared_memory_region in shared_memory_regions {
562 mem::forget(shared_memory_region);
563 }
564 Ok(())
565 }
566 }
567}
568
569pub enum OsIpcChannel {
570 Sender(OsIpcSender),
571 Receiver(OsIpcReceiver),
572}
573
574impl OsIpcChannel {
575 fn port(&self) -> mach_port_t {
576 match *self {
577 OsIpcChannel::Sender(ref sender) => sender.port,
578 OsIpcChannel::Receiver(ref receiver) => receiver.port.get(),
579 }
580 }
581}
582
583#[derive(PartialEq, Debug)]
584pub struct OsOpaqueIpcChannel {
585 port: mach_port_t,
586}
587
588impl Drop for OsOpaqueIpcChannel {
589 fn drop(&mut self) {
590 debug_assert!(self.port == MACH_PORT_NULL);
592 }
593}
594
595impl OsOpaqueIpcChannel {
596 fn from_name(name: mach_port_t) -> OsOpaqueIpcChannel {
597 OsOpaqueIpcChannel { port: name }
598 }
599
600 pub fn to_sender(&mut self) -> OsIpcSender {
601 OsIpcSender {
602 port: mem::replace(&mut self.port, MACH_PORT_NULL),
603 nosync_marker: PhantomData,
604 }
605 }
606
607 pub fn to_receiver(&mut self) -> OsIpcReceiver {
608 OsIpcReceiver::from_name(mem::replace(&mut self.port, MACH_PORT_NULL))
609 }
610}
611
612pub struct OsIpcReceiverSet {
613 port: mach_port_t,
614 ports: Vec<mach_port_t>,
615}
616
617impl OsIpcReceiverSet {
618 pub fn new() -> Result<OsIpcReceiverSet, MachError> {
619 let port = mach_port_allocate(MACH_PORT_RIGHT_PORT_SET)?;
620 Ok(OsIpcReceiverSet {
621 port,
622 ports: vec![],
623 })
624 }
625
626 pub fn add(&mut self, receiver: OsIpcReceiver) -> Result<u64, MachError> {
627 mach_port_move_member(receiver.extract_port(), self.port)?;
628 let receiver_port = receiver.consume_port();
629 self.ports.push(receiver_port);
630 Ok(receiver_port as u64)
631 }
632
633 pub fn select(&mut self) -> Result<Vec<OsIpcSelectionResult>, MachError> {
634 select(self.port, BlockingMode::Blocking).map(|result| vec![result])
635 }
636}
637
638impl Drop for OsIpcReceiverSet {
639 fn drop(&mut self) {
640 for port in &self.ports {
641 mach_port_mod_release(*port, MACH_PORT_RIGHT_RECEIVE).unwrap();
642 }
643 mach_port_mod_release(self.port, MACH_PORT_RIGHT_PORT_SET).unwrap();
644 }
645}
646
647pub enum OsIpcSelectionResult {
648 DataReceived(u64, IpcMessage),
649 ChannelClosed(u64),
650}
651
652impl OsIpcSelectionResult {
653 pub fn unwrap(self) -> (u64, IpcMessage) {
654 match self {
655 OsIpcSelectionResult::DataReceived(id, ipc_message) => (id, ipc_message),
656 OsIpcSelectionResult::ChannelClosed(id) => {
657 panic!("OsIpcSelectionResult::unwrap(): receiver ID {id} was closed!")
658 },
659 }
660 }
661}
662
663#[derive(Copy, Clone)]
664enum BlockingMode {
665 Blocking,
666 Nonblocking,
667 Timeout(Duration),
668}
669
670fn select(
671 port: mach_port_t,
672 blocking_mode: BlockingMode,
673) -> Result<OsIpcSelectionResult, MachError> {
674 debug_assert!(port != MACH_PORT_NULL);
675 unsafe {
676 let mut buffer = [0; SMALL_MESSAGE_SIZE];
677 let mut allocated_buffer = None;
678 setup_receive_buffer(&mut buffer, port);
679 let mut message = &mut buffer[0] as *mut _ as *mut Message;
680 let (flags, timeout) = match blocking_mode {
681 BlockingMode::Blocking => (MACH_RCV_MSG | MACH_RCV_LARGE, MACH_MSG_TIMEOUT_NONE),
682 BlockingMode::Nonblocking => (MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, 0),
683 BlockingMode::Timeout(duration) => duration
684 .as_millis()
685 .try_into()
686 .map(|ms| (MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIMEOUT, ms))
687 .unwrap_or((MACH_RCV_MSG | MACH_RCV_LARGE, MACH_MSG_TIMEOUT_NONE)),
688 };
689 match mach_sys::mach_msg(
690 message as *mut _,
691 flags,
692 0,
693 (*message).header.msgh_size,
694 port,
695 timeout,
696 MACH_PORT_NULL,
697 ) {
698 MACH_RCV_TOO_LARGE => {
699 let max_trailer_size =
700 mem::size_of::<mach_sys::mach_msg_max_trailer_t>() as mach_sys::mach_msg_size_t;
701 let mut actual_size = (*message).header.msgh_size + max_trailer_size;
703 loop {
704 allocated_buffer = Some(libc::malloc(actual_size as size_t));
705 setup_receive_buffer(
706 slice::from_raw_parts_mut(
707 allocated_buffer.unwrap() as *mut u8,
708 actual_size as usize,
709 ),
710 port,
711 );
712 message = allocated_buffer.unwrap() as *mut Message;
713 match mach_sys::mach_msg(
714 message as *mut _,
715 flags,
716 0,
717 actual_size,
718 port,
719 timeout,
720 MACH_PORT_NULL,
721 ) {
722 MACH_MSG_SUCCESS => break,
723 MACH_RCV_TOO_LARGE => {
724 actual_size = (*message).header.msgh_size + max_trailer_size;
725 libc::free(allocated_buffer.unwrap() as *mut _);
726 continue;
727 },
728 os_result => {
729 libc::free(allocated_buffer.unwrap() as *mut _);
730 return Err(MachError::from(os_result));
731 },
732 }
733 }
734 },
735 MACH_MSG_SUCCESS => {},
736 os_result => return Err(MachError::from(os_result)),
737 }
738
739 let local_port = (*message).header.msgh_local_port;
740 if (*message).header.msgh_id == MACH_NOTIFY_NO_SENDERS {
741 return Ok(OsIpcSelectionResult::ChannelClosed(local_port as u64));
742 }
743
744 let (mut ports, mut shared_memory_regions) = (Vec::new(), Vec::new());
745 let mut port_descriptor = message.offset(1) as *mut mach_msg_port_descriptor_t;
746 let mut descriptors_remaining = (*message).body.msgh_descriptor_count;
747 while descriptors_remaining > 0 {
748 if (*port_descriptor).type_() != MACH_MSG_PORT_DESCRIPTOR {
749 break;
750 }
751 ports.push(OsOpaqueIpcChannel::from_name((*port_descriptor).name));
752 port_descriptor = port_descriptor.offset(1);
753 descriptors_remaining -= 1;
754 }
755
756 let mut shared_memory_descriptor = port_descriptor as *mut mach_msg_ool_descriptor_t;
757 while descriptors_remaining > 0 {
758 debug_assert!((*shared_memory_descriptor).type_() == MACH_MSG_OOL_DESCRIPTOR);
759 shared_memory_regions.push(OsIpcSharedMemory::from_raw_parts(
760 (*shared_memory_descriptor).address as *mut u8,
761 (*shared_memory_descriptor).size as usize,
762 ));
763 shared_memory_descriptor = shared_memory_descriptor.offset(1);
764 descriptors_remaining -= 1;
765 }
766
767 let has_inline_data_ptr = shared_memory_descriptor as *mut bool;
768 let has_inline_data = *has_inline_data_ptr;
769 let payload = if has_inline_data {
770 let padding_start = has_inline_data_ptr.offset(1) as *mut u8;
771 let padding_count = Message::payload_padding(padding_start as usize);
772 let payload_size_ptr = padding_start.add(padding_count) as *mut usize;
773 let payload_size = *payload_size_ptr;
774 let max_payload_size = message as usize + ((*message).header.msgh_size as usize)
775 - (shared_memory_descriptor as usize);
776 assert!(payload_size <= max_payload_size);
777 let payload_ptr = payload_size_ptr.offset(1) as *mut u8;
778 slice::from_raw_parts(payload_ptr, payload_size).to_vec()
779 } else {
780 let ool_payload = shared_memory_regions
781 .pop()
782 .expect("Missing OOL shared memory region");
783 ool_payload.to_vec()
784 };
785
786 if let Some(allocated_buffer) = allocated_buffer {
787 libc::free(allocated_buffer)
788 }
789
790 Ok(OsIpcSelectionResult::DataReceived(
791 local_port as u64,
792 IpcMessage::new(payload, ports, shared_memory_regions),
793 ))
794 }
795}
796
797pub struct OsIpcOneShotServer {
798 receiver: OsIpcReceiver,
799 name: String,
800 registration_port: u32,
801}
802
803impl Drop for OsIpcOneShotServer {
804 fn drop(&mut self) {
805 let _ = OsIpcReceiver::unregister_global_name(std::mem::take(&mut self.name));
806 deallocate_mach_port(self.registration_port);
807 }
808}
809
810impl OsIpcOneShotServer {
811 pub fn new() -> Result<(OsIpcOneShotServer, String), MachError> {
812 let receiver = OsIpcReceiver::new()?;
813 let (registration_port, name) = receiver.register_bootstrap_name()?;
814 Ok((
815 OsIpcOneShotServer {
816 receiver,
817 name: name.clone(),
818 registration_port,
819 },
820 name,
821 ))
822 }
823
824 pub fn accept(self) -> Result<(OsIpcReceiver, IpcMessage), MachError> {
825 let ipc_message = self.receiver.recv()?;
826 Ok((self.receiver.consume(), ipc_message))
827 }
828}
829
830pub struct OsIpcSharedMemory {
831 ptr: *mut u8,
832 length: usize,
833}
834
835unsafe impl Send for OsIpcSharedMemory {}
836unsafe impl Sync for OsIpcSharedMemory {}
837
838impl Drop for OsIpcSharedMemory {
839 fn drop(&mut self) {
840 if !self.ptr.is_null() {
841 unsafe {
842 assert!(
843 mach_sys::vm_deallocate(mach_task_self(), self.ptr as usize, self.length)
844 == KERN_SUCCESS
845 );
846 }
847 }
848 }
849}
850
851impl Clone for OsIpcSharedMemory {
852 fn clone(&self) -> OsIpcSharedMemory {
853 let mut address = 0;
854 unsafe {
855 if !self.ptr.is_null() {
856 let err = mach_sys::vm_remap(
857 mach_task_self(),
858 &mut address,
859 self.length,
860 0,
861 1,
862 mach_task_self(),
863 self.ptr as usize,
864 0,
865 &mut 0,
866 &mut 0,
867 VM_INHERIT_SHARE,
868 );
869 assert!(err == KERN_SUCCESS);
870 }
871 OsIpcSharedMemory::from_raw_parts(address as *mut u8, self.length)
872 }
873 }
874}
875
876impl PartialEq for OsIpcSharedMemory {
877 fn eq(&self, other: &OsIpcSharedMemory) -> bool {
878 **self == **other
879 }
880}
881
882impl Debug for OsIpcSharedMemory {
883 fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
884 (**self).fmt(formatter)
885 }
886}
887
888impl Deref for OsIpcSharedMemory {
889 type Target = [u8];
890
891 #[inline]
892 fn deref(&self) -> &[u8] {
893 if self.ptr.is_null() && self.length > 0 {
894 panic!("attempted to access a consumed `OsIpcSharedMemory`")
895 }
896 unsafe { slice::from_raw_parts(self.ptr, self.length) }
897 }
898}
899
900impl OsIpcSharedMemory {
901 unsafe fn from_raw_parts(ptr: *mut u8, length: usize) -> OsIpcSharedMemory {
902 OsIpcSharedMemory { ptr, length }
903 }
904
905 pub fn from_byte(byte: u8, length: usize) -> OsIpcSharedMemory {
906 unsafe {
907 let address = allocate_vm_pages(length);
908 for element in slice::from_raw_parts_mut(address, length) {
909 *element = byte;
910 }
911 OsIpcSharedMemory::from_raw_parts(address, length)
912 }
913 }
914
915 pub fn from_bytes(bytes: &[u8]) -> OsIpcSharedMemory {
916 unsafe {
917 let address = allocate_vm_pages(bytes.len());
918 ptr::copy_nonoverlapping(bytes.as_ptr(), address, bytes.len());
919 OsIpcSharedMemory::from_raw_parts(address, bytes.len())
920 }
921 }
922}
923
924unsafe fn allocate_vm_pages(length: usize) -> *mut u8 {
925 let mut address = 0;
926 let result = mach_sys::vm_allocate(mach_task_self(), &mut address, length, 1);
927 if result != KERN_SUCCESS {
928 panic!("`vm_allocate()` failed: {}", result);
929 }
930 address as *mut u8
931}
932
933unsafe fn setup_receive_buffer(buffer: &mut [u8], port_name: mach_port_t) {
934 let message = buffer.as_mut_ptr() as *mut mach_msg_header_t;
935 (*message).msgh_local_port = port_name;
936 (*message).msgh_size = buffer.len() as u32
937}
938
939unsafe fn mach_task_self() -> mach_port_t {
940 mach_task_self_
941}
942
943fn deallocate_mach_port(port: mach_port_t) {
944 let err = unsafe { mach_port_deallocate(mach_task_self(), port) };
949 if err != KERN_SUCCESS {
950 panic!("mach_port_deallocate({}) failed: {:?}", port, err);
951 }
952}
953
954#[repr(C)]
955struct Message {
956 header: mach_msg_header_t,
957 body: mach_msg_body_t,
958}
959
960impl Message {
961 fn payload_padding(unaligned: usize) -> usize {
962 ((unaligned + 7) & !7) - unaligned }
964
965 fn size_of(data: &SendData, port_length: usize, shared_memory_length: usize) -> usize {
966 let mut size = mem::size_of::<Message>()
967 + mem::size_of::<mach_msg_port_descriptor_t>() * port_length
968 + mem::size_of::<mach_msg_ool_descriptor_t>() * shared_memory_length
969 + mem::size_of::<bool>();
970
971 if data.is_inline() {
972 size += Self::payload_padding(size);
975 size += mem::size_of::<usize>() + data.inline_data().len();
976 }
977
978 if (size & 0x3) != 0 {
980 size = (size & !0x3) + 4;
981 }
982
983 size
984 }
985}
986
987#[derive(Clone, Copy, Debug, PartialEq)]
988pub enum KernelError {
989 Success,
990 NoSpace,
991 InvalidName,
992 InvalidRight,
993 InvalidValue,
994 InvalidCapability,
995 UrefsOverflow,
996 NotInSet,
997 Unknown(kern_return_t),
998}
999
1000impl fmt::Display for KernelError {
1001 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1002 match *self {
1003 KernelError::Success => write!(fmt, "Success."),
1004 KernelError::NoSpace => write!(fmt, "No room in IPC name space for another right."),
1005 KernelError::InvalidName => write!(fmt, "Name doesn't denote a right in the task."),
1006 KernelError::InvalidRight => {
1007 write!(fmt, "Name denotes a right, but not an appropriate right.")
1008 },
1009 KernelError::InvalidValue => write!(fmt, "Blatant range error."),
1010 KernelError::InvalidCapability => {
1011 write!(fmt, "The supplied (port) capability is improper.")
1012 },
1013 KernelError::UrefsOverflow => {
1014 write!(fmt, "Operation would overflow limit on user-references.")
1015 },
1016 KernelError::NotInSet => write!(fmt, "Receive right is not a member of a port set."),
1017 KernelError::Unknown(code) => write!(fmt, "Unknown kernel error: {:x}", code),
1018 }
1019 }
1020}
1021
1022impl StdError for KernelError {}
1023
1024impl From<kern_return_t> for KernelError {
1025 fn from(code: kern_return_t) -> KernelError {
1026 match code {
1027 KERN_SUCCESS => KernelError::Success,
1028 KERN_NO_SPACE => KernelError::NoSpace,
1029 KERN_INVALID_NAME => KernelError::InvalidName,
1030 KERN_INVALID_RIGHT => KernelError::InvalidRight,
1031 KERN_INVALID_VALUE => KernelError::InvalidValue,
1032 KERN_INVALID_CAPABILITY => KernelError::InvalidCapability,
1033 KERN_UREFS_OVERFLOW => KernelError::UrefsOverflow,
1034 KERN_NOT_IN_SET => KernelError::NotInSet,
1035 code => KernelError::Unknown(code),
1036 }
1037 }
1038}
1039
1040#[derive(Clone, Copy, Debug, PartialEq)]
1041pub enum MachError {
1042 Success,
1043 Kernel(KernelError),
1044 IpcSpace,
1045 VmSpace,
1046 IpcKernel,
1047 VmKernel,
1048 RcvInProgress,
1049 RcvInvalidName,
1050 RcvTimedOut,
1051 RcvTooLarge,
1052 RcvInterrupted,
1053 RcvPortChanged,
1054 RcvInvalidNotify,
1055 RcvInvalidData,
1056 RcvPortDied,
1057 RcvInSet,
1058 RcvHeaderError,
1059 RcvBodyError,
1060 RcvInvalidType,
1061 RcvScatterSmall,
1062 RcvInvalidTrailer,
1063 RcvInProgressTimed,
1064 NotifyNoSenders,
1065 SendInterrupted,
1066 SendInvalidData,
1067 SendInvalidDest,
1068 SendInvalidHeader,
1069 SendInvalidMemory,
1070 SendInvalidNotify,
1071 SendInvalidReply,
1072 SendInvalidRight,
1073 SendInvalidRtOolSize,
1074 SendInvalidTrailer,
1075 SendInvalidType,
1076 SendInvalidVoucher,
1077 SendInProgress,
1078 SendMsgTooSmall,
1079 SendNoBuffer,
1080 SendTimedOut,
1081 SendTooLarge,
1082 Unknown(mach_msg_return_t),
1083}
1084
1085impl MachError {
1086 #[allow(dead_code)]
1087 pub fn channel_is_closed(&self) -> bool {
1088 *self == MachError::NotifyNoSenders
1089 }
1090}
1091
1092impl fmt::Display for MachError {
1093 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1094 match *self {
1095 MachError::Success => write!(fmt, "Success"),
1096 MachError::Kernel(kernel_error) => fmt::Display::fmt(&kernel_error, fmt),
1097 MachError::IpcSpace => write!(
1098 fmt,
1099 "No room in IPC name space for another capability name."
1100 ),
1101 MachError::VmSpace => {
1102 write!(fmt, "No room in VM address space for out-of-line memory.")
1103 },
1104 MachError::IpcKernel => {
1105 write!(fmt, "Kernel resource shortage handling an IPC capability.")
1106 },
1107 MachError::VmKernel => {
1108 write!(fmt, "Kernel resource shortage handling out-of-line memory.")
1109 },
1110 MachError::SendInProgress => {
1111 write!(fmt, "Thread is waiting to send. (Internal use only.)")
1112 },
1113 MachError::SendInvalidData => write!(fmt, "Bogus in-line data."),
1114 MachError::SendInvalidDest => write!(fmt, "Bogus destination port."),
1115 MachError::SendTimedOut => write!(fmt, "Message not sent before timeout expired."),
1116 MachError::SendInvalidVoucher => write!(fmt, "Bogus voucher port."),
1117 MachError::SendInterrupted => write!(fmt, "Software interrupt."),
1118 MachError::SendMsgTooSmall => write!(fmt, "Data doesn't contain a complete message."),
1119 MachError::SendInvalidReply => write!(fmt, "Bogus reply port."),
1120 MachError::SendInvalidRight => write!(fmt, "Bogus port rights in the message body."),
1121 MachError::SendInvalidNotify => write!(fmt, "Bogus notify port argument."),
1122 MachError::SendInvalidMemory => write!(fmt, "Invalid out-of-line memory pointer."),
1123 MachError::SendNoBuffer => write!(fmt, "No message buffer is available."),
1124 MachError::SendTooLarge => write!(fmt, "Send is too large for port"),
1125 MachError::SendInvalidType => write!(fmt, "Invalid msg-type specification."),
1126 MachError::SendInvalidHeader => write!(fmt, "A field in the header had a bad value."),
1127 MachError::SendInvalidTrailer => {
1128 write!(fmt, "The trailer to be sent does not match kernel format.")
1129 },
1130 MachError::SendInvalidRtOolSize => {
1131 write!(fmt, "compatibility: no longer a returned error")
1132 },
1133 MachError::RcvInProgress => {
1134 write!(fmt, "Thread is waiting for receive. (Internal use only.)")
1135 },
1136 MachError::RcvInvalidName => write!(fmt, "Bogus name for receive port/port-set."),
1137 MachError::RcvTimedOut => write!(fmt, "Didn't get a message within the timeout value."),
1138 MachError::RcvTooLarge => {
1139 write!(fmt, "Message buffer is not large enough for inline data.")
1140 },
1141 MachError::RcvInterrupted => write!(fmt, "Software interrupt."),
1142 MachError::RcvPortChanged => write!(fmt, "compatibility: no longer a returned error"),
1143 MachError::RcvInvalidNotify => write!(fmt, "Bogus notify port argument."),
1144 MachError::RcvInvalidData => write!(fmt, "Bogus message buffer for inline data."),
1145 MachError::RcvPortDied => write!(fmt, "Port/set was sent away/died during receive."),
1146 MachError::RcvInSet => write!(fmt, "compatibility: no longer a returned error"),
1147 MachError::RcvHeaderError => {
1148 write!(fmt, "Error receiving message header. See special bits.")
1149 },
1150 MachError::RcvBodyError => {
1151 write!(fmt, "Error receiving message body. See special bits.")
1152 },
1153 MachError::RcvInvalidType => {
1154 write!(fmt, "Invalid msg-type specification in scatter list.")
1155 },
1156 MachError::RcvScatterSmall => {
1157 write!(fmt, "Out-of-line overwrite region is not large enough")
1158 },
1159 MachError::RcvInvalidTrailer => write!(
1160 fmt,
1161 "trailer type or number of trailer elements not supported"
1162 ),
1163 MachError::RcvInProgressTimed => write!(
1164 fmt,
1165 "Waiting for receive with timeout. (Internal use only.)"
1166 ),
1167 MachError::NotifyNoSenders => write!(fmt, "No senders exist for this port."),
1168 MachError::Unknown(mach_error_number) => {
1169 write!(fmt, "Unknown Mach error: {:x}", mach_error_number)
1170 },
1171 }
1172 }
1173}
1174
1175impl StdError for MachError {}
1176
1177impl From<MachError> for bincode::Error {
1178 fn from(mach_error: MachError) -> Self {
1179 io::Error::from(mach_error).into()
1180 }
1181}
1182
1183impl From<mach_msg_return_t> for MachError {
1184 fn from(code: mach_msg_return_t) -> MachError {
1185 match code {
1186 MACH_MSG_SUCCESS => MachError::Success,
1187 MACH_MSG_IPC_KERNEL => MachError::IpcKernel,
1188 MACH_MSG_IPC_SPACE => MachError::IpcSpace,
1189 MACH_MSG_VM_KERNEL => MachError::VmKernel,
1190 MACH_MSG_VM_SPACE => MachError::VmSpace,
1191 MACH_RCV_BODY_ERROR => MachError::RcvBodyError,
1192 MACH_RCV_HEADER_ERROR => MachError::RcvHeaderError,
1193 MACH_RCV_INTERRUPTED => MachError::RcvInterrupted,
1194 MACH_RCV_INVALID_DATA => MachError::RcvInvalidData,
1195 MACH_RCV_INVALID_NAME => MachError::RcvInvalidName,
1196 MACH_RCV_INVALID_NOTIFY => MachError::RcvInvalidNotify,
1197 MACH_RCV_INVALID_TRAILER => MachError::RcvInvalidTrailer,
1198 MACH_RCV_INVALID_TYPE => MachError::RcvInvalidType,
1199 MACH_RCV_IN_PROGRESS => MachError::RcvInProgress,
1200 MACH_RCV_IN_PROGRESS_TIMED => MachError::RcvInProgressTimed,
1201 MACH_RCV_IN_SET => MachError::RcvInSet,
1202 MACH_RCV_PORT_CHANGED => MachError::RcvPortChanged,
1203 MACH_RCV_PORT_DIED => MachError::RcvPortDied,
1204 MACH_RCV_SCATTER_SMALL => MachError::RcvScatterSmall,
1205 MACH_RCV_TIMED_OUT => MachError::RcvTimedOut,
1206 MACH_RCV_TOO_LARGE => MachError::RcvTooLarge,
1207 MACH_NOTIFY_NO_SENDERS => MachError::NotifyNoSenders,
1208 MACH_SEND_INTERRUPTED => MachError::SendInterrupted,
1209 MACH_SEND_INVALID_DATA => MachError::SendInvalidData,
1210 MACH_SEND_INVALID_DEST => MachError::SendInvalidDest,
1211 MACH_SEND_INVALID_HEADER => MachError::SendInvalidHeader,
1212 MACH_SEND_INVALID_MEMORY => MachError::SendInvalidMemory,
1213 MACH_SEND_INVALID_NOTIFY => MachError::SendInvalidNotify,
1214 MACH_SEND_INVALID_REPLY => MachError::SendInvalidReply,
1215 MACH_SEND_INVALID_RIGHT => MachError::SendInvalidRight,
1216 MACH_SEND_INVALID_RT_OOL_SIZE => MachError::SendInvalidRtOolSize,
1217 MACH_SEND_INVALID_TRAILER => MachError::SendInvalidTrailer,
1218 MACH_SEND_INVALID_TYPE => MachError::SendInvalidType,
1219 MACH_SEND_INVALID_VOUCHER => MachError::SendInvalidVoucher,
1220 MACH_SEND_IN_PROGRESS => MachError::SendInProgress,
1221 MACH_SEND_MSG_TOO_SMALL => MachError::SendMsgTooSmall,
1222 MACH_SEND_NO_BUFFER => MachError::SendNoBuffer,
1223 MACH_SEND_TIMED_OUT => MachError::SendTimedOut,
1224 MACH_SEND_TOO_LARGE => MachError::SendTooLarge,
1225 code => MachError::Unknown(code),
1226 }
1227 }
1228}
1229
1230impl From<KernelError> for MachError {
1231 fn from(kernel_error: KernelError) -> MachError {
1232 MachError::Kernel(kernel_error)
1233 }
1234}
1235
1236impl From<MachError> for ipc::TryRecvError {
1237 fn from(error: MachError) -> Self {
1238 match error {
1239 MachError::NotifyNoSenders => ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected),
1240 MachError::RcvTimedOut => ipc::TryRecvError::Empty,
1241 e => ipc::TryRecvError::IpcError(ipc::IpcError::Io(io::Error::from(e))),
1242 }
1243 }
1244}
1245
1246impl From<MachError> for ipc::IpcError {
1247 fn from(error: MachError) -> Self {
1248 match error {
1249 MachError::NotifyNoSenders => ipc::IpcError::Disconnected,
1250 e => ipc::IpcError::Io(io::Error::from(e)),
1251 }
1252 }
1253}
1254
1255impl From<MachError> for io::Error {
1256 fn from(mach_error: MachError) -> io::Error {
1258 let kind = match mach_error {
1259 MachError::Success => io::ErrorKind::Other,
1260 MachError::Kernel(KernelError::Success) => io::ErrorKind::Other,
1261 MachError::Kernel(KernelError::NoSpace) => io::ErrorKind::Other,
1262 MachError::Kernel(KernelError::InvalidName) => io::ErrorKind::Other,
1263 MachError::Kernel(KernelError::InvalidRight) => io::ErrorKind::Other,
1264 MachError::Kernel(KernelError::InvalidValue) => io::ErrorKind::Other,
1265 MachError::Kernel(KernelError::InvalidCapability) => io::ErrorKind::Other,
1266 MachError::Kernel(KernelError::UrefsOverflow) => io::ErrorKind::Other,
1267 MachError::Kernel(KernelError::NotInSet) => io::ErrorKind::Other,
1268 MachError::Kernel(KernelError::Unknown(_)) => io::ErrorKind::Other,
1269 MachError::IpcSpace => io::ErrorKind::Other,
1270 MachError::VmSpace => io::ErrorKind::Other,
1271 MachError::IpcKernel => io::ErrorKind::Other,
1272 MachError::VmKernel => io::ErrorKind::Other,
1273 MachError::SendInProgress => io::ErrorKind::Interrupted,
1274 MachError::SendInvalidData => io::ErrorKind::InvalidData,
1275 MachError::SendInvalidDest => io::ErrorKind::NotFound,
1276 MachError::SendTimedOut => io::ErrorKind::TimedOut,
1277 MachError::SendInvalidVoucher => io::ErrorKind::NotFound,
1278 MachError::SendInterrupted => io::ErrorKind::Interrupted,
1279 MachError::SendMsgTooSmall => io::ErrorKind::InvalidData,
1280 MachError::SendInvalidReply => io::ErrorKind::InvalidInput,
1281 MachError::SendInvalidRight => io::ErrorKind::InvalidInput,
1282 MachError::SendInvalidNotify => io::ErrorKind::InvalidInput,
1283 MachError::SendInvalidMemory => io::ErrorKind::InvalidInput,
1284 MachError::SendNoBuffer => io::ErrorKind::Other,
1285 MachError::SendTooLarge => io::ErrorKind::InvalidData,
1286 MachError::SendInvalidType => io::ErrorKind::InvalidInput,
1287 MachError::SendInvalidHeader => io::ErrorKind::InvalidInput,
1288 MachError::SendInvalidTrailer => io::ErrorKind::InvalidData,
1289 MachError::SendInvalidRtOolSize => io::ErrorKind::Other,
1290 MachError::RcvInProgress => io::ErrorKind::Interrupted,
1291 MachError::RcvInvalidName => io::ErrorKind::InvalidInput,
1292 MachError::RcvTimedOut => io::ErrorKind::TimedOut,
1293 MachError::RcvTooLarge => io::ErrorKind::InvalidInput,
1294 MachError::RcvInterrupted => io::ErrorKind::Interrupted,
1295 MachError::RcvPortChanged => io::ErrorKind::Other,
1296 MachError::RcvInvalidNotify => io::ErrorKind::InvalidInput,
1297 MachError::RcvInvalidData => io::ErrorKind::InvalidInput,
1298 MachError::RcvPortDied => io::ErrorKind::BrokenPipe,
1299 MachError::RcvInSet => io::ErrorKind::Other,
1300 MachError::RcvHeaderError => io::ErrorKind::Other,
1301 MachError::RcvBodyError => io::ErrorKind::Other,
1302 MachError::RcvInvalidType => io::ErrorKind::InvalidInput,
1303 MachError::RcvScatterSmall => io::ErrorKind::InvalidInput,
1304 MachError::RcvInvalidTrailer => io::ErrorKind::InvalidInput,
1305 MachError::RcvInProgressTimed => io::ErrorKind::Interrupted,
1306 MachError::NotifyNoSenders => io::ErrorKind::ConnectionReset,
1307 MachError::Unknown(_) => io::ErrorKind::Other,
1308 };
1309 io::Error::new(kind, mach_error)
1310 }
1311}
1312
1313extern "C" {
1314 fn bootstrap_register2(
1315 bp: mach_port_t,
1316 service_name: name_t,
1317 sp: mach_port_t,
1318 flags: u64,
1319 ) -> kern_return_t;
1320 fn bootstrap_look_up(
1321 bp: mach_port_t,
1322 service_name: name_t,
1323 sp: *mut mach_port_t,
1324 ) -> kern_return_t;
1325}