From d0178934a1c7e5ce13a55e00e57b01f5f39a2535 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sat, 21 Nov 2009 10:25:30 -0800 Subject: [PATCH] basic ipc framework --- lib/ipc/Makefile.am | 31 +++ lib/ipc/client.c | 541 ++++++++++++++++++++++++++++++++++++ lib/ipc/common.c | 155 +++++++++++ lib/ipc/heim-ipc.h | 117 ++++++++ lib/ipc/heim_ipc.defs | 66 +++++ lib/ipc/heim_ipc_async.defs | 56 ++++ lib/ipc/heim_ipc_reply.defs | 51 ++++ lib/ipc/heim_ipc_types.h | 44 +++ lib/ipc/hi_locl.h | 54 ++++ lib/ipc/server.c | 492 ++++++++++++++++++++++++++++++++ lib/ipc/tc.c | 82 ++++++ lib/ipc/ts.c | 67 +++++ 12 files changed, 1756 insertions(+) create mode 100644 lib/ipc/Makefile.am create mode 100644 lib/ipc/client.c create mode 100644 lib/ipc/common.c create mode 100644 lib/ipc/heim-ipc.h create mode 100644 lib/ipc/heim_ipc.defs create mode 100644 lib/ipc/heim_ipc_async.defs create mode 100644 lib/ipc/heim_ipc_reply.defs create mode 100644 lib/ipc/heim_ipc_types.h create mode 100644 lib/ipc/hi_locl.h create mode 100644 lib/ipc/server.c create mode 100644 lib/ipc/tc.c create mode 100644 lib/ipc/ts.c diff --git a/lib/ipc/Makefile.am b/lib/ipc/Makefile.am new file mode 100644 index 000000000..6ec7b0d03 --- /dev/null +++ b/lib/ipc/Makefile.am @@ -0,0 +1,31 @@ +# $Id: Makefile.am,v 1.1 2004/12/20 08:31:45 assar Exp $ + +include $(top_srcdir)/Makefile.am.common + +noinst_LTLIBRARIES = libheim-ipcc.la libheim-ipcs.la + +libheim_ipcc_la_SOURCES = client.c common.c +libheim_ipcs_la_SOURCES = server.c common.c + +include_HEADERS = heim-ipc.h + +libheim_ipsc_la_LDFLAGS = -version-info 0:0:0 +libheim_ipss_la_LDFLAGS = -version-info 0:0:0 + +libheim_ipsc_la_LIBADD = \ + $(LIB_roken) + +libheim_ipss_la_LIBADD = $(libheim_ipsc_la_LIBADD) + +if versionscript +libheim_ipsc_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-scriptc.map +libheim_ipss_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-scripts.map +endif + +TESTS = $(check_PROGRAMS) + +noinst_PROGRAMS = tc ts + +ts_LDADD = libheim-ipcs.la +tc_LDADD = libheim-ipcc.la + diff --git a/lib/ipc/client.c b/lib/ipc/client.c new file mode 100644 index 000000000..20ae89a17 --- /dev/null +++ b/lib/ipc/client.c @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hi_locl.h" + +#ifdef __APPLE__ + +#include "heim_ipc.h" +#include "heim_ipc_asyncServer.h" + +#include +#include + +static dispatch_once_t jobqinited = 0; +static dispatch_queue_t jobq = NULL; +static dispatch_queue_t syncq; + +struct mach_ctx { + mach_port_t server; + char *name; +}; + +static int +mach_release(void *ctx); + +static int +mach_init(const char *service, void **ctx) +{ + struct mach_ctx *ipc; + mach_port_t sport; + int ret; + + dispatch_once(&jobqinited, ^{ + jobq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + syncq = dispatch_queue_create("heim-ipc-syncq", NULL); + }); + + ret = bootstrap_look_up(bootstrap_port, service, &sport); + if (ret) + return ret; + + ipc = malloc(sizeof(*ipc)); + if (ipc == NULL) { + mach_port_destroy(mach_task_self(), sport); + return ENOMEM; + } + + ipc->server = sport; + ipc->name = strdup(service); + if (ipc->name == NULL) { + mach_release(ipc); + return ENOMEM; + } + + *ctx = ipc; + + return 0; +} + +static int +mach_ipc(void *ctx, + const heim_idata *request, heim_idata *response, + heim_icred *cred) +{ + struct mach_ctx *ipc = ctx; + heim_ipc_message_inband_t requestin; + mach_msg_type_number_t requestin_length = 0; + heim_ipc_message_outband_t requestout = NULL; + mach_msg_type_number_t requestout_length = 0; + heim_ipc_message_inband_t replyin; + mach_msg_type_number_t replyin_length; + heim_ipc_message_outband_t replyout; + mach_msg_type_number_t replyout_length; + int ret, errorcode, retries = 0; + + memcpy(requestin, request->data, request->length); + requestin_length = request->length; + + while (retries < 2) { + __block mach_port_t sport; + + dispatch_sync(syncq, ^{ sport = ipc->server; }); + + ret = mheim_ipc_call(sport, + requestin, requestin_length, + requestout, requestout_length, + &errorcode, + replyin, &replyin_length, + &replyout, &replyout_length); + if (ret == MACH_SEND_INVALID_DEST) { + mach_port_t nport; + /* race other threads to get a new port */ + ret = bootstrap_look_up(bootstrap_port, ipc->name, &nport); + if (ret) + return ret; + dispatch_sync(syncq, ^{ + /* check if we lost the race to lookup the port */ + if (sport != ipc->server) { + mach_port_deallocate(mach_task_self(), nport); + } else { + mach_port_deallocate(mach_task_self(), ipc->server); + ipc->server = nport; + } + }); + retries++; + } else if (ret) { + return ret; + } else + break; + } + if (retries >= 2) + return EINVAL; + + if (errorcode) { + if (replyout_length) + vm_deallocate (mach_task_self (), (vm_address_t) replyout, + replyout_length); + return errorcode; + } + + if (replyout_length) { + response->data = malloc(replyout_length); + if (response->data == NULL) { + vm_deallocate (mach_task_self (), (vm_address_t) replyout, + replyout_length); + return ENOMEM; + } + memcpy(response->data, replyout, replyout_length); + response->length = replyout_length; + vm_deallocate (mach_task_self (), (vm_address_t) replyout, + replyout_length); + } else { + response->data = malloc(replyin_length); + if (response->data == NULL) + return ENOMEM; + memcpy(response->data, replyin, replyin_length); + response->length = replyin_length; + } + + return 0; +} + +struct async_client { + mach_port_t mp; + dispatch_source_t source; + dispatch_queue_t queue; + void (*func)(void *, int, heim_idata *, heim_icred); + void *userctx; +}; + +kern_return_t +mheim_ado_acall_reply(mach_port_t server_port, + audit_token_t client_creds, + int returnvalue, + heim_ipc_message_inband_t replyin, + mach_msg_type_number_t replyinCnt, + heim_ipc_message_outband_t replyout, + mach_msg_type_number_t replyoutCnt) +{ + struct async_client *c = dispatch_get_context(dispatch_get_current_queue()); + heim_idata response; + + if (returnvalue) { + response.data = NULL; + response.length = 0; + } else if (replyoutCnt) { + response.data = replyout; + response.length = replyoutCnt; + } else { + response.data = replyin; + response.length = replyinCnt; + } + + (*c->func)(c->userctx, returnvalue, &response, NULL); + + if (replyoutCnt) + vm_deallocate (mach_task_self (), (vm_address_t) replyout, replyoutCnt); + + dispatch_source_cancel(c->source); + + return 0; + + +} + + +static int +mach_async(void *ctx, const heim_idata *request, void *userctx, + void (*func)(void *, int, heim_idata *, heim_icred)) +{ + struct mach_ctx *ipc = ctx; + heim_ipc_message_inband_t requestin; + mach_msg_type_number_t requestin_length = 0; + heim_ipc_message_outband_t requestout = NULL; + mach_msg_type_number_t requestout_length = 0; + int ret, retries = 0; + kern_return_t kr; + struct async_client *c; + + /* first create the service that will catch the reply from the server */ + /* XXX these object should be cached and reused */ + + c = malloc(sizeof(*c)); + if (c == NULL) + return ENOMEM; + + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &c->mp); + if (kr != KERN_SUCCESS) + return EINVAL; + + c->queue = dispatch_queue_create("heim-ipc-async-client", NULL); + c->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, c->mp, 0, c->queue); + dispatch_set_context(c->queue, c); + + dispatch_source_set_event_handler(c->source, ^{ + dispatch_mig_server(c->source, + sizeof(union __RequestUnion__mheim_ado_mheim_aipc_subsystem), + mheim_aipc_server); + }); + + dispatch_source_set_cancel_handler(c->source, ^{ + struct async_client *s = dispatch_get_context(dispatch_get_current_queue()); + mach_port_mod_refs(mach_task_self(), c->mp, + MACH_PORT_RIGHT_RECEIVE, -1); + dispatch_release(c->queue); + dispatch_release(c->source); + free(c); + }); + + c->func = func; + c->userctx = userctx; + + dispatch_resume(c->source); + + /* ok, send the message */ + + memcpy(requestin, request->data, request->length); + requestin_length = request->length; + + while (retries < 2) { + __block mach_port_t sport; + + dispatch_sync(syncq, ^{ sport = ipc->server; }); + + ret = mheim_ipc_call_request(sport, c->mp, + requestin, requestin_length, + requestout, requestout_length); + if (ret == MACH_SEND_INVALID_DEST) { + ret = bootstrap_look_up(bootstrap_port, ipc->name, &sport); + if (ret) { + dispatch_source_cancel(c->source); + return ret; + } + mach_port_deallocate(mach_task_self(), ipc->server); + ipc->server = sport; + retries++; + } else if (ret) { + dispatch_source_cancel(c->source); + return ret; + } else + break; + } + if (retries >= 2) { + dispatch_source_cancel(c->source); + return EINVAL; + } + + return 0; +} + +static int +mach_release(void *ctx) +{ + struct mach_ctx *ipc = ctx; + if (ipc->server != MACH_PORT_NULL) + mach_port_deallocate(mach_task_self(), ipc->server); + free(ipc->name); + free(ipc); + return 0; +} + +#endif + +struct path_ctx { + char *path; + int fd; +}; + +static int common_release(void *); + +static int +connect_unix(struct path_ctx *s) +{ + struct sockaddr_un addr; + + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, s->path, sizeof(addr.sun_path)); + + s->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (s->fd < 0) + return errno; + rk_cloexec(s->fd); + + if (connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + close(s->fd); + return errno; + } + + return 0; +} + +static int +common_path_init(const char *service, + const char *file, + void **ctx) +{ + struct path_ctx *s; + const char *path; + char *apath = NULL; + int ret; + int *fd; + + s = malloc(sizeof(*s)); + if (s == NULL) + return ENOMEM; + s->fd = -1; + + if (service[0] == '\0') + asprintf(&s->path, "/var/run/.heim_%s", file); + else + s->path = strdup(service); + + *ctx = s; + + return 0; +} + +static int +unix_socket_init(const char *service, + void **ctx) +{ + int ret; + + ret = common_path_init(service, "socket", ctx); + if (ret) + return ret; + ret = connect_unix(*ctx); + if (ret) + common_release(*ctx); + + return ret; +} + + +static int +unix_socket_ipc(void *ctx, + const heim_idata *request, heim_idata *response, + heim_icred *cred) +{ + return EINVAL; +} + +int +common_release(void *ctx) +{ + struct path_ctx *s = ctx; + if (s->fd >= 0) + close(s->fd); + free(s->path); + free(s); + return 0; +} + +#ifdef HAVE_DOOR + +static int +door_init(const char *service, + void **ctx) +{ + ret = common_path_init(context, service, name, "door", ctx); + if (ret) + return ret; + ret = connect_door(*ctx); + if (ret) + common_release(*ctx); + return ret; +} + +static int +door_ipc(void *ctx, + const heim_idata *request, heim_idata *response, + heim_icred *cred) +{ + door_arg_t arg; + int ret; + + arg.data_ptr = request->data; + arg.data_size = request->length; + arg.desc_ptr = NULL; + arg.desc_num = 0; + arg.rbuf = NULL; + arg.rsize = 0; + + ret = door_call(fd, &arg); + close(fd); + if (ret != 0) + return errno; + + response->data = malloc(arg.rsize); + if (response->data == NULL) { + munmap(arg.rbuf, arg.rsize); + return ENOMEM; + } + memcpy(response->data, arg.rbuf, arg.rsize); + response->length = arg.rsize; + munmap(arg.rbuf, arg.rsize); + + return ret; +} + +#endif + +struct hipc_ops { + const char *prefix; + int (*init)(const char *, void **); + int (*release)(void *); + int (*ipc)(void *,const heim_idata *, heim_idata *, heim_icred *); + int (*async)(void *, const heim_idata *, void *, + void (*)(void *, int, heim_idata *, heim_icred)); +}; + +struct hipc_ops ipcs[] = { +#ifdef __APPLE__ + { "MACH", mach_init, mach_release, mach_ipc, mach_async }, +#endif +#ifdef HAVE_DOOR + { "DOOR", door_init, common_release, door_ipc } +#endif + { "UNIX", unix_socket_init, common_release, unix_socket_ipc } +}; + +struct heim_ipc { + struct hipc_ops *ops; + void *ctx; +}; + + +int +heim_ipc_init_context(const char *name, heim_ipc *ctx) +{ + unsigned int i; + int ret, any = 0; + + for(i = 0; i < sizeof(ipcs)/sizeof(ipcs[0]); i++) { + size_t prefix_len = strlen(ipcs[i].prefix); + heim_ipc c; + if(strncmp(ipcs[i].prefix, name, prefix_len) == 0 + && name[prefix_len] == ':') { + } else if (strncmp("ANY:", name, 4) == 0) { + prefix_len = 3; + any = 1; + } else + continue; + + c = calloc(1, sizeof(*c)); + if (c == NULL) + return ENOMEM; + + c->ops = &ipcs[i]; + + ret = (c->ops->init)(name + prefix_len + 1, &c->ctx); + if (ret) { + free(c); + if (any) + continue; + return ret; + } + + *ctx = c; + return 0; + } + + return ENOENT; +} + +void +heim_ipc_free_context(heim_ipc ctx) +{ + (ctx->ops->release)(ctx->ctx); + free(ctx); +} + +int +heim_ipc_call(heim_ipc ctx, const heim_idata *send, heim_idata *recv, + heim_icred *cred) +{ + if (cred) + *cred = NULL; + return (ctx->ops->ipc)(ctx->ctx, send, recv, cred); +} + +int +heim_ipc_async(heim_ipc ctx, const heim_idata *send, void *userctx, + void (*func)(void *, int, heim_idata *, heim_icred)) +{ + if (ctx->ops->async == NULL) + return EAGAIN; /* XXX */ + return (ctx->ops->async)(ctx->ctx, send, userctx, func); +} diff --git a/lib/ipc/common.c b/lib/ipc/common.c new file mode 100644 index 000000000..e0e8d0464 --- /dev/null +++ b/lib/ipc/common.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hi_locl.h" +#ifdef __APPLE__ +#include +#endif + +struct heim_icred { + uid_t uid; + gid_t gid; + pid_t pid; + pid_t session; +}; + +void +heim_ipc_free_cred(heim_icred cred) +{ + free(cred); +} + +uid_t +heim_ipc_cred_get_uid(heim_icred cred) +{ + return cred->uid; +} + +gid_t +heim_ipc_cred_get_gid(heim_icred cred) +{ + return cred->gid; +} + +pid_t +heim_ipc_cred_get_pid(heim_icred cred) +{ + return cred->pid; +} + +pid_t +heim_ipc_cred_get_session(heim_icred cred) +{ + return cred->session; +} + + +int +_heim_ipc_create_cred(uid_t uid, gid_t gid, pid_t pid, pid_t session, heim_icred *cred) +{ + *cred = calloc(1, sizeof(**cred)); + if (*cred == NULL) + return ENOMEM; + (*cred)->uid = uid; + (*cred)->gid = gid; + (*cred)->pid = pid; + (*cred)->session = session; + return 0; +} + +void +heim_ipc_main(void) +{ +#if __APPLE__ + dispatch_main(); +#else + abort(); +#endif +} + +heim_isemaphore +heim_ipc_semaphore_create(long value) +{ +#ifdef __APPLE__ + return (heim_isemaphore)dispatch_semaphore_create(value); +#else + abort(); +#endif +} + +long +heim_ipc_semaphore_wait(heim_isemaphore s, time_t t) +{ +#ifdef __APPLE__ + uint64_t timeout; + if (t == HEIM_IPC_WAIT_FOREVER) + timeout = DISPATCH_TIME_FOREVER; + else + timeout = (uint64_t)t * NSEC_PER_SEC; + + return dispatch_semaphore_wait((dispatch_semaphore_t)s, timeout); +#else + abort(); +#endif +} + +long +heim_ipc_semaphore_signal(heim_isemaphore s) +{ +#ifdef __APPLE__ + return dispatch_semaphore_signal((dispatch_semaphore_t)s); +#else + abort(); +#endif +} + +void +heim_ipc_semaphore_release(heim_isemaphore s) +{ +#ifdef __APPLE__ + return dispatch_release((dispatch_semaphore_t)s); +#else + abort(); +#endif +} + +void +heim_ipc_free_data(heim_idata *data) +{ + if (data->data) + free(data->data); + data->data = NULL; + data->length = 0; +} diff --git a/lib/ipc/heim-ipc.h b/lib/ipc/heim-ipc.h new file mode 100644 index 000000000..1a7a85969 --- /dev/null +++ b/lib/ipc/heim-ipc.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +typedef struct heim_ipc *heim_ipc; +typedef struct heim_sipc *heim_sipc; +typedef struct heim_icred *heim_icred; +typedef struct heim_isemaphore *heim_isemaphore; +typedef struct heim_octet_string heim_idata; +typedef struct heim_sipc_call *heim_sipc_call; + +/* common */ + +void +heim_ipc_free_cred(heim_icred); + +uid_t +heim_ipc_cred_get_uid(heim_icred); + +gid_t +heim_ipc_cred_get_gid(heim_icred); + +pid_t +heim_ipc_cred_get_pid(heim_icred); + +pid_t +heim_ipc_cred_get_session(heim_icred); + +void +heim_ipc_main(void); + +heim_isemaphore +heim_ipc_semaphore_create(long); + +long +heim_ipc_semaphore_wait(heim_isemaphore, time_t); + +long +heim_ipc_semaphore_signal(heim_isemaphore); + +void +heim_ipc_semaphore_release(heim_isemaphore); + +#define HEIM_IPC_WAIT_FOREVER ((time_t)-1) + +void +heim_ipc_free_data(heim_idata *); + +/* client */ + +int +heim_ipc_init_context(const char *, heim_ipc *); + +void +heim_ipc_free_context(heim_ipc); + +int +heim_ipc_call(heim_ipc, const heim_idata *, heim_idata *, heim_icred *); + +int +heim_ipc_async(heim_ipc, const heim_idata *, void *, void (*func)(void *, int, heim_idata *, heim_icred)); + +/* server */ + +typedef void +(*heim_ipc_complete)(heim_sipc_call, int, heim_idata *); + +typedef void +(*heim_ipc_callback)(void *, const heim_idata *, + const heim_icred, heim_ipc_complete, heim_sipc_call); + + +int +heim_sipc_launchd_mach_init(const char *, heim_ipc_callback, + void *, heim_sipc *); + +void +heim_sipc_timeout(time_t); + +void +heim_sipc_set_timeout_handler(void (*)(void)); + +void +heim_sipc_free_context(heim_sipc); diff --git a/lib/ipc/heim_ipc.defs b/lib/ipc/heim_ipc.defs new file mode 100644 index 000000000..ae8479137 --- /dev/null +++ b/lib/ipc/heim_ipc.defs @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +type heim_ipc_message_inband_t = array [ * : 2048 ] of char; +type heim_ipc_message_outband_t = array [] of char; + +import "heim_ipc_types.h"; + +subsystem mheim_ipc 1; +userprefix mheim_ipc_; +serverprefix mheim_do_; + +routine call( + server_port : mach_port_t; + ServerAuditToken client_creds : audit_token_t; + sreplyport reply_port : mach_port_make_send_once_t; + in requestin : heim_ipc_message_inband_t; + in requestout : heim_ipc_message_outband_t; + out returnvalue : int; + out replyin : heim_ipc_message_inband_t; + out replyout : heim_ipc_message_outband_t, dealloc); + +simpleroutine call_request( + server_port : mach_port_t; + ServerAuditToken client_creds : audit_token_t; + in reply_to : mach_port_make_send_once_t; + in requestin : heim_ipc_message_inband_t; + in requestout : heim_ipc_message_outband_t); + + + diff --git a/lib/ipc/heim_ipc_async.defs b/lib/ipc/heim_ipc_async.defs new file mode 100644 index 000000000..73157c0d1 --- /dev/null +++ b/lib/ipc/heim_ipc_async.defs @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +type heim_ipc_message_inband_t = array [ * : 2048 ] of char; +type heim_ipc_message_outband_t = array [] of char; + +import "heim_ipc_types.h"; + +subsystem mheim_aipc 201; +userprefix mheim_aipc_; +serverprefix mheim_ado_; + +simpleroutine acall_reply( + server_port : mach_port_move_send_once_t; + ServerAuditToken client_creds : audit_token_t; + in returnvalue : int; + in requestin : heim_ipc_message_inband_t; + in requestout : heim_ipc_message_outband_t); + + + diff --git a/lib/ipc/heim_ipc_reply.defs b/lib/ipc/heim_ipc_reply.defs new file mode 100644 index 000000000..820948556 --- /dev/null +++ b/lib/ipc/heim_ipc_reply.defs @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +type heim_ipc_message_inband_t = array [ * : 2048 ] of char; +type heim_ipc_message_outband_t = array [] of char; + +import "heim_ipc_types.h"; + +subsystem heim_ipc 101; +userprefix mheim_ripc_; + +simpleroutine call_reply( + reply_port : mach_port_move_send_once_t; + returnvalue : int; + replyin : heim_ipc_message_inband_t; + replyout : heim_ipc_message_outband_t, dealloc); diff --git a/lib/ipc/heim_ipc_types.h b/lib/ipc/heim_ipc_types.h new file mode 100644 index 000000000..c853610f1 --- /dev/null +++ b/lib/ipc/heim_ipc_types.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _HEIM_IPC_TYPES_H_ +#define _HEIM_IPC_TYPES_H_ + +#define HEIM_KCM_BOOTSTRAP_NAME "org.h5l.Kerberos.kcm" + +typedef char heim_ipc_message_inband_t[2048]; +typedef char *heim_ipc_message_outband_t; + +#endif diff --git a/lib/ipc/hi_locl.h b/lib/ipc/hi_locl.h new file mode 100644 index 000000000..44975c8a2 --- /dev/null +++ b/lib/ipc/hi_locl.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +int +_heim_ipc_create_cred(uid_t, gid_t, pid_t, pid_t, heim_icred *); diff --git a/lib/ipc/server.c b/lib/ipc/server.c new file mode 100644 index 000000000..f31f84e15 --- /dev/null +++ b/lib/ipc/server.c @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hi_locl.h" + +struct heim_sipc { + int (*release)(heim_sipc ctx); + heim_ipc_callback callback; + void *userctx; + void *mech; +}; + +#ifdef __APPLE__ + +#include +#include +#include +#include "heim_ipcServer.h" +#include "heim_ipc_reply.h" + +static dispatch_source_t timer; +static dispatch_queue_t timerq; +static uint64_t timeoutvalue; + +static dispatch_queue_t workq; + +static void +default_timer_ev(void) +{ + exit(0); +} + +static void (*timer_ev)(void) = default_timer_ev; + +static void +set_timer(void) +{ + dispatch_source_set_timer(timer, + dispatch_time(DISPATCH_TIME_NOW, + timeoutvalue * NSEC_PER_SEC), + timeoutvalue * NSEC_PER_SEC, 1000000); +} + +static void +init_globals(void) +{ + static dispatch_once_t once; + dispatch_once(&once, ^{ + timerq = dispatch_queue_create("hiem-sipc-timer-q", NULL); + timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerq); + dispatch_source_set_event_handler(timer, ^{ timer_ev(); } ); + + workq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + }); +} + +static void +suspend_timer(void) +{ + dispatch_suspend(timer); +} + +static void +restart_timer(void) +{ + dispatch_sync(timerq, ^{ set_timer(); }); + dispatch_resume(timer); +} + +struct mach_service { + mach_port_t sport; + dispatch_source_t source; + dispatch_queue_t queue; +}; + +struct mach_call_ctx { + mach_port_t reply_port; + heim_icred cred; + heim_idata req; +}; + + +static void +mach_complete_sync(heim_sipc_call ctx, int returnvalue, heim_idata *reply) +{ + struct mach_call_ctx *s = (struct mach_call_ctx *)ctx; + heim_ipc_message_inband_t replyin; + mach_msg_type_number_t replyinCnt; + heim_ipc_message_outband_t replyout; + mach_msg_type_number_t replyoutCnt; + kern_return_t kr; + + if (returnvalue) { + /* on error, no reply */ + replyinCnt = 0; + replyout = 0; replyoutCnt = 0; + kr = KERN_SUCCESS; + } else if (reply->length < 2048) { + replyinCnt = reply->length; + memcpy(replyin, reply->data, replyinCnt); + replyout = 0; replyoutCnt = 0; + kr = KERN_SUCCESS; + } else { + replyinCnt = 0; + kr = vm_read(mach_task_self(), + (vm_address_t)reply->data, reply->length, + (vm_address_t *)&replyout, &replyoutCnt); + } + + mheim_ripc_call_reply(s->reply_port, returnvalue, + replyin, replyinCnt, + replyout, replyoutCnt); + + heim_ipc_free_cred(s->cred); + free(s->req.data); + free(s); + restart_timer(); +} + +static void +mach_complete_async(heim_sipc_call ctx, int returnvalue, heim_idata *reply) +{ + struct mach_call_ctx *s = (struct mach_call_ctx *)ctx; + heim_ipc_message_inband_t replyin; + mach_msg_type_number_t replyinCnt; + heim_ipc_message_outband_t replyout; + mach_msg_type_number_t replyoutCnt; + kern_return_t kr; + + if (returnvalue) { + /* on error, no reply */ + replyinCnt = 0; + replyout = 0; replyoutCnt = 0; + kr = KERN_SUCCESS; + } else if (reply->length < 2048) { + replyinCnt = reply->length; + memcpy(replyin, reply->data, replyinCnt); + replyout = 0; replyoutCnt = 0; + kr = KERN_SUCCESS; + } else { + replyinCnt = 0; + kr = vm_read(mach_task_self(), + (vm_address_t)reply->data, reply->length, + (vm_address_t *)&replyout, &replyoutCnt); + } + + kr = mheim_aipc_acall_reply(s->reply_port, returnvalue, + replyin, replyinCnt, + replyout, replyoutCnt); + heim_ipc_free_cred(s->cred); + free(s->req.data); + free(s); + restart_timer(); +} + + +kern_return_t +mheim_do_call(mach_port_t server_port, + audit_token_t client_creds, + mach_port_t reply_port, + heim_ipc_message_inband_t requestin, + mach_msg_type_number_t requestinCnt, + heim_ipc_message_outband_t requestout, + mach_msg_type_number_t requestoutCnt, + int *returnvalue, + heim_ipc_message_inband_t replyin, + mach_msg_type_number_t *replyinCnt, + heim_ipc_message_outband_t *replyout, + mach_msg_type_number_t *replyoutCnt) +{ + heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue()); + struct mach_service *st = ctx->mech; + struct mach_call_ctx *s; + kern_return_t kr; + heim_icred cred; + uid_t uid; + gid_t gid; + pid_t pid; + au_asid_t session; + + *replyout = NULL; + *replyoutCnt = 0; + *replyinCnt = 0; + + s = malloc(sizeof(*s)); + if (s == NULL) + return KERN_MEMORY_FAILURE; /* XXX */ + + s->reply_port = reply_port; + + audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL); + + kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred); + if (kr) { + free(s); + return kr; + } + + suspend_timer(); + + if (requestinCnt) { + s->req.data = malloc(requestinCnt); + memcpy(s->req.data, requestin, requestinCnt); + s->req.length = requestinCnt; + } else { + s->req.data = malloc(requestoutCnt); + memcpy(s->req.data, requestout, requestoutCnt); + s->req.length = requestoutCnt; + } + + dispatch_async(workq, ^{ + (ctx->callback)(ctx->userctx, &s->req, s->cred, + mach_complete_sync, (heim_sipc_call)s); + }); + + return MIG_NO_REPLY; +} + +kern_return_t +mheim_do_call_request(mach_port_t server_port, + audit_token_t client_creds, + mach_port_t reply_port, + heim_ipc_message_inband_t requestin, + mach_msg_type_number_t requestinCnt, + heim_ipc_message_outband_t requestout, + mach_msg_type_number_t requestoutCnt) +{ + heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue()); + struct mach_service *st = ctx->mech; + struct mach_call_ctx *s; + kern_return_t kr; + heim_icred cred; + uid_t uid; + gid_t gid; + pid_t pid; + au_asid_t session; + + s = malloc(sizeof(*s)); + if (s == NULL) + return KERN_MEMORY_FAILURE; /* XXX */ + + s->reply_port = reply_port; + + audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL); + + kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred); + if (kr) { + free(s); + return kr; + } + + suspend_timer(); + + if (requestinCnt) { + s->req.data = malloc(requestinCnt); + memcpy(s->req.data, requestin, requestinCnt); + s->req.length = requestinCnt; + } else { + s->req.data = malloc(requestoutCnt); + memcpy(s->req.data, requestout, requestoutCnt); + s->req.length = requestoutCnt; + } + + dispatch_async(workq, ^{ + (ctx->callback)(ctx->userctx, &s->req, s->cred, + mach_complete_async, (heim_sipc_call)s); + }); + + return KERN_SUCCESS; +} + + + +static int +mach_init(const char *service, mach_port_t sport, heim_sipc ctx) +{ + struct mach_service *s; + kern_return_t kr; + char *name; + + init_globals(); + + s = calloc(1, sizeof(*s)); + if (s == NULL) + return ENOMEM; + + asprintf(&name, "heim-ipc-mach-%s", service); + + s->queue = dispatch_queue_create(name, NULL); + free(name); + s->sport = sport; + + s->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, + s->sport, 0, s->queue); + if (s->source == NULL) { + dispatch_release(s->queue); + free(s); + return ENOMEM; + } + ctx->mech = s; + + dispatch_set_context(s->queue, ctx); + dispatch_set_context(s->source, s); + + dispatch_source_set_event_handler(s->source, ^{ + dispatch_mig_server(s->source, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem), mheim_ipc_server); + }); + + dispatch_source_set_cancel_handler(s->source, ^{ + heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue()); + struct mach_service *st = ctx->mech; + mach_port_mod_refs(mach_task_self(), st->sport, + MACH_PORT_RIGHT_RECEIVE, -1); + dispatch_release(st->queue); + dispatch_release(st->source); + free(st); + free(ctx); + }); + + dispatch_resume(s->source); + + return 0; +} + +static int +mach_release(heim_sipc ctx) +{ + struct mach_service *s = ctx->mech; + dispatch_source_cancel(s->source); + dispatch_release(s->source); + return 0; +} + +static mach_port_t +mach_checkin_or_register(const char *service) +{ + mach_port_t mp; + kern_return_t kr; + + kr = bootstrap_check_in(bootstrap_port, service, &mp); + if (kr == KERN_SUCCESS) + return mp; + + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp); + if (kr != KERN_SUCCESS) + return MACH_PORT_NULL; + + kr = mach_port_insert_right(mach_task_self(), mp, mp, + MACH_MSG_TYPE_MAKE_SEND); + if (kr != KERN_SUCCESS) { + mach_port_destroy(mach_task_self(), mp); + return MACH_PORT_NULL; + } + + kr = bootstrap_register(bootstrap_port, service, mp); + if (kr != KERN_SUCCESS) { + mach_port_destroy(mach_task_self(), mp); + return MACH_PORT_NULL; + } + + return mp; +} + + +#endif /* __APPLE__ */ + +int +heim_sipc_launchd_mach_init(const char *service, + heim_ipc_callback callback, + void *user, heim_sipc *ctx) +{ +#ifdef __APPLE__ + mach_port_t sport = MACH_PORT_NULL; + heim_sipc c; + int ret; + + *ctx = NULL; + + sport = mach_checkin_or_register(service); + if (sport == MACH_PORT_NULL) { + ret = ENOENT; + goto error; + } + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + ret = ENOMEM; + goto error; + } + c->release = mach_release; + c->userctx = user; + c->callback = callback; + + ret = mach_init(service, sport, c); + if (ret) + goto error; + + *ctx = c; + return 0; + error: + if (c) + free(c); + if (sport != MACH_PORT_NULL) + mach_port_mod_refs(mach_task_self(), sport, + MACH_PORT_RIGHT_RECEIVE, -1); + return ret; +#else + *ctx = NULL; + return EINVAL; +#endif +} + +/** + * Set the idle timeout value + + * The timeout event handler is triggered recurrently every idle + * period `t'. The default action is rather draconian and just calls + * exit(0), so you might want to change this to something more + * graceful using heim_sipc_set_timeout_handler(). + */ + +void +heim_sipc_timeout(time_t t) +{ +#if __APPLE__ + static dispatch_once_t timeoutonce; + init_globals(); + dispatch_sync(timerq, ^{ + timeoutvalue = t; + set_timer(); + }); + dispatch_once(&timeoutonce, ^{ dispatch_resume(timer); }); +#else + abort(); +#endif +} + +/** + * Set the timeout event handler + * + * Replaces the default idle timeout action. + */ + +void +heim_sipc_set_timeout_handler(void (*func)(void)) +{ +#ifdef __APPLE__ + init_globals(); + dispatch_sync(timerq, ^{ timer_ev = func; }); +#else + abort(); +#endif +} + + +void +heim_sipc_free_context(heim_sipc ctx) +{ + (ctx->release)(ctx); +} diff --git a/lib/ipc/tc.c b/lib/ipc/tc.c new file mode 100644 index 000000000..d976e8fac --- /dev/null +++ b/lib/ipc/tc.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + + +static void +reply(void *ctx, int errorcode, heim_idata *reply, heim_icred cred) +{ + printf("got reply\n"); + heim_ipc_semaphore_signal((heim_isemaphore)ctx); /* tell caller we are done */ +} + +int +main(int argc, char **argv) +{ + heim_isemaphore s; + heim_idata req, rep; + heim_ipc ipc; + int ret; + + ret = heim_ipc_init_context("ANY:org.h5l.test-ipc", &ipc); + if (ret) + errx(1, "heim_ipc_init_context: %d", ret); + + req.length = 0; + req.data = NULL; + + ret = heim_ipc_call(ipc, &req, &rep, NULL); + if (ret) + errx(1, "heim_ipc_call: %d", ret); + + s = heim_ipc_semaphore_create(0); + if (s == NULL) + errx(1, "heim_ipc_semaphore_create"); + + ret = heim_ipc_async(ipc, &req, s, reply); + if (ret) + errx(1, "heim_ipc_async: %d", ret); + + heim_ipc_semaphore_wait(s, HEIM_IPC_WAIT_FOREVER); /* wait for reply to complete the work */ + + heim_ipc_free_context(ipc); + + return 0; +} diff --git a/lib/ipc/ts.c b/lib/ipc/ts.c new file mode 100644 index 000000000..e9953a58d --- /dev/null +++ b/lib/ipc/ts.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +static void +test_service(void *ctx, const heim_idata *req, + const heim_icred cred, + heim_ipc_complete complete, + heim_sipc_call cctx) +{ + heim_idata rep; + printf("got request\n"); + rep.length = 0; + rep.data = NULL; + (*complete)(cctx, 0, &rep); +} + + +int +main(int argc, char **argv) +{ +#if __APPLE__ + { + heim_sipc mach; + heim_sipc_launchd_mach_init("org.h5l.test-ipc", + test_service, NULL, &mach); + } +#endif + heim_ipc_main(); + + return 0; +}