1 /* $NetBSD: server.c,v 1.1.1.2 2014/04/24 12:45:48 pettai Exp $ */
4 * Copyright (c) 2009 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the Institute nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 #define MAX_PACKET_SIZE (128 * 1024)
44 int (*release
)(heim_sipc ctx
);
45 heim_ipc_callback callback
;
50 #if defined(__APPLE__) && defined(HAVE_GCD)
52 #include "heim_ipcServer.h"
53 #include "heim_ipc_reply.h"
54 #include "heim_ipc_async.h"
56 static dispatch_source_t timer
;
57 static dispatch_queue_t timerq
;
58 static uint64_t timeoutvalue
;
60 static dispatch_queue_t eventq
;
62 static dispatch_queue_t workq
;
65 default_timer_ev(void)
70 static void (*timer_ev
)(void) = default_timer_ev
;
75 dispatch_source_set_timer(timer
,
76 dispatch_time(DISPATCH_TIME_NOW
,
77 timeoutvalue
* NSEC_PER_SEC
),
78 timeoutvalue
* NSEC_PER_SEC
, 1000000);
84 static dispatch_once_t once
;
85 dispatch_once(&once
, ^{
86 timerq
= dispatch_queue_create("hiem-sipc-timer-q", NULL
);
87 timer
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, timerq
);
88 dispatch_source_set_event_handler(timer
, ^{ timer_ev(); } );
90 workq
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
91 eventq
= dispatch_queue_create("heim-ipc.event-queue", NULL
);
98 dispatch_suspend(timer
);
104 dispatch_sync(timerq
, ^{ set_timer(); });
105 dispatch_resume(timer
);
108 struct mach_service
{
110 dispatch_source_t source
;
111 dispatch_queue_t queue
;
114 struct mach_call_ctx
{
115 mach_port_t reply_port
;
122 mach_complete_sync(heim_sipc_call ctx
, int returnvalue
, heim_idata
*reply
)
124 struct mach_call_ctx
*s
= (struct mach_call_ctx
*)ctx
;
125 heim_ipc_message_inband_t replyin
;
126 mach_msg_type_number_t replyinCnt
;
127 heim_ipc_message_outband_t replyout
;
128 mach_msg_type_number_t replyoutCnt
;
132 /* on error, no reply */
134 replyout
= 0; replyoutCnt
= 0;
136 } else if (reply
->length
< 2048) {
137 replyinCnt
= reply
->length
;
138 memcpy(replyin
, reply
->data
, replyinCnt
);
139 replyout
= 0; replyoutCnt
= 0;
143 kr
= vm_read(mach_task_self(),
144 (vm_address_t
)reply
->data
, reply
->length
,
145 (vm_address_t
*)&replyout
, &replyoutCnt
);
148 mheim_ripc_call_reply(s
->reply_port
, returnvalue
,
150 replyout
, replyoutCnt
);
152 heim_ipc_free_cred(s
->cred
);
159 mach_complete_async(heim_sipc_call ctx
, int returnvalue
, heim_idata
*reply
)
161 struct mach_call_ctx
*s
= (struct mach_call_ctx
*)ctx
;
162 heim_ipc_message_inband_t replyin
;
163 mach_msg_type_number_t replyinCnt
;
164 heim_ipc_message_outband_t replyout
;
165 mach_msg_type_number_t replyoutCnt
;
169 /* on error, no reply */
171 replyout
= 0; replyoutCnt
= 0;
173 } else if (reply
->length
< 2048) {
174 replyinCnt
= reply
->length
;
175 memcpy(replyin
, reply
->data
, replyinCnt
);
176 replyout
= 0; replyoutCnt
= 0;
180 kr
= vm_read(mach_task_self(),
181 (vm_address_t
)reply
->data
, reply
->length
,
182 (vm_address_t
*)&replyout
, &replyoutCnt
);
185 kr
= mheim_aipc_acall_reply(s
->reply_port
, returnvalue
,
187 replyout
, replyoutCnt
);
188 heim_ipc_free_cred(s
->cred
);
196 mheim_do_call(mach_port_t server_port
,
197 audit_token_t client_creds
,
198 mach_port_t reply_port
,
199 heim_ipc_message_inband_t requestin
,
200 mach_msg_type_number_t requestinCnt
,
201 heim_ipc_message_outband_t requestout
,
202 mach_msg_type_number_t requestoutCnt
,
204 heim_ipc_message_inband_t replyin
,
205 mach_msg_type_number_t
*replyinCnt
,
206 heim_ipc_message_outband_t
*replyout
,
207 mach_msg_type_number_t
*replyoutCnt
)
209 heim_sipc ctx
= dispatch_get_context(dispatch_get_current_queue());
210 struct mach_call_ctx
*s
;
221 s
= malloc(sizeof(*s
));
223 return KERN_MEMORY_FAILURE
; /* XXX */
225 s
->reply_port
= reply_port
;
227 audit_token_to_au32(client_creds
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, &session
, NULL
);
229 kr
= _heim_ipc_create_cred(uid
, gid
, pid
, session
, &s
->cred
);
238 s
->req
.data
= malloc(requestinCnt
);
239 memcpy(s
->req
.data
, requestin
, requestinCnt
);
240 s
->req
.length
= requestinCnt
;
242 s
->req
.data
= malloc(requestoutCnt
);
243 memcpy(s
->req
.data
, requestout
, requestoutCnt
);
244 s
->req
.length
= requestoutCnt
;
247 dispatch_async(workq
, ^{
248 (ctx
->callback
)(ctx
->userctx
, &s
->req
, s
->cred
,
249 mach_complete_sync
, (heim_sipc_call
)s
);
256 mheim_do_call_request(mach_port_t server_port
,
257 audit_token_t client_creds
,
258 mach_port_t reply_port
,
259 heim_ipc_message_inband_t requestin
,
260 mach_msg_type_number_t requestinCnt
,
261 heim_ipc_message_outband_t requestout
,
262 mach_msg_type_number_t requestoutCnt
)
264 heim_sipc ctx
= dispatch_get_context(dispatch_get_current_queue());
265 struct mach_call_ctx
*s
;
272 s
= malloc(sizeof(*s
));
274 return KERN_MEMORY_FAILURE
; /* XXX */
276 s
->reply_port
= reply_port
;
278 audit_token_to_au32(client_creds
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, &session
, NULL
);
280 kr
= _heim_ipc_create_cred(uid
, gid
, pid
, session
, &s
->cred
);
289 s
->req
.data
= malloc(requestinCnt
);
290 memcpy(s
->req
.data
, requestin
, requestinCnt
);
291 s
->req
.length
= requestinCnt
;
293 s
->req
.data
= malloc(requestoutCnt
);
294 memcpy(s
->req
.data
, requestout
, requestoutCnt
);
295 s
->req
.length
= requestoutCnt
;
298 dispatch_async(workq
, ^{
299 (ctx
->callback
)(ctx
->userctx
, &s
->req
, s
->cred
,
300 mach_complete_async
, (heim_sipc_call
)s
);
307 mach_init(const char *service
, mach_port_t sport
, heim_sipc ctx
)
309 struct mach_service
*s
;
314 s
= calloc(1, sizeof(*s
));
318 asprintf(&name
, "heim-ipc-mach-%s", service
);
320 s
->queue
= dispatch_queue_create(name
, NULL
);
324 s
->source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV
,
325 s
->sport
, 0, s
->queue
);
326 if (s
->source
== NULL
) {
327 dispatch_release(s
->queue
);
333 dispatch_set_context(s
->queue
, ctx
);
334 dispatch_set_context(s
->source
, s
);
336 dispatch_source_set_event_handler(s
->source
, ^{
337 dispatch_mig_server(s
->source
, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem
), mheim_ipc_server
);
340 dispatch_source_set_cancel_handler(s
->source
, ^{
341 heim_sipc ctx
= dispatch_get_context(dispatch_get_current_queue());
342 struct mach_service
*st
= ctx
->mech
;
343 mach_port_mod_refs(mach_task_self(), st
->sport
,
344 MACH_PORT_RIGHT_RECEIVE
, -1);
345 dispatch_release(st
->queue
);
346 dispatch_release(st
->source
);
351 dispatch_resume(s
->source
);
357 mach_release(heim_sipc ctx
)
359 struct mach_service
*s
= ctx
->mech
;
360 dispatch_source_cancel(s
->source
);
361 dispatch_release(s
->source
);
366 mach_checkin_or_register(const char *service
)
371 kr
= bootstrap_check_in(bootstrap_port
, service
, &mp
);
372 if (kr
== KERN_SUCCESS
)
375 #if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
376 /* Pre SnowLeopard version */
377 kr
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &mp
);
378 if (kr
!= KERN_SUCCESS
)
379 return MACH_PORT_NULL
;
381 kr
= mach_port_insert_right(mach_task_self(), mp
, mp
,
382 MACH_MSG_TYPE_MAKE_SEND
);
383 if (kr
!= KERN_SUCCESS
) {
384 mach_port_destroy(mach_task_self(), mp
);
385 return MACH_PORT_NULL
;
388 kr
= bootstrap_register(bootstrap_port
, rk_UNCONST(service
), mp
);
389 if (kr
!= KERN_SUCCESS
) {
390 mach_port_destroy(mach_task_self(), mp
);
391 return MACH_PORT_NULL
;
396 return MACH_PORT_NULL
;
401 #endif /* __APPLE__ && HAVE_GCD */
405 heim_sipc_launchd_mach_init(const char *service
,
406 heim_ipc_callback callback
,
407 void *user
, heim_sipc
*ctx
)
409 #if defined(__APPLE__) && defined(HAVE_GCD)
410 mach_port_t sport
= MACH_PORT_NULL
;
416 sport
= mach_checkin_or_register(service
);
417 if (sport
== MACH_PORT_NULL
) {
422 c
= calloc(1, sizeof(*c
));
427 c
->release
= mach_release
;
429 c
->callback
= callback
;
431 ret
= mach_init(service
, sport
, c
);
440 if (sport
!= MACH_PORT_NULL
)
441 mach_port_mod_refs(mach_task_self(), sport
,
442 MACH_PORT_RIGHT_RECEIVE
, -1);
444 #else /* !(__APPLE__ && HAVE_GCD) */
447 #endif /* __APPLE__ && HAVE_GCD */
452 heim_ipc_callback callback
;
455 #define LISTEN_SOCKET 1
456 #define WAITING_READ 2
457 #define WAITING_WRITE 4
458 #define WAITING_CLOSE 8
460 #define HTTP_REPLY 16
462 #define INHERIT_MASK 0xffff0000
463 #define INCLUDE_ERROR_CODE (1 << 16)
464 #define ALLOW_HTTP (1<<17)
465 #define UNIX_SOCKET (1<<18)
472 dispatch_source_t in
;
473 dispatch_source_t out
;
483 static unsigned num_clients
= 0;
484 static struct client
**clients
= NULL
;
487 static void handle_read(struct client
*);
488 static void handle_write(struct client
*);
489 static int maybe_close(struct client
*);
492 * Update peer credentials from socket.
494 * SCM_CREDS can only be updated the first time there is read data to
495 * read from the filedescriptor, so if we read do it before this
496 * point, the cred data might not be is not there yet.
500 update_client_creds(struct client
*c
)
502 #ifdef HAVE_GETPEERUCRED
507 if (getpeerucred(c
->fd
, &peercred
) != 0) {
508 c
->unixrights
.uid
= ucred_geteuid(peercred
);
509 c
->unixrights
.gid
= ucred_getegid(peercred
);
510 c
->unixrights
.pid
= 0;
511 ucred_free(peercred
);
516 #ifdef HAVE_GETPEEREID
517 /* FreeBSD, OpenBSD */
522 if (getpeereid(c
->fd
, &uid
, &gid
) == 0) {
523 c
->unixrights
.uid
= uid
;
524 c
->unixrights
.gid
= gid
;
525 c
->unixrights
.pid
= 0;
530 #if defined(SO_PEERCRED) && defined(__linux__)
534 socklen_t pclen
= sizeof(pc
);
536 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_PEERCRED
, (void *)&pc
, &pclen
) == 0) {
537 c
->unixrights
.uid
= pc
.uid
;
538 c
->unixrights
.gid
= pc
.gid
;
539 c
->unixrights
.pid
= pc
.pid
;
544 #if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
546 struct xucred peercred
;
547 socklen_t peercredlen
= sizeof(peercred
);
549 if (getsockopt(c
->fd
, LOCAL_PEERCRED
, 1,
550 (void *)&peercred
, &peercredlen
) == 0
551 && peercred
.cr_version
== XUCRED_VERSION
)
553 c
->unixrights
.uid
= peercred
.cr_uid
;
554 c
->unixrights
.gid
= peercred
.cr_gid
;
555 c
->unixrights
.pid
= 0;
560 #if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
562 if (c
->unixrights
.uid
== (uid_t
)-1) {
569 memset(&msg
, 0, sizeof(msg
));
570 crmsgsize
= CMSG_SPACE(SOCKCREDSIZE(NGROUPS
));
574 crmsg
= malloc(crmsgsize
);
576 goto failed_scm_creds
;
578 memset(crmsg
, 0, crmsgsize
);
580 msg
.msg_control
= crmsg
;
581 msg
.msg_controllen
= crmsgsize
;
583 if (recvmsg(c
->fd
, &msg
, 0) < 0) {
585 goto failed_scm_creds
;
588 if (msg
.msg_controllen
== 0 || (msg
.msg_flags
& MSG_CTRUNC
) != 0) {
590 goto failed_scm_creds
;
593 cmp
= CMSG_FIRSTHDR(&msg
);
594 if (cmp
->cmsg_level
!= SOL_SOCKET
|| cmp
->cmsg_type
!= SCM_CREDS
) {
596 goto failed_scm_creds
;
599 sc
= (struct sockcred
*)(void *)CMSG_DATA(cmp
);
601 c
->unixrights
.uid
= sc
->sc_euid
;
602 c
->unixrights
.gid
= sc
->sc_egid
;
603 c
->unixrights
.pid
= 0;
608 /* we already got the cred, just return it */
617 static struct client
*
618 add_new_socket(int fd
,
620 heim_ipc_callback callback
,
626 c
= calloc(1, sizeof(*c
));
630 if (flags
& LISTEN_SOCKET
) {
633 c
->fd
= accept(fd
, NULL
, NULL
);
641 c
->callback
= callback
;
642 c
->userctx
= userctx
;
644 fileflags
= fcntl(c
->fd
, F_GETFL
, 0);
645 fcntl(c
->fd
, F_SETFL
, fileflags
| O_NONBLOCK
);
650 c
->in
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
,
652 c
->out
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
,
655 dispatch_source_set_event_handler(c
->in
, ^{
656 int rw
= (c
->flags
& WAITING_WRITE
);
658 if (rw
== 0 && (c
->flags
& WAITING_WRITE
))
659 dispatch_resume(c
->out
);
660 if ((c
->flags
& WAITING_READ
) == 0)
661 dispatch_suspend(c
->in
);
664 dispatch_source_set_event_handler(c
->out
, ^{
666 if ((c
->flags
& WAITING_WRITE
) == 0) {
667 dispatch_suspend(c
->out
);
672 dispatch_resume(c
->in
);
674 clients
= erealloc(clients
, sizeof(clients
[0]) * (num_clients
+ 1));
675 clients
[num_clients
] = c
;
683 maybe_close(struct client
*c
)
687 if (c
->flags
& (WAITING_READ
|WAITING_WRITE
))
691 dispatch_source_cancel(c
->in
);
692 if ((c
->flags
& WAITING_READ
) == 0)
693 dispatch_resume(c
->in
);
694 dispatch_release(c
->in
);
696 dispatch_source_cancel(c
->out
);
697 if ((c
->flags
& WAITING_WRITE
) == 0)
698 dispatch_resume(c
->out
);
699 dispatch_release(c
->out
);
701 close(c
->fd
); /* ref count fd close */
714 output_data(struct client
*c
, const void *data
, size_t len
)
716 if (c
->olen
+ len
< c
->olen
)
718 c
->outmsg
= erealloc(c
->outmsg
, c
->olen
+ len
);
719 memcpy(&c
->outmsg
[c
->olen
], data
, len
);
721 c
->flags
|= WAITING_WRITE
;
725 socket_complete(heim_sipc_call ctx
, int returnvalue
, heim_idata
*reply
)
727 struct socket_call
*sc
= (struct socket_call
*)ctx
;
728 struct client
*c
= sc
->c
;
730 /* double complete ? */
734 if ((c
->flags
& WAITING_CLOSE
) == 0) {
738 u32
= htonl(reply
->length
);
739 output_data(c
, &u32
, sizeof(u32
));
742 if (c
->flags
& INCLUDE_ERROR_CODE
) {
743 u32
= htonl(returnvalue
);
744 output_data(c
, &u32
, sizeof(u32
));
748 output_data(c
, reply
->data
, reply
->length
);
750 /* if HTTP, close connection */
751 if (c
->flags
& HTTP_REPLY
) {
752 c
->flags
|= WAITING_CLOSE
;
753 c
->flags
&= ~WAITING_READ
;
759 heim_ipc_free_cred(sc
->cred
);
761 sc
->c
= NULL
; /* so we can catch double complete */
767 /* remove HTTP %-quoting from buf */
771 unsigned char *p
, *q
;
772 for(p
= q
= (unsigned char *)buf
; *p
; p
++, q
++) {
773 if(*p
== '%' && isxdigit(p
[1]) && isxdigit(p
[2])) {
775 if(sscanf((char *)p
+ 1, "%2x", &x
) != 1)
786 static struct socket_call
*
787 handle_http_tcp(struct client
*c
)
789 struct socket_call
*cs
;
795 s
= (char *)c
->inmsg
;
797 p
= strstr(s
, "\r\n");
804 t
= strtok_r(s
, " \t", &p
);
808 t
= strtok_r(NULL
, " \t", &p
);
812 data
= malloc(strlen(t
));
818 if(de_http(t
) != 0) {
822 proto
= strtok_r(NULL
, " \t", &p
);
827 len
= base64_decode(t
, data
);
831 "Server: Heimdal/" VERSION
"\r\n"
832 "Cache-Control: no-cache\r\n"
833 "Pragma: no-cache\r\n"
834 "Content-type: text/html\r\n"
835 "Content-transfer-encoding: 8bit\r\n\r\n"
836 "<TITLE>404 Not found</TITLE>\r\n"
837 "<H1>404 Not found</H1>\r\n"
838 "That page doesn't exist, maybe you are looking for "
839 "<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n";
841 output_data(c
, proto
, strlen(proto
));
842 output_data(c
, msg
, strlen(msg
));
846 cs
= emalloc(sizeof(*cs
));
855 "Server: Heimdal/" VERSION
"\r\n"
856 "Cache-Control: no-cache\r\n"
857 "Pragma: no-cache\r\n"
858 "Content-type: application/octet-stream\r\n"
859 "Content-transfer-encoding: binary\r\n\r\n";
860 output_data(c
, proto
, strlen(proto
));
861 output_data(c
, msg
, strlen(msg
));
869 handle_read(struct client
*c
)
874 if (c
->flags
& LISTEN_SOCKET
) {
875 add_new_socket(c
->fd
,
876 WAITING_READ
| (c
->flags
& INHERIT_MASK
),
882 if (c
->ptr
- c
->len
< 1024) {
883 c
->inmsg
= erealloc(c
->inmsg
,
888 len
= read(c
->fd
, c
->inmsg
+ c
->ptr
, c
->len
- c
->ptr
);
890 c
->flags
|= WAITING_CLOSE
;
891 c
->flags
&= ~WAITING_READ
;
898 while (c
->ptr
>= sizeof(dlen
)) {
899 struct socket_call
*cs
;
901 if((c
->flags
& ALLOW_HTTP
) && c
->ptr
>= 4 &&
902 strncmp((char *)c
->inmsg
, "GET ", 4) == 0 &&
903 strncmp((char *)c
->inmsg
+ c
->ptr
- 4, "\r\n\r\n", 4) == 0) {
905 /* remove the trailing \r\n\r\n so the string is NUL terminated */
906 c
->inmsg
[c
->ptr
- 4] = '\0';
908 c
->flags
|= HTTP_REPLY
;
910 cs
= handle_http_tcp(c
);
912 c
->flags
|= WAITING_CLOSE
;
913 c
->flags
&= ~WAITING_READ
;
917 memcpy(&dlen
, c
->inmsg
, sizeof(dlen
));
920 if (dlen
> MAX_PACKET_SIZE
) {
921 c
->flags
|= WAITING_CLOSE
;
922 c
->flags
&= ~WAITING_READ
;
925 if (dlen
> c
->ptr
- sizeof(dlen
)) {
929 cs
= emalloc(sizeof(*cs
));
931 cs
->in
.data
= emalloc(dlen
);
932 memcpy(cs
->in
.data
, c
->inmsg
+ sizeof(dlen
), dlen
);
933 cs
->in
.length
= dlen
;
935 c
->ptr
-= sizeof(dlen
) + dlen
;
937 c
->inmsg
+ sizeof(dlen
) + dlen
,
943 if ((c
->flags
& UNIX_SOCKET
) != 0) {
944 if (update_client_creds(c
))
945 _heim_ipc_create_cred(c
->unixrights
.uid
, c
->unixrights
.gid
,
946 c
->unixrights
.pid
, -1, &cs
->cred
);
949 c
->callback(c
->userctx
, &cs
->in
,
950 cs
->cred
, socket_complete
,
956 handle_write(struct client
*c
)
960 len
= write(c
->fd
, c
->outmsg
, c
->olen
);
962 c
->flags
|= WAITING_CLOSE
;
963 c
->flags
&= ~(WAITING_WRITE
);
964 } else if (c
->olen
!= (size_t)len
) {
965 memmove(&c
->outmsg
[0], &c
->outmsg
[len
], c
->olen
- len
);
971 c
->flags
&= ~(WAITING_WRITE
);
985 while(num_clients
> 0) {
987 fds
= malloc(num_clients
* sizeof(fds
[0]));
991 num_fds
= num_clients
;
993 for (n
= 0 ; n
< num_fds
; n
++) {
994 fds
[n
].fd
= clients
[n
]->fd
;
996 if (clients
[n
]->flags
& WAITING_READ
)
997 fds
[n
].events
|= POLLIN
;
998 if (clients
[n
]->flags
& WAITING_WRITE
)
999 fds
[n
].events
|= POLLOUT
;
1004 poll(fds
, num_fds
, -1);
1006 for (n
= 0 ; n
< num_fds
; n
++) {
1007 if (clients
[n
] == NULL
)
1009 if (fds
[n
].revents
& POLLERR
) {
1010 clients
[n
]->flags
|= WAITING_CLOSE
;
1014 if (fds
[n
].revents
& POLLIN
)
1015 handle_read(clients
[n
]);
1016 if (fds
[n
].revents
& POLLOUT
)
1017 handle_write(clients
[n
]);
1021 while (n
< num_clients
) {
1022 struct client
*c
= clients
[n
];
1023 if (maybe_close(c
)) {
1024 if (n
< num_clients
- 1)
1025 clients
[n
] = clients
[num_clients
- 1];
1038 socket_release(heim_sipc ctx
)
1040 struct client
*c
= ctx
->mech
;
1041 c
->flags
|= WAITING_CLOSE
;
1046 heim_sipc_stream_listener(int fd
, int type
,
1047 heim_ipc_callback callback
,
1048 void *user
, heim_sipc
*ctx
)
1050 heim_sipc ct
= calloc(1, sizeof(*ct
));
1053 if ((type
& HEIM_SIPC_TYPE_IPC
) && (type
& (HEIM_SIPC_TYPE_UINT32
|HEIM_SIPC_TYPE_HTTP
)))
1057 case HEIM_SIPC_TYPE_IPC
:
1058 c
= add_new_socket(fd
, LISTEN_SOCKET
|WAITING_READ
|INCLUDE_ERROR_CODE
, callback
, user
);
1060 case HEIM_SIPC_TYPE_UINT32
:
1061 c
= add_new_socket(fd
, LISTEN_SOCKET
|WAITING_READ
, callback
, user
);
1063 case HEIM_SIPC_TYPE_HTTP
:
1064 case HEIM_SIPC_TYPE_UINT32
|HEIM_SIPC_TYPE_HTTP
:
1065 c
= add_new_socket(fd
, LISTEN_SOCKET
|WAITING_READ
|ALLOW_HTTP
, callback
, user
);
1073 ct
->release
= socket_release
;
1075 c
->unixrights
.uid
= (uid_t
) -1;
1076 c
->unixrights
.gid
= (gid_t
) -1;
1077 c
->unixrights
.pid
= (pid_t
) 0;
1084 heim_sipc_service_unix(const char *service
,
1085 heim_ipc_callback callback
,
1086 void *user
, heim_sipc
*ctx
)
1088 struct sockaddr_un un
;
1091 un
.sun_family
= AF_UNIX
;
1093 snprintf(un
.sun_path
, sizeof(un
.sun_path
),
1094 "/var/run/.heim_%s-socket", service
);
1095 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1099 socket_set_reuseaddr(fd
, 1);
1103 setsockopt(fd
, 0, LOCAL_CREDS
, (void *)&one
, sizeof(one
));
1107 unlink(un
.sun_path
);
1109 if (bind(fd
, (struct sockaddr
*)&un
, sizeof(un
)) < 0) {
1114 if (listen(fd
, SOMAXCONN
) < 0) {
1119 chmod(un
.sun_path
, 0666);
1121 ret
= heim_sipc_stream_listener(fd
, HEIM_SIPC_TYPE_IPC
,
1122 callback
, user
, ctx
);
1124 struct client
*c
= (*ctx
)->mech
;
1125 c
->flags
|= UNIX_SOCKET
;
1132 * Set the idle timeout value
1134 * The timeout event handler is triggered recurrently every idle
1135 * period `t'. The default action is rather draconian and just calls
1136 * exit(0), so you might want to change this to something more
1137 * graceful using heim_sipc_set_timeout_handler().
1141 heim_sipc_timeout(time_t t
)
1144 static dispatch_once_t timeoutonce
;
1146 dispatch_sync(timerq
, ^{
1150 dispatch_once(&timeoutonce
, ^{ dispatch_resume(timer
); });
1157 * Set the timeout event handler
1159 * Replaces the default idle timeout action.
1163 heim_sipc_set_timeout_handler(void (*func
)(void))
1167 dispatch_sync(timerq
, ^{ timer_ev
= func
; });
1175 heim_sipc_free_context(heim_sipc ctx
)
1177 (ctx
->release
)(ctx
);