mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-27 19:54:38 +00:00
183 lines
6.6 KiB
Diff
183 lines
6.6 KiB
Diff
diff --git a/src/connection.m b/src/connection.m
|
|
index 366f985..b7b979a 100644
|
|
--- a/src/connection.m
|
|
+++ b/src/connection.m
|
|
@@ -964,6 +964,14 @@ error_out:
|
|
XPC_CLASS(dictionary)* result = nil;
|
|
mach_msg_header_t* header = NULL;
|
|
|
|
+ if (!MACH_PORT_VALID(this->send_port)) {
|
|
+ // Fail fast: the channel was never connected (e.g. the named service
|
|
+ // does not exist, so the bootstrap lookup produced no send right).
|
|
+ // Without this, the message queues behind a dead channel and the
|
|
+ // blocking reply wait below hangs forever (darling-lol M2b).
|
|
+ return XPC_ERROR_CONNECTION_INVALID;
|
|
+ }
|
|
+
|
|
@autoreleasepool {
|
|
XPC_CLASS(serializer)* serializer = [XPC_CLASS(serializer) serializer];
|
|
dispatch_mach_msg_t message = NULL;
|
|
diff --git a/src/event.m b/src/event.m
|
|
index 0870a6c..e2d4bd6 100644
|
|
--- a/src/event.m
|
|
+++ b/src/event.m
|
|
@@ -19,9 +19,10 @@
|
|
|
|
#import <xpc/xpc.h>
|
|
#import <xpc/util.h>
|
|
-
|
|
-// actually, the event publisher is it's own class
|
|
-typedef xpc_object_t xpc_event_publisher_t;
|
|
+#import <xpc/launchd_defs.h>
|
|
+#import <dispatch/dispatch.h>
|
|
+#import <stdlib.h>
|
|
+#import <Block.h>
|
|
|
|
XPC_EXPORT const char* const _xpc_event_key_name = "XPCEventName";
|
|
XPC_EXPORT const char* const _xpc_event_key_stream_name = "XPCEventStreamName";
|
|
@@ -30,15 +31,77 @@ XPC_EXPORT const char* const _xpc_event_key_stream_name = "XPCEventStreamName";
|
|
// private C API
|
|
//
|
|
|
|
+/*
|
|
+ * darling-lol: minimal but FUNCTIONAL event publisher.
|
|
+ *
|
|
+ * xpc_event_publisher_* was entirely stubbed (create -> NULL, set_handler
|
|
+ * -> dropped, activate -> no-op). That silently broke any daemon that gates
|
|
+ * its real initialization on the publisher's INITIAL_BARRIER callback.
|
|
+ *
|
|
+ * notifyd is exactly such a daemon: it creates the publisher for
|
|
+ * "com.apple.notifyd.matching" and only calls dispatch_mach_connect() for
|
|
+ * its Mach channels from inside the handler when it sees
|
|
+ * XPC_EVENT_PUBLISHER_ACTION_INITIAL_BARRIER. Because activate() did
|
|
+ * nothing, the barrier never fired, the channels were never connected, and
|
|
+ * the `com.apple.system.notification_center` Mach service registered with
|
|
+ * launchd was left without a serving endpoint. Clients then either hung in
|
|
+ * bootstrap/check-in or failed outright -- e.g. Chromium's
|
|
+ * ThermalStateObserverMac logged "unable to register to power
|
|
+ * notifications. Result: 9" (NOTIFY_STATUS_SERVER_NOT_FOUND).
|
|
+ *
|
|
+ * We do not need a real launchd-backed event stream here; we only need the
|
|
+ * lifecycle the server expects:
|
|
+ * - create() gives back a usable object,
|
|
+ * - set_handler()/set_error_handler() remember the blocks,
|
|
+ * - activate() delivers the INITIAL_BARRIER action once, synchronously
|
|
+ * (Apple delivers it asynchronously on the publisher's queue; sync is
|
|
+ * sufficient for notifyd, which only needs its connects to happen
|
|
+ * before dispatch_main()).
|
|
+ * ADD/REMOVE actions are only ever produced by launchd from registered
|
|
+ * event streams, which Darling does not have; they are not needed to bring
|
|
+ * notifyd's channels up.
|
|
+ */
|
|
+
|
|
+typedef struct _xpc_event_publisher_s {
|
|
+ const char* name;
|
|
+ dispatch_queue_t queue;
|
|
+ void (^handler)(xpc_event_publisher_action_t action, uint64_t event_token, xpc_object_t descriptor);
|
|
+ void (^error_handler)(int error);
|
|
+ bool activated;
|
|
+} *xpc_event_publisher_t;
|
|
+
|
|
XPC_EXPORT
|
|
void xpc_event_publisher_activate(xpc_event_publisher_t xpub) {
|
|
- xpc_stub();
|
|
+ if (xpub == NULL || xpub->activated)
|
|
+ return;
|
|
+ xpub->activated = true;
|
|
+
|
|
+ void (^handler)(xpc_event_publisher_action_t, uint64_t, xpc_object_t) = xpub->handler;
|
|
+ if (handler == NULL)
|
|
+ // Nothing to deliver; without a handler there is no barrier
|
|
+ // contract to honor.
|
|
+ return;
|
|
+
|
|
+ // Deliver the barrier synchronously. Apple's real implementation
|
|
+ // delivers it asynchronously on the publisher's queue, but the only
|
|
+ // in-tree consumer (notifyd) just needs dispatch_mach_connect() to run
|
|
+ // before dispatch_main(); synchronous delivery satisfies that without
|
|
+ // depending on the queue being ready to run async blocks yet.
|
|
+ handler(XPC_EVENT_PUBLISHER_ACTION_INITIAL_BARRIER, 0, NULL);
|
|
};
|
|
|
|
XPC_EXPORT
|
|
xpc_object_t xpc_event_publisher_create(const char* name, void* some_parameter) {
|
|
- xpc_stub();
|
|
- return NULL;
|
|
+ xpc_event_publisher_t xpub = calloc(1, sizeof(struct _xpc_event_publisher_s));
|
|
+ if (xpub == NULL)
|
|
+ return NULL;
|
|
+ xpub->name = name;
|
|
+ // Apple passes the workloop/queue as the second parameter; callers
|
|
+ // (notifyd) pass a dispatch queue. Retained for possible future async
|
|
+ // delivery; the current implementation delivers the barrier
|
|
+ // synchronously in activate().
|
|
+ xpub->queue = (dispatch_queue_t) some_parameter;
|
|
+ return (xpc_object_t) xpub;
|
|
};
|
|
|
|
XPC_EXPORT
|
|
@@ -76,15 +139,25 @@ au_asid_t xpc_event_publisher_get_subscriber_asid(xpc_event_publisher_t xpub, ui
|
|
|
|
XPC_EXPORT
|
|
void xpc_event_publisher_set_error_handler(xpc_event_publisher_t xpub, void (^handler)()) {
|
|
- // no clue what the parameters for the handler are
|
|
- // (probably includes some sort of error parameter, but i have no clue what that is)
|
|
- xpc_stub();
|
|
+ if (xpub == NULL)
|
|
+ return;
|
|
+ // The real signature takes a single `int error` argument.
|
|
+ // NOTE: use Block_copy(), NOT [handler copy]. The latter sends an ObjC
|
|
+ // message (objc_msgSend) which dereferences the block's isa; if the
|
|
+ // caller's blocks runtime leaves isa NULL/unmapped (observed: notifyd
|
|
+ // SEGV addr=0x0 inside [handler copy]), messaging crashes. Block_copy
|
|
+ // operates on the block struct directly and is safe.
|
|
+ xpub->error_handler = (void (^)(int)) Block_copy((const void*)handler);
|
|
};
|
|
|
|
XPC_EXPORT
|
|
void xpc_event_publisher_set_handler(xpc_event_publisher_t xpub, void (^handler)()) {
|
|
- // likewise, no clue what the parameters to the handler are
|
|
- xpc_stub();
|
|
+ if (xpub == NULL)
|
|
+ return;
|
|
+ // The real signature is:
|
|
+ // void (^)(xpc_event_publisher_action_t action,
|
|
+ // uint64_t event_token, xpc_object_t descriptor)
|
|
+ xpub->handler = (void (^)(xpc_event_publisher_action_t, uint64_t, xpc_object_t)) Block_copy((const void*)handler);
|
|
};
|
|
|
|
XPC_EXPORT
|
|
diff --git a/src/pipe.m b/src/pipe.m
|
|
index d04fb98..f60e6ac 100644
|
|
--- a/src/pipe.m
|
|
+++ b/src/pipe.m
|
|
@@ -209,7 +209,9 @@ out:
|
|
goto out;
|
|
}
|
|
|
|
- *incomingMessage = dict;
|
|
+ // The deserializer autoreleases its result. The C pipe API
|
|
+ // transfers an owned reference to the caller.
|
|
+ *incomingMessage = [dict retain];
|
|
|
|
status = 0;
|
|
} else {
|
|
@@ -249,7 +251,7 @@ out:
|
|
goto out;
|
|
}
|
|
|
|
- *incomingMessage = dict;
|
|
+ *incomingMessage = [dict retain];
|
|
*replyPort = header->msgh_local_port;
|
|
|
|
status = 0;
|
|
@@ -581,7 +583,7 @@ retry:
|
|
goto out;
|
|
}
|
|
|
|
- *reply = dict;
|
|
+ *reply = [dict retain];
|
|
|
|
status = 0;
|
|
} else {
|