Slide 1

Slide 1 text

IPC on macOS

Slide 2

Slide 2 text

Before we dive in The Berkeley Software Distribution (BSD) is an operating system based on early Unix.

Slide 3

Slide 3 text

BSD became the basics for several open-source OS: FreeBSD, OpenBSD, NetBSD, DragonFly BSD, TrueOS and Darwin

Slide 4

Slide 4 text

Darwin is an open-source Unix-like operating system first released by Apple in 2000

Slide 5

Slide 5 text

Darwin forms the core set of components upon which macOS, iOS, watchOS, tvOS, iPadOS and audioOS are based

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

BSD supports POSIX standard, so POSIX APIs are avaliable to us on macOS.

Slide 8

Slide 8 text

POSIX == Portable Operating System Interface

Slide 9

Slide 9 text

Available IPC techniques

Slide 10

Slide 10 text

BSD 1. BSD sockets 2. BSD pipes 3. BSD signals

Slide 11

Slide 11 text

Other low level 1. Shared Memory + Semaphores for large resources (like movie)

Slide 12

Slide 12 text

Darwin low-level 1. Mach Ports

Slide 13

Slide 13 text

The Mach port object is the underlying primitive used for all interprocess communication in macOS

Slide 14

Slide 14 text

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)

Slide 15

Slide 15 text

Even higher level no explicit setup for communication 1. NSPasteboard 2. Services API

Slide 16

Slide 16 text

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)

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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.

Slide 19

Slide 19 text

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.

Slide 20

Slide 20 text

Mach Ports Available APIs: — Darwin C API — Core Foundation — CFMachPort and friends — Foundation — NSMachPort and friends

Slide 21

Slide 21 text

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) };

Slide 22

Slide 22 text

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) { // ... }

Slide 23

Slide 23 text

Darwin C API Not recommended to use directly: interfaces will change with kernel updates.

Slide 24

Slide 24 text

CFMachPort & NSMachPort

Slide 25

Slide 25 text

Apple Events

Slide 26

Slide 26 text

Apple Events NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager]; [appleEventManager setEventHandler:self andSelector:@selector(handleAppleEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

CFMessagePort

Slide 29

Slide 29 text

CFMessagePort High-performance counterpart of Apple Events

Slide 30

Slide 30 text

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? in RemoteServer.shared.handleInMessage(port: port, messageId: messageId, data: data) } }

Slide 31

Slide 31 text

func postMessage(message: RemoteMessageOut, waitForResponse wait: Bool = false) -> RemoteServerResponse? { guard let outPort = CFMessagePortCreateRemote( nil, RemoteServerPortName.server as CFString!) else { return nil } var respData: Unmanaged? = 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] }

Slide 32

Slide 32 text

Distributed Notifications

Slide 33

Slide 33 text

[NSDistributedNotificationCenter default addObserver:self selector:@selector(_openPreferences) name:notificationName object:nil];

Slide 34

Slide 34 text

distributedNotificationCenter.postNotificationName(@"NotificationName", object: nil, userInfo: userInfo, deliverImmediately: true)

Slide 35

Slide 35 text

Distributed objects Deprecated and has !!!

Slide 36

Slide 36 text

Distributed objects NSConnection and friends are deprecated and have !!!

Slide 37

Slide 37 text

XPC Available APIs: — C API (use from C, C++ code) — Objective-C API (use from Objective-C, Swift)

Slide 38

Slide 38 text

Obj-C XPC — modern API — Protocol-oriented(!) — Available since 10.8 (year of 2012) — API of choice for IPC on macOS

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

IPC workshop

Slide 43

Slide 43 text

Thank you!