1226031Sstas/*
2226031Sstas * Copyright (c) 2009 Kungliga Tekniska H�gskolan
3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4226031Sstas * All rights reserved.
5226031Sstas *
6226031Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7226031Sstas *
8226031Sstas * Redistribution and use in source and binary forms, with or without
9226031Sstas * modification, are permitted provided that the following conditions
10226031Sstas * are met:
11226031Sstas *
12226031Sstas * 1. Redistributions of source code must retain the above copyright
13226031Sstas *    notice, this list of conditions and the following disclaimer.
14226031Sstas *
15226031Sstas * 2. Redistributions in binary form must reproduce the above copyright
16226031Sstas *    notice, this list of conditions and the following disclaimer in the
17226031Sstas *    documentation and/or other materials provided with the distribution.
18226031Sstas *
19226031Sstas * 3. Neither the name of the Institute nor the names of its contributors
20226031Sstas *    may be used to endorse or promote products derived from this software
21226031Sstas *    without specific prior written permission.
22226031Sstas *
23226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26226031Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33226031Sstas * SUCH DAMAGE.
34226031Sstas */
35226031Sstas
36226031Sstas#include "hi_locl.h"
37226031Sstas
38226031Sstas#if defined(__APPLE__) && defined(HAVE_GCD)
39226031Sstas
40226031Sstas#include "heim_ipc.h"
41226031Sstas#include "heim_ipc_asyncServer.h"
42226031Sstas
43226031Sstas#include <dispatch/dispatch.h>
44226031Sstas#include <mach/mach.h>
45226031Sstas
46226031Sstasstatic dispatch_once_t jobqinited = 0;
47226031Sstasstatic dispatch_queue_t jobq = NULL;
48226031Sstasstatic dispatch_queue_t syncq;
49226031Sstas
50226031Sstasstruct mach_ctx {
51226031Sstas    mach_port_t server;
52226031Sstas    char *name;
53226031Sstas};
54226031Sstas
55226031Sstasstatic int
56226031Sstasmach_release(void *ctx);
57226031Sstas
58226031Sstasstatic int
59226031Sstasmach_init(const char *service, void **ctx)
60226031Sstas{
61226031Sstas    struct mach_ctx *ipc;
62226031Sstas    mach_port_t sport;
63226031Sstas    int ret;
64226031Sstas
65226031Sstas    dispatch_once(&jobqinited, ^{
66226031Sstas	    jobq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
67226031Sstas	    syncq = dispatch_queue_create("heim-ipc-syncq", NULL);
68226031Sstas	});
69226031Sstas
70226031Sstas    ret = bootstrap_look_up(bootstrap_port, service, &sport);
71226031Sstas    if (ret)
72226031Sstas	return ret;
73226031Sstas
74226031Sstas    ipc = malloc(sizeof(*ipc));
75226031Sstas    if (ipc == NULL) {
76226031Sstas	mach_port_destroy(mach_task_self(), sport);
77226031Sstas	return ENOMEM;
78226031Sstas    }
79226031Sstas
80226031Sstas    ipc->server = sport;
81226031Sstas    ipc->name = strdup(service);
82226031Sstas    if (ipc->name == NULL) {
83226031Sstas	mach_release(ipc);
84226031Sstas	return ENOMEM;
85226031Sstas    }
86226031Sstas
87226031Sstas    *ctx = ipc;
88226031Sstas
89226031Sstas    return 0;
90226031Sstas}
91226031Sstas
92226031Sstasstatic int
93226031Sstasmach_ipc(void *ctx,
94226031Sstas	 const heim_idata *request, heim_idata *response,
95226031Sstas	 heim_icred *cred)
96226031Sstas{
97226031Sstas    struct mach_ctx *ipc = ctx;
98226031Sstas    heim_ipc_message_inband_t requestin;
99226031Sstas    mach_msg_type_number_t requestin_length = 0;
100226031Sstas    heim_ipc_message_outband_t requestout = NULL;
101226031Sstas    mach_msg_type_number_t requestout_length = 0;
102226031Sstas    heim_ipc_message_inband_t replyin;
103226031Sstas    mach_msg_type_number_t replyin_length;
104226031Sstas    heim_ipc_message_outband_t replyout;
105226031Sstas    mach_msg_type_number_t replyout_length;
106226031Sstas    int ret, errorcode, retries = 0;
107226031Sstas
108226031Sstas    memcpy(requestin, request->data, request->length);
109226031Sstas    requestin_length = request->length;
110226031Sstas
111226031Sstas    while (retries < 2) {
112226031Sstas	__block mach_port_t sport;
113226031Sstas
114226031Sstas	dispatch_sync(syncq, ^{ sport = ipc->server; });
115226031Sstas
116226031Sstas	ret = mheim_ipc_call(sport,
117226031Sstas			     requestin, requestin_length,
118226031Sstas			     requestout, requestout_length,
119226031Sstas			     &errorcode,
120226031Sstas			     replyin, &replyin_length,
121226031Sstas			     &replyout, &replyout_length);
122226031Sstas	if (ret == MACH_SEND_INVALID_DEST) {
123226031Sstas	    mach_port_t nport;
124226031Sstas	    /* race other threads to get a new port */
125226031Sstas	    ret = bootstrap_look_up(bootstrap_port, ipc->name, &nport);
126226031Sstas	    if (ret)
127226031Sstas		return ret;
128226031Sstas	    dispatch_sync(syncq, ^{
129226031Sstas		    /* check if we lost the race to lookup the port */
130226031Sstas		    if (sport != ipc->server) {
131226031Sstas			mach_port_deallocate(mach_task_self(), nport);
132226031Sstas		    } else {
133226031Sstas			mach_port_deallocate(mach_task_self(), ipc->server);
134226031Sstas			ipc->server = nport;
135226031Sstas		    }
136226031Sstas		});
137226031Sstas	    retries++;
138226031Sstas	} else if (ret) {
139226031Sstas	    return ret;
140226031Sstas	} else
141226031Sstas	    break;
142226031Sstas    }
143226031Sstas    if (retries >= 2)
144226031Sstas	return EINVAL;
145226031Sstas
146226031Sstas    if (errorcode) {
147226031Sstas	if (replyout_length)
148226031Sstas	    vm_deallocate (mach_task_self (), (vm_address_t) replyout,
149226031Sstas			   replyout_length);
150226031Sstas	return errorcode;
151226031Sstas    }
152226031Sstas
153226031Sstas    if (replyout_length) {
154226031Sstas	response->data = malloc(replyout_length);
155226031Sstas	if (response->data == NULL) {
156226031Sstas	    vm_deallocate (mach_task_self (), (vm_address_t) replyout,
157226031Sstas			   replyout_length);
158226031Sstas	    return ENOMEM;
159226031Sstas	}
160226031Sstas	memcpy(response->data, replyout, replyout_length);
161226031Sstas	response->length = replyout_length;
162226031Sstas	vm_deallocate (mach_task_self (), (vm_address_t) replyout,
163226031Sstas		       replyout_length);
164226031Sstas    } else {
165226031Sstas	response->data = malloc(replyin_length);
166226031Sstas	if (response->data == NULL)
167226031Sstas	    return ENOMEM;
168226031Sstas	memcpy(response->data, replyin, replyin_length);
169226031Sstas	response->length = replyin_length;
170226031Sstas    }
171226031Sstas
172226031Sstas    return 0;
173226031Sstas}
174226031Sstas
175226031Sstasstruct async_client {
176226031Sstas    mach_port_t mp;
177226031Sstas    dispatch_source_t source;
178226031Sstas    dispatch_queue_t queue;
179226031Sstas    void (*func)(void *, int, heim_idata *, heim_icred);
180226031Sstas    void *userctx;
181226031Sstas};
182226031Sstas
183226031Sstaskern_return_t
184226031Sstasmheim_ado_acall_reply(mach_port_t server_port,
185226031Sstas		      audit_token_t client_creds,
186226031Sstas		      int returnvalue,
187226031Sstas		      heim_ipc_message_inband_t replyin,
188226031Sstas		      mach_msg_type_number_t replyinCnt,
189226031Sstas		      heim_ipc_message_outband_t replyout,
190226031Sstas		      mach_msg_type_number_t replyoutCnt)
191226031Sstas{
192226031Sstas    struct async_client *c = dispatch_get_context(dispatch_get_current_queue());
193226031Sstas    heim_idata response;
194226031Sstas
195226031Sstas    if (returnvalue) {
196226031Sstas	response.data = NULL;
197226031Sstas	response.length = 0;
198226031Sstas    } else if (replyoutCnt) {
199226031Sstas	response.data = replyout;
200226031Sstas	response.length = replyoutCnt;
201226031Sstas    } else {
202226031Sstas	response.data = replyin;
203226031Sstas	response.length = replyinCnt;
204226031Sstas    }
205226031Sstas
206226031Sstas    (*c->func)(c->userctx, returnvalue, &response, NULL);
207226031Sstas
208226031Sstas    if (replyoutCnt)
209226031Sstas	vm_deallocate (mach_task_self (), (vm_address_t) replyout, replyoutCnt);
210226031Sstas
211226031Sstas    dispatch_source_cancel(c->source);
212226031Sstas
213226031Sstas    return 0;
214226031Sstas
215226031Sstas
216226031Sstas}
217226031Sstas
218226031Sstas
219226031Sstasstatic int
220226031Sstasmach_async(void *ctx, const heim_idata *request, void *userctx,
221226031Sstas	   void (*func)(void *, int, heim_idata *, heim_icred))
222226031Sstas{
223226031Sstas    struct mach_ctx *ipc = ctx;
224226031Sstas    heim_ipc_message_inband_t requestin;
225226031Sstas    mach_msg_type_number_t requestin_length = 0;
226226031Sstas    heim_ipc_message_outband_t requestout = NULL;
227226031Sstas    mach_msg_type_number_t requestout_length = 0;
228226031Sstas    int ret, retries = 0;
229226031Sstas    kern_return_t kr;
230226031Sstas    struct async_client *c;
231226031Sstas
232226031Sstas    /* first create the service that will catch the reply from the server */
233226031Sstas    /* XXX these object should be cached and reused */
234226031Sstas
235226031Sstas    c = malloc(sizeof(*c));
236226031Sstas    if (c == NULL)
237226031Sstas	return ENOMEM;
238226031Sstas
239226031Sstas    kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &c->mp);
240226031Sstas    if (kr != KERN_SUCCESS)
241226031Sstas	return EINVAL;
242226031Sstas
243226031Sstas    c->queue = dispatch_queue_create("heim-ipc-async-client", NULL);
244226031Sstas    c->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, c->mp, 0, c->queue);
245226031Sstas    dispatch_set_context(c->queue, c);
246226031Sstas
247226031Sstas    dispatch_source_set_event_handler(c->source, ^{
248226031Sstas	    dispatch_mig_server(c->source,
249226031Sstas				sizeof(union __RequestUnion__mheim_ado_mheim_aipc_subsystem),
250226031Sstas				mheim_aipc_server);
251226031Sstas	});
252226031Sstas
253226031Sstas    dispatch_source_set_cancel_handler(c->source, ^{
254226031Sstas	    mach_port_mod_refs(mach_task_self(), c->mp,
255226031Sstas			       MACH_PORT_RIGHT_RECEIVE, -1);
256226031Sstas	    dispatch_release(c->queue);
257226031Sstas	    dispatch_release(c->source);
258226031Sstas	    free(c);
259226031Sstas	});
260226031Sstas
261226031Sstas    c->func = func;
262226031Sstas    c->userctx = userctx;
263226031Sstas
264226031Sstas    dispatch_resume(c->source);
265226031Sstas
266226031Sstas    /* ok, send the message */
267226031Sstas
268226031Sstas    memcpy(requestin, request->data, request->length);
269226031Sstas    requestin_length = request->length;
270226031Sstas
271226031Sstas    while (retries < 2) {
272226031Sstas	__block mach_port_t sport;
273226031Sstas
274226031Sstas	dispatch_sync(syncq, ^{ sport = ipc->server; });
275226031Sstas
276226031Sstas	ret = mheim_ipc_call_request(sport, c->mp,
277226031Sstas				     requestin, requestin_length,
278226031Sstas				     requestout, requestout_length);
279226031Sstas	if (ret == MACH_SEND_INVALID_DEST) {
280226031Sstas	    ret = bootstrap_look_up(bootstrap_port, ipc->name, &sport);
281226031Sstas	    if (ret) {
282226031Sstas		dispatch_source_cancel(c->source);
283226031Sstas		return ret;
284226031Sstas	    }
285226031Sstas	    mach_port_deallocate(mach_task_self(), ipc->server);
286226031Sstas	    ipc->server = sport;
287226031Sstas	    retries++;
288226031Sstas	} else if (ret) {
289226031Sstas	    dispatch_source_cancel(c->source);
290226031Sstas	    return ret;
291226031Sstas	} else
292226031Sstas	    break;
293226031Sstas    }
294226031Sstas    if (retries >= 2) {
295226031Sstas	dispatch_source_cancel(c->source);
296226031Sstas	return EINVAL;
297226031Sstas    }
298226031Sstas
299226031Sstas    return 0;
300226031Sstas}
301226031Sstas
302226031Sstasstatic int
303226031Sstasmach_release(void *ctx)
304226031Sstas{
305226031Sstas    struct mach_ctx *ipc = ctx;
306226031Sstas    if (ipc->server != MACH_PORT_NULL)
307226031Sstas	mach_port_deallocate(mach_task_self(), ipc->server);
308226031Sstas    free(ipc->name);
309226031Sstas    free(ipc);
310226031Sstas    return 0;
311226031Sstas}
312226031Sstas
313226031Sstas#endif
314226031Sstas
315226031Sstasstruct path_ctx {
316226031Sstas    char *path;
317226031Sstas    int fd;
318226031Sstas};
319226031Sstas
320226031Sstasstatic int common_release(void *);
321226031Sstas
322226031Sstasstatic int
323226031Sstasconnect_unix(struct path_ctx *s)
324226031Sstas{
325226031Sstas    struct sockaddr_un addr;
326226031Sstas
327226031Sstas    addr.sun_family = AF_UNIX;
328226031Sstas    strlcpy(addr.sun_path, s->path, sizeof(addr.sun_path));
329226031Sstas
330226031Sstas    s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
331226031Sstas    if (s->fd < 0)
332226031Sstas	return errno;
333226031Sstas    rk_cloexec(s->fd);
334226031Sstas
335226031Sstas    if (connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
336226031Sstas	close(s->fd);
337226031Sstas	return errno;
338226031Sstas    }
339226031Sstas
340226031Sstas    return 0;
341226031Sstas}
342226031Sstas
343226031Sstasstatic int
344226031Sstascommon_path_init(const char *service,
345226031Sstas		 const char *file,
346226031Sstas		 void **ctx)
347226031Sstas{
348226031Sstas    struct path_ctx *s;
349226031Sstas
350226031Sstas    s = malloc(sizeof(*s));
351226031Sstas    if (s == NULL)
352226031Sstas	return ENOMEM;
353226031Sstas    s->fd = -1;
354226031Sstas
355226031Sstas    asprintf(&s->path, "/var/run/.heim_%s-%s", service, file);
356226031Sstas
357226031Sstas    *ctx = s;
358226031Sstas
359226031Sstas    return 0;
360226031Sstas}
361226031Sstas
362226031Sstasstatic int
363226031Sstasunix_socket_init(const char *service,
364226031Sstas		 void **ctx)
365226031Sstas{
366226031Sstas    int ret;
367226031Sstas
368226031Sstas    ret = common_path_init(service, "socket", ctx);
369226031Sstas    if (ret)
370226031Sstas	return ret;
371226031Sstas    ret = connect_unix(*ctx);
372226031Sstas    if (ret)
373226031Sstas	common_release(*ctx);
374226031Sstas
375226031Sstas    return ret;
376226031Sstas}
377226031Sstas
378226031Sstasstatic int
379226031Sstasunix_socket_ipc(void *ctx,
380226031Sstas		const heim_idata *req, heim_idata *rep,
381226031Sstas		heim_icred *cred)
382226031Sstas{
383226031Sstas    struct path_ctx *s = ctx;
384226031Sstas    uint32_t len = htonl(req->length);
385226031Sstas    uint32_t rv;
386226031Sstas    int retval;
387226031Sstas
388226031Sstas    if (cred)
389226031Sstas	*cred = NULL;
390226031Sstas
391226031Sstas    rep->data = NULL;
392226031Sstas    rep->length = 0;
393226031Sstas
394226031Sstas    if (net_write(s->fd, &len, sizeof(len)) != sizeof(len))
395226031Sstas	return -1;
396226031Sstas    if (net_write(s->fd, req->data, req->length) != (ssize_t)req->length)
397226031Sstas	return -1;
398226031Sstas
399226031Sstas    if (net_read(s->fd, &len, sizeof(len)) != sizeof(len))
400226031Sstas	return -1;
401226031Sstas    if (net_read(s->fd, &rv, sizeof(rv)) != sizeof(rv))
402226031Sstas	return -1;
403226031Sstas    retval = ntohl(rv);
404226031Sstas
405226031Sstas    rep->length = ntohl(len);
406226031Sstas    if (rep->length > 0) {
407226031Sstas	rep->data = malloc(rep->length);
408226031Sstas	if (rep->data == NULL)
409226031Sstas	    return -1;
410226031Sstas	if (net_read(s->fd, rep->data, rep->length) != (ssize_t)rep->length)
411226031Sstas	    return -1;
412226031Sstas    } else
413226031Sstas	rep->data = NULL;
414226031Sstas
415226031Sstas    return retval;
416226031Sstas}
417226031Sstas
418226031Sstasint
419226031Sstascommon_release(void *ctx)
420226031Sstas{
421226031Sstas    struct path_ctx *s = ctx;
422226031Sstas    if (s->fd >= 0)
423226031Sstas	close(s->fd);
424226031Sstas    free(s->path);
425226031Sstas    free(s);
426226031Sstas    return 0;
427226031Sstas}
428226031Sstas
429226031Sstas#ifdef HAVE_DOOR
430226031Sstas
431226031Sstasstatic int
432226031Sstasdoor_init(const char *service,
433226031Sstas	  void **ctx)
434226031Sstas{
435226031Sstas    ret = common_path_init(context, service, "door", ctx);
436226031Sstas    if (ret)
437226031Sstas	return ret;
438226031Sstas    ret = connect_door(*ctx);
439226031Sstas    if (ret)
440226031Sstas	common_release(*ctx);
441226031Sstas    return ret;
442226031Sstas}
443226031Sstas
444226031Sstasstatic int
445226031Sstasdoor_ipc(void *ctx,
446226031Sstas	 const heim_idata *request, heim_idata *response,
447226031Sstas	 heim_icred *cred)
448226031Sstas{
449226031Sstas    door_arg_t arg;
450226031Sstas    int ret;
451226031Sstas
452226031Sstas    arg.data_ptr = request->data;
453226031Sstas    arg.data_size = request->length;
454226031Sstas    arg.desc_ptr = NULL;
455226031Sstas    arg.desc_num = 0;
456226031Sstas    arg.rbuf = NULL;
457226031Sstas    arg.rsize = 0;
458226031Sstas
459226031Sstas    ret = door_call(fd, &arg);
460226031Sstas    close(fd);
461226031Sstas    if (ret != 0)
462226031Sstas	return errno;
463226031Sstas
464226031Sstas    response->data = malloc(arg.rsize);
465226031Sstas    if (response->data == NULL) {
466226031Sstas	munmap(arg.rbuf, arg.rsize);
467226031Sstas	return ENOMEM;
468226031Sstas    }
469226031Sstas    memcpy(response->data, arg.rbuf, arg.rsize);
470226031Sstas    response->length = arg.rsize;
471226031Sstas    munmap(arg.rbuf, arg.rsize);
472226031Sstas
473226031Sstas    return ret;
474226031Sstas}
475226031Sstas
476226031Sstas#endif
477226031Sstas
478226031Sstasstruct hipc_ops {
479226031Sstas    const char *prefix;
480226031Sstas    int (*init)(const char *, void **);
481226031Sstas    int (*release)(void *);
482226031Sstas    int (*ipc)(void *,const heim_idata *, heim_idata *, heim_icred *);
483226031Sstas    int (*async)(void *, const heim_idata *, void *,
484226031Sstas		 void (*)(void *, int, heim_idata *, heim_icred));
485226031Sstas};
486226031Sstas
487226031Sstasstruct hipc_ops ipcs[] = {
488226031Sstas#if defined(__APPLE__) && defined(HAVE_GCD)
489226031Sstas    { "MACH", mach_init, mach_release, mach_ipc, mach_async },
490226031Sstas#endif
491226031Sstas#ifdef HAVE_DOOR
492226031Sstas    { "DOOR", door_init, common_release, door_ipc, NULL }
493226031Sstas#endif
494226031Sstas    { "UNIX", unix_socket_init, common_release, unix_socket_ipc, NULL }
495226031Sstas};
496226031Sstas
497226031Sstasstruct heim_ipc {
498226031Sstas    struct hipc_ops *ops;
499226031Sstas    void *ctx;
500226031Sstas};
501226031Sstas
502226031Sstas
503226031Sstasint
504226031Sstasheim_ipc_init_context(const char *name, heim_ipc *ctx)
505226031Sstas{
506226031Sstas    unsigned int i;
507226031Sstas    int ret, any = 0;
508226031Sstas
509226031Sstas    for(i = 0; i < sizeof(ipcs)/sizeof(ipcs[0]); i++) {
510226031Sstas	size_t prefix_len = strlen(ipcs[i].prefix);
511226031Sstas	heim_ipc c;
512226031Sstas	if(strncmp(ipcs[i].prefix, name, prefix_len) == 0
513226031Sstas	   && name[prefix_len] == ':')  {
514226031Sstas	} else if (strncmp("ANY:", name, 4) == 0) {
515226031Sstas	    prefix_len = 3;
516226031Sstas	    any = 1;
517226031Sstas	} else
518226031Sstas	    continue;
519226031Sstas
520226031Sstas	c = calloc(1, sizeof(*c));
521226031Sstas	if (c == NULL)
522226031Sstas	    return ENOMEM;
523226031Sstas
524226031Sstas	c->ops = &ipcs[i];
525226031Sstas
526226031Sstas	ret = (c->ops->init)(name + prefix_len + 1, &c->ctx);
527226031Sstas	if (ret) {
528226031Sstas	    free(c);
529226031Sstas	    if (any)
530226031Sstas		continue;
531226031Sstas	    return ret;
532226031Sstas	}
533226031Sstas
534226031Sstas	*ctx = c;
535226031Sstas	return 0;
536226031Sstas    }
537226031Sstas
538226031Sstas    return ENOENT;
539226031Sstas}
540226031Sstas
541226031Sstasvoid
542226031Sstasheim_ipc_free_context(heim_ipc ctx)
543226031Sstas{
544226031Sstas    (ctx->ops->release)(ctx->ctx);
545226031Sstas    free(ctx);
546226031Sstas}
547226031Sstas
548226031Sstasint
549226031Sstasheim_ipc_call(heim_ipc ctx, const heim_idata *snd, heim_idata *rcv,
550226031Sstas	      heim_icred *cred)
551226031Sstas{
552226031Sstas    if (cred)
553226031Sstas	*cred = NULL;
554226031Sstas    return (ctx->ops->ipc)(ctx->ctx, snd, rcv, cred);
555226031Sstas}
556226031Sstas
557226031Sstasint
558226031Sstasheim_ipc_async(heim_ipc ctx, const heim_idata *snd, void *userctx,
559226031Sstas	       void (*func)(void *, int, heim_idata *, heim_icred))
560226031Sstas{
561226031Sstas    if (ctx->ops->async == NULL) {
562226031Sstas	heim_idata rcv;
563226031Sstas	heim_icred cred = NULL;
564226031Sstas	int ret;
565226031Sstas
566226031Sstas	ret = (ctx->ops->ipc)(ctx->ctx, snd, &rcv, &cred);
567226031Sstas	(*func)(userctx, ret, &rcv, cred);
568226031Sstas	heim_ipc_free_cred(cred);
569226031Sstas	free(rcv.data);
570226031Sstas	return ret;
571226031Sstas    } else {
572226031Sstas	return (ctx->ops->async)(ctx->ctx, snd, userctx, func);
573226031Sstas    }
574226031Sstas}
575