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