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 #include <assert.h>
38ae771770SStanislav Sedov
39ae771770SStanislav Sedov #define MAX_PACKET_SIZE (128 * 1024)
40ae771770SStanislav Sedov
41ae771770SStanislav Sedov struct heim_sipc {
42ae771770SStanislav Sedov int (*release)(heim_sipc ctx);
43ae771770SStanislav Sedov heim_ipc_callback callback;
44ae771770SStanislav Sedov void *userctx;
45ae771770SStanislav Sedov void *mech;
46ae771770SStanislav Sedov };
47ae771770SStanislav Sedov
48ae771770SStanislav Sedov #if defined(__APPLE__) && defined(HAVE_GCD)
49ae771770SStanislav Sedov
50ae771770SStanislav Sedov #include "heim_ipcServer.h"
51ae771770SStanislav Sedov #include "heim_ipc_reply.h"
52ae771770SStanislav Sedov #include "heim_ipc_async.h"
53ae771770SStanislav Sedov
54ae771770SStanislav Sedov static dispatch_source_t timer;
55ae771770SStanislav Sedov static dispatch_queue_t timerq;
56ae771770SStanislav Sedov static uint64_t timeoutvalue;
57ae771770SStanislav Sedov
58ae771770SStanislav Sedov static dispatch_queue_t eventq;
59ae771770SStanislav Sedov
60ae771770SStanislav Sedov static dispatch_queue_t workq;
61ae771770SStanislav Sedov
62ae771770SStanislav Sedov static void
default_timer_ev(void)63ae771770SStanislav Sedov default_timer_ev(void)
64ae771770SStanislav Sedov {
65ae771770SStanislav Sedov exit(0);
66ae771770SStanislav Sedov }
67ae771770SStanislav Sedov
68ae771770SStanislav Sedov static void (*timer_ev)(void) = default_timer_ev;
69ae771770SStanislav Sedov
70ae771770SStanislav Sedov static void
set_timer(void)71ae771770SStanislav Sedov set_timer(void)
72ae771770SStanislav Sedov {
73ae771770SStanislav Sedov dispatch_source_set_timer(timer,
74ae771770SStanislav Sedov dispatch_time(DISPATCH_TIME_NOW,
75ae771770SStanislav Sedov timeoutvalue * NSEC_PER_SEC),
76ae771770SStanislav Sedov timeoutvalue * NSEC_PER_SEC, 1000000);
77ae771770SStanislav Sedov }
78ae771770SStanislav Sedov
79ae771770SStanislav Sedov static void
init_globals(void)80ae771770SStanislav Sedov init_globals(void)
81ae771770SStanislav Sedov {
82ae771770SStanislav Sedov static dispatch_once_t once;
83ae771770SStanislav Sedov dispatch_once(&once, ^{
84ae771770SStanislav Sedov timerq = dispatch_queue_create("hiem-sipc-timer-q", NULL);
85ae771770SStanislav Sedov timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerq);
86ae771770SStanislav Sedov dispatch_source_set_event_handler(timer, ^{ timer_ev(); } );
87ae771770SStanislav Sedov
88ae771770SStanislav Sedov workq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
89ae771770SStanislav Sedov eventq = dispatch_queue_create("heim-ipc.event-queue", NULL);
90ae771770SStanislav Sedov });
91ae771770SStanislav Sedov }
92ae771770SStanislav Sedov
93ae771770SStanislav Sedov static void
suspend_timer(void)94ae771770SStanislav Sedov suspend_timer(void)
95ae771770SStanislav Sedov {
96ae771770SStanislav Sedov dispatch_suspend(timer);
97ae771770SStanislav Sedov }
98ae771770SStanislav Sedov
99ae771770SStanislav Sedov static void
restart_timer(void)100ae771770SStanislav Sedov restart_timer(void)
101ae771770SStanislav Sedov {
102ae771770SStanislav Sedov dispatch_sync(timerq, ^{ set_timer(); });
103ae771770SStanislav Sedov dispatch_resume(timer);
104ae771770SStanislav Sedov }
105ae771770SStanislav Sedov
106ae771770SStanislav Sedov struct mach_service {
107ae771770SStanislav Sedov mach_port_t sport;
108ae771770SStanislav Sedov dispatch_source_t source;
109ae771770SStanislav Sedov dispatch_queue_t queue;
110ae771770SStanislav Sedov };
111ae771770SStanislav Sedov
112ae771770SStanislav Sedov struct mach_call_ctx {
113ae771770SStanislav Sedov mach_port_t reply_port;
114ae771770SStanislav Sedov heim_icred cred;
115ae771770SStanislav Sedov heim_idata req;
116ae771770SStanislav Sedov };
117ae771770SStanislav Sedov
118ae771770SStanislav Sedov
119ae771770SStanislav Sedov static void
mach_complete_sync(heim_sipc_call ctx,int returnvalue,heim_idata * reply)120ae771770SStanislav Sedov mach_complete_sync(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
121ae771770SStanislav Sedov {
122ae771770SStanislav Sedov struct mach_call_ctx *s = (struct mach_call_ctx *)ctx;
123ae771770SStanislav Sedov heim_ipc_message_inband_t replyin;
124ae771770SStanislav Sedov mach_msg_type_number_t replyinCnt;
125ae771770SStanislav Sedov heim_ipc_message_outband_t replyout;
126ae771770SStanislav Sedov mach_msg_type_number_t replyoutCnt;
127ae771770SStanislav Sedov kern_return_t kr;
128ae771770SStanislav Sedov
129ae771770SStanislav Sedov if (returnvalue) {
130ae771770SStanislav Sedov /* on error, no reply */
131ae771770SStanislav Sedov replyinCnt = 0;
132ae771770SStanislav Sedov replyout = 0; replyoutCnt = 0;
133ae771770SStanislav Sedov kr = KERN_SUCCESS;
134ae771770SStanislav Sedov } else if (reply->length < 2048) {
135ae771770SStanislav Sedov replyinCnt = reply->length;
136ae771770SStanislav Sedov memcpy(replyin, reply->data, replyinCnt);
137ae771770SStanislav Sedov replyout = 0; replyoutCnt = 0;
138ae771770SStanislav Sedov kr = KERN_SUCCESS;
139ae771770SStanislav Sedov } else {
140ae771770SStanislav Sedov replyinCnt = 0;
141ae771770SStanislav Sedov kr = vm_read(mach_task_self(),
142ae771770SStanislav Sedov (vm_address_t)reply->data, reply->length,
143ae771770SStanislav Sedov (vm_address_t *)&replyout, &replyoutCnt);
144ae771770SStanislav Sedov }
145ae771770SStanislav Sedov
146ae771770SStanislav Sedov mheim_ripc_call_reply(s->reply_port, returnvalue,
147ae771770SStanislav Sedov replyin, replyinCnt,
148ae771770SStanislav Sedov replyout, replyoutCnt);
149ae771770SStanislav Sedov
150ae771770SStanislav Sedov heim_ipc_free_cred(s->cred);
151ae771770SStanislav Sedov free(s->req.data);
152ae771770SStanislav Sedov free(s);
153ae771770SStanislav Sedov restart_timer();
154ae771770SStanislav Sedov }
155ae771770SStanislav Sedov
156ae771770SStanislav Sedov static void
mach_complete_async(heim_sipc_call ctx,int returnvalue,heim_idata * reply)157ae771770SStanislav Sedov mach_complete_async(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
158ae771770SStanislav Sedov {
159ae771770SStanislav Sedov struct mach_call_ctx *s = (struct mach_call_ctx *)ctx;
160ae771770SStanislav Sedov heim_ipc_message_inband_t replyin;
161ae771770SStanislav Sedov mach_msg_type_number_t replyinCnt;
162ae771770SStanislav Sedov heim_ipc_message_outband_t replyout;
163ae771770SStanislav Sedov mach_msg_type_number_t replyoutCnt;
164ae771770SStanislav Sedov kern_return_t kr;
165ae771770SStanislav Sedov
166ae771770SStanislav Sedov if (returnvalue) {
167ae771770SStanislav Sedov /* on error, no reply */
168ae771770SStanislav Sedov replyinCnt = 0;
169ae771770SStanislav Sedov replyout = 0; replyoutCnt = 0;
170ae771770SStanislav Sedov kr = KERN_SUCCESS;
171ae771770SStanislav Sedov } else if (reply->length < 2048) {
172ae771770SStanislav Sedov replyinCnt = reply->length;
173ae771770SStanislav Sedov memcpy(replyin, reply->data, replyinCnt);
174ae771770SStanislav Sedov replyout = 0; replyoutCnt = 0;
175ae771770SStanislav Sedov kr = KERN_SUCCESS;
176ae771770SStanislav Sedov } else {
177ae771770SStanislav Sedov replyinCnt = 0;
178ae771770SStanislav Sedov kr = vm_read(mach_task_self(),
179ae771770SStanislav Sedov (vm_address_t)reply->data, reply->length,
180ae771770SStanislav Sedov (vm_address_t *)&replyout, &replyoutCnt);
181ae771770SStanislav Sedov }
182ae771770SStanislav Sedov
183ae771770SStanislav Sedov kr = mheim_aipc_acall_reply(s->reply_port, returnvalue,
184ae771770SStanislav Sedov replyin, replyinCnt,
185ae771770SStanislav Sedov replyout, replyoutCnt);
186ae771770SStanislav Sedov heim_ipc_free_cred(s->cred);
187ae771770SStanislav Sedov free(s->req.data);
188ae771770SStanislav Sedov free(s);
189ae771770SStanislav Sedov restart_timer();
190ae771770SStanislav Sedov }
191ae771770SStanislav Sedov
192ae771770SStanislav Sedov
193ae771770SStanislav Sedov 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)194ae771770SStanislav Sedov mheim_do_call(mach_port_t server_port,
195ae771770SStanislav Sedov audit_token_t client_creds,
196ae771770SStanislav Sedov mach_port_t reply_port,
197ae771770SStanislav Sedov heim_ipc_message_inband_t requestin,
198ae771770SStanislav Sedov mach_msg_type_number_t requestinCnt,
199ae771770SStanislav Sedov heim_ipc_message_outband_t requestout,
200ae771770SStanislav Sedov mach_msg_type_number_t requestoutCnt,
201ae771770SStanislav Sedov int *returnvalue,
202ae771770SStanislav Sedov heim_ipc_message_inband_t replyin,
203ae771770SStanislav Sedov mach_msg_type_number_t *replyinCnt,
204ae771770SStanislav Sedov heim_ipc_message_outband_t *replyout,
205ae771770SStanislav Sedov mach_msg_type_number_t *replyoutCnt)
206ae771770SStanislav Sedov {
207ae771770SStanislav Sedov heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
208ae771770SStanislav Sedov struct mach_call_ctx *s;
209ae771770SStanislav Sedov kern_return_t kr;
210ae771770SStanislav Sedov uid_t uid;
211ae771770SStanislav Sedov gid_t gid;
212ae771770SStanislav Sedov pid_t pid;
213ae771770SStanislav Sedov au_asid_t session;
214ae771770SStanislav Sedov
215ae771770SStanislav Sedov *replyout = NULL;
216ae771770SStanislav Sedov *replyoutCnt = 0;
217ae771770SStanislav Sedov *replyinCnt = 0;
218ae771770SStanislav Sedov
219ae771770SStanislav Sedov s = malloc(sizeof(*s));
220ae771770SStanislav Sedov if (s == NULL)
221ae771770SStanislav Sedov return KERN_MEMORY_FAILURE; /* XXX */
222ae771770SStanislav Sedov
223ae771770SStanislav Sedov s->reply_port = reply_port;
224ae771770SStanislav Sedov
225ae771770SStanislav Sedov audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL);
226ae771770SStanislav Sedov
227ae771770SStanislav Sedov kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred);
228ae771770SStanislav Sedov if (kr) {
229ae771770SStanislav Sedov free(s);
230ae771770SStanislav Sedov return kr;
231ae771770SStanislav Sedov }
232ae771770SStanislav Sedov
233ae771770SStanislav Sedov suspend_timer();
234ae771770SStanislav Sedov
235ae771770SStanislav Sedov if (requestinCnt) {
236ae771770SStanislav Sedov s->req.data = malloc(requestinCnt);
237ae771770SStanislav Sedov memcpy(s->req.data, requestin, requestinCnt);
238ae771770SStanislav Sedov s->req.length = requestinCnt;
239ae771770SStanislav Sedov } else {
240ae771770SStanislav Sedov s->req.data = malloc(requestoutCnt);
241ae771770SStanislav Sedov memcpy(s->req.data, requestout, requestoutCnt);
242ae771770SStanislav Sedov s->req.length = requestoutCnt;
243ae771770SStanislav Sedov }
244ae771770SStanislav Sedov
245ae771770SStanislav Sedov dispatch_async(workq, ^{
246ae771770SStanislav Sedov (ctx->callback)(ctx->userctx, &s->req, s->cred,
247ae771770SStanislav Sedov mach_complete_sync, (heim_sipc_call)s);
248ae771770SStanislav Sedov });
249ae771770SStanislav Sedov
250ae771770SStanislav Sedov return MIG_NO_REPLY;
251ae771770SStanislav Sedov }
252ae771770SStanislav Sedov
253ae771770SStanislav Sedov 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)254ae771770SStanislav Sedov mheim_do_call_request(mach_port_t server_port,
255ae771770SStanislav Sedov audit_token_t client_creds,
256ae771770SStanislav Sedov mach_port_t reply_port,
257ae771770SStanislav Sedov heim_ipc_message_inband_t requestin,
258ae771770SStanislav Sedov mach_msg_type_number_t requestinCnt,
259ae771770SStanislav Sedov heim_ipc_message_outband_t requestout,
260ae771770SStanislav Sedov mach_msg_type_number_t requestoutCnt)
261ae771770SStanislav Sedov {
262ae771770SStanislav Sedov heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
263ae771770SStanislav Sedov struct mach_call_ctx *s;
264ae771770SStanislav Sedov kern_return_t kr;
265ae771770SStanislav Sedov uid_t uid;
266ae771770SStanislav Sedov gid_t gid;
267ae771770SStanislav Sedov pid_t pid;
268ae771770SStanislav Sedov au_asid_t session;
269ae771770SStanislav Sedov
270ae771770SStanislav Sedov s = malloc(sizeof(*s));
271ae771770SStanislav Sedov if (s == NULL)
272ae771770SStanislav Sedov return KERN_MEMORY_FAILURE; /* XXX */
273ae771770SStanislav Sedov
274ae771770SStanislav Sedov s->reply_port = reply_port;
275ae771770SStanislav Sedov
276ae771770SStanislav Sedov audit_token_to_au32(client_creds, NULL, &uid, &gid, NULL, NULL, &pid, &session, NULL);
277ae771770SStanislav Sedov
278ae771770SStanislav Sedov kr = _heim_ipc_create_cred(uid, gid, pid, session, &s->cred);
279ae771770SStanislav Sedov if (kr) {
280ae771770SStanislav Sedov free(s);
281ae771770SStanislav Sedov return kr;
282ae771770SStanislav Sedov }
283ae771770SStanislav Sedov
284ae771770SStanislav Sedov suspend_timer();
285ae771770SStanislav Sedov
286ae771770SStanislav Sedov if (requestinCnt) {
287ae771770SStanislav Sedov s->req.data = malloc(requestinCnt);
288ae771770SStanislav Sedov memcpy(s->req.data, requestin, requestinCnt);
289ae771770SStanislav Sedov s->req.length = requestinCnt;
290ae771770SStanislav Sedov } else {
291ae771770SStanislav Sedov s->req.data = malloc(requestoutCnt);
292ae771770SStanislav Sedov memcpy(s->req.data, requestout, requestoutCnt);
293ae771770SStanislav Sedov s->req.length = requestoutCnt;
294ae771770SStanislav Sedov }
295ae771770SStanislav Sedov
296ae771770SStanislav Sedov dispatch_async(workq, ^{
297ae771770SStanislav Sedov (ctx->callback)(ctx->userctx, &s->req, s->cred,
298ae771770SStanislav Sedov mach_complete_async, (heim_sipc_call)s);
299ae771770SStanislav Sedov });
300ae771770SStanislav Sedov
301ae771770SStanislav Sedov return KERN_SUCCESS;
302ae771770SStanislav Sedov }
303ae771770SStanislav Sedov
304ae771770SStanislav Sedov static int
mach_init(const char * service,mach_port_t sport,heim_sipc ctx)305ae771770SStanislav Sedov mach_init(const char *service, mach_port_t sport, heim_sipc ctx)
306ae771770SStanislav Sedov {
307ae771770SStanislav Sedov struct mach_service *s;
308ae771770SStanislav Sedov char *name;
309ae771770SStanislav Sedov
310ae771770SStanislav Sedov init_globals();
311ae771770SStanislav Sedov
312ae771770SStanislav Sedov s = calloc(1, sizeof(*s));
313ae771770SStanislav Sedov if (s == NULL)
314ae771770SStanislav Sedov return ENOMEM;
315ae771770SStanislav Sedov
316ae771770SStanislav Sedov asprintf(&name, "heim-ipc-mach-%s", service);
317ae771770SStanislav Sedov
318ae771770SStanislav Sedov s->queue = dispatch_queue_create(name, NULL);
319ae771770SStanislav Sedov free(name);
320ae771770SStanislav Sedov s->sport = sport;
321ae771770SStanislav Sedov
322ae771770SStanislav Sedov s->source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
323ae771770SStanislav Sedov s->sport, 0, s->queue);
324ae771770SStanislav Sedov if (s->source == NULL) {
325ae771770SStanislav Sedov dispatch_release(s->queue);
326ae771770SStanislav Sedov free(s);
327ae771770SStanislav Sedov return ENOMEM;
328ae771770SStanislav Sedov }
329ae771770SStanislav Sedov ctx->mech = s;
330ae771770SStanislav Sedov
331ae771770SStanislav Sedov dispatch_set_context(s->queue, ctx);
332ae771770SStanislav Sedov dispatch_set_context(s->source, s);
333ae771770SStanislav Sedov
334ae771770SStanislav Sedov dispatch_source_set_event_handler(s->source, ^{
335ae771770SStanislav Sedov dispatch_mig_server(s->source, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem), mheim_ipc_server);
336ae771770SStanislav Sedov });
337ae771770SStanislav Sedov
338ae771770SStanislav Sedov dispatch_source_set_cancel_handler(s->source, ^{
339ae771770SStanislav Sedov heim_sipc ctx = dispatch_get_context(dispatch_get_current_queue());
340ae771770SStanislav Sedov struct mach_service *st = ctx->mech;
341ae771770SStanislav Sedov mach_port_mod_refs(mach_task_self(), st->sport,
342ae771770SStanislav Sedov MACH_PORT_RIGHT_RECEIVE, -1);
343ae771770SStanislav Sedov dispatch_release(st->queue);
344ae771770SStanislav Sedov dispatch_release(st->source);
345ae771770SStanislav Sedov free(st);
346ae771770SStanislav Sedov free(ctx);
347ae771770SStanislav Sedov });
348ae771770SStanislav Sedov
349ae771770SStanislav Sedov dispatch_resume(s->source);
350ae771770SStanislav Sedov
351ae771770SStanislav Sedov return 0;
352ae771770SStanislav Sedov }
353ae771770SStanislav Sedov
354ae771770SStanislav Sedov static int
mach_release(heim_sipc ctx)355ae771770SStanislav Sedov mach_release(heim_sipc ctx)
356ae771770SStanislav Sedov {
357ae771770SStanislav Sedov struct mach_service *s = ctx->mech;
358ae771770SStanislav Sedov dispatch_source_cancel(s->source);
359ae771770SStanislav Sedov dispatch_release(s->source);
360ae771770SStanislav Sedov return 0;
361ae771770SStanislav Sedov }
362ae771770SStanislav Sedov
363ae771770SStanislav Sedov static mach_port_t
mach_checkin_or_register(const char * service)364ae771770SStanislav Sedov mach_checkin_or_register(const char *service)
365ae771770SStanislav Sedov {
366ae771770SStanislav Sedov mach_port_t mp;
367ae771770SStanislav Sedov kern_return_t kr;
368ae771770SStanislav Sedov
369ae771770SStanislav Sedov kr = bootstrap_check_in(bootstrap_port, service, &mp);
370ae771770SStanislav Sedov if (kr == KERN_SUCCESS)
371ae771770SStanislav Sedov return mp;
372ae771770SStanislav Sedov
373ae771770SStanislav Sedov #if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
374ae771770SStanislav Sedov /* Pre SnowLeopard version */
375ae771770SStanislav Sedov kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
376ae771770SStanislav Sedov if (kr != KERN_SUCCESS)
377ae771770SStanislav Sedov return MACH_PORT_NULL;
378ae771770SStanislav Sedov
379ae771770SStanislav Sedov kr = mach_port_insert_right(mach_task_self(), mp, mp,
380ae771770SStanislav Sedov MACH_MSG_TYPE_MAKE_SEND);
381ae771770SStanislav Sedov if (kr != KERN_SUCCESS) {
382ae771770SStanislav Sedov mach_port_destroy(mach_task_self(), mp);
383ae771770SStanislav Sedov return MACH_PORT_NULL;
384ae771770SStanislav Sedov }
385ae771770SStanislav Sedov
386ae771770SStanislav Sedov kr = bootstrap_register(bootstrap_port, rk_UNCONST(service), mp);
387ae771770SStanislav Sedov if (kr != KERN_SUCCESS) {
388ae771770SStanislav Sedov mach_port_destroy(mach_task_self(), mp);
389ae771770SStanislav Sedov return MACH_PORT_NULL;
390ae771770SStanislav Sedov }
391ae771770SStanislav Sedov
392ae771770SStanislav Sedov return mp;
393ae771770SStanislav Sedov #else
394ae771770SStanislav Sedov return MACH_PORT_NULL;
395ae771770SStanislav Sedov #endif
396ae771770SStanislav Sedov }
397ae771770SStanislav Sedov
398ae771770SStanislav Sedov
399ae771770SStanislav Sedov #endif /* __APPLE__ && HAVE_GCD */
400ae771770SStanislav Sedov
401ae771770SStanislav Sedov
402ae771770SStanislav Sedov int
heim_sipc_launchd_mach_init(const char * service,heim_ipc_callback callback,void * user,heim_sipc * ctx)403ae771770SStanislav Sedov heim_sipc_launchd_mach_init(const char *service,
404ae771770SStanislav Sedov heim_ipc_callback callback,
405ae771770SStanislav Sedov void *user, heim_sipc *ctx)
406ae771770SStanislav Sedov {
407ae771770SStanislav Sedov #if defined(__APPLE__) && defined(HAVE_GCD)
408ae771770SStanislav Sedov mach_port_t sport = MACH_PORT_NULL;
409ae771770SStanislav Sedov heim_sipc c = NULL;
410ae771770SStanislav Sedov int ret;
411ae771770SStanislav Sedov
412ae771770SStanislav Sedov *ctx = NULL;
413ae771770SStanislav Sedov
414ae771770SStanislav Sedov sport = mach_checkin_or_register(service);
415ae771770SStanislav Sedov if (sport == MACH_PORT_NULL) {
416ae771770SStanislav Sedov ret = ENOENT;
417ae771770SStanislav Sedov goto error;
418ae771770SStanislav Sedov }
419ae771770SStanislav Sedov
420ae771770SStanislav Sedov c = calloc(1, sizeof(*c));
421ae771770SStanislav Sedov if (c == NULL) {
422ae771770SStanislav Sedov ret = ENOMEM;
423ae771770SStanislav Sedov goto error;
424ae771770SStanislav Sedov }
425ae771770SStanislav Sedov c->release = mach_release;
426ae771770SStanislav Sedov c->userctx = user;
427ae771770SStanislav Sedov c->callback = callback;
428ae771770SStanislav Sedov
429ae771770SStanislav Sedov ret = mach_init(service, sport, c);
430ae771770SStanislav Sedov if (ret)
431ae771770SStanislav Sedov goto error;
432ae771770SStanislav Sedov
433ae771770SStanislav Sedov *ctx = c;
434ae771770SStanislav Sedov return 0;
435ae771770SStanislav Sedov error:
436ae771770SStanislav Sedov if (c)
437ae771770SStanislav Sedov free(c);
438ae771770SStanislav Sedov if (sport != MACH_PORT_NULL)
439ae771770SStanislav Sedov mach_port_mod_refs(mach_task_self(), sport,
440ae771770SStanislav Sedov MACH_PORT_RIGHT_RECEIVE, -1);
441ae771770SStanislav Sedov return ret;
442ae771770SStanislav Sedov #else /* !(__APPLE__ && HAVE_GCD) */
443ae771770SStanislav Sedov *ctx = NULL;
444ae771770SStanislav Sedov return EINVAL;
445ae771770SStanislav Sedov #endif /* __APPLE__ && HAVE_GCD */
446ae771770SStanislav Sedov }
447ae771770SStanislav Sedov
448ae771770SStanislav Sedov struct client {
449ae771770SStanislav Sedov int fd;
450ae771770SStanislav Sedov heim_ipc_callback callback;
451ae771770SStanislav Sedov void *userctx;
452ae771770SStanislav Sedov int flags;
453ae771770SStanislav Sedov #define LISTEN_SOCKET 1
454ae771770SStanislav Sedov #define WAITING_READ 2
455ae771770SStanislav Sedov #define WAITING_WRITE 4
456ae771770SStanislav Sedov #define WAITING_CLOSE 8
457ae771770SStanislav Sedov
458ae771770SStanislav Sedov #define HTTP_REPLY 16
459ae771770SStanislav Sedov
460ae771770SStanislav Sedov #define INHERIT_MASK 0xffff0000
461ae771770SStanislav Sedov #define INCLUDE_ERROR_CODE (1 << 16)
462ae771770SStanislav Sedov #define ALLOW_HTTP (1<<17)
463ae771770SStanislav Sedov #define UNIX_SOCKET (1<<18)
464ae771770SStanislav Sedov unsigned calls;
465ae771770SStanislav Sedov size_t ptr, len;
466ae771770SStanislav Sedov uint8_t *inmsg;
467ae771770SStanislav Sedov size_t olen;
468ae771770SStanislav Sedov uint8_t *outmsg;
469ae771770SStanislav Sedov #ifdef HAVE_GCD
470ae771770SStanislav Sedov dispatch_source_t in;
471ae771770SStanislav Sedov dispatch_source_t out;
472ae771770SStanislav Sedov #endif
473ae771770SStanislav Sedov struct {
474ae771770SStanislav Sedov uid_t uid;
475ae771770SStanislav Sedov gid_t gid;
476ae771770SStanislav Sedov pid_t pid;
477ae771770SStanislav Sedov } unixrights;
478ae771770SStanislav Sedov };
479ae771770SStanislav Sedov
480ae771770SStanislav Sedov #ifndef HAVE_GCD
481ae771770SStanislav Sedov static unsigned num_clients = 0;
482ae771770SStanislav Sedov static struct client **clients = NULL;
483ae771770SStanislav Sedov #endif
484ae771770SStanislav Sedov
485ae771770SStanislav Sedov static void handle_read(struct client *);
486ae771770SStanislav Sedov static void handle_write(struct client *);
487ae771770SStanislav Sedov static int maybe_close(struct client *);
488ae771770SStanislav Sedov
489ae771770SStanislav Sedov /*
490ae771770SStanislav Sedov * Update peer credentials from socket.
491ae771770SStanislav Sedov *
492ae771770SStanislav Sedov * SCM_CREDS can only be updated the first time there is read data to
493ae771770SStanislav Sedov * read from the filedescriptor, so if we read do it before this
494ae771770SStanislav Sedov * point, the cred data might not be is not there yet.
495ae771770SStanislav Sedov */
496ae771770SStanislav Sedov
497ae771770SStanislav Sedov static int
update_client_creds(struct client * c)498ae771770SStanislav Sedov update_client_creds(struct client *c)
499ae771770SStanislav Sedov {
500ae771770SStanislav Sedov #ifdef HAVE_GETPEERUCRED
501ae771770SStanislav Sedov /* Solaris 10 */
502ae771770SStanislav Sedov {
503ae771770SStanislav Sedov ucred_t *peercred;
504ae771770SStanislav Sedov
505ae771770SStanislav Sedov if (getpeerucred(c->fd, &peercred) != 0) {
506ae771770SStanislav Sedov c->unixrights.uid = ucred_geteuid(peercred);
507ae771770SStanislav Sedov c->unixrights.gid = ucred_getegid(peercred);
508ae771770SStanislav Sedov c->unixrights.pid = 0;
509ae771770SStanislav Sedov ucred_free(peercred);
510ae771770SStanislav Sedov return 1;
511ae771770SStanislav Sedov }
512ae771770SStanislav Sedov }
513ae771770SStanislav Sedov #endif
514ae771770SStanislav Sedov #ifdef HAVE_GETPEEREID
515ae771770SStanislav Sedov /* FreeBSD, OpenBSD */
516ae771770SStanislav Sedov {
517ae771770SStanislav Sedov uid_t uid;
518ae771770SStanislav Sedov gid_t gid;
519ae771770SStanislav Sedov
520ae771770SStanislav Sedov if (getpeereid(c->fd, &uid, &gid) == 0) {
521ae771770SStanislav Sedov c->unixrights.uid = uid;
522ae771770SStanislav Sedov c->unixrights.gid = gid;
523ae771770SStanislav Sedov c->unixrights.pid = 0;
524ae771770SStanislav Sedov return 1;
525ae771770SStanislav Sedov }
526ae771770SStanislav Sedov }
527ae771770SStanislav Sedov #endif
528ae771770SStanislav Sedov #ifdef SO_PEERCRED
529ae771770SStanislav Sedov /* Linux */
530ae771770SStanislav Sedov {
531ae771770SStanislav Sedov struct ucred pc;
532ae771770SStanislav Sedov socklen_t pclen = sizeof(pc);
533ae771770SStanislav Sedov
534ae771770SStanislav Sedov if (getsockopt(c->fd, SOL_SOCKET, SO_PEERCRED, (void *)&pc, &pclen) == 0) {
535ae771770SStanislav Sedov c->unixrights.uid = pc.uid;
536ae771770SStanislav Sedov c->unixrights.gid = pc.gid;
537ae771770SStanislav Sedov c->unixrights.pid = pc.pid;
538ae771770SStanislav Sedov return 1;
539ae771770SStanislav Sedov }
540ae771770SStanislav Sedov }
541ae771770SStanislav Sedov #endif
542ae771770SStanislav Sedov #if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
543ae771770SStanislav Sedov {
544ae771770SStanislav Sedov struct xucred peercred;
545ae771770SStanislav Sedov socklen_t peercredlen = sizeof(peercred);
546ae771770SStanislav Sedov
547ae771770SStanislav Sedov if (getsockopt(c->fd, LOCAL_PEERCRED, 1,
548ae771770SStanislav Sedov (void *)&peercred, &peercredlen) == 0
549ae771770SStanislav Sedov && peercred.cr_version == XUCRED_VERSION)
550ae771770SStanislav Sedov {
551ae771770SStanislav Sedov c->unixrights.uid = peercred.cr_uid;
552ae771770SStanislav Sedov c->unixrights.gid = peercred.cr_gid;
553*c5afec6eSDmitry Chagin c->unixrights.pid = peercred.cr_pid;
554ae771770SStanislav Sedov return 1;
555ae771770SStanislav Sedov }
556ae771770SStanislav Sedov }
557ae771770SStanislav Sedov #endif
558ae771770SStanislav Sedov #if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
559ae771770SStanislav Sedov /* NetBSD */
560ae771770SStanislav Sedov if (c->unixrights.uid == (uid_t)-1) {
561ae771770SStanislav Sedov struct msghdr msg;
562ae771770SStanislav Sedov socklen_t crmsgsize;
563ae771770SStanislav Sedov void *crmsg;
564ae771770SStanislav Sedov struct cmsghdr *cmp;
565ae771770SStanislav Sedov struct sockcred *sc;
566ae771770SStanislav Sedov
567ae771770SStanislav Sedov memset(&msg, 0, sizeof(msg));
568ae771770SStanislav Sedov crmsgsize = CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX));
569ae771770SStanislav Sedov if (crmsgsize == 0)
570ae771770SStanislav Sedov return 1 ;
571ae771770SStanislav Sedov
572ae771770SStanislav Sedov crmsg = malloc(crmsgsize);
573ae771770SStanislav Sedov if (crmsg == NULL)
574ae771770SStanislav Sedov goto failed_scm_creds;
575ae771770SStanislav Sedov
576ae771770SStanislav Sedov memset(crmsg, 0, crmsgsize);
577ae771770SStanislav Sedov
578ae771770SStanislav Sedov msg.msg_control = crmsg;
579ae771770SStanislav Sedov msg.msg_controllen = crmsgsize;
580ae771770SStanislav Sedov
581ae771770SStanislav Sedov if (recvmsg(c->fd, &msg, 0) < 0) {
582ae771770SStanislav Sedov free(crmsg);
583ae771770SStanislav Sedov goto failed_scm_creds;
584ae771770SStanislav Sedov }
585ae771770SStanislav Sedov
586ae771770SStanislav Sedov if (msg.msg_controllen == 0 || (msg.msg_flags & MSG_CTRUNC) != 0) {
587ae771770SStanislav Sedov free(crmsg);
588ae771770SStanislav Sedov goto failed_scm_creds;
589ae771770SStanislav Sedov }
590ae771770SStanislav Sedov
591ae771770SStanislav Sedov cmp = CMSG_FIRSTHDR(&msg);
592ae771770SStanislav Sedov if (cmp->cmsg_level != SOL_SOCKET || cmp->cmsg_type != SCM_CREDS) {
593ae771770SStanislav Sedov free(crmsg);
594ae771770SStanislav Sedov goto failed_scm_creds;
595ae771770SStanislav Sedov }
596ae771770SStanislav Sedov
597ae771770SStanislav Sedov sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
598ae771770SStanislav Sedov
599ae771770SStanislav Sedov c->unixrights.uid = sc->sc_euid;
600ae771770SStanislav Sedov c->unixrights.gid = sc->sc_egid;
601ae771770SStanislav Sedov c->unixrights.pid = 0;
602ae771770SStanislav Sedov
603ae771770SStanislav Sedov free(crmsg);
604ae771770SStanislav Sedov return 1;
605ae771770SStanislav Sedov } else {
606ae771770SStanislav Sedov /* we already got the cred, just return it */
607ae771770SStanislav Sedov return 1;
608ae771770SStanislav Sedov }
609ae771770SStanislav Sedov failed_scm_creds:
610ae771770SStanislav Sedov #endif
611ae771770SStanislav Sedov return 0;
612ae771770SStanislav Sedov }
613ae771770SStanislav Sedov
614ae771770SStanislav Sedov
615ae771770SStanislav Sedov static struct client *
add_new_socket(int fd,int flags,heim_ipc_callback callback,void * userctx)616ae771770SStanislav Sedov add_new_socket(int fd,
617ae771770SStanislav Sedov int flags,
618ae771770SStanislav Sedov heim_ipc_callback callback,
619ae771770SStanislav Sedov void *userctx)
620ae771770SStanislav Sedov {
621ae771770SStanislav Sedov struct client *c;
622ae771770SStanislav Sedov int fileflags;
623ae771770SStanislav Sedov
624ae771770SStanislav Sedov c = calloc(1, sizeof(*c));
625ae771770SStanislav Sedov if (c == NULL)
626ae771770SStanislav Sedov return NULL;
627ae771770SStanislav Sedov
628ae771770SStanislav Sedov if (flags & LISTEN_SOCKET) {
629ae771770SStanislav Sedov c->fd = fd;
630ae771770SStanislav Sedov } else {
631ae771770SStanislav Sedov c->fd = accept(fd, NULL, NULL);
632ae771770SStanislav Sedov if(c->fd < 0) {
633ae771770SStanislav Sedov free(c);
634ae771770SStanislav Sedov return NULL;
635ae771770SStanislav Sedov }
636ae771770SStanislav Sedov }
637ae771770SStanislav Sedov
638ae771770SStanislav Sedov c->flags = flags;
639ae771770SStanislav Sedov c->callback = callback;
640ae771770SStanislav Sedov c->userctx = userctx;
641ae771770SStanislav Sedov
642ae771770SStanislav Sedov fileflags = fcntl(c->fd, F_GETFL, 0);
643ae771770SStanislav Sedov fcntl(c->fd, F_SETFL, fileflags | O_NONBLOCK);
644ae771770SStanislav Sedov
645ae771770SStanislav Sedov #ifdef HAVE_GCD
646ae771770SStanislav Sedov init_globals();
647ae771770SStanislav Sedov
648ae771770SStanislav Sedov c->in = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
649ae771770SStanislav Sedov c->fd, 0, eventq);
650ae771770SStanislav Sedov c->out = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE,
651ae771770SStanislav Sedov c->fd, 0, eventq);
652ae771770SStanislav Sedov
653ae771770SStanislav Sedov dispatch_source_set_event_handler(c->in, ^{
654ae771770SStanislav Sedov int rw = (c->flags & WAITING_WRITE);
655ae771770SStanislav Sedov handle_read(c);
656ae771770SStanislav Sedov if (rw == 0 && (c->flags & WAITING_WRITE))
657ae771770SStanislav Sedov dispatch_resume(c->out);
658ae771770SStanislav Sedov if ((c->flags & WAITING_READ) == 0)
659ae771770SStanislav Sedov dispatch_suspend(c->in);
660ae771770SStanislav Sedov maybe_close(c);
661ae771770SStanislav Sedov });
662ae771770SStanislav Sedov dispatch_source_set_event_handler(c->out, ^{
663ae771770SStanislav Sedov handle_write(c);
664ae771770SStanislav Sedov if ((c->flags & WAITING_WRITE) == 0) {
665ae771770SStanislav Sedov dispatch_suspend(c->out);
666ae771770SStanislav Sedov }
667ae771770SStanislav Sedov maybe_close(c);
668ae771770SStanislav Sedov });
669ae771770SStanislav Sedov
670ae771770SStanislav Sedov dispatch_resume(c->in);
671ae771770SStanislav Sedov #else
672ae771770SStanislav Sedov clients = erealloc(clients, sizeof(clients[0]) * (num_clients + 1));
673ae771770SStanislav Sedov clients[num_clients] = c;
674ae771770SStanislav Sedov num_clients++;
675ae771770SStanislav Sedov #endif
676ae771770SStanislav Sedov
677ae771770SStanislav Sedov return c;
678ae771770SStanislav Sedov }
679ae771770SStanislav Sedov
680ae771770SStanislav Sedov static int
maybe_close(struct client * c)681ae771770SStanislav Sedov maybe_close(struct client *c)
682ae771770SStanislav Sedov {
683ae771770SStanislav Sedov if (c->calls != 0)
684ae771770SStanislav Sedov return 0;
685ae771770SStanislav Sedov if (c->flags & (WAITING_READ|WAITING_WRITE))
686ae771770SStanislav Sedov return 0;
687ae771770SStanislav Sedov
688ae771770SStanislav Sedov #ifdef HAVE_GCD
689ae771770SStanislav Sedov dispatch_source_cancel(c->in);
690ae771770SStanislav Sedov if ((c->flags & WAITING_READ) == 0)
691ae771770SStanislav Sedov dispatch_resume(c->in);
692ae771770SStanislav Sedov dispatch_release(c->in);
693ae771770SStanislav Sedov
694ae771770SStanislav Sedov dispatch_source_cancel(c->out);
695ae771770SStanislav Sedov if ((c->flags & WAITING_WRITE) == 0)
696ae771770SStanislav Sedov dispatch_resume(c->out);
697ae771770SStanislav Sedov dispatch_release(c->out);
698ae771770SStanislav Sedov #endif
699ae771770SStanislav Sedov close(c->fd); /* ref count fd close */
700ae771770SStanislav Sedov free(c);
701ae771770SStanislav Sedov return 1;
702ae771770SStanislav Sedov }
703ae771770SStanislav Sedov
704ae771770SStanislav Sedov
705ae771770SStanislav Sedov struct socket_call {
706ae771770SStanislav Sedov heim_idata in;
707ae771770SStanislav Sedov struct client *c;
708ae771770SStanislav Sedov heim_icred cred;
709ae771770SStanislav Sedov };
710ae771770SStanislav Sedov
711ae771770SStanislav Sedov static void
output_data(struct client * c,const void * data,size_t len)712ae771770SStanislav Sedov output_data(struct client *c, const void *data, size_t len)
713ae771770SStanislav Sedov {
714ae771770SStanislav Sedov if (c->olen + len < c->olen)
715ae771770SStanislav Sedov abort();
716ae771770SStanislav Sedov c->outmsg = erealloc(c->outmsg, c->olen + len);
717ae771770SStanislav Sedov memcpy(&c->outmsg[c->olen], data, len);
718ae771770SStanislav Sedov c->olen += len;
719ae771770SStanislav Sedov c->flags |= WAITING_WRITE;
720ae771770SStanislav Sedov }
721ae771770SStanislav Sedov
722ae771770SStanislav Sedov static void
socket_complete(heim_sipc_call ctx,int returnvalue,heim_idata * reply)723ae771770SStanislav Sedov socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
724ae771770SStanislav Sedov {
725ae771770SStanislav Sedov struct socket_call *sc = (struct socket_call *)ctx;
726ae771770SStanislav Sedov struct client *c = sc->c;
727ae771770SStanislav Sedov
728ae771770SStanislav Sedov /* double complete ? */
729ae771770SStanislav Sedov if (c == NULL)
730ae771770SStanislav Sedov abort();
731ae771770SStanislav Sedov
732ae771770SStanislav Sedov if ((c->flags & WAITING_CLOSE) == 0) {
733ae771770SStanislav Sedov uint32_t u32;
734ae771770SStanislav Sedov
735ae771770SStanislav Sedov /* length */
736ae771770SStanislav Sedov u32 = htonl(reply->length);
737ae771770SStanislav Sedov output_data(c, &u32, sizeof(u32));
738ae771770SStanislav Sedov
739ae771770SStanislav Sedov /* return value */
740ae771770SStanislav Sedov if (c->flags & INCLUDE_ERROR_CODE) {
741ae771770SStanislav Sedov u32 = htonl(returnvalue);
742ae771770SStanislav Sedov output_data(c, &u32, sizeof(u32));
743ae771770SStanislav Sedov }
744ae771770SStanislav Sedov
745ae771770SStanislav Sedov /* data */
746ae771770SStanislav Sedov output_data(c, reply->data, reply->length);
747ae771770SStanislav Sedov
748ae771770SStanislav Sedov /* if HTTP, close connection */
749ae771770SStanislav Sedov if (c->flags & HTTP_REPLY) {
750ae771770SStanislav Sedov c->flags |= WAITING_CLOSE;
751ae771770SStanislav Sedov c->flags &= ~WAITING_READ;
752ae771770SStanislav Sedov }
753ae771770SStanislav Sedov }
754ae771770SStanislav Sedov
755ae771770SStanislav Sedov c->calls--;
756ae771770SStanislav Sedov if (sc->cred)
757ae771770SStanislav Sedov heim_ipc_free_cred(sc->cred);
758ae771770SStanislav Sedov free(sc->in.data);
759ae771770SStanislav Sedov sc->c = NULL; /* so we can catch double complete */
760ae771770SStanislav Sedov free(sc);
761ae771770SStanislav Sedov
762ae771770SStanislav Sedov maybe_close(c);
763ae771770SStanislav Sedov }
764ae771770SStanislav Sedov
765ae771770SStanislav Sedov /* remove HTTP %-quoting from buf */
766ae771770SStanislav Sedov static int
de_http(char * buf)767ae771770SStanislav Sedov de_http(char *buf)
768ae771770SStanislav Sedov {
769ae771770SStanislav Sedov unsigned char *p, *q;
770ae771770SStanislav Sedov for(p = q = (unsigned char *)buf; *p; p++, q++) {
771ae771770SStanislav Sedov if(*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) {
772ae771770SStanislav Sedov unsigned int x;
773ae771770SStanislav Sedov if(sscanf((char *)p + 1, "%2x", &x) != 1)
774ae771770SStanislav Sedov return -1;
775ae771770SStanislav Sedov *q = x;
776ae771770SStanislav Sedov p += 2;
777ae771770SStanislav Sedov } else
778ae771770SStanislav Sedov *q = *p;
779ae771770SStanislav Sedov }
780ae771770SStanislav Sedov *q = '\0';
781ae771770SStanislav Sedov return 0;
782ae771770SStanislav Sedov }
783ae771770SStanislav Sedov
784ae771770SStanislav Sedov static struct socket_call *
handle_http_tcp(struct client * c)785ae771770SStanislav Sedov handle_http_tcp(struct client *c)
786ae771770SStanislav Sedov {
787ae771770SStanislav Sedov struct socket_call *cs;
788ae771770SStanislav Sedov char *s, *p, *t;
789ae771770SStanislav Sedov void *data;
790ae771770SStanislav Sedov char *proto;
791ae771770SStanislav Sedov int len;
792ae771770SStanislav Sedov
793ae771770SStanislav Sedov s = (char *)c->inmsg;
794ae771770SStanislav Sedov
795ae771770SStanislav Sedov p = strstr(s, "\r\n");
796ae771770SStanislav Sedov if (p == NULL)
797ae771770SStanislav Sedov return NULL;
798ae771770SStanislav Sedov
799ae771770SStanislav Sedov *p = 0;
800ae771770SStanislav Sedov
801ae771770SStanislav Sedov p = NULL;
802ae771770SStanislav Sedov t = strtok_r(s, " \t", &p);
803ae771770SStanislav Sedov if (t == NULL)
804ae771770SStanislav Sedov return NULL;
805ae771770SStanislav Sedov
806ae771770SStanislav Sedov t = strtok_r(NULL, " \t", &p);
807ae771770SStanislav Sedov if (t == NULL)
808ae771770SStanislav Sedov return NULL;
809ae771770SStanislav Sedov
810ae771770SStanislav Sedov data = malloc(strlen(t));
811ae771770SStanislav Sedov if (data == NULL)
812ae771770SStanislav Sedov return NULL;
813ae771770SStanislav Sedov
814ae771770SStanislav Sedov if(*t == '/')
815ae771770SStanislav Sedov t++;
816ae771770SStanislav Sedov if(de_http(t) != 0) {
817ae771770SStanislav Sedov free(data);
818ae771770SStanislav Sedov return NULL;
819ae771770SStanislav Sedov }
820ae771770SStanislav Sedov proto = strtok_r(NULL, " \t", &p);
821ae771770SStanislav Sedov if (proto == NULL) {
822ae771770SStanislav Sedov free(data);
823ae771770SStanislav Sedov return NULL;
824ae771770SStanislav Sedov }
825ae771770SStanislav Sedov len = base64_decode(t, data);
826ae771770SStanislav Sedov if(len <= 0){
827ae771770SStanislav Sedov const char *msg =
828ae771770SStanislav Sedov " 404 Not found\r\n"
829ae771770SStanislav Sedov "Server: Heimdal/" VERSION "\r\n"
830ae771770SStanislav Sedov "Cache-Control: no-cache\r\n"
831ae771770SStanislav Sedov "Pragma: no-cache\r\n"
832ae771770SStanislav Sedov "Content-type: text/html\r\n"
833ae771770SStanislav Sedov "Content-transfer-encoding: 8bit\r\n\r\n"
834ae771770SStanislav Sedov "<TITLE>404 Not found</TITLE>\r\n"
835ae771770SStanislav Sedov "<H1>404 Not found</H1>\r\n"
836ae771770SStanislav Sedov "That page doesn't exist, maybe you are looking for "
837ae771770SStanislav Sedov "<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n";
838ae771770SStanislav Sedov free(data);
839ae771770SStanislav Sedov output_data(c, proto, strlen(proto));
840ae771770SStanislav Sedov output_data(c, msg, strlen(msg));
841ae771770SStanislav Sedov return NULL;
842ae771770SStanislav Sedov }
843ae771770SStanislav Sedov
844ae771770SStanislav Sedov cs = emalloc(sizeof(*cs));
845ae771770SStanislav Sedov cs->c = c;
846ae771770SStanislav Sedov cs->in.data = data;
847ae771770SStanislav Sedov cs->in.length = len;
848ae771770SStanislav Sedov c->ptr = 0;
849ae771770SStanislav Sedov
850ae771770SStanislav Sedov {
851ae771770SStanislav Sedov const char *msg =
852ae771770SStanislav Sedov " 200 OK\r\n"
853ae771770SStanislav Sedov "Server: Heimdal/" VERSION "\r\n"
854ae771770SStanislav Sedov "Cache-Control: no-cache\r\n"
855ae771770SStanislav Sedov "Pragma: no-cache\r\n"
856ae771770SStanislav Sedov "Content-type: application/octet-stream\r\n"
857ae771770SStanislav Sedov "Content-transfer-encoding: binary\r\n\r\n";
858ae771770SStanislav Sedov output_data(c, proto, strlen(proto));
859ae771770SStanislav Sedov output_data(c, msg, strlen(msg));
860ae771770SStanislav Sedov }
861ae771770SStanislav Sedov
862ae771770SStanislav Sedov return cs;
863ae771770SStanislav Sedov }
864ae771770SStanislav Sedov
865ae771770SStanislav Sedov
866ae771770SStanislav Sedov static void
handle_read(struct client * c)867ae771770SStanislav Sedov handle_read(struct client *c)
868ae771770SStanislav Sedov {
869ae771770SStanislav Sedov ssize_t len;
870ae771770SStanislav Sedov uint32_t dlen;
871ae771770SStanislav Sedov
872ae771770SStanislav Sedov if (c->flags & LISTEN_SOCKET) {
873ae771770SStanislav Sedov add_new_socket(c->fd,
874ae771770SStanislav Sedov WAITING_READ | (c->flags & INHERIT_MASK),
875ae771770SStanislav Sedov c->callback,
876ae771770SStanislav Sedov c->userctx);
877ae771770SStanislav Sedov return;
878ae771770SStanislav Sedov }
879ae771770SStanislav Sedov
880ae771770SStanislav Sedov if (c->ptr - c->len < 1024) {
881ae771770SStanislav Sedov c->inmsg = erealloc(c->inmsg,
882ae771770SStanislav Sedov c->len + 1024);
883ae771770SStanislav Sedov c->len += 1024;
884ae771770SStanislav Sedov }
885ae771770SStanislav Sedov
886ae771770SStanislav Sedov len = read(c->fd, c->inmsg + c->ptr, c->len - c->ptr);
887ae771770SStanislav Sedov if (len <= 0) {
888ae771770SStanislav Sedov c->flags |= WAITING_CLOSE;
889ae771770SStanislav Sedov c->flags &= ~WAITING_READ;
890ae771770SStanislav Sedov return;
891ae771770SStanislav Sedov }
892ae771770SStanislav Sedov c->ptr += len;
893ae771770SStanislav Sedov if (c->ptr > c->len)
894ae771770SStanislav Sedov abort();
895ae771770SStanislav Sedov
896ae771770SStanislav Sedov while (c->ptr >= sizeof(dlen)) {
897ae771770SStanislav Sedov struct socket_call *cs;
898ae771770SStanislav Sedov
899ae771770SStanislav Sedov if((c->flags & ALLOW_HTTP) && c->ptr >= 4 &&
900ae771770SStanislav Sedov strncmp((char *)c->inmsg, "GET ", 4) == 0 &&
901ae771770SStanislav Sedov strncmp((char *)c->inmsg + c->ptr - 4, "\r\n\r\n", 4) == 0) {
902ae771770SStanislav Sedov
903ae771770SStanislav Sedov /* remove the trailing \r\n\r\n so the string is NUL terminated */
904ae771770SStanislav Sedov c->inmsg[c->ptr - 4] = '\0';
905ae771770SStanislav Sedov
906ae771770SStanislav Sedov c->flags |= HTTP_REPLY;
907ae771770SStanislav Sedov
908ae771770SStanislav Sedov cs = handle_http_tcp(c);
909ae771770SStanislav Sedov if (cs == NULL) {
910ae771770SStanislav Sedov c->flags |= WAITING_CLOSE;
911ae771770SStanislav Sedov c->flags &= ~WAITING_READ;
912ae771770SStanislav Sedov break;
913ae771770SStanislav Sedov }
914ae771770SStanislav Sedov } else {
915ae771770SStanislav Sedov memcpy(&dlen, c->inmsg, sizeof(dlen));
916ae771770SStanislav Sedov dlen = ntohl(dlen);
917ae771770SStanislav Sedov
918ae771770SStanislav Sedov if (dlen > MAX_PACKET_SIZE) {
919ae771770SStanislav Sedov c->flags |= WAITING_CLOSE;
920ae771770SStanislav Sedov c->flags &= ~WAITING_READ;
921ae771770SStanislav Sedov return;
922ae771770SStanislav Sedov }
923ae771770SStanislav Sedov if (dlen > c->ptr - sizeof(dlen)) {
924ae771770SStanislav Sedov break;
925ae771770SStanislav Sedov }
926ae771770SStanislav Sedov
927ae771770SStanislav Sedov cs = emalloc(sizeof(*cs));
928ae771770SStanislav Sedov cs->c = c;
929ae771770SStanislav Sedov cs->in.data = emalloc(dlen);
930ae771770SStanislav Sedov memcpy(cs->in.data, c->inmsg + sizeof(dlen), dlen);
931ae771770SStanislav Sedov cs->in.length = dlen;
932ae771770SStanislav Sedov
933ae771770SStanislav Sedov c->ptr -= sizeof(dlen) + dlen;
934ae771770SStanislav Sedov memmove(c->inmsg,
935ae771770SStanislav Sedov c->inmsg + sizeof(dlen) + dlen,
936ae771770SStanislav Sedov c->ptr);
937ae771770SStanislav Sedov }
938ae771770SStanislav Sedov
939ae771770SStanislav Sedov c->calls++;
940ae771770SStanislav Sedov
941ae771770SStanislav Sedov if ((c->flags & UNIX_SOCKET) != 0) {
942ae771770SStanislav Sedov if (update_client_creds(c))
943ae771770SStanislav Sedov _heim_ipc_create_cred(c->unixrights.uid, c->unixrights.gid,
944ae771770SStanislav Sedov c->unixrights.pid, -1, &cs->cred);
945ae771770SStanislav Sedov }
946ae771770SStanislav Sedov
947ae771770SStanislav Sedov c->callback(c->userctx, &cs->in,
948ae771770SStanislav Sedov cs->cred, socket_complete,
949ae771770SStanislav Sedov (heim_sipc_call)cs);
950ae771770SStanislav Sedov }
951ae771770SStanislav Sedov }
952ae771770SStanislav Sedov
953ae771770SStanislav Sedov static void
handle_write(struct client * c)954ae771770SStanislav Sedov handle_write(struct client *c)
955ae771770SStanislav Sedov {
956ae771770SStanislav Sedov ssize_t len;
957ae771770SStanislav Sedov
958ae771770SStanislav Sedov len = write(c->fd, c->outmsg, c->olen);
959ae771770SStanislav Sedov if (len <= 0) {
960ae771770SStanislav Sedov c->flags |= WAITING_CLOSE;
961ae771770SStanislav Sedov c->flags &= ~(WAITING_WRITE);
962ae771770SStanislav Sedov } else if (c->olen != (size_t)len) {
963ae771770SStanislav Sedov memmove(&c->outmsg[0], &c->outmsg[len], c->olen - len);
964ae771770SStanislav Sedov c->olen -= len;
965ae771770SStanislav Sedov } else {
966ae771770SStanislav Sedov c->olen = 0;
967ae771770SStanislav Sedov free(c->outmsg);
968ae771770SStanislav Sedov c->outmsg = NULL;
969ae771770SStanislav Sedov c->flags &= ~(WAITING_WRITE);
970ae771770SStanislav Sedov }
971ae771770SStanislav Sedov }
972ae771770SStanislav Sedov
973ae771770SStanislav Sedov
974ae771770SStanislav Sedov #ifndef HAVE_GCD
975ae771770SStanislav Sedov
976ae771770SStanislav Sedov static void
process_loop(void)977ae771770SStanislav Sedov process_loop(void)
978ae771770SStanislav Sedov {
979ae771770SStanislav Sedov struct pollfd *fds;
980ae771770SStanislav Sedov unsigned n;
981ae771770SStanislav Sedov unsigned num_fds;
982ae771770SStanislav Sedov
983ae771770SStanislav Sedov while(num_clients > 0) {
984ae771770SStanislav Sedov
985ae771770SStanislav Sedov fds = malloc(num_clients * sizeof(fds[0]));
986ae771770SStanislav Sedov if(fds == NULL)
987ae771770SStanislav Sedov abort();
988ae771770SStanislav Sedov
989ae771770SStanislav Sedov num_fds = num_clients;
990ae771770SStanislav Sedov
991ae771770SStanislav Sedov for (n = 0 ; n < num_fds; n++) {
992ae771770SStanislav Sedov fds[n].fd = clients[n]->fd;
993ae771770SStanislav Sedov fds[n].events = 0;
994ae771770SStanislav Sedov if (clients[n]->flags & WAITING_READ)
995ae771770SStanislav Sedov fds[n].events |= POLLIN;
996ae771770SStanislav Sedov if (clients[n]->flags & WAITING_WRITE)
997ae771770SStanislav Sedov fds[n].events |= POLLOUT;
998ae771770SStanislav Sedov
999ae771770SStanislav Sedov fds[n].revents = 0;
1000ae771770SStanislav Sedov }
1001ae771770SStanislav Sedov
1002ae771770SStanislav Sedov poll(fds, num_fds, -1);
1003ae771770SStanislav Sedov
1004ae771770SStanislav Sedov for (n = 0 ; n < num_fds; n++) {
1005ae771770SStanislav Sedov if (clients[n] == NULL)
1006ae771770SStanislav Sedov continue;
1007ae771770SStanislav Sedov if (fds[n].revents & POLLERR) {
1008ae771770SStanislav Sedov clients[n]->flags |= WAITING_CLOSE;
1009ae771770SStanislav Sedov continue;
1010ae771770SStanislav Sedov }
1011ae771770SStanislav Sedov
1012ae771770SStanislav Sedov if (fds[n].revents & POLLIN)
1013ae771770SStanislav Sedov handle_read(clients[n]);
1014ae771770SStanislav Sedov if (fds[n].revents & POLLOUT)
1015ae771770SStanislav Sedov handle_write(clients[n]);
1016ae771770SStanislav Sedov }
1017ae771770SStanislav Sedov
1018ae771770SStanislav Sedov n = 0;
1019ae771770SStanislav Sedov while (n < num_clients) {
1020ae771770SStanislav Sedov struct client *c = clients[n];
1021ae771770SStanislav Sedov if (maybe_close(c)) {
1022ae771770SStanislav Sedov if (n < num_clients - 1)
1023ae771770SStanislav Sedov clients[n] = clients[num_clients - 1];
1024ae771770SStanislav Sedov num_clients--;
1025ae771770SStanislav Sedov } else
1026ae771770SStanislav Sedov n++;
1027ae771770SStanislav Sedov }
1028ae771770SStanislav Sedov
1029ae771770SStanislav Sedov free(fds);
1030ae771770SStanislav Sedov }
1031ae771770SStanislav Sedov }
1032ae771770SStanislav Sedov
1033ae771770SStanislav Sedov #endif
1034ae771770SStanislav Sedov
1035ae771770SStanislav Sedov static int
socket_release(heim_sipc ctx)1036ae771770SStanislav Sedov socket_release(heim_sipc ctx)
1037ae771770SStanislav Sedov {
1038ae771770SStanislav Sedov struct client *c = ctx->mech;
1039ae771770SStanislav Sedov c->flags |= WAITING_CLOSE;
1040ae771770SStanislav Sedov return 0;
1041ae771770SStanislav Sedov }
1042ae771770SStanislav Sedov
1043ae771770SStanislav Sedov int
heim_sipc_stream_listener(int fd,int type,heim_ipc_callback callback,void * user,heim_sipc * ctx)1044ae771770SStanislav Sedov heim_sipc_stream_listener(int fd, int type,
1045ae771770SStanislav Sedov heim_ipc_callback callback,
1046ae771770SStanislav Sedov void *user, heim_sipc *ctx)
1047ae771770SStanislav Sedov {
1048ae771770SStanislav Sedov heim_sipc ct = calloc(1, sizeof(*ct));
1049ae771770SStanislav Sedov struct client *c;
1050ae771770SStanislav Sedov
1051ae771770SStanislav Sedov if ((type & HEIM_SIPC_TYPE_IPC) && (type & (HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP)))
1052ae771770SStanislav Sedov return EINVAL;
1053ae771770SStanislav Sedov
1054ae771770SStanislav Sedov switch (type) {
1055ae771770SStanislav Sedov case HEIM_SIPC_TYPE_IPC:
1056ae771770SStanislav Sedov c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|INCLUDE_ERROR_CODE, callback, user);
1057ae771770SStanislav Sedov break;
1058ae771770SStanislav Sedov case HEIM_SIPC_TYPE_UINT32:
1059ae771770SStanislav Sedov c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ, callback, user);
1060ae771770SStanislav Sedov break;
1061ae771770SStanislav Sedov case HEIM_SIPC_TYPE_HTTP:
1062ae771770SStanislav Sedov case HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP:
1063ae771770SStanislav Sedov c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|ALLOW_HTTP, callback, user);
1064ae771770SStanislav Sedov break;
1065ae771770SStanislav Sedov default:
1066ae771770SStanislav Sedov free(ct);
1067ae771770SStanislav Sedov return EINVAL;
1068ae771770SStanislav Sedov }
1069ae771770SStanislav Sedov
1070ae771770SStanislav Sedov ct->mech = c;
1071ae771770SStanislav Sedov ct->release = socket_release;
1072ae771770SStanislav Sedov
1073ae771770SStanislav Sedov c->unixrights.uid = (uid_t) -1;
1074ae771770SStanislav Sedov c->unixrights.gid = (gid_t) -1;
1075ae771770SStanislav Sedov c->unixrights.pid = (pid_t) 0;
1076ae771770SStanislav Sedov
1077ae771770SStanislav Sedov *ctx = ct;
1078ae771770SStanislav Sedov return 0;
1079ae771770SStanislav Sedov }
1080ae771770SStanislav Sedov
1081ae771770SStanislav Sedov int
heim_sipc_service_unix(const char * service,heim_ipc_callback callback,void * user,heim_sipc * ctx)1082ae771770SStanislav Sedov heim_sipc_service_unix(const char *service,
1083ae771770SStanislav Sedov heim_ipc_callback callback,
1084ae771770SStanislav Sedov void *user, heim_sipc *ctx)
1085ae771770SStanislav Sedov {
1086ae771770SStanislav Sedov struct sockaddr_un un;
1087ae771770SStanislav Sedov int fd, ret;
1088ae771770SStanislav Sedov
1089ae771770SStanislav Sedov un.sun_family = AF_UNIX;
1090ae771770SStanislav Sedov
1091ae771770SStanislav Sedov snprintf(un.sun_path, sizeof(un.sun_path),
1092ae771770SStanislav Sedov "/var/run/.heim_%s-socket", service);
1093ae771770SStanislav Sedov fd = socket(AF_UNIX, SOCK_STREAM, 0);
1094ae771770SStanislav Sedov if (fd < 0)
1095ae771770SStanislav Sedov return errno;
1096ae771770SStanislav Sedov
1097ae771770SStanislav Sedov socket_set_reuseaddr(fd, 1);
1098ae771770SStanislav Sedov #ifdef LOCAL_CREDS
1099ae771770SStanislav Sedov {
1100ae771770SStanislav Sedov int one = 1;
1101ae771770SStanislav Sedov setsockopt(fd, 0, LOCAL_CREDS, (void *)&one, sizeof(one));
1102ae771770SStanislav Sedov }
1103ae771770SStanislav Sedov #endif
1104ae771770SStanislav Sedov
1105ae771770SStanislav Sedov unlink(un.sun_path);
1106ae771770SStanislav Sedov
1107ae771770SStanislav Sedov if (bind(fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
1108ae771770SStanislav Sedov close(fd);
1109ae771770SStanislav Sedov return errno;
1110ae771770SStanislav Sedov }
1111ae771770SStanislav Sedov
1112ae771770SStanislav Sedov if (listen(fd, SOMAXCONN) < 0) {
1113ae771770SStanislav Sedov close(fd);
1114ae771770SStanislav Sedov return errno;
1115ae771770SStanislav Sedov }
1116ae771770SStanislav Sedov
1117ae771770SStanislav Sedov chmod(un.sun_path, 0666);
1118ae771770SStanislav Sedov
1119ae771770SStanislav Sedov ret = heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC,
1120ae771770SStanislav Sedov callback, user, ctx);
1121ae771770SStanislav Sedov if (ret == 0) {
1122ae771770SStanislav Sedov struct client *c = (*ctx)->mech;
1123ae771770SStanislav Sedov c->flags |= UNIX_SOCKET;
1124ae771770SStanislav Sedov }
1125ae771770SStanislav Sedov
1126ae771770SStanislav Sedov return ret;
1127ae771770SStanislav Sedov }
1128ae771770SStanislav Sedov
1129ae771770SStanislav Sedov /**
1130ae771770SStanislav Sedov * Set the idle timeout value
1131ae771770SStanislav Sedov
1132ae771770SStanislav Sedov * The timeout event handler is triggered recurrently every idle
1133ae771770SStanislav Sedov * period `t'. The default action is rather draconian and just calls
1134ae771770SStanislav Sedov * exit(0), so you might want to change this to something more
1135ae771770SStanislav Sedov * graceful using heim_sipc_set_timeout_handler().
1136ae771770SStanislav Sedov */
1137ae771770SStanislav Sedov
1138ae771770SStanislav Sedov void
heim_sipc_timeout(time_t t)1139ae771770SStanislav Sedov heim_sipc_timeout(time_t t)
1140ae771770SStanislav Sedov {
1141ae771770SStanislav Sedov #ifdef HAVE_GCD
1142ae771770SStanislav Sedov static dispatch_once_t timeoutonce;
1143ae771770SStanislav Sedov init_globals();
1144ae771770SStanislav Sedov dispatch_sync(timerq, ^{
1145ae771770SStanislav Sedov timeoutvalue = t;
1146ae771770SStanislav Sedov set_timer();
1147ae771770SStanislav Sedov });
1148ae771770SStanislav Sedov dispatch_once(&timeoutonce, ^{ dispatch_resume(timer); });
1149ae771770SStanislav Sedov #else
1150ae771770SStanislav Sedov abort();
1151ae771770SStanislav Sedov #endif
1152ae771770SStanislav Sedov }
1153ae771770SStanislav Sedov
1154ae771770SStanislav Sedov /**
1155ae771770SStanislav Sedov * Set the timeout event handler
1156ae771770SStanislav Sedov *
1157ae771770SStanislav Sedov * Replaces the default idle timeout action.
1158ae771770SStanislav Sedov */
1159ae771770SStanislav Sedov
1160ae771770SStanislav Sedov void
heim_sipc_set_timeout_handler(void (* func)(void))1161ae771770SStanislav Sedov heim_sipc_set_timeout_handler(void (*func)(void))
1162ae771770SStanislav Sedov {
1163ae771770SStanislav Sedov #ifdef HAVE_GCD
1164ae771770SStanislav Sedov init_globals();
1165ae771770SStanislav Sedov dispatch_sync(timerq, ^{ timer_ev = func; });
1166ae771770SStanislav Sedov #else
1167ae771770SStanislav Sedov abort();
1168ae771770SStanislav Sedov #endif
1169ae771770SStanislav Sedov }
1170ae771770SStanislav Sedov
1171ae771770SStanislav Sedov
1172ae771770SStanislav Sedov void
heim_sipc_free_context(heim_sipc ctx)1173ae771770SStanislav Sedov heim_sipc_free_context(heim_sipc ctx)
1174ae771770SStanislav Sedov {
1175ae771770SStanislav Sedov (ctx->release)(ctx);
1176ae771770SStanislav Sedov }
1177ae771770SStanislav Sedov
1178ae771770SStanislav Sedov void
heim_ipc_main(void)1179ae771770SStanislav Sedov heim_ipc_main(void)
1180ae771770SStanislav Sedov {
1181ae771770SStanislav Sedov #ifdef HAVE_GCD
1182ae771770SStanislav Sedov dispatch_main();
1183ae771770SStanislav Sedov #else
1184ae771770SStanislav Sedov process_loop();
1185ae771770SStanislav Sedov #endif
1186ae771770SStanislav Sedov }
1187ae771770SStanislav Sedov
1188