Upgrade to Pro — share decks privately, control downloads, hide ads and more …

IPC on macOS

IPC on macOS

vashchenko

August 17, 2019
Tweet

More Decks by vashchenko

Other Decks in Programming

Transcript

  1. Before we dive in The Berkeley Software Distribution (BSD) is

    an operating system based on early Unix.
  2. Darwin forms the core set of components upon which macOS,

    iOS, watchOS, tvOS, iPadOS and audioOS are based
  3. The Mach port object is the underlying primitive used for

    all interprocess communication in macOS
  4. High-level macOS-specific 1. Apple Events 2. High-performance counterpart of Apple

    Events — CFMessagePort and friends 3. Distributed Notifications 4. Distributed objects (NSConnection and friends) 5. XPC (C API and Objective-C API)
  5. BSD Sockets You can implement inter-process communication using BSD sockets

    via: — POSIX API (socket() and friends) — Core Foundation API (CFSocket and friends; also used for networking)
  6. BSD Pipes One-way communication. 2 types: — Unnamed pipe (example:

    command line shell cat magic.txt | grep -e Gwendoyln sends the contents of magic.text to the grep command) — Named pipe is a special type of file without any content on filesystem
  7. BSD signals Usually a process terminates on receiving a signal.

    But it can implement a signal handler function to override this behaviour. Used by OS kernel to tell the process about an exception (like division by 0). Command line kill command is another example of using signals. The signal namespace is just one integer, so collisions are very possible. Not recommended to use signals for IPC.
  8. Shared Memory + Semaphores A process allocates a memory region,

    that can be read and written by other processes. Advantages: * data is never copied * any process with appropriate permission can read and write Disadvantage: * fragile—if it is corrupted, all processes are corrupted Access it from one process, use more conventional IPC.
  9. Mach Ports Available APIs: — Darwin C API — Core

    Foundation — CFMachPort and friends — Foundation — NSMachPort and friends
  10. Darwin C API: sending natural_t data; mach_port_t port; struct {

    mach_msg_header_t header; mach_msg_body_t body; mach_msg_type_descriptor_t type; } message; message.header = (mach_msg_header_t) { .msgh_remote_port = port, .msgh_local_port = MACH_PORT_NULL, .msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0), .msgh_size = sizeof(message) };
  11. message.body = (mach_msg_body_t) { .msgh_descriptor_count = 1 }; message.type =

    (mach_msg_type_descriptor_t) { .pad1 = data, .pad2 = sizeof(data) }; mach_msg_return_t error = mach_msg_send(&message.header); if (error == MACH_MSG_SUCCESS) { // ... }
  12. private struct RemoteServerPortName { static let client = "com.hideez.port.client" static

    let server = "com.hideez.port.server" } private var inPort: CFMessagePort? func startListening() { guard nil == inPort else { return } inPort = CFMessagePortCreateLocal( nil, RemoteServerPortName.client as CFString!, getInMessageCallback(), nil, nil) let runLoopSource = CFMessagePortCreateRunLoopSource(nil, inPort, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, CFRunLoopMode.commonModes); } func getInMessageCallback() -> CFMessagePortCallBack { return {(port: CFMessagePort?, messageId:Int32, data: CFData?, _: UnsafeMutableRawPointer?) -> Unmanaged<CFData>? in RemoteServer.shared.handleInMessage(port: port, messageId: messageId, data: data) } }
  13. func postMessage(message: RemoteMessageOut, waitForResponse wait: Bool = false) -> RemoteServerResponse?

    { guard let outPort = CFMessagePortCreateRemote( nil, RemoteServerPortName.server as CFString!) else { return nil } var respData: Unmanaged<CFData>? = Unmanaged.passRetained(CFDataCreate(nil, nil, 0)!) CFMessagePortSendRequest( outPort, message.id.rawValue, (message.data ?? Data()) as CFData, 30.0, wait ? 30.0 : 0.0, wait ? CFRunLoopMode.defaultMode.rawValue : nil, &respData) let data = respData!.takeUnretainedValue() as Data CFMessagePortInvalidate(outPort) return data.isEmpty ? nil : NSKeyedUnarchiver.unarchiveObject(with: data) as? [String : Any] }
  14. XPC Available APIs: — C API (use from C, C++

    code) — Objective-C API (use from Objective-C, Swift)
  15. Obj-C XPC — modern API — Protocol-oriented(!) — Available since

    10.8 (year of 2012) — API of choice for IPC on macOS