1ae771770SStanislav Sedov /*
2ae771770SStanislav Sedov * Copyright (c) 2009 Kungliga Tekniska H�gskolan
3ae771770SStanislav Sedov * (Royal Institute of Technology, Stockholm, Sweden).
4ae771770SStanislav Sedov * All rights reserved.
5ae771770SStanislav Sedov *
6ae771770SStanislav Sedov * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7ae771770SStanislav Sedov *
8ae771770SStanislav Sedov * Redistribution and use in source and binary forms, with or without
9ae771770SStanislav Sedov * modification, are permitted provided that the following conditions
10ae771770SStanislav Sedov * are met:
11ae771770SStanislav Sedov *
12ae771770SStanislav Sedov * 1. Redistributions of source code must retain the above copyright
13ae771770SStanislav Sedov * notice, this list of conditions and the following disclaimer.
14ae771770SStanislav Sedov *
15ae771770SStanislav Sedov * 2. Redistributions in binary form must reproduce the above copyright
16ae771770SStanislav Sedov * notice, this list of conditions and the following disclaimer in the
17ae771770SStanislav Sedov * documentation and/or other materials provided with the distribution.
18ae771770SStanislav Sedov *
19ae771770SStanislav Sedov * 3. Neither the name of the Institute nor the names of its contributors
20ae771770SStanislav Sedov * may be used to endorse or promote products derived from this software
21ae771770SStanislav Sedov * without specific prior written permission.
22ae771770SStanislav Sedov *
23ae771770SStanislav Sedov * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ae771770SStanislav Sedov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ae771770SStanislav Sedov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ae771770SStanislav Sedov * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ae771770SStanislav Sedov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ae771770SStanislav Sedov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ae771770SStanislav Sedov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ae771770SStanislav Sedov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ae771770SStanislav Sedov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ae771770SStanislav Sedov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ae771770SStanislav Sedov * SUCH DAMAGE.
34ae771770SStanislav Sedov */
35ae771770SStanislav Sedov
36ae771770SStanislav Sedov #include "hi_locl.h"
37ae771770SStanislav Sedov
38ae771770SStanislav Sedov #if defined(__APPLE__) && defined(HAVE_GCD)
39ae771770SStanislav Sedov
40ae771770SStanislav Sedov #include "heim_ipc.h"
41ae771770SStanislav Sedov #include "heim_ipc_asyncServer.h"
42ae771770SStanislav Sedov
43ae771770SStanislav Sedov #include <dispatch/dispatch.h>
44ae771770SStanislav Sedov #include <mach/mach.h>
45ae771770SStanislav Sedov
46ae771770SStanislav Sedov static dispatch_once_t jobqinited = 0;
47ae771770SStanislav Sedov static dispatch_queue_t jobq = NULL;
48ae771770SStanislav Sedov static dispatch_queue_t syncq;
49ae771770SStanislav Sedov
50ae771770SStanislav Sedov struct mach_ctx {
51ae771770SStanislav Sedov mach_port_t server;
52ae771770SStanislav Sedov char *name;
53ae771770SStanislav Sedov };
54ae771770SStanislav Sedov
55ae771770SStanislav Sedov static int
56ae771770SStanislav Sedov mach_release(void *ctx);
57ae771770SStanislav Sedov
58ae771770SStanislav Sedov static int
mach_init(const char * service,void ** ctx)59ae771770SStanislav Sedov mach_init(const char *service, void **ctx)
60ae771770SStanislav Sedov {
61ae771770SStanislav Sedov struct mach_ctx *ipc;
62ae771770SStanislav Sedov mach_port_t sport;
63ae771770SStanislav Sedov int ret;
64ae771770SStanislav Sedov
65ae771770SStanislav Sedov dispatch_once(&jobqinited, ^{
66ae771770SStanislav Sedov jobq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
67ae771770SStanislav Sedov syncq = dispatch_queue_create("heim-ipc-syncq", NULL);
68ae771770SStanislav Sedov });
69ae771770SStanislav Sedov
70ae771770SStanislav Sedov ret = bootstrap_look_up(bootstrap_port, service, &sport);
71ae771770SStanislav Sedov if (ret)
72ae771770SStanislav Sedov return ret;
73ae771770SStanislav Sedov
74ae771770SStanislav Sedov ipc = malloc(sizeof(*ipc));
75ae771770SStanislav Sedov if (ipc == NULL) {
76ae771770SStanislav Sedov mach_port_destroy(mach_task_self(), sport);
77ae771770SStanislav Sedov return ENOMEM;
78ae771770SStanislav Sedov }
79ae771770SStanislav Sedov
80ae771770SStanislav Sedov ipc->server = sport;
81ae771770SStanislav Sedov ipc->name = strdup(service);
82ae771770SStanislav Sedov if (ipc->name == NULL) {
83ae771770SStanislav Sedov mach_release(ipc);
84ae771770SStanislav Sedov return ENOMEM;
85ae771770SStanislav Sedov }
86ae771770SStanislav Sedov
87ae771770SStanislav Sedov *ctx = ipc;
88ae771770SStanislav Sedov
89ae771770SStanislav Sedov return 0;
90ae771770SStanislav Sedov }
91ae771770SStanislav Sedov
92ae771770SStanislav Sedov static int
mach_ipc(void * ctx,const heim_idata * request,heim_idata * response,heim_icred * cred)93ae771770SStanislav Sedov mach_ipc(void *ctx,
94ae771770SStanislav Sedov const heim_idata *request, heim_idata *response,
95ae771770SStanislav Sedov heim_icred *cred)
96ae771770SStanislav Sedov {
97ae771770SStanislav Sedov struct mach_ctx *ipc = ctx;
98ae771770SStanislav Sedov heim_ipc_message_inband_t requestin;
99ae771770SStanislav Sedov mach_msg_type_number_t requestin_length = 0;
100ae771770SStanislav Sedov heim_ipc_message_outband_t requestout = NULL;
101ae771770SStanislav Sedov mach_msg_type_number_t requestout_length = 0;
102ae771770SStanislav Sedov heim_ipc_message_inband_t replyin;
103ae771770SStanislav Sedov mach_msg_type_number_t replyin_length;
104ae771770SStanislav Sedov heim_ipc_message_outband_t replyout;
105ae771770SStanislav Sedov mach_msg_type_number_t replyout_length;
106ae771770SStanislav Sedov int ret, errorcode, retries = 0;
107ae771770SStanislav Sedov
108ae771770SStanislav Sedov memcpy(requestin, request->data, request->length);
109ae771770SStanislav Sedov requestin_length = request->length;
110ae771770SStanislav Sedov
111ae771770SStanislav Sedov while (retries < 2) {
112ae771770SStanislav Sedov __block mach_port_t sport;
113ae771770SStanislav Sedov
114ae771770SStanislav Sedov dispatch_sync(syncq, ^{ sport = ipc->server; });
115ae771770SStanislav Sedov
116ae771770SStanislav Sedov ret = mheim_ipc_call(sport,
117ae771770SStanislav Sedov requestin, requestin_length,
118ae771770SStanislav Sedov requestout, requestout_length,
119ae771770SStanislav Sedov &errorcode,
120ae771770SStanislav Sedov replyin, &replyin_length,
121ae771770SStanislav Sedov &replyout, &replyout_length);
122ae771770SStanislav Sedov if (ret == MACH_SEND_INVALID_DEST) {
123ae771770SStanislav Sedov mach_port_t nport;
124ae771770SStanislav Sedov /* race other threads to get a new port */
125ae771770SStanislav Sedov ret = bootstrap_look_up(bootstrap_port, ipc->name, &nport);
126ae771770SStanislav Sedov if (ret)
127ae771770SStanislav Sedov return ret;
128ae771770SStanislav Sedov dispatch_sync(syncq, ^{
129ae771770SStanislav Sedov /* check if we lost the race to lookup the port */
130ae771770SStanislav Sedov if (sport != ipc->server) {
131ae771770SStanislav Sedov mach_port_deallocate(mach_task_self(), nport);
132ae771770SStanislav Sedov } else {
133ae771770SStanislav Sedov mach_port_deallocate(mach_task_self(), ipc->server);
134ae771770SStanislav Sedov ipc->server = nport;
135ae771770SStanislav Sedov }
136ae771770SStanislav Sedov });
137ae771770SStanislav Sedov retries++;
138ae771770SStanislav Sedov } else if (ret) {
139ae771770SStanislav Sedov return ret;
140ae771770SStanislav Sedov } else
141ae771770SStanislav Sedov break;
142ae771770SStanislav Sedov }
143ae771770SStanislav Sedov if (retries >= 2)
144ae771770SStanislav Sedov return EINVAL;
145ae771770SStanislav Sedov
146ae771770SStanislav Sedov if (errorcode) {
147ae771770SStanislav Sedov if (replyout_length)
148ae771770SStanislav Sedov vm_deallocate (mach_task_self (), (vm_address_t) replyout,
149ae771770SStanislav Sedov replyout_length);
150ae771770SStanislav Sedov return errorcode;
151ae771770SStanislav Sedov }
152ae771770SStanislav Sedov
153ae771770SStanislav Sedov if (replyout_length) {
154ae771770SStanislav Sedov response->data = malloc(replyout_length);
155ae771770SStanislav Sedov if (response->data == NULL) {
156ae771770SStanislav Sedov vm_deallocate (mach_task_self (), (vm_address_t) replyout,
157ae771770SStanislav Sedov replyout_length);
158ae771770SStanislav Sedov return ENOMEM;
159ae771770SStanislav Sedov }
160ae771770SStanislav Sedov memcpy(response->data, replyout, replyout_length);
161ae771770SStanislav Sedov response->length = replyout_length;
162ae771770SStanislav Sedov vm_deallocate (mach_task_self (), (vm_address_t) replyout,
163ae771770SStanislav Sedov replyout_length);
164ae771770SStanislav Sedov } else {
165ae771770SStanislav Sedov response->data = malloc(replyin_length);
166ae771770SStanislav Sedov if (response->data == NULL)
167ae771770SStanislav Sedov return ENOMEM;
168ae771770SStanislav Sedov memcpy(response->data, replyin, replyin_length);
169ae771770SStanislav Sedov response->length = replyin_length;
170ae771770SStanislav Sedov }
171ae771770SStanislav Sedov
172ae771770SStanislav Sedov return 0;
173ae771770SStanislav Sedov }
174ae771770SStanislav Sedov
175ae771770SStanislav Sedov struct async_client {
176ae771770SStanislav Sedov mach_port_t mp;
177ae771770SStanislav Sedov dispatch_source_t source;
178ae771770SStanislav Sedov dispatch_queue_t queue;
179ae771770SStanislav Sedov void (*func)(void *, int, heim_idata *, heim_icred);
180ae771770SStanislav Sedov void *userctx;
181ae771770SStanislav Sedov };
182ae771770SStanislav Sedov
183ae771770SStanislav Sedov 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)184ae771770SStanislav Sedov mheim_ado_acall_reply(mach_port_t server_port,
185ae771770SStanislav Sedov audit_token_t client_creds,
186ae771770SStanislav Sedov int returnvalue,
187ae771770SStanislav Sedov heim_ipc_message_inband_t replyin,
188ae771770SStanislav Sedov mach_msg_type_number_t replyinCnt,
189ae771770SStanislav Sedov heim_ipc_message_outband_t replyout,
190ae771770SStanislav Sedov mach_msg_type_number_t replyoutCnt)
191ae771770SStanislav Sedov {
192ae771770SStanislav Sedov struct async_client *c = dispatch_get_context(dispatch_get_current_queue());
193ae771770SStanislav Sedov heim_idata response;
194ae771770SStanislav Sedov
195ae771770SStanislav Sedov if (returnvalue) {
196ae771770SStanislav Sedov response.data = NULL;
197ae771770SStanislav Sedov response.length = 0;
198ae771770SStanislav Sedov } else if (replyoutCnt) {
199ae771770SStanislav Sedov response.data = replyout;
200ae771770SStanislav Sedov response.length = replyoutCnt;
201ae771770SStanislav Sedov } else {
202ae771770SStanislav Sedov response.data = replyin;
203ae771770SStanislav Sedov response.length = replyinCnt;
204ae771770SStanislav Sedov }
205ae771770SStanislav Sedov
206ae771770SStanislav Sedov (*c->func)(c->userctx, returnvalue, &response, NULL);
207ae771770SStanislav Sedov
208ae771770SStanislav Sedov if (replyoutCnt)
209ae771770SStanislav Sedov vm_deallocate (mach_task_self (), (vm_address_t) replyout, replyoutCnt);
210ae771770SStanislav Sedov
211ae771770SStanislav Sedov dispatch_source_cancel(c->source);
212ae771770SStanislav Sedov
213ae771770SStanislav Sedov return 0;
214ae771770SStanislav Sedov
215ae771770SStanislav Sedov
216ae771770SStanislav Sedov }
217ae771770SStanislav Sedov
218ae771770SStanislav Sedov
219ae771770SStanislav Sedov static int
mach_async(void * ctx,const heim_idata * request,void * userctx,void (* func)(void *,int,heim_idata *,heim_icred))220ae771770SStanislav Sedov mach_async(void *ctx, const heim_idata *request, void *userctx,
221ae771770SStanislav Sedov void (*func)(void *, int, heim_idata *, heim_icred))
222ae771770SStanislav Sedov {
223ae771770SStanislav Sedov struct mach_ctx *ipc = ctx;
224ae771770SStanislav Sedov heim_ipc_message_inband_t requestin;
225ae771770SStanislav Sedov mach_msg_type_number_t requestin_length = 0;
226ae771770SStanislav Sedov heim_ipc_message_outband_t requestout = NULL;
227ae771770SStanislav Sedov mach_msg_type_number_t requestout_length = 0;
228ae771770SStanislav Sedov int ret, retries = 0;
229ae771770SStanislav Sedov kern_return_t kr;
230ae771770SStanislav Sedov struct async_client *c;
231ae771770SStanislav Sedov
232ae771770SStanislav Sedov /* first create the service that will catch the reply from the server */
233ae771770SStanislav Sedov /* XXX these object should be cached and reused */
234ae771770SStanislav Sedov
235ae771770SStanislav Sedov c = malloc(sizeof(*c));
236ae771770SStanislav Sedov if (c == NULL)
237ae771770SStanislav Sedov return ENOMEM;
238ae771770SStanislav Sedov
239ae771770SStanislav Sedov kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &c->mp);
240ae771770SStanislav Sedov if (kr != KERN_SUCCESS)
241ae771770SStanislav Sedov return EINVAL;
242ae771770SStanislav Sedov
243ae771770SStanislav Sedov c->queue = dispatch_queue_create("heim-ipc-async-client", NULL);
244ae771770SStanislav Sedov c->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, c->mp, 0, c->queue);
245ae771770SStanislav Sedov dispatch_set_context(c->queue, c);
246ae771770SStanislav Sedov
247ae771770SStanislav Sedov dispatch_source_set_event_handler(c->source, ^{
248ae771770SStanislav Sedov dispatch_mig_server(c->source,
249ae771770SStanislav Sedov sizeof(union __RequestUnion__mheim_ado_mheim_aipc_subsystem),
250ae771770SStanislav Sedov mheim_aipc_server);
251ae771770SStanislav Sedov });
252ae771770SStanislav Sedov
253ae771770SStanislav Sedov dispatch_source_set_cancel_handler(c->source, ^{
254ae771770SStanislav Sedov mach_port_mod_refs(mach_task_self(), c->mp,
255ae771770SStanislav Sedov MACH_PORT_RIGHT_RECEIVE, -1);
256ae771770SStanislav Sedov dispatch_release(c->queue);
257ae771770SStanislav Sedov dispatch_release(c->source);
258ae771770SStanislav Sedov free(c);
259ae771770SStanislav Sedov });
260ae771770SStanislav Sedov
261ae771770SStanislav Sedov c->func = func;
262ae771770SStanislav Sedov c->userctx = userctx;
263ae771770SStanislav Sedov
264ae771770SStanislav Sedov dispatch_resume(c->source);
265ae771770SStanislav Sedov
266ae771770SStanislav Sedov /* ok, send the message */
267ae771770SStanislav Sedov
268ae771770SStanislav Sedov memcpy(requestin, request->data, request->length);
269ae771770SStanislav Sedov requestin_length = request->length;
270ae771770SStanislav Sedov
271ae771770SStanislav Sedov while (retries < 2) {
272ae771770SStanislav Sedov __block mach_port_t sport;
273ae771770SStanislav Sedov
274ae771770SStanislav Sedov dispatch_sync(syncq, ^{ sport = ipc->server; });
275ae771770SStanislav Sedov
276ae771770SStanislav Sedov ret = mheim_ipc_call_request(sport, c->mp,
277ae771770SStanislav Sedov requestin, requestin_length,
278ae771770SStanislav Sedov requestout, requestout_length);
279ae771770SStanislav Sedov if (ret == MACH_SEND_INVALID_DEST) {
280ae771770SStanislav Sedov ret = bootstrap_look_up(bootstrap_port, ipc->name, &sport);
281ae771770SStanislav Sedov if (ret) {
282ae771770SStanislav Sedov dispatch_source_cancel(c->source);
283ae771770SStanislav Sedov return ret;
284ae771770SStanislav Sedov }
285ae771770SStanislav Sedov mach_port_deallocate(mach_task_self(), ipc->server);
286ae771770SStanislav Sedov ipc->server = sport;
287ae771770SStanislav Sedov retries++;
288ae771770SStanislav Sedov } else if (ret) {
289ae771770SStanislav Sedov dispatch_source_cancel(c->source);
290ae771770SStanislav Sedov return ret;
291ae771770SStanislav Sedov } else
292ae771770SStanislav Sedov break;
293ae771770SStanislav Sedov }
294ae771770SStanislav Sedov if (retries >= 2) {
295ae771770SStanislav Sedov dispatch_source_cancel(c->source);
296ae771770SStanislav Sedov return EINVAL;
297ae771770SStanislav Sedov }
298ae771770SStanislav Sedov
299ae771770SStanislav Sedov return 0;
300ae771770SStanislav Sedov }
301ae771770SStanislav Sedov
302ae771770SStanislav Sedov static int
mach_release(void * ctx)303ae771770SStanislav Sedov mach_release(void *ctx)
304ae771770SStanislav Sedov {
305ae771770SStanislav Sedov struct mach_ctx *ipc = ctx;
306ae771770SStanislav Sedov if (ipc->server != MACH_PORT_NULL)
307ae771770SStanislav Sedov mach_port_deallocate(mach_task_self(), ipc->server);
308ae771770SStanislav Sedov free(ipc->name);
309ae771770SStanislav Sedov free(ipc);
310ae771770SStanislav Sedov return 0;
311ae771770SStanislav Sedov }
312ae771770SStanislav Sedov
313ae771770SStanislav Sedov #endif
314ae771770SStanislav Sedov
315ae771770SStanislav Sedov struct path_ctx {
316ae771770SStanislav Sedov char *path;
317ae771770SStanislav Sedov int fd;
318ae771770SStanislav Sedov };
319ae771770SStanislav Sedov
320ae771770SStanislav Sedov static int common_release(void *);
321ae771770SStanislav Sedov
322ae771770SStanislav Sedov static int
connect_unix(struct path_ctx * s)323ae771770SStanislav Sedov connect_unix(struct path_ctx *s)
324ae771770SStanislav Sedov {
325ae771770SStanislav Sedov struct sockaddr_un addr;
326ae771770SStanislav Sedov
327ae771770SStanislav Sedov addr.sun_family = AF_UNIX;
328ae771770SStanislav Sedov strlcpy(addr.sun_path, s->path, sizeof(addr.sun_path));
329ae771770SStanislav Sedov
330ae771770SStanislav Sedov s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
331ae771770SStanislav Sedov if (s->fd < 0)
332ae771770SStanislav Sedov return errno;
333ae771770SStanislav Sedov rk_cloexec(s->fd);
334ae771770SStanislav Sedov
335*ed549cb0SCy Schubert if (connect(s->fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
336ae771770SStanislav Sedov return errno;
337ae771770SStanislav Sedov
338ae771770SStanislav Sedov return 0;
339ae771770SStanislav Sedov }
340ae771770SStanislav Sedov
341ae771770SStanislav Sedov static int
common_path_init(const char * service,const char * file,void ** ctx)342ae771770SStanislav Sedov common_path_init(const char *service,
343ae771770SStanislav Sedov const char *file,
344ae771770SStanislav Sedov void **ctx)
345ae771770SStanislav Sedov {
346ae771770SStanislav Sedov struct path_ctx *s;
347ae771770SStanislav Sedov
348ae771770SStanislav Sedov s = malloc(sizeof(*s));
349ae771770SStanislav Sedov if (s == NULL)
350ae771770SStanislav Sedov return ENOMEM;
351ae771770SStanislav Sedov s->fd = -1;
352ae771770SStanislav Sedov
353ae771770SStanislav Sedov asprintf(&s->path, "/var/run/.heim_%s-%s", service, file);
354ae771770SStanislav Sedov
355ae771770SStanislav Sedov *ctx = s;
356ae771770SStanislav Sedov
357ae771770SStanislav Sedov return 0;
358ae771770SStanislav Sedov }
359ae771770SStanislav Sedov
360ae771770SStanislav Sedov static int
unix_socket_init(const char * service,void ** ctx)361ae771770SStanislav Sedov unix_socket_init(const char *service,
362ae771770SStanislav Sedov void **ctx)
363ae771770SStanislav Sedov {
364ae771770SStanislav Sedov int ret;
365ae771770SStanislav Sedov
366ae771770SStanislav Sedov ret = common_path_init(service, "socket", ctx);
367ae771770SStanislav Sedov if (ret)
368ae771770SStanislav Sedov return ret;
369ae771770SStanislav Sedov ret = connect_unix(*ctx);
370ae771770SStanislav Sedov if (ret)
371ae771770SStanislav Sedov common_release(*ctx);
372ae771770SStanislav Sedov
373ae771770SStanislav Sedov return ret;
374ae771770SStanislav Sedov }
375ae771770SStanislav Sedov
376ae771770SStanislav Sedov static int
unix_socket_ipc(void * ctx,const heim_idata * req,heim_idata * rep,heim_icred * cred)377ae771770SStanislav Sedov unix_socket_ipc(void *ctx,
378ae771770SStanislav Sedov const heim_idata *req, heim_idata *rep,
379ae771770SStanislav Sedov heim_icred *cred)
380ae771770SStanislav Sedov {
381ae771770SStanislav Sedov struct path_ctx *s = ctx;
382ae771770SStanislav Sedov uint32_t len = htonl(req->length);
383ae771770SStanislav Sedov uint32_t rv;
384ae771770SStanislav Sedov int retval;
385ae771770SStanislav Sedov
386ae771770SStanislav Sedov if (cred)
387ae771770SStanislav Sedov *cred = NULL;
388ae771770SStanislav Sedov
389ae771770SStanislav Sedov rep->data = NULL;
390ae771770SStanislav Sedov rep->length = 0;
391ae771770SStanislav Sedov
392ae771770SStanislav Sedov if (net_write(s->fd, &len, sizeof(len)) != sizeof(len))
393ae771770SStanislav Sedov return -1;
394ae771770SStanislav Sedov if (net_write(s->fd, req->data, req->length) != (ssize_t)req->length)
395ae771770SStanislav Sedov return -1;
396ae771770SStanislav Sedov
397ae771770SStanislav Sedov if (net_read(s->fd, &len, sizeof(len)) != sizeof(len))
398ae771770SStanislav Sedov return -1;
399ae771770SStanislav Sedov if (net_read(s->fd, &rv, sizeof(rv)) != sizeof(rv))
400ae771770SStanislav Sedov return -1;
401ae771770SStanislav Sedov retval = ntohl(rv);
402ae771770SStanislav Sedov
403ae771770SStanislav Sedov rep->length = ntohl(len);
404ae771770SStanislav Sedov if (rep->length > 0) {
405ae771770SStanislav Sedov rep->data = malloc(rep->length);
406ae771770SStanislav Sedov if (rep->data == NULL)
407ae771770SStanislav Sedov return -1;
408ae771770SStanislav Sedov if (net_read(s->fd, rep->data, rep->length) != (ssize_t)rep->length)
409ae771770SStanislav Sedov return -1;
410ae771770SStanislav Sedov } else
411ae771770SStanislav Sedov rep->data = NULL;
412ae771770SStanislav Sedov
413ae771770SStanislav Sedov return retval;
414ae771770SStanislav Sedov }
415ae771770SStanislav Sedov
416ae771770SStanislav Sedov int
common_release(void * ctx)417ae771770SStanislav Sedov common_release(void *ctx)
418ae771770SStanislav Sedov {
419ae771770SStanislav Sedov struct path_ctx *s = ctx;
420ae771770SStanislav Sedov if (s->fd >= 0)
421ae771770SStanislav Sedov close(s->fd);
422ae771770SStanislav Sedov free(s->path);
423ae771770SStanislav Sedov free(s);
424ae771770SStanislav Sedov return 0;
425ae771770SStanislav Sedov }
426ae771770SStanislav Sedov
427ae771770SStanislav Sedov #ifdef HAVE_DOOR
428ae771770SStanislav Sedov
429ae771770SStanislav Sedov static int
door_init(const char * service,void ** ctx)430ae771770SStanislav Sedov door_init(const char *service,
431ae771770SStanislav Sedov void **ctx)
432ae771770SStanislav Sedov {
433ae771770SStanislav Sedov ret = common_path_init(context, service, "door", ctx);
434ae771770SStanislav Sedov if (ret)
435ae771770SStanislav Sedov return ret;
436ae771770SStanislav Sedov ret = connect_door(*ctx);
437ae771770SStanislav Sedov if (ret)
438ae771770SStanislav Sedov common_release(*ctx);
439ae771770SStanislav Sedov return ret;
440ae771770SStanislav Sedov }
441ae771770SStanislav Sedov
442ae771770SStanislav Sedov static int
door_ipc(void * ctx,const heim_idata * request,heim_idata * response,heim_icred * cred)443ae771770SStanislav Sedov door_ipc(void *ctx,
444ae771770SStanislav Sedov const heim_idata *request, heim_idata *response,
445ae771770SStanislav Sedov heim_icred *cred)
446ae771770SStanislav Sedov {
447ae771770SStanislav Sedov door_arg_t arg;
448ae771770SStanislav Sedov int ret;
449ae771770SStanislav Sedov
450ae771770SStanislav Sedov arg.data_ptr = request->data;
451ae771770SStanislav Sedov arg.data_size = request->length;
452ae771770SStanislav Sedov arg.desc_ptr = NULL;
453ae771770SStanislav Sedov arg.desc_num = 0;
454ae771770SStanislav Sedov arg.rbuf = NULL;
455ae771770SStanislav Sedov arg.rsize = 0;
456ae771770SStanislav Sedov
457ae771770SStanislav Sedov ret = door_call(fd, &arg);
458ae771770SStanislav Sedov close(fd);
459ae771770SStanislav Sedov if (ret != 0)
460ae771770SStanislav Sedov return errno;
461ae771770SStanislav Sedov
462ae771770SStanislav Sedov response->data = malloc(arg.rsize);
463ae771770SStanislav Sedov if (response->data == NULL) {
464ae771770SStanislav Sedov munmap(arg.rbuf, arg.rsize);
465ae771770SStanislav Sedov return ENOMEM;
466ae771770SStanislav Sedov }
467ae771770SStanislav Sedov memcpy(response->data, arg.rbuf, arg.rsize);
468ae771770SStanislav Sedov response->length = arg.rsize;
469ae771770SStanislav Sedov munmap(arg.rbuf, arg.rsize);
470ae771770SStanislav Sedov
471ae771770SStanislav Sedov return ret;
472ae771770SStanislav Sedov }
473ae771770SStanislav Sedov
474ae771770SStanislav Sedov #endif
475ae771770SStanislav Sedov
476ae771770SStanislav Sedov struct hipc_ops {
477ae771770SStanislav Sedov const char *prefix;
478ae771770SStanislav Sedov int (*init)(const char *, void **);
479ae771770SStanislav Sedov int (*release)(void *);
480ae771770SStanislav Sedov int (*ipc)(void *,const heim_idata *, heim_idata *, heim_icred *);
481ae771770SStanislav Sedov int (*async)(void *, const heim_idata *, void *,
482ae771770SStanislav Sedov void (*)(void *, int, heim_idata *, heim_icred));
483ae771770SStanislav Sedov };
484ae771770SStanislav Sedov
485ae771770SStanislav Sedov struct hipc_ops ipcs[] = {
486ae771770SStanislav Sedov #if defined(__APPLE__) && defined(HAVE_GCD)
487ae771770SStanislav Sedov { "MACH", mach_init, mach_release, mach_ipc, mach_async },
488ae771770SStanislav Sedov #endif
489ae771770SStanislav Sedov #ifdef HAVE_DOOR
490ae771770SStanislav Sedov { "DOOR", door_init, common_release, door_ipc, NULL }
491ae771770SStanislav Sedov #endif
492ae771770SStanislav Sedov { "UNIX", unix_socket_init, common_release, unix_socket_ipc, NULL }
493ae771770SStanislav Sedov };
494ae771770SStanislav Sedov
495ae771770SStanislav Sedov struct heim_ipc {
496ae771770SStanislav Sedov struct hipc_ops *ops;
497ae771770SStanislav Sedov void *ctx;
498ae771770SStanislav Sedov };
499ae771770SStanislav Sedov
500ae771770SStanislav Sedov
501ae771770SStanislav Sedov int
heim_ipc_init_context(const char * name,heim_ipc * ctx)502ae771770SStanislav Sedov heim_ipc_init_context(const char *name, heim_ipc *ctx)
503ae771770SStanislav Sedov {
504ae771770SStanislav Sedov unsigned int i;
505ae771770SStanislav Sedov int ret, any = 0;
506ae771770SStanislav Sedov
507ae771770SStanislav Sedov for(i = 0; i < sizeof(ipcs)/sizeof(ipcs[0]); i++) {
508ae771770SStanislav Sedov size_t prefix_len = strlen(ipcs[i].prefix);
509ae771770SStanislav Sedov heim_ipc c;
510ae771770SStanislav Sedov if(strncmp(ipcs[i].prefix, name, prefix_len) == 0
511ae771770SStanislav Sedov && name[prefix_len] == ':') {
512ae771770SStanislav Sedov } else if (strncmp("ANY:", name, 4) == 0) {
513ae771770SStanislav Sedov prefix_len = 3;
514ae771770SStanislav Sedov any = 1;
515ae771770SStanislav Sedov } else
516ae771770SStanislav Sedov continue;
517ae771770SStanislav Sedov
518ae771770SStanislav Sedov c = calloc(1, sizeof(*c));
519ae771770SStanislav Sedov if (c == NULL)
520ae771770SStanislav Sedov return ENOMEM;
521ae771770SStanislav Sedov
522ae771770SStanislav Sedov c->ops = &ipcs[i];
523ae771770SStanislav Sedov
524ae771770SStanislav Sedov ret = (c->ops->init)(name + prefix_len + 1, &c->ctx);
525ae771770SStanislav Sedov if (ret) {
526ae771770SStanislav Sedov free(c);
527ae771770SStanislav Sedov if (any)
528ae771770SStanislav Sedov continue;
529ae771770SStanislav Sedov return ret;
530ae771770SStanislav Sedov }
531ae771770SStanislav Sedov
532ae771770SStanislav Sedov *ctx = c;
533ae771770SStanislav Sedov return 0;
534ae771770SStanislav Sedov }
535ae771770SStanislav Sedov
536ae771770SStanislav Sedov return ENOENT;
537ae771770SStanislav Sedov }
538ae771770SStanislav Sedov
539ae771770SStanislav Sedov void
heim_ipc_free_context(heim_ipc ctx)540ae771770SStanislav Sedov heim_ipc_free_context(heim_ipc ctx)
541ae771770SStanislav Sedov {
542ae771770SStanislav Sedov (ctx->ops->release)(ctx->ctx);
543ae771770SStanislav Sedov free(ctx);
544ae771770SStanislav Sedov }
545ae771770SStanislav Sedov
546ae771770SStanislav Sedov int
heim_ipc_call(heim_ipc ctx,const heim_idata * snd,heim_idata * rcv,heim_icred * cred)547ae771770SStanislav Sedov heim_ipc_call(heim_ipc ctx, const heim_idata *snd, heim_idata *rcv,
548ae771770SStanislav Sedov heim_icred *cred)
549ae771770SStanislav Sedov {
550ae771770SStanislav Sedov if (cred)
551ae771770SStanislav Sedov *cred = NULL;
552ae771770SStanislav Sedov return (ctx->ops->ipc)(ctx->ctx, snd, rcv, cred);
553ae771770SStanislav Sedov }
554ae771770SStanislav Sedov
555ae771770SStanislav Sedov int
heim_ipc_async(heim_ipc ctx,const heim_idata * snd,void * userctx,void (* func)(void *,int,heim_idata *,heim_icred))556ae771770SStanislav Sedov heim_ipc_async(heim_ipc ctx, const heim_idata *snd, void *userctx,
557ae771770SStanislav Sedov void (*func)(void *, int, heim_idata *, heim_icred))
558ae771770SStanislav Sedov {
559ae771770SStanislav Sedov if (ctx->ops->async == NULL) {
560ae771770SStanislav Sedov heim_idata rcv;
561ae771770SStanislav Sedov heim_icred cred = NULL;
562ae771770SStanislav Sedov int ret;
563ae771770SStanislav Sedov
564ae771770SStanislav Sedov ret = (ctx->ops->ipc)(ctx->ctx, snd, &rcv, &cred);
565ae771770SStanislav Sedov (*func)(userctx, ret, &rcv, cred);
566ae771770SStanislav Sedov heim_ipc_free_cred(cred);
567ae771770SStanislav Sedov free(rcv.data);
568ae771770SStanislav Sedov return ret;
569ae771770SStanislav Sedov } else {
570ae771770SStanislav Sedov return (ctx->ops->async)(ctx->ctx, snd, userctx, func);
571ae771770SStanislav Sedov }
572ae771770SStanislav Sedov }
573