#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <sys/ipc.h>
#include <sys/signal.h>
#include <sys/syslimits.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/time.h>
#include <bootstrap_priv.h>
#include <errno.h>
#include <pthread.h>
#include <TargetConditionals.h>
#include <AvailabilityMacros.h>
#include <Block.h>
#include <dispatch/dispatch.h>
#include <dispatch/private.h>
#include <_simple.h>
#include "libnotify.h"
#include "notify.h"
#include "notify_internal.h"
#include "notify_ipc.h"
#include "notify_private.h"
#ifdef DEBUG
#define DEBUG_REGISTRATION 0x00000001
#define DEBUG_NOTIFICATION 0x00000002
#define DEBUG_RETAIN_RELEASE 0x00000004
#define DEBUG_CANCEL 0x00000008
#define DEBUG_GET_STATE 0x00000010
#define DEBUG_SEND_NO_BLOCK 0x00000020
#define DEBUG_NODES 0x00000040
#define DEBUG_API 0x00000080
#define DEBUG_USER 0x80000000
#define DEBUG_ALL 0xffffffff
static uint32_t _libnotify_debug = DEBUG_ALL;
#endif
#define INITIAL_TOKEN_ID 0
WEAK_IMPORT_ATTRIBUTE bool _dispatch_is_multithreaded(void);
#define EVENT_INIT 0
#define EVENT_REGEN 1
#define SELF_PREFIX "self."
#define SELF_PREFIX_LEN 5
#define COMMON_SELF_PORT_KEY "self.com.apple.system.notify.common"
#define MULTIPLE_REGISTRATION_WARNING_TRIGGER 20
extern uint32_t _notify_lib_peek(notify_state_t *ns, pid_t pid, int token, int *val);
extern int *_notify_lib_check_addr(notify_state_t *ns, pid_t pid, int token);
#define CLIENT_NAME_TABLE_SIZE 256
#define NID_UNSET 0xffffffffffffffffL
#define NID_CALLED_ONCE 0xfffffffffffffffeL
typedef struct
{
pthread_mutex_t lock;
int32_t refcount;
uint32_t coalesce_base_token;
char *name;
size_t name_len;
uint64_t name_id;
TAILQ_HEAD(, __registration_node_s) coalesced;
struct __registration_node_s *coalesce_base;
} name_node_t;
typedef struct __registration_node_s
{
TAILQ_ENTRY(__registration_node_s) registration_coalesced_entry;
int32_t refcount;
uint32_t token;
uint32_t flags;
uint32_t slot;
uint32_t val;
int fd;
int signal;
mach_port_t mp;
dispatch_queue_t queue;
notify_handler_t block;
uint32_t client_id;
uint64_t set_state_val;
uint64_t set_state_time;
char *path;
int path_flags;
name_node_t *name_node;
} registration_node_t;
static void _notify_lib_regenerate(int src);
static void notify_retain_mach_port(mach_port_t mp, int mine);
static void _notify_dispatch_handle(mach_port_t port);
static notify_state_t *_notify_lib_self_state();
static void registration_node_release(registration_node_t *r);
static void notify_release_file_descriptor(int fd);
static void notify_release_mach_port(mach_port_t mp, uint32_t flags);
static registration_node_t *registration_node_retain(registration_node_t *r);
uint32_t notify_register_plain(const char *name, int *out_token);
#ifdef DEBUG_MUTEX
#define mutex_lock(s,x,f,l) \
_notify_client_log(ASL_LEVEL_NOTICE, "attempting mutex lock %s %p from %s:%u", s, x, f, l); \
pthread_mutex_lock(x); \
_notify_client_log(ASL_LEVEL_NOTICE, "acquired mutex lock %s %p from %s:%u", s, x, f, l);
#define mutex_unlock(s,x,f,l) \
_notify_client_log(ASL_LEVEL_NOTICE, "dropping mutex lock %s %p from %s:%u", s, x, f, l); \
pthread_mutex_unlock(x);
#else
#define mutex_lock(s,x,f,l) pthread_mutex_lock(x)
#define mutex_unlock(s,x,f,l) pthread_mutex_unlock(x)
#endif
static void
_notify_client_log(int level, const char *fmt, ...)
{
va_list ap;
char *msg = NULL;
va_start(ap, fmt);
vasprintf(&msg, fmt, ap);
va_end(ap);
if (msg != NULL)
{
_simple_asl_log(level, "com.apple.notify", msg);
}
free(msg);
}
#pragma mark -
#pragma mark name_node_t
#ifdef DEBUG
static void
name_node_dump(int level, name_node_t *n)
{
if (n == NULL)
{
_notify_client_log(level, "name_node_t NULL\n");
return;
}
_notify_client_log(level, "name_node_t %p name=%s name_id=%llu refcount=%d coalesce_base_token=%u coalesce_base=%p\n", (n->name == NULL) ? "NULL" : n->name, n->name_id, n->refcount, n->coalesce_base_token, n->coalesce_base);
}
#endif
static name_node_t *
name_node_for_name(const char *name, uint64_t nid, bool create, bool glock)
{
if (name == NULL) return NULL;
notify_globals_t globals = _notify_globals();
if (glock)
{
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
}
name_node_t *n = (name_node_t *)_nc_table_find(globals->name_table, name);
if (n != NULL)
{
OSAtomicIncrement32(&n->refcount);
}
else if (create)
{
n = (name_node_t *)calloc(1, sizeof(name_node_t));
if (n == NULL)
{
#ifdef DEBUG
_notify_client_log(ASL_LEVEL_ERR, "name_node_for_name name %s calloc failed errno %d [%s]\n", name, errno, strerror(errno));
#endif
goto unlock_and_return;
}
n->name = strdup(name);
if (n->name == NULL)
{
free(n);
n = NULL;
goto unlock_and_return;
}
n->refcount = 1;
n->name_len = strlen(name);
n->name_id = nid;
TAILQ_INIT(&n->coalesced);
n->coalesce_base_token = NOTIFY_TOKEN_INVALID;
pthread_mutex_init(&n->lock, NULL);
_nc_table_insert_no_copy(globals->name_table, n->name, n);
}
unlock_and_return:
if (glock)
{
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NODES)
{
if (n == NULL) _notify_client_log(ASL_LEVEL_NOTICE, "name_node_for_name name %s returning NULL\n", name);
else _notify_client_log(ASL_LEVEL_NOTICE, "name_node_for_name name %s refcount %d %p\n", n->name, n->refcount, n);
}
#endif
return n;
}
#ifdef NOTDEF
static name_node_t *
name_node_retain(name_node_t *n)
{
if (n != NULL) OSAtomicIncrement32(&n->refcount);
return n;
}
#endif
static void
name_node_release(name_node_t *n)
{
if (n == NULL) return;
notify_globals_t globals = _notify_globals();
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
mutex_lock(n->name, &n->lock, __func__, __LINE__);
if (OSAtomicDecrement32(&n->refcount) > 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NODES) _notify_client_log(ASL_LEVEL_NOTICE, "name_node_release name %s refcount %d %p", n->name, n->refcount, n);
#endif
mutex_unlock(n->name, &n->lock, __func__, __LINE__);
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NODES) _notify_client_log(ASL_LEVEL_NOTICE, "name_node_release name %s refcount %d %p FREE", n->name, n->refcount, n);
#endif
_nc_table_delete(globals->name_table, n->name);
mutex_unlock(n->name, &n->lock, __func__, __LINE__);
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
free(n->name);
n->name = NULL;
free(n);
}
static void
name_node_add_coalesced_registration(name_node_t *n, registration_node_t *r)
{
if (n == NULL) return;
if (r == NULL) return;
mutex_lock(n->name, &n->lock, __func__, __LINE__);
registration_node_retain(n->coalesce_base);
TAILQ_INSERT_TAIL(&n->coalesced, r, registration_coalesced_entry);
mutex_unlock(n->name, &n->lock, __func__, __LINE__);
}
static void
name_node_remove_coalesced_registration(name_node_t *n, registration_node_t *r)
{
if (n == NULL) return;
if (r == NULL) return;
mutex_lock(n->name, &n->lock, __func__, __LINE__);
TAILQ_REMOVE(&n->coalesced, r, registration_coalesced_entry);
mutex_unlock(n->name, &n->lock, __func__, __LINE__);
registration_node_release(n->coalesce_base);
}
static void
name_node_set_nid(name_node_t *n, uint64_t nid)
{
if (n == NULL) return;
mutex_lock(n->name, &n->lock, __func__, __LINE__);
n->name_id = nid;
mutex_unlock(n->name, &n->lock, __func__, __LINE__);
}
#pragma mark -
#pragma mark registration_node_t
static registration_node_t *
registration_node_find(uint32_t token)
{
notify_globals_t globals = _notify_globals();
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
registration_node_t *r = (registration_node_t *)_nc_table_find_n(globals->registration_table, token);
if (r != NULL) OSAtomicIncrement32(&r->refcount);
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NODES) _notify_client_log(ASL_LEVEL_NOTICE, "registration_node_find token %u refcount %d -> %p", token, r ? r->refcount : -1, r);
#endif
return r;
}
bool
notify_is_valid_token(int val)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
bool valid = true;
notify_globals_t globals = _notify_globals();
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
registration_node_t *r = (registration_node_t *)_nc_table_find_n(globals->registration_table, val);
if (r == NULL) valid = false;
else if (r->flags & NOTIFY_TYPE_COALESCE_BASE) valid = false;
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return valid;
}
static registration_node_t *
registration_node_retain(registration_node_t *r)
{
if (r != NULL) OSAtomicIncrement32(&r->refcount);
return r;
}
static void
registration_node_free(registration_node_t *r)
{
notify_globals_t globals = _notify_globals();
name_node_t *n = r->name_node;
if (r->flags & NOTIFY_TYPE_COALESCED)
{
name_node_remove_coalesced_registration(n, r);
}
else if (r->flags & NOTIFY_TYPE_COALESCE_BASE)
{
mutex_lock(n->name, &n->lock, __func__, __LINE__);
n->coalesce_base_token = NOTIFY_TOKEN_INVALID;
n->coalesce_base = NULL;
mutex_unlock(n->name, &n->lock, __func__, __LINE__);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_CANCEL) _notify_client_log(ASL_LEVEL_NOTICE, "_notify_server_cancel_2 token %u", r->token);
#endif
(void)_notify_server_cancel_2(globals->notify_server_port, r->token);
}
notify_release_file_descriptor(r->fd);
notify_release_mach_port(r->mp, r->flags);
free(r->path);
if (r->block != NULL) dispatch_async_f(r->queue, r->block, (dispatch_function_t)_Block_release);
r->block = NULL;
if (r->queue != NULL) dispatch_release(r->queue);
r->queue = NULL;
free(r);
name_node_release(n);
}
static void
registration_node_release(registration_node_t *r)
{
if (r == NULL) return;
notify_globals_t globals = _notify_globals();
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
if (OSAtomicDecrement32(&r->refcount) > 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NODES) _notify_client_log(ASL_LEVEL_NOTICE, "registration_node_release token %u refcount %d flags 0x%08x %p", r->token, r->refcount, r->flags, r);
#endif
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NODES) _notify_client_log(ASL_LEVEL_NOTICE, "registration_node_release token %u refcount %d flags 0x%08x %p FREE", r->token, r->refcount, r->flags, r);
#endif
_nc_table_delete_n(globals->registration_table, r->token);
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
registration_node_free(r);
}
#pragma mark -
#if TARGET_IPHONE_SIMULATOR
const char *
_notify_shm_id()
{
static dispatch_once_t once;
static char *shm_id;
dispatch_once(&once, ^{
const char *udid = getenv("SIMULATOR_UDID");
if (udid && strlen(udid) == 36) {
char scratch[34];
memcpy(scratch, udid, 8);
memcpy(scratch+8, udid+9, 4);
memcpy(scratch+12, udid+14, 4);
scratch[16] = '\0';
memcpy(scratch+17, udid+19, 4);
memcpy(scratch+21, udid+24, 12);
scratch[33] = '\0';
uint64_t upper = strtoull(scratch, NULL, 16);
uint64_t lower = strtoull(scratch + 17, NULL, 16);
const char *c64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
scratch[0] = c64[(upper >> 57) & 0xf];
scratch[1] = c64[(upper >> 50) & 0xf];
scratch[2] = c64[(upper >> 43) & 0xf];
scratch[3] = c64[(upper >> 36) & 0xf];
scratch[4] = c64[(upper >> 29) & 0xf];
scratch[5] = c64[(upper >> 22) & 0xf];
scratch[6] = c64[(upper >> 15) & 0xf];
scratch[7] = c64[(upper >> 8) & 0xf];
scratch[8] = c64[(upper >> 1) & 0xf];
scratch[10] = c64[(lower >> 57) & 0xf];
scratch[11] = c64[(lower >> 50) & 0xf];
scratch[12] = c64[(lower >> 43) & 0xf];
scratch[13] = c64[(lower >> 36) & 0xf];
scratch[14] = c64[(lower >> 29) & 0xf];
scratch[15] = c64[(lower >> 22) & 0xf];
scratch[16] = c64[(lower >> 15) & 0xf];
scratch[17] = c64[(lower >> 8) & 0xf];
scratch[18] = c64[(lower >> 1) & 0xf];
scratch[19] = '\0';
asprintf(&shm_id, "sim.not.%s", scratch);
assert(shm_id);
}
if (shm_id == NULL)
{
shm_id = "apple.shm.notification_center";
}
});
return shm_id;
}
#endif
static int
shm_attach(uint32_t size)
{
int32_t shmfd;
notify_globals_t globals = _notify_globals();
shmfd = shm_open(SHM_ID, O_RDONLY, 0);
if (shmfd == -1) return -1;
globals->shm_base = mmap(NULL, size, PROT_READ, MAP_SHARED, shmfd, 0);
close(shmfd);
if (globals->shm_base == (uint32_t *)-1) globals->shm_base = NULL;
if (globals->shm_base == NULL) return -1;
return 0;
}
#ifdef NOTDEF
static void
shm_detach(void)
{
if (shm_base != NULL)
{
shmdt(shm_base);
shm_base = NULL;
}
}
#endif
void
_notify_init_globals(void * _globals)
{
notify_globals_t globals = _globals;
pthread_mutex_init(&globals->notify_lock, NULL);
globals->token_id = INITIAL_TOKEN_ID;
globals->notify_common_token = -1;
globals->name_table = _nc_table_new(CLIENT_NAME_TABLE_SIZE);
globals->registration_table = _nc_table_new(CLIENT_NAME_TABLE_SIZE);
globals->checkLock = OS_SPINLOCK_INIT;
}
#if !_NOTIFY_HAS_ALLOC_ONCE
notify_globals_t
_notify_globals_impl(void)
{
static dispatch_once_t once;
static notify_globals_t globals;
dispatch_once(&once, ^{
globals = calloc(1, sizeof(struct notify_globals_s));
_notify_init_globals(globals);
});
return globals;
}
#endif
static uint32_t
_notify_lib_init(uint32_t event)
{
__block kern_return_t kstatus;
__block bool first = false;
int status, cid;
uint64_t state;
notify_globals_t globals = _notify_globals();
if (globals->client_opts & NOTIFY_OPT_DISABLE) return NOTIFY_STATUS_FAILED;
kstatus = KERN_SUCCESS;
dispatch_once(&globals->notify_server_port_once, ^{
first = true;
kstatus = bootstrap_look_up2(bootstrap_port, NOTIFY_SERVICE_NAME, &globals->notify_server_port, 0, BOOTSTRAP_PRIVILEGED_SERVER);
});
if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED;
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
if (_dispatch_is_multithreaded)
{
if (_dispatch_is_multithreaded()) globals->client_opts |= (NOTIFY_OPT_DISPATCH | NOTIFY_OPT_REGEN);
}
if (first || (event == EVENT_REGEN))
{
pid_t last_pid = globals->notify_server_pid;
globals->notify_ipc_version = 0;
globals->notify_server_pid = 0;
kstatus = _notify_server_register_plain(globals->notify_server_port, NOTIFY_IPC_VERSION_NAME, NOTIFY_IPC_VERSION_NAME_LEN, &cid, &status);
if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK))
{
kstatus = _notify_server_get_state(globals->notify_server_port, cid, &state, &status);
if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK))
{
globals->notify_ipc_version = (int32_t)state;
state >>= 32;
globals->notify_server_pid = (int32_t)state;
}
_notify_server_cancel(globals->notify_server_port, cid, &status);
if ((last_pid == globals->notify_server_pid) && (event == EVENT_REGEN))
{
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return NOTIFY_STATUS_INVALID_REQUEST;
}
}
if (globals->server_proc_source != NULL)
{
dispatch_source_cancel(globals->server_proc_source);
dispatch_release(globals->server_proc_source);
globals->server_proc_source = NULL;
}
}
if (globals->notify_ipc_version < 2)
{
globals->client_opts &= ~NOTIFY_OPT_REGEN;
}
if ((globals->server_proc_source == NULL) && (globals->client_opts & NOTIFY_OPT_REGEN) && (globals->notify_server_pid != 0))
{
globals->server_proc_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, (uintptr_t)globals->notify_server_pid, DISPATCH_PROC_EXIT, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
dispatch_source_set_event_handler(globals->server_proc_source, ^{ _notify_lib_regenerate(1); });
dispatch_resume(globals->server_proc_source);
}
if ((globals->client_opts & NOTIFY_OPT_DISPATCH) && (globals->notify_common_port == MACH_PORT_NULL))
{
kern_return_t kr;
task_t task = mach_task_self();
kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &globals->notify_common_port);
if (kr == KERN_SUCCESS)
{
globals->notify_dispatch_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, globals->notify_common_port, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
dispatch_source_set_event_handler(globals->notify_dispatch_source, ^{
notify_globals_t globals = _notify_globals();
_notify_dispatch_handle(globals->notify_common_port);
});
dispatch_source_set_cancel_handler(globals->notify_dispatch_source, ^{
task_t task = mach_task_self();
notify_globals_t globals = _notify_globals();
mach_port_mod_refs(task, globals->notify_common_port, MACH_PORT_RIGHT_RECEIVE, -1);
});
dispatch_resume(globals->notify_dispatch_source);
}
}
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
if (globals->notify_common_port != MACH_PORT_NULL && (first || event == EVENT_REGEN))
{
status = notify_register_mach_port(COMMON_PORT_KEY, &globals->notify_common_port, NOTIFY_REUSE | NOTIFY_NO_DISPATCH, &globals->notify_common_token);
}
return NOTIFY_STATUS_OK;
}
void
_notify_fork_child(void)
{
notify_globals_t globals = _notify_globals();
_notify_init_globals(globals);
if (globals->notify_server_port != MACH_PORT_NULL) globals->client_opts = NOTIFY_OPT_DISABLE;
if (_dispatch_is_multithreaded) {
if (_dispatch_is_multithreaded()) globals->client_opts = NOTIFY_OPT_DISABLE;
}
globals->self_state = NULL;
globals->notify_server_port = MACH_PORT_NULL;
globals->notify_ipc_version = 0;
globals->notify_server_pid = 0;
globals->fd_count = 0;
globals->fd_clnt = NULL;
globals->fd_srv = NULL;
globals->fd_refcount = NULL;
globals->mp_count = 0;
globals->mp_list = NULL;
globals->mp_refcount = NULL;
globals->mp_mine = NULL;
globals->shm_base = NULL;
}
static int
client_registration_create(const char *name, size_t namelen, uint64_t nid, uint32_t token, uint32_t cid, uint32_t slot, uint32_t flags, int sig, int fd, mach_port_t mp)
{
name_node_t *name_node = NULL;
registration_node_t *reg_node;
uint32_t warn_count = 0;
notify_globals_t globals = _notify_globals();
if (globals->name_table == NULL) return -1;
if (globals->registration_table == NULL) return -1;
if (name == NULL) return -1;
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
reg_node = (registration_node_t *)_nc_table_find_n(globals->registration_table, token);
if (reg_node != NULL) goto client_registration_create_fail;
name_node = name_node_for_name(name, nid, true, false);
if (name_node == NULL) goto client_registration_create_fail;
reg_node = (registration_node_t *)calloc(1, sizeof(registration_node_t));
if (reg_node == NULL)
{
#ifdef DEBUG
_notify_client_log(ASL_LEVEL_ERR, "client_registration_create name %s calloc failed errno %d [%s]\n", name, errno, strerror(errno));
#endif
name_node_release(name_node);
goto client_registration_create_fail;
}
reg_node->refcount = 1;
reg_node->token = token;
_nc_table_insert_n(globals->registration_table, token, reg_node);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NODES) _notify_client_log(ASL_LEVEL_NOTICE, "client_registration_create token %u refcount %d -> %p", token, reg_node->refcount, reg_node);
#endif
#ifdef DEBUG
if (_libnotify_debug & DEBUG_REGISTRATION)
{
if (nid == NID_UNSET) _notify_client_log(ASL_LEVEL_NOTICE, "client_registration_create reg_node %p name %s name_node %p nid NID_UNSET token %u flags 0x%08x", reg_node, name, name_node, token, flags);
else if (nid == NID_CALLED_ONCE) _notify_client_log(ASL_LEVEL_NOTICE, "client_registration_create reg_node %p name %s name_node %p nid NID_CALLED_ONCE token %u flags 0x%08x", reg_node, name, name_node, token, flags);
else _notify_client_log(ASL_LEVEL_NOTICE, "client_registration_create reg_node %p name %s name_node %p nid %llu token %u flags 0x%08x", reg_node, name, name_node, nid, token, flags);
}
#endif
if (flags & NOTIFY_TYPE_COALESCED) flags &= ~NOTIFY_FLAG_REGEN;
reg_node->flags = flags;
reg_node->slot = slot;
reg_node->val = 0;
reg_node->fd = fd;
reg_node->mp = mp;
reg_node->signal = sig;
reg_node->client_id = cid;
reg_node->name_node = name_node;
if ((globals->client_opts & NOTIFY_OPT_DISPATCH) && (flags & NOTIFY_TYPE_DELIVERED))
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_REGISTRATION) _notify_client_log(ASL_LEVEL_NOTICE, "Add coalesced registration %p to name %s name node %p base %p", reg_node, name, name_node, name_node->coalesce_base);
#endif
name_node_add_coalesced_registration(name_node, reg_node);
}
if ((name_node->refcount % MULTIPLE_REGISTRATION_WARNING_TRIGGER) == 0)
{
warn_count = name_node->refcount;
}
if (warn_count > 0)
{
_notify_client_log(ASL_LEVEL_WARNING, "notify name \"%s\" has been registered %d times - this may be a leak", name, warn_count);
}
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return 0;
client_registration_create_fail:
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return -1;
}
static int
base_registration_create(const char *name, size_t namelen, uint64_t nid, uint32_t token, uint32_t flags, mach_port_t mp)
{
name_node_t *name_node = NULL;
registration_node_t *reg_node;
notify_globals_t globals = _notify_globals();
if (globals->name_table == NULL) return -1;
if (globals->registration_table == NULL) return -1;
if (name == NULL) return -1;
reg_node = (registration_node_t *)_nc_table_find_n(globals->registration_table, token);
if (reg_node != NULL) return -1;
reg_node = (registration_node_t *)calloc(1, sizeof(registration_node_t));
if (reg_node == NULL)
{
#ifdef DEBUG
_notify_client_log(ASL_LEVEL_ERR, "base_registration_create name %s calloc failed errno %d [%s]\n", name, errno, strerror(errno));
#endif
return -1;
}
name_node = name_node_for_name(name, nid, true, false);
if (name_node == NULL)
{
free(reg_node);
return -1;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_REGISTRATION)
{
if (nid == NID_UNSET) _notify_client_log(ASL_LEVEL_NOTICE, "base_registration_create reg_node %p name %s name_node %p nid NID_UNSET token %u flags 0x%08x", reg_node, name, name_node, token, flags);
else if (nid == NID_CALLED_ONCE) _notify_client_log(ASL_LEVEL_NOTICE, "base_registration_create reg_node %p name %s name_node %p nid NID_CALLED_ONCE token %u flags 0x%08x", reg_node, name, name_node, token, flags);
else _notify_client_log(ASL_LEVEL_NOTICE, "base_registration_create reg_node %p name %s name_node %p nid %llu token %u flags 0x%08x", reg_node, name, name_node, nid, token, flags);
}
#endif
reg_node->refcount = 1;
reg_node->token = token;
reg_node->client_id = token;
reg_node->flags = flags | NOTIFY_TYPE_COALESCE_BASE;
reg_node->mp = mp;
reg_node->val = 0;
reg_node->slot = SLOT_NONE;
reg_node->fd = FD_NONE;
reg_node->signal = SIGNAL_NONE;
reg_node->name_node = name_node;
name_node->coalesce_base = reg_node;
name_node->coalesce_base_token = token;
_nc_table_insert_n(globals->registration_table, token, reg_node);
return 0;
}
static void
_notify_lib_regenerate_registration(registration_node_t *r)
{
uint32_t type;
int status, new_slot;
kern_return_t kstatus;
mach_port_t port;
uint64_t new_nid;
size_t pathlen;
notify_globals_t globals = _notify_globals();
if (r == NULL) return;
if (r->flags & NOTIFY_FLAG_SELF) return;
if ((r->flags & NOTIFY_FLAG_REGEN) == 0) return;
if (!strcmp(r->name_node->name, COMMON_PORT_KEY)) return;
port = MACH_PORT_NULL;
if (r->flags & NOTIFY_TYPE_PORT)
{
port = globals->notify_common_port;
}
pathlen = 0;
if (r->path != NULL) pathlen = strlen(r->path);
type = r->flags & 0x000000ff;
kstatus = _notify_server_regenerate(globals->notify_server_port, (caddr_t)r->name_node->name, (mach_msg_type_number_t)r->name_node->name_len, r->token, type, port, r->signal, r->slot, r->set_state_val, r->set_state_time, r->path, (mach_msg_type_number_t)pathlen, r->path_flags, &new_slot, &new_nid, &status);
if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
if (status != NOTIFY_STATUS_OK) return;
r->slot = new_slot;
r->name_node->name_id = new_nid;
}
static void
_notify_lib_regenerate(int src)
{
void *tt;
registration_node_t *reg;
notify_globals_t globals = _notify_globals();
if ((globals->client_opts & NOTIFY_OPT_REGEN) == 0) return;
if (_notify_lib_init(EVENT_REGEN) == NOTIFY_STATUS_OK)
{
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
tt = _nc_table_traverse_start(globals->registration_table);
while (tt != NULL)
{
reg = _nc_table_traverse(globals->registration_table, tt);
if (reg == NULL) break;
_notify_lib_regenerate_registration(reg);
}
_nc_table_traverse_end(globals->name_table, tt);
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
}
}
static inline void
regenerate_check()
{
notify_globals_t globals = _notify_globals();
if ((globals->client_opts & NOTIFY_OPT_REGEN) == 0) return;
if ((globals->shm_base != NULL) && (globals->shm_base[0] != globals->notify_server_pid)) _notify_lib_regenerate(0);
}
static void
notify_retain_file_descriptor(int clnt, int srv)
{
int x, i;
notify_globals_t globals = _notify_globals();
if (clnt < 0) return;
if (srv < 0) return;
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
x = -1;
for (i = 0; (i < globals->fd_count) && (x < 0); i++)
{
if (globals->fd_clnt[i] == clnt) x = i;
}
if (x >= 0)
{
globals->fd_refcount[x]++;
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
x = globals->fd_count;
globals->fd_count++;
globals->fd_clnt = (int *)reallocf(globals->fd_clnt, globals->fd_count * sizeof(int));
globals->fd_srv = (int *)reallocf(globals->fd_srv, globals->fd_count * sizeof(int));
globals->fd_refcount = (int *)reallocf(globals->fd_refcount, globals->fd_count * sizeof(int));
if ((globals->fd_clnt == NULL) || (globals->fd_srv == NULL) || (globals->fd_refcount == NULL))
{
#ifdef DEBUG
_notify_client_log(ASL_LEVEL_ERR, "notify_retain_file_descriptor reallocf failed errno %d [%s]\n", errno, strerror(errno));
#endif
free(globals->fd_clnt);
globals->fd_clnt = NULL;
free(globals->fd_srv);
globals->fd_srv = NULL;
free(globals->fd_refcount);
globals->fd_refcount = NULL;
globals->fd_count = 0;
}
else
{
globals->fd_clnt[x] = clnt;
globals->fd_srv[x] = srv;
globals->fd_refcount[x] = 1;
}
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
}
static void
notify_release_file_descriptor(int fd)
{
int x, i, j;
notify_globals_t globals = _notify_globals();
if (fd < 0) return;
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
x = -1;
for (i = 0; (i < globals->fd_count) && (x < 0); i++)
{
if (globals->fd_clnt[i] == fd) x = i;
}
if (x < 0)
{
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
if (globals->fd_refcount[x] > 0) globals->fd_refcount[x]--;
if (globals->fd_refcount[x] > 0)
{
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
close(globals->fd_clnt[x]);
close(globals->fd_srv[x]);
if (globals->fd_count == 1)
{
free(globals->fd_clnt);
free(globals->fd_srv);
free(globals->fd_refcount);
globals->fd_count = 0;
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
for (i = x + 1, j = x; i < globals->fd_count; i++, j++)
{
globals->fd_clnt[j] = globals->fd_clnt[i];
globals->fd_srv[j] = globals->fd_srv[i];
globals->fd_refcount[j] = globals->fd_refcount[i];
}
globals->fd_count--;
globals->fd_clnt = (int *)reallocf(globals->fd_clnt, globals->fd_count * sizeof(int));
globals->fd_srv = (int *)reallocf(globals->fd_srv, globals->fd_count * sizeof(int));
globals->fd_refcount = (int *)reallocf(globals->fd_refcount, globals->fd_count * sizeof(int));
if ((globals->fd_clnt == NULL) || (globals->fd_srv == NULL) || (globals->fd_refcount == NULL))
{
#ifdef DEBUG
_notify_client_log(ASL_LEVEL_ERR, "notify_release_file_descriptor reallocf failed errno %d [%s]\n", errno, strerror(errno));
#endif
free(globals->fd_clnt);
free(globals->fd_srv);
free(globals->fd_refcount);
globals->fd_count = 0;
}
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
}
static void
notify_retain_mach_port(mach_port_t mp, int mine)
{
int x, i;
notify_globals_t globals = _notify_globals();
if (mp == MACH_PORT_NULL) return;
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
x = -1;
for (i = 0; (i < globals->mp_count) && (x < 0); i++)
{
if (globals->mp_list[i] == mp) x = i;
}
if (x >= 0)
{
globals->mp_refcount[x]++;
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
x = globals->mp_count;
globals->mp_count++;
globals->mp_list = (mach_port_t *)reallocf(globals->mp_list, globals->mp_count * sizeof(mach_port_t));
globals->mp_refcount = (int *)reallocf(globals->mp_refcount, globals->mp_count * sizeof(int));
globals->mp_mine = (int *)reallocf(globals->mp_mine, globals->mp_count * sizeof(int));
if ((globals->mp_list == NULL) || (globals->mp_refcount == NULL) || (globals->mp_mine == NULL))
{
#ifdef DEBUG
_notify_client_log(ASL_LEVEL_ERR, "notify_retain_mach_port reallocf failed errno %d [%s]\n", errno, strerror(errno));
#endif
free(globals->mp_list);
globals->mp_list = NULL;
free(globals->mp_refcount);
globals->mp_refcount = NULL;
free(globals->mp_mine);
globals->mp_mine = NULL;
globals->mp_count = 0;
}
else
{
globals->mp_list[x] = mp;
globals->mp_refcount[x] = 1;
globals->mp_mine[x] = mine;
}
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
}
static void
notify_release_mach_port(mach_port_t mp, uint32_t flags)
{
int x, i;
notify_globals_t globals = _notify_globals();
if (mp == MACH_PORT_NULL) return;
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
x = -1;
for (i = 0; (i < globals->mp_count) && (x < 0); i++)
{
if (globals->mp_list[i] == mp) x = i;
}
if (x < 0)
{
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
if (globals->mp_refcount[x] > 0) globals->mp_refcount[x]--;
if (globals->mp_refcount[x] > 0)
{
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
if (globals->mp_mine[x] == 1)
{
mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1);
if (flags & NOTIFY_FLAG_SELF) mach_port_deallocate(mach_task_self(), mp);
}
if (flags & NOTIFY_FLAG_RELEASE_SEND)
{
mach_port_deallocate(mach_task_self(), mp);
}
if (globals->mp_count == 1)
{
free(globals->mp_list);
globals->mp_list = NULL;
free(globals->mp_refcount);
globals->mp_refcount = NULL;
free(globals->mp_mine);
globals->mp_mine = NULL;
globals->mp_count = 0;
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
for (i = x + 1; i < globals->mp_count; i++)
{
globals->mp_list[i - 1] = globals->mp_list[i];
globals->mp_refcount[i - 1] = globals->mp_refcount[i];
globals->mp_mine[i - 1] = globals->mp_mine[i];
}
globals->mp_count--;
globals->mp_list = (mach_port_t *)reallocf(globals->mp_list, globals->mp_count * sizeof(mach_port_t));
globals->mp_refcount = (int *)reallocf(globals->mp_refcount, globals->mp_count * sizeof(int));
globals->mp_mine = (int *)reallocf(globals->mp_mine, globals->mp_count * sizeof(int));
if ((globals->mp_list == NULL) || (globals->mp_refcount == NULL) || (globals->mp_mine == NULL))
{
#ifdef DEBUG
_notify_client_log(ASL_LEVEL_ERR, "notify_release_mach_port reallocf failed errno %d [%s]\n", errno, strerror(errno));
#endif
if (globals->mp_list != NULL) free(globals->mp_list);
if (globals->mp_refcount != NULL) free(globals->mp_refcount);
if (globals->mp_mine != NULL) free(globals->mp_mine);
globals->mp_count = 0;
}
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
}
static notify_state_t *
_notify_lib_self_state()
{
notify_globals_t globals = _notify_globals();
dispatch_once(&globals->self_state_once, ^{
globals->self_state = _notify_lib_notify_state_new(NOTIFY_STATE_USE_LOCKS, 0);
});
return globals->self_state;
}
void
notify_set_options(uint32_t opts)
{
notify_globals_t globals = _notify_globals();
if (globals->client_opts & NOTIFY_OPT_DISABLE)
{
if ((opts & NOTIFY_OPT_ENABLE) == 0) return;
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
globals->client_opts = globals->saved_opts;
globals->notify_server_port = globals->saved_server_port;
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
if (opts & NOTIFY_OPT_DISABLE)
{
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
globals->saved_opts = globals->client_opts;
globals->client_opts = NOTIFY_OPT_DISABLE;
globals->saved_server_port = globals->notify_server_port;
globals->notify_server_port = MACH_PORT_NULL;
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
return;
}
globals->client_opts = opts;
_notify_lib_init(EVENT_INIT);
}
uint32_t
notify_post(const char *name)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status;
size_t namelen = 0;
name_node_t *n;
uint64_t nid = UINT64_MAX;
notify_globals_t globals = _notify_globals();
regenerate_check();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL) return NOTIFY_STATUS_FAILED;
_notify_lib_post(ns_self, name, 0, 0);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
if (globals->notify_ipc_version == 0)
{
namelen = strlen(name);
kstatus = _notify_server_post(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, (int32_t *)&status);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
namelen = strlen(name);
n = name_node_for_name(name, NID_UNSET, false, true);
if (n != NULL)
{
if (n->name_id == NID_UNSET)
{
kstatus = _notify_server_post_4(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen);
if (kstatus != KERN_SUCCESS)
{
name_node_release(n);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
name_node_set_nid(n, NID_CALLED_ONCE);
}
else if (n->name_id == NID_CALLED_ONCE)
{
kstatus = _notify_server_post_2(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, &nid, (int32_t *)&status);
if (kstatus != KERN_SUCCESS)
{
name_node_release(n);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
name_node_set_nid(n, nid);
}
else
{
kstatus = _notify_server_post_3(globals->notify_server_port, n->name_id);
if (kstatus != KERN_SUCCESS)
{
name_node_release(n);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
name_node_release(n);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
kstatus = _notify_server_post_4(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
uint32_t
notify_set_owner(const char *name, uint32_t uid, uint32_t gid)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status;
notify_globals_t globals = _notify_globals();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
status = _notify_lib_set_owner(ns_self, name, uid, gid);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
kstatus = _notify_server_set_owner(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)strlen(name), uid, gid, (int32_t *)&status);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_get_owner(const char *name, uint32_t *uid, uint32_t *gid)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status;
notify_globals_t globals = _notify_globals();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
status = _notify_lib_get_owner(ns_self, name, uid, gid);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
kstatus = _notify_server_get_owner(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)strlen(name), (int32_t *)uid, (int32_t *)gid, (int32_t *)&status);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_set_access(const char *name, uint32_t access)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status;
notify_globals_t globals = _notify_globals();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
status = _notify_lib_set_access(ns_self, name, access);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
kstatus = _notify_server_set_access(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)strlen(name), access, (int32_t *)&status);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_get_access(const char *name, uint32_t *access)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status;
notify_globals_t globals = _notify_globals();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
status = _notify_lib_get_access(ns_self, name, access);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
kstatus = _notify_server_get_access(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)strlen(name), (int32_t *)access, (int32_t *)&status);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_release_name(const char *name)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API)
{
_notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
_notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 3);
}
#endif
return NOTIFY_STATUS_OK;
}
static void
_notify_dispatch_local_notification(registration_node_t *r)
{
if (r == NULL) return;
if (r->queue == NULL) return;
if (r->block == NULL) return;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NOTIFICATION)
{
if (r->flags & NOTIFY_TYPE_COALESCED) _notify_client_log(ASL_LEVEL_NOTICE, "coalesced notification for token %d (name %s)", r->token, r->name_node->name);
else if (r->flags & NOTIFY_TYPE_COALESCE_BASE) _notify_client_log(ASL_LEVEL_NOTICE, "coalesced base notification for token %d (name %s)", r->token, r->name_node->name);
else _notify_client_log(ASL_LEVEL_NOTICE, "dispatch notification for token %d (name %s)", r->token, r->name_node->name);
}
#endif
int token = r->token;
notify_handler_t theblock = Block_copy(r->block);
dispatch_queue_t thequeue = r->queue;
dispatch_retain(thequeue);
dispatch_async(thequeue, ^{
bool valid = notify_is_valid_token(token);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NOTIFICATION) _notify_client_log(ASL_LEVEL_NOTICE, "-> dispatch_async token %d (%svalid) registration node %p", token, valid ? "" : "in", r);
#endif
if (valid) theblock(token);
_Block_release(theblock);
dispatch_release(thequeue);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NOTIFICATION) _notify_client_log(ASL_LEVEL_NOTICE, "<- dispatch_async token %d", token);
#endif
});
}
static void
_notify_dispatch_handle(mach_port_t port)
{
name_node_t *n;
registration_node_t *r;
int token;
mach_msg_empty_rcv_t msg;
kern_return_t status;
if (port == MACH_PORT_NULL) return;
memset(&msg, 0, sizeof(msg));
status = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof(msg), port, 0, MACH_PORT_NULL);
if (status != KERN_SUCCESS) return;
token = msg.header.msgh_id;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_NOTIFICATION) _notify_client_log(ASL_LEVEL_NOTICE, "_notify_dispatch_handle token %d", token);
#endif
r = registration_node_find(token);
if (r == NULL) return;
n = r->name_node;
if (n == NULL)
{
registration_node_release(r);
return;
}
mutex_lock(n->name, &n->lock, __func__, __LINE__);
if (r->flags & NOTIFY_TYPE_COALESCE_BASE)
{
registration_node_t *x;
TAILQ_FOREACH(x, &n->coalesced, registration_coalesced_entry)
{
if ((x != NULL) && (x != r)) _notify_dispatch_local_notification(x);
}
}
else
{
_notify_dispatch_local_notification(r);
}
mutex_unlock(n->name, &n->lock, __func__, __LINE__);
registration_node_release(r);
}
uint32_t
notify_register_dispatch(const char *name, int *out_token, dispatch_queue_t queue, notify_handler_t handler)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
uint32_t status;
registration_node_t *r;
notify_globals_t globals = _notify_globals();
regenerate_check();
if (queue == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
if (handler == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
notify_set_options(NOTIFY_OPT_DISPATCH | NOTIFY_OPT_REGEN);
status = notify_register_mach_port(name, &globals->notify_common_port, NOTIFY_REUSE, out_token);
if (status != NOTIFY_STATUS_OK)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
r = registration_node_find(*out_token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
r->queue = queue;
dispatch_retain(r->queue);
r->block = Block_copy(handler);
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
static uint32_t
notify_register_mux_fd(const char *name, int *out_token, int rfd, int wfd)
{
uint32_t status;
registration_node_t *r;
int val;
notify_globals_t globals = _notify_globals();
status = NOTIFY_STATUS_OK;
if (globals->notify_common_port == MACH_PORT_NULL) return NOTIFY_STATUS_FAILED;
status = notify_register_mach_port(name, &globals->notify_common_port, NOTIFY_REUSE, out_token);
r = registration_node_find(*out_token);
if (r == NULL) return NOTIFY_STATUS_FAILED;
r->token = *out_token;
r->fd = rfd;
r->queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_retain(r->queue);
val = htonl(r->token);
r->block = (notify_handler_t)Block_copy(^(int unused){ write(wfd, &val, sizeof(val)); });
registration_node_release(r);
return NOTIFY_STATUS_OK;
}
#pragma mark -
#pragma mark registration
uint32_t
notify_register_check(const char *name, int *out_token)
{
#if TARGET_IPHONE_SIMULATOR
return notify_register_plain(name, out_token);
#endif
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status, token;
uint64_t nid;
int32_t slot, shmsize;
size_t namelen;
uint32_t cid;
notify_globals_t globals = _notify_globals();
regenerate_check();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
if (out_token == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
*out_token = -1;
namelen = strlen(name);
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
status = _notify_lib_register_plain(ns_self, name, NOTIFY_CLIENT_SELF, token, SLOT_NONE, 0, 0, &nid);
if (status != NOTIFY_STATUS_OK)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
cid = token;
client_registration_create(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PLAIN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL);
*out_token = token;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
kstatus = KERN_SUCCESS;
if (globals->notify_ipc_version == 0)
{
nid = NID_UNSET;
kstatus = _notify_server_register_check(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, &shmsize, &slot, (int32_t *)&cid, (int32_t *)&status);
}
else
{
cid = token;
kstatus = _notify_server_register_check_2(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, token, &shmsize, &slot, &nid, (int32_t *)&status);
}
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
if (status != NOTIFY_STATUS_OK)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
if (shmsize != -1)
{
if (globals->shm_base == NULL)
{
if (shm_attach(shmsize) != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
if (globals->shm_base == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
client_registration_create(name, namelen, nid, token, cid, slot, NOTIFY_TYPE_MEMORY | NOTIFY_FLAG_REGEN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL);
}
else
{
client_registration_create(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_TYPE_PLAIN | NOTIFY_FLAG_REGEN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL);
}
*out_token = token;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_register_plain(const char *name, int *out_token)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status;
uint64_t nid;
size_t namelen;
int token;
uint32_t cid;
notify_globals_t globals = _notify_globals();
regenerate_check();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
namelen = strlen(name);
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
status = _notify_lib_register_plain(ns_self, name, NOTIFY_CLIENT_SELF, token, SLOT_NONE, 0, 0, &nid);
if (status != NOTIFY_STATUS_OK)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
cid = token;
client_registration_create(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PLAIN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL);
*out_token = token;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
if (globals->notify_ipc_version == 0)
{
kstatus = _notify_server_register_plain(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, (int32_t *)&cid, (int32_t *)&status);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
if (status != NOTIFY_STATUS_OK)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
}
else
{
cid = token;
kstatus = _notify_server_register_plain_2(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, token);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
client_registration_create(name, namelen, NID_UNSET, token, cid, SLOT_NONE, NOTIFY_TYPE_PLAIN | NOTIFY_FLAG_REGEN, SIGNAL_NONE, FD_NONE, MACH_PORT_NULL);
*out_token = token;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
uint32_t
notify_register_signal(const char *name, int sig, int *out_token)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status;
uint64_t nid;
size_t namelen;
int token;
uint32_t cid;
notify_globals_t globals = _notify_globals();
regenerate_check();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
namelen = strlen(name);
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
status = _notify_lib_register_signal(ns_self, name, NOTIFY_CLIENT_SELF, token, sig, 0, 0, &nid);
if (status != NOTIFY_STATUS_OK)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
cid = token;
client_registration_create(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_SIGNAL, sig, FD_NONE, MACH_PORT_NULL);
*out_token = token;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->client_opts & NOTIFY_OPT_DISPATCH)
{
status = notify_register_dispatch(name, out_token, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int unused){ kill(getpid(), sig); });
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
if (globals->notify_ipc_version == 0)
{
kstatus = _notify_server_register_signal(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, sig, (int32_t *)&cid, (int32_t *)&status);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
if (status != NOTIFY_STATUS_OK)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
}
else
{
cid = token;
kstatus = _notify_server_register_signal_2(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, token, sig);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
client_registration_create(name, namelen, NID_UNSET, token, cid, SLOT_NONE, NOTIFY_TYPE_SIGNAL | NOTIFY_FLAG_REGEN, sig, FD_NONE, MACH_PORT_NULL);
*out_token = token;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
uint32_t
notify_register_mach_port(const char *name, mach_port_name_t *notify_port, int flags, int *out_token)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
kern_return_t kstatus;
uint32_t status;
uint64_t nid;
task_t task;
int token, mine;
size_t namelen;
uint32_t cid, tflags;
registration_node_t *r;
name_node_t *n = NULL;
mach_port_name_t port;
notify_globals_t globals = _notify_globals();
bool create_base = false;
regenerate_check();
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
if (notify_port == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_PORT;
}
mine = 0;
namelen = strlen(name);
task = mach_task_self();
if ((flags & NOTIFY_REUSE) == 0)
{
mine = 1;
kstatus = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, notify_port);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
kstatus = mach_port_insert_right(task, *notify_port, *notify_port, MACH_MSG_TYPE_MAKE_SEND);
if (kstatus != KERN_SUCCESS)
{
if (mine == 1) mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
if (mine == 1)
{
mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
}
mach_port_deallocate(task, *notify_port);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
status = _notify_lib_register_mach_port(ns_self, name, NOTIFY_CLIENT_SELF, token, *notify_port, 0, 0, &nid);
if (status != NOTIFY_STATUS_OK)
{
if (mine == 1)
{
mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
}
mach_port_deallocate(task, *notify_port);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
cid = token;
client_registration_create(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_PORT, SIGNAL_NONE, FD_NONE, *notify_port);
*out_token = token;
notify_retain_mach_port(*notify_port, mine);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
if (mine == 1) mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
mach_port_deallocate(task, *notify_port);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
if ((globals->client_opts & NOTIFY_OPT_DISPATCH) && (*notify_port != globals->notify_common_port))
{
port = globals->notify_common_port;
kstatus = mach_port_insert_right(task, globals->notify_common_port, globals->notify_common_port, MACH_MSG_TYPE_MAKE_SEND);
if (kstatus != KERN_SUCCESS)
{
if (mine == 1) mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
mach_port_deallocate(task, *notify_port);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
else
{
port = *notify_port;
}
tflags = NOTIFY_TYPE_PORT;
if (port == globals->notify_common_port) tflags |= NOTIFY_FLAG_REGEN;
token = -1;
cid = -1;
if ((globals->client_opts & NOTIFY_OPT_DISPATCH) && ((flags & NOTIFY_NO_DISPATCH) == 0))
{
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
n = (name_node_t *)_nc_table_find(globals->name_table, name);
if (n == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_REGISTRATION) _notify_client_log(ASL_LEVEL_NOTICE, "%s %d: name table find %s -> NULL", __func__, __LINE__, name);
#endif
create_base = true;
}
else if (n->coalesce_base == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_REGISTRATION) _notify_client_log(ASL_LEVEL_NOTICE, "%s %d: name table find %s -> %p, coalesce_base = NULL", __func__, __LINE__, name, n);
#endif
create_base = true;
}
#ifdef DEBUG
else
{
if (_libnotify_debug & DEBUG_REGISTRATION) _notify_client_log(ASL_LEVEL_NOTICE, "%s %d: name table find %s -> %p, coalesce_base = %p", __func__, __LINE__, name, n, n->coalesce_base);
}
#endif
if (create_base)
{
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
cid = token;
kstatus = _notify_server_register_mach_port_2(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, token, globals->notify_common_port);
if (kstatus != KERN_SUCCESS)
{
if (mine == 1) mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
mach_port_deallocate(task, *notify_port);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
base_registration_create(name, namelen, NID_UNSET, token, tflags, globals->notify_common_port);
}
n = (name_node_t *)_nc_table_find(globals->name_table, name);
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
cid = token;
tflags |= NOTIFY_TYPE_COALESCED;
}
else
{
if (globals->notify_ipc_version == 0)
{
kstatus = _notify_server_register_mach_port(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, port, token, (int32_t *)&cid, (int32_t *)&status);
if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
}
else
{
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
cid = token;
kstatus = _notify_server_register_mach_port_2(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, token, port);
}
if (kstatus != KERN_SUCCESS)
{
if (mine == 1) mach_port_mod_refs(task, *notify_port, MACH_PORT_RIGHT_RECEIVE, -1);
mach_port_deallocate(task, *notify_port);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
client_registration_create(name, namelen, NID_UNSET, token, cid, SLOT_NONE, tflags, SIGNAL_NONE, FD_NONE, *notify_port);
if (create_base && (n != NULL)) registration_node_release(n->coalesce_base);
if ((globals->client_opts & NOTIFY_OPT_DISPATCH) && (*notify_port != globals->notify_common_port))
{
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
r->flags |= NOTIFY_FLAG_RELEASE_SEND;
port = *notify_port;
r->queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_retain(r->queue);
r->block = (notify_handler_t)Block_copy(^(int unused){
mach_msg_empty_send_t msg;
kern_return_t kstatus;
memset(&msg, 0, sizeof(msg));
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO);
msg.header.msgh_remote_port = port;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
msg.header.msgh_id = token;
kstatus = mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, msg.header.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
if (kstatus == MACH_SEND_TIMED_OUT)
{
dispatch_once(&globals->make_background_send_queue_once, ^{
globals->background_send_queue = dispatch_queue_create("com.apple.notify.background.local.notification", NULL);
});
if (globals->background_send_queue != NULL) dispatch_async(globals->background_send_queue, ^{
mach_msg_empty_send_t msg;
kern_return_t kstatus;
memset(&msg, 0, sizeof(msg));
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO);
msg.header.msgh_remote_port = port;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_size = sizeof(mach_msg_empty_send_t);
msg.header.msgh_id = token;
kstatus = mach_msg(&msg.header, MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
});
}
});
registration_node_release(r);
}
*out_token = token;
notify_retain_mach_port(*notify_port, mine);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
static char *
_notify_mk_tmp_path(int tid)
{
#if TARGET_OS_EMBEDDED
int freetmp = 0;
char *path, *tmp = getenv("TMPDIR");
if (tmp == NULL)
{
asprintf(&tmp, "/tmp/com.apple.notify.%d", geteuid());
mkdir(tmp, 0755);
freetmp = 1;
}
if (tmp == NULL) return NULL;
asprintf(&path, "%s/com.apple.notify.%d.%d", tmp, getpid(), tid);
if (freetmp) free(tmp);
return path;
#else
char tmp[PATH_MAX], *path;
if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmp, sizeof(tmp)) <= 0) return NULL;
#endif
path = NULL;
asprintf(&path, "%s/com.apple.notify.%d.%d", tmp, getpid(), tid);
return path;
}
uint32_t
notify_register_file_descriptor(const char *name, int *notify_fd, int flags, int *out_token)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
notify_state_t *ns_self;
uint32_t i, status;
uint64_t nid;
int token, mine, fdpair[2];
size_t namelen;
fileport_t fileport;
kern_return_t kstatus;
uint32_t cid;
notify_globals_t globals = _notify_globals();
regenerate_check();
mine = 0;
if (name == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor name=NULL\n");
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_NAME;
}
if (notify_fd == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor notify_fd=NULL\n");
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_FILE;
}
namelen = strlen(name);
if ((flags & NOTIFY_REUSE) == 0)
{
if (pipe(fdpair) < 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s [non-reused[ pipe failed errno=%d [%s]\n, name, errno, strerror(errno)");
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
mine = 1;
*notify_fd = fdpair[0];
}
else
{
for (i = 0; i < globals->fd_count; i++)
{
if (globals->fd_clnt[i] == *notify_fd) break;
}
if (i >= globals->fd_count)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s [reused] file not found\n", name);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_FILE;
}
fdpair[0] = globals->fd_clnt[i];
fdpair[1] = globals->fd_srv[i];
}
if (!strncmp(name, SELF_PREFIX, SELF_PREFIX_LEN))
{
ns_self = _notify_lib_self_state();
if (ns_self == NULL)
{
if (mine == 1)
{
close(fdpair[0]);
close(fdpair[1]);
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s [self] _notify_lib_self_state failed\n", name);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
status = _notify_lib_register_file_descriptor(ns_self, name, NOTIFY_CLIENT_SELF, token, fdpair[1], 0, 0, &nid);
if (status != NOTIFY_STATUS_OK)
{
if (mine == 1)
{
close(fdpair[0]);
close(fdpair[1]);
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s [self] _notify_lib_register_file_descriptor failed status=%u\n", name, status);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
cid = token;
client_registration_create(name, namelen, nid, token, cid, SLOT_NONE, NOTIFY_FLAG_SELF | NOTIFY_TYPE_FILE, SIGNAL_NONE, *notify_fd, MACH_PORT_NULL);
*out_token = token;
notify_retain_file_descriptor(fdpair[0], fdpair[1]);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->client_opts & NOTIFY_OPT_DISPATCH)
{
status = notify_register_mux_fd(name, out_token, fdpair[0], fdpair[1]);
if (status != NOTIFY_STATUS_OK)
{
if (mine == 1)
{
close(fdpair[0]);
close(fdpair[1]);
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s notify_register_mux_fd failed status=%u\n", name, status);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
notify_retain_file_descriptor(fdpair[0], fdpair[1]);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
if (mine == 1)
{
close(fdpair[0]);
close(fdpair[1]);
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s _notify_lib_init failed status=%u\n", name, status);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
fileport = MACH_PORT_NULL;
if (fileport_makeport(fdpair[1], (fileport_t *)&fileport) < 0)
{
if (mine == 1)
{
close(fdpair[0]);
close(fdpair[1]);
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s fileport_makeport failed errno=%d [%s]\n", name, errno, strerror(errno));
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
token = OSAtomicIncrement32((int32_t *)&globals->token_id);
if (globals->notify_ipc_version == 0)
{
kstatus = _notify_server_register_file_descriptor(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, (mach_port_t)fileport, token, (int32_t *)&cid, (int32_t *)&status);
if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK))
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s [IPC version 0] _notify_server_register_file_descriptor returned status=%u\n", name, status);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
kstatus = KERN_FAILURE;
}
}
else
{
kstatus = _notify_server_register_file_descriptor_2(globals->notify_server_port, (caddr_t)name, (mach_msg_type_number_t)namelen, token, (mach_port_t)fileport);
}
if (kstatus != KERN_SUCCESS)
{
if (mine == 1)
{
close(fdpair[0]);
close(fdpair[1]);
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_register_file_descriptor %s _notify_server_register_file_descriptor[_2] failed status=0x%08xu\n", name, kstatus);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
client_registration_create(name, namelen, NID_UNSET, token, cid, SLOT_NONE, NOTIFY_TYPE_FILE, SIGNAL_NONE, *notify_fd, MACH_PORT_NULL);
*out_token = token;
notify_retain_file_descriptor(fdpair[0], fdpair[1]);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
uint32_t
notify_check(int token, int *check)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
kern_return_t kstatus;
uint32_t status = NOTIFY_STATUS_OK;
registration_node_t *r;
uint32_t tid;
notify_globals_t globals = _notify_globals();
regenerate_check();
if (check == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check check=NULL\n", token);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d registration node not found\n", token);
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->flags & NOTIFY_FLAG_SELF)
{
status = _notify_lib_check(globals->self_state, NOTIFY_CLIENT_SELF, token, check);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d self registration _notify_lib_check status %u check %d\n", token, status, *check);
if ((_libnotify_debug & DEBUG_USER) && (status != NOTIFY_STATUS_FAILED)) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d [self] _notify_lib_check failed status=%u\n", token, status);
#endif
goto release_and_return;
}
if (r->flags & NOTIFY_TYPE_MEMORY)
{
if (globals->shm_base == NULL)
{
status = NOTIFY_STATUS_FAILED;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d [memory] globals->shm_base is NULL\n", token);
#endif
goto release_and_return;
}
*check = 0;
OSSpinLockLock(&(globals->checkLock));
if (r->val != globals->shm_base[r->slot])
{
*check = 1;
r->val = globals->shm_base[r->slot];
}
OSSpinLockUnlock(&(globals->checkLock));
status = NOTIFY_STATUS_OK;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d shared memory check status %u check %d\n", token, status, *check);
#endif
goto release_and_return;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d in not a shared memory registration\n", token);
#endif
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d [non-memory] _notify_lib_init failed status=%u\n", token, status);
#endif
goto release_and_return;
}
}
tid = token;
if (globals->notify_ipc_version == 0) tid = r->client_id;
if (r->flags & NOTIFY_TYPE_COALESCED) tid = r->name_node->coalesce_base_token;
kstatus = _notify_server_check(globals->notify_server_port, tid, check, (int32_t *)&status);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d [%d] _notify_server_check kstatus 0x%08x status %u check %d\n", token, tid, kstatus, status, *check);
#endif
if (kstatus != KERN_SUCCESS)
{
status = NOTIFY_STATUS_FAILED;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_USER) _notify_client_log(ASL_LEVEL_ERR, "notify_check token %d [non-memory] _notify_server_check failed kstatus=0x%08x status=%u\n", token, kstatus, status);
#endif
}
release_and_return:
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d] status %u check %d\n", __func__, __LINE__ + 2, status, *check);
#endif
return status;
}
uint32_t
notify_peek(int token, uint32_t *val)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
registration_node_t *r;
uint32_t status;
notify_globals_t globals = _notify_globals();
regenerate_check();
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->flags & NOTIFY_FLAG_SELF)
{
status = _notify_lib_peek(globals->self_state, NOTIFY_CLIENT_SELF, token, (int *)val);
goto release_and_return;
}
status = NOTIFY_STATUS_INVALID_REQUEST;
if (r->flags & NOTIFY_TYPE_MEMORY)
{
if (globals->shm_base == NULL)
{
status = NOTIFY_STATUS_FAILED;
goto release_and_return;
}
*val = globals->shm_base[r->slot];
status = NOTIFY_STATUS_OK;
}
release_and_return:
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
int *
notify_check_addr(int token)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
registration_node_t *r;
int *val = NULL;
notify_globals_t globals = _notify_globals();
regenerate_check();
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NULL;
}
if (r->flags & NOTIFY_FLAG_SELF)
{
val = _notify_lib_check_addr(globals->self_state, NOTIFY_CLIENT_SELF, token);
goto release_and_return;
}
if ((r->flags & NOTIFY_TYPE_MEMORY) && (globals->shm_base != NULL)) val = (int *)&(globals->shm_base[r->slot]);
release_and_return:
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return val;
}
uint32_t
notify_monitor_file(int token, char *path, int flags)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
kern_return_t kstatus;
uint32_t status, len;
registration_node_t *r;
char *dup;
notify_globals_t globals = _notify_globals();
regenerate_check();
if (path == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_REQUEST;
}
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->flags & NOTIFY_FLAG_SELF)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_REQUEST;
}
if (r->path != NULL)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_REQUEST;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
len = (uint32_t)strlen(path);
dup = strdup(path);
if (dup == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
if (globals->notify_ipc_version == 0)
{
kstatus = _notify_server_monitor_file(globals->notify_server_port, r->client_id, path, len, flags, (int32_t *)&status);
if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
}
else
{
int xtoken = token;
if (r->flags & NOTIFY_TYPE_COALESCED) xtoken = r->name_node->coalesce_base_token;
kstatus = _notify_server_monitor_file_2(globals->notify_server_port, xtoken, path, len, flags);
}
r->path = dup;
r->path_flags = flags;
registration_node_release(r);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
uint32_t
notify_get_event(int token, int *ev, char *buf, int *len)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
if (ev != NULL) *ev = 0;
if (len != NULL) *len = 0;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
uint32_t
notify_get_state(int token, uint64_t *state)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
kern_return_t kstatus;
uint32_t status;
registration_node_t *r;
uint64_t nid;
notify_globals_t globals = _notify_globals();
regenerate_check();
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->name_node == NULL)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->flags & NOTIFY_FLAG_SELF)
{
status = _notify_lib_get_state(globals->self_state, r->name_node->name_id, state, 0, 0);
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
if (globals->notify_ipc_version == 0)
{
kstatus = _notify_server_get_state(globals->notify_server_port, r->client_id, state, (int32_t *)&status);
if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
}
else
{
int xtoken = token;
if (r->flags & NOTIFY_TYPE_COALESCED) xtoken = r->name_node->coalesce_base_token;
nid = r->name_node->name_id;
if ((nid == NID_UNSET) || (nid == NID_CALLED_ONCE))
{
kstatus = _notify_server_get_state_3(globals->notify_server_port, xtoken, state, (uint64_t *)&nid, (int32_t *)&status);
if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) name_node_set_nid(r->name_node, nid);
}
else
{
kstatus = _notify_server_get_state_2(globals->notify_server_port, r->name_node->name_id, state, (int32_t *)&status);
}
}
registration_node_release(r);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_set_state(int token, uint64_t state)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
kern_return_t kstatus;
uint32_t status;
registration_node_t *r;
uint64_t nid;
notify_globals_t globals = _notify_globals();
regenerate_check();
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->name_node == NULL)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->flags & NOTIFY_FLAG_SELF)
{
status = _notify_lib_set_state(globals->self_state, r->name_node->name_id, state, 0, 0);
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
status = NOTIFY_STATUS_OK;
if (globals->notify_ipc_version == 0)
{
kstatus = _notify_server_set_state(globals->notify_server_port, r->client_id, state, (int32_t *)&status);
if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
}
else
{
int xtoken = token;
if (r->flags & NOTIFY_TYPE_COALESCED) xtoken = r->name_node->coalesce_base_token;
nid = r->name_node->name_id;
if ((nid == NID_UNSET) || (nid == NID_CALLED_ONCE))
{
kstatus = _notify_server_set_state_3(globals->notify_server_port, xtoken, state, (uint64_t *)&nid, (int32_t *)&status);
if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK)) name_node_set_nid(r->name_node, nid);
}
else
{
status = NOTIFY_STATUS_OK;
kstatus = _notify_server_set_state_2(globals->notify_server_port, r->name_node->name_id, state);
}
}
if ((kstatus == KERN_SUCCESS) && (status == NOTIFY_STATUS_OK))
{
r->set_state_time = mach_absolute_time();
r->set_state_val = state;
}
registration_node_release(r);
if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
uint32_t
notify_cancel(int token)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
registration_node_t *r;
uint32_t status;
kern_return_t kstatus = KERN_SUCCESS;
notify_globals_t globals = _notify_globals();
regenerate_check();
mutex_lock("global", &globals->notify_lock, __func__, __LINE__);
r = (registration_node_t *)_nc_table_find_n(globals->registration_table, token);
if (r == NULL)
{
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (OSAtomicDecrement32(&r->refcount) > 0)
{
#ifdef DEBUG
if (_libnotify_debug & (DEBUG_NODES | DEBUG_CANCEL)) _notify_client_log(ASL_LEVEL_NOTICE, "notify_cancel token %u refcount %d flags 0x%08x %p", r->token, r->refcount, r->flags, r);
#endif
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
_nc_table_delete_n(globals->registration_table, r->token);
mutex_unlock("global", &globals->notify_lock, __func__, __LINE__);
if (r->flags & NOTIFY_FLAG_SELF)
{
_notify_lib_cancel(globals->self_state, NOTIFY_CLIENT_SELF, r->token);
registration_node_free(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (r->flags & NOTIFY_TYPE_COALESCE_BASE)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_CANCEL) _notify_client_log(ASL_LEVEL_NOTICE, "notify_cancel token %d NOTIFY_TYPE_COALESCE_BASE", token);
#endif
registration_node_free(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->notify_ipc_version == 0)
{
kstatus = _notify_server_cancel(globals->notify_server_port, r->client_id, (int32_t *)&status);
if ((kstatus == KERN_SUCCESS) && (status != NOTIFY_STATUS_OK)) kstatus = KERN_FAILURE;
}
else if ((r->flags & NOTIFY_TYPE_COALESCED) == 0)
{
kstatus = _notify_server_cancel_2(globals->notify_server_port, token);
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_CANCEL) _notify_client_log(ASL_LEVEL_NOTICE, "notify_cancel token %d reg_node %p has been cancelled", token, r);
#endif
registration_node_free(r);
if ((kstatus == MIG_SERVER_DIED) || (kstatus == MACH_SEND_INVALID_DEST))
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
else if (kstatus != KERN_SUCCESS)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
uint32_t
notify_suspend(int token)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
registration_node_t *r;
uint32_t status, tid;
kern_return_t kstatus;
notify_globals_t globals = _notify_globals();
regenerate_check();
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->flags & NOTIFY_FLAG_SELF)
{
_notify_lib_suspend(globals->self_state, NOTIFY_CLIENT_SELF, r->token);
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
int xtoken = token;
if (r->flags & NOTIFY_TYPE_COALESCED) xtoken = r->name_node->coalesce_base_token;
tid = xtoken;
if (globals->notify_ipc_version == 0) tid = r->client_id;
if (r->flags & NOTIFY_TYPE_COALESCED) tid = r->name_node->coalesce_base_token;
kstatus = _notify_server_suspend(globals->notify_server_port, tid, (int32_t *)&status);
registration_node_release(r);
if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_resume(int token)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
registration_node_t *r;
uint32_t status, tid;
kern_return_t kstatus;
notify_globals_t globals = _notify_globals();
regenerate_check();
r = registration_node_find(token);
if (r == NULL)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_INVALID_TOKEN;
}
if (r->flags & NOTIFY_FLAG_SELF)
{
_notify_lib_resume(globals->self_state, NOTIFY_CLIENT_SELF, r->token);
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_OK;
}
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
registration_node_release(r);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
int xtoken = token;
if (r->flags & NOTIFY_TYPE_COALESCED) xtoken = r->name_node->coalesce_base_token;
tid = xtoken;
if (globals->notify_ipc_version == 0) tid = r->client_id;
if (r->flags & NOTIFY_TYPE_COALESCED) tid = r->name_node->coalesce_base_token;
kstatus = _notify_server_resume(globals->notify_server_port, tid, (int32_t *)&status);
registration_node_release(r);
if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_suspend_pid(pid_t pid)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
uint32_t status;
kern_return_t kstatus;
notify_globals_t globals = _notify_globals();
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
kstatus = _notify_server_suspend_pid(globals->notify_server_port, pid, (int32_t *)&status);
if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_resume_pid(pid_t pid)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
uint32_t status;
kern_return_t kstatus;
notify_globals_t globals = _notify_globals();
if (globals->notify_server_port == MACH_PORT_NULL)
{
status = _notify_lib_init(EVENT_INIT);
if (status != 0)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return NOTIFY_STATUS_FAILED;
}
}
kstatus = _notify_server_resume_pid(globals->notify_server_port, pid, (int32_t *)&status);
if (kstatus != KERN_SUCCESS) status = NOTIFY_STATUS_FAILED;
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}
uint32_t
notify_simple_post(const char *name)
{
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "-> %s\n", __func__);
#endif
uint32_t status = notify_post(name);
#ifdef DEBUG
if (_libnotify_debug & DEBUG_API) _notify_client_log(ASL_LEVEL_NOTICE, "<- %s [%d]\n", __func__, __LINE__ + 2);
#endif
return status;
}