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