[WIP] A library to support using Mach ports on Darwin platforms

I'm currently developing a crate that provides primitives to manage userspace Mach port handles (aka names) and exchange Mach messages on Darwin platforms (only macOS and iOS for now). The plan is to eventually integrate it into tokio to provide asynchronous Mach port communications.

Why?

Mach ports are an IPC mechanism Darwin platforms use for IPC almost exclusively. Userspace daemons tend to use either XPC or Mach ports directly, all communication with the kernel drivers is done through the I/O Kit framework which is also based on Mach ports.

Currently wrappers for APIs avoided using Mach ports directly by using frameworks provided by Apple to avoid the complexity of Mach messages which is usually what you want, but this also has drawbacks:

  1. You can't use Rust's async capabilities. While you technically can use asynchronous interfaces, you're forced to either use Apple's event loops (libdispatch and CFRunLoop), but you can't use tokio or some other event loop. This complicates usage of some nice features like asynchronously waiting for devices to connect or detecting other system state changes. In case you decide to use these features anyway, you'll have to bridge the Apple's event loops with what you use adding an additional layer of complexity. Some I/O kit drivers only provide async interfaces which is also a pain. Having such a library is a first step to integration of Mach ports into mio and later tokio (this can be done using kqueue which is used by tokio on Darwin anyway).
  2. You're missing out on a great native IPC mechanism. Mach ports provide a lot of interesting capabilities like passing handles to certain system resources (which also happen to be represented by Mach ports) through messages or sharing virtual memory regions with copy-on-wriite semantics. It's also a nice way to build faster IPC channels on Darwin.

What's already there

Currently I've implemented a bare minimum required to exchange Mach messages and manage the names. The library can:

  1. Manage references to almost all kinds of port rights. Port sets are not supported currently.
  2. Build and send Mach messages with inline data and port descriptors. Out-of-line ports and data as well as guarded port descriptors are not supported currently.
  3. Receive and parse Mach messages with the same properties as in 2.

Open questions

  1. Handling OOL ports and data descriptors.
  2. Error handling. How to best handle unexpected errors returned from Mach APIs? Should it be different from the expected errors? What's the best error type design in that case (looking at msg::error module)?
  3. Guarded ports and how to best handle them.
  4. Various trailers and the types they expose. These can generally be skipped and won't be provided by the kernel unless the caller explicitly asks for that.
  5. AsRawName/IntoRawName traits design. Is it optimal?
  6. Some more advanced APIs like sending and receiving a message in one call to mach_msg.

Conclusion

I'd also like other suggestions, definitely open to name bikeshedding right now, suggestions on docs, anything.

3 Likes

This might be a better post for the users forum: https://users.rust-lang.org. This is more focused on the development of Rust itself, rather than tools and libraries implemented in Rust.

That said, I think this is a cool library (not having looked at the source), and agree that not enough stuff uses it in Rust... that said, it is hard to justify for cross-platform code a lot of the time.

Anyway, good luck with your library, but I think you might be in the wrong place.

1 Like

Thanks!

I thought it's the right place because this is kind of similar to handles on Windows which are a part of the standard library, but I agree this isn't something usable by cross-platform code as is.

Definitely supporting it in the stdlib is a larger question (and wouldn't be done via a third-party library, most likely).

In the short term I'm not in favor of it really. On Windows we have no choice, but most things work without need to reach for mach ports on Darwin platforms. We don't like exposing large API surfaces that would be behind cfg if we can help it either -- it's a real problem for maintenance of the stdlib.