2 * Copyright (c) 2009 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #define MAX_PACKET_SIZE (128 * 1024)
42 int (*release
)(heim_sipc ctx
);
43 heim_ipc_callback callback
;
48 #if defined(__APPLE__) && defined(HAVE_GCD)
50 #include "heim_ipcServer.h"
51 #include "heim_ipc_reply.h"
52 #include "heim_ipc_async.h"
54 static dispatch_source_t timer
;
55 static dispatch_queue_t timerq
;
56 static uint64_t timeoutvalue
;
58 static dispatch_queue_t eventq
;
60 static dispatch_queue_t workq
;
63 default_timer_ev(void)
68 static void (*timer_ev
)(void) = default_timer_ev
;
73 dispatch_source_set_timer(timer
,
74 dispatch_time(DISPATCH_TIME_NOW
,
75 timeoutvalue
* NSEC_PER_SEC
),
76 timeoutvalue
* NSEC_PER_SEC
, 1000000);
82 static dispatch_once_t once
;
83 dispatch_once(&once
, ^{
84 timerq
= dispatch_queue_create("hiem-sipc-timer-q", NULL
);
85 timer
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, timerq
);
86 dispatch_source_set_event_handler(timer
, ^{ timer_ev(); } );
88 workq
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
89 eventq
= dispatch_queue_create("heim-ipc.event-queue", NULL
);
96 dispatch_suspend(timer
);
102 dispatch_sync(timerq
, ^{ set_timer(); });
103 dispatch_resume(timer
);
106 struct mach_service
{
108 dispatch_source_t source
;
109 dispatch_queue_t queue
;
112 struct mach_call_ctx
{
113 mach_port_t reply_port
;
120 mach_complete_sync(heim_sipc_call ctx
, int returnvalue
, heim_idata
*reply
)
122 struct mach_call_ctx
*s
= (struct mach_call_ctx
*)ctx
;
123 heim_ipc_message_inband_t replyin
;
124 mach_msg_type_number_t replyinCnt
;
125 heim_ipc_message_outband_t replyout
;
126 mach_msg_type_number_t replyoutCnt
;
130 /* on error, no reply */
132 replyout
= 0; replyoutCnt
= 0;
134 } else if (reply
->length
< 2048) {
135 replyinCnt
= reply
->length
;
136 memcpy(replyin
, reply
->data
, replyinCnt
);
137 replyout
= 0; replyoutCnt
= 0;
141 kr
= vm_read(mach_task_self(),
142 (vm_address_t
)reply
->data
, reply
->length
,
143 (vm_address_t
*)&replyout
, &replyoutCnt
);
146 mheim_ripc_call_reply(s
->reply_port
, returnvalue
,
148 replyout
, replyoutCnt
);
150 heim_ipc_free_cred(s
->cred
);
157 mach_complete_async(heim_sipc_call ctx
, int returnvalue
, heim_idata
*reply
)
159 struct mach_call_ctx
*s
= (struct mach_call_ctx
*)ctx
;
160 heim_ipc_message_inband_t replyin
;
161 mach_msg_type_number_t replyinCnt
;
162 heim_ipc_message_outband_t replyout
;
163 mach_msg_type_number_t replyoutCnt
;
167 /* on error, no reply */
169 replyout
= 0; replyoutCnt
= 0;
171 } else if (reply
->length
< 2048) {
172 replyinCnt
= reply
->length
;
173 memcpy(replyin
, reply
->data
, replyinCnt
);
174 replyout
= 0; replyoutCnt
= 0;
178 kr
= vm_read(mach_task_self(),
179 (vm_address_t
)reply
->data
, reply
->length
,
180 (vm_address_t
*)&replyout
, &replyoutCnt
);
183 kr
= mheim_aipc_acall_reply(s
->reply_port
, returnvalue
,
185 replyout
, replyoutCnt
);
186 heim_ipc_free_cred(s
->cred
);
194 mheim_do_call(mach_port_t server_port
,
195 audit_token_t client_creds
,
196 mach_port_t reply_port
,
197 heim_ipc_message_inband_t requestin
,
198 mach_msg_type_number_t requestinCnt
,
199 heim_ipc_message_outband_t requestout
,
200 mach_msg_type_number_t requestoutCnt
,
202 heim_ipc_message_inband_t replyin
,
203 mach_msg_type_number_t
*replyinCnt
,
204 heim_ipc_message_outband_t
*replyout
,
205 mach_msg_type_number_t
*replyoutCnt
)
207 heim_sipc ctx
= dispatch_get_context(dispatch_get_current_queue());
208 struct mach_call_ctx
*s
;
219 s
= malloc(sizeof(*s
));
221 return KERN_MEMORY_FAILURE
; /* XXX */
223 s
->reply_port
= reply_port
;
225 audit_token_to_au32(client_creds
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, &session
, NULL
);
227 kr
= _heim_ipc_create_cred(uid
, gid
, pid
, session
, &s
->cred
);
236 s
->req
.data
= malloc(requestinCnt
);
237 memcpy(s
->req
.data
, requestin
, requestinCnt
);
238 s
->req
.length
= requestinCnt
;
240 s
->req
.data
= malloc(requestoutCnt
);
241 memcpy(s
->req
.data
, requestout
, requestoutCnt
);
242 s
->req
.length
= requestoutCnt
;
245 dispatch_async(workq
, ^{
246 (ctx
->callback
)(ctx
->userctx
, &s
->req
, s
->cred
,
247 mach_complete_sync
, (heim_sipc_call
)s
);
254 mheim_do_call_request(mach_port_t server_port
,
255 audit_token_t client_creds
,
256 mach_port_t reply_port
,
257 heim_ipc_message_inband_t requestin
,
258 mach_msg_type_number_t requestinCnt
,
259 heim_ipc_message_outband_t requestout
,
260 mach_msg_type_number_t requestoutCnt
)
262 heim_sipc ctx
= dispatch_get_context(dispatch_get_current_queue());
263 struct mach_call_ctx
*s
;
270 s
= malloc(sizeof(*s
));
272 return KERN_MEMORY_FAILURE
; /* XXX */
274 s
->reply_port
= reply_port
;
276 audit_token_to_au32(client_creds
, NULL
, &uid
, &gid
, NULL
, NULL
, &pid
, &session
, NULL
);
278 kr
= _heim_ipc_create_cred(uid
, gid
, pid
, session
, &s
->cred
);
287 s
->req
.data
= malloc(requestinCnt
);
288 memcpy(s
->req
.data
, requestin
, requestinCnt
);
289 s
->req
.length
= requestinCnt
;
291 s
->req
.data
= malloc(requestoutCnt
);
292 memcpy(s
->req
.data
, requestout
, requestoutCnt
);
293 s
->req
.length
= requestoutCnt
;
296 dispatch_async(workq
, ^{
297 (ctx
->callback
)(ctx
->userctx
, &s
->req
, s
->cred
,
298 mach_complete_async
, (heim_sipc_call
)s
);
305 mach_init(const char *service
, mach_port_t sport
, heim_sipc ctx
)
307 struct mach_service
*s
;
312 s
= calloc(1, sizeof(*s
));
316 asprintf(&name
, "heim-ipc-mach-%s", service
);
318 s
->queue
= dispatch_queue_create(name
, NULL
);
322 s
->source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV
,
323 s
->sport
, 0, s
->queue
);
324 if (s
->source
== NULL
) {
325 dispatch_release(s
->queue
);
331 dispatch_set_context(s
->queue
, ctx
);
332 dispatch_set_context(s
->source
, s
);
334 dispatch_source_set_event_handler(s
->source
, ^{
335 dispatch_mig_server(s
->source
, sizeof(union __RequestUnion__mheim_do_mheim_ipc_subsystem
), mheim_ipc_server
);
338 dispatch_source_set_cancel_handler(s
->source
, ^{
339 heim_sipc sctx
= dispatch_get_context(dispatch_get_current_queue());
340 struct mach_service
*st
= sctx
->mech
;
341 mach_port_mod_refs(mach_task_self(), st
->sport
,
342 MACH_PORT_RIGHT_RECEIVE
, -1);
343 dispatch_release(st
->queue
);
344 dispatch_release(st
->source
);
349 dispatch_resume(s
->source
);
355 mach_release(heim_sipc ctx
)
357 struct mach_service
*s
= ctx
->mech
;
358 dispatch_source_cancel(s
->source
);
359 dispatch_release(s
->source
);
364 mach_checkin_or_register(const char *service
)
369 kr
= bootstrap_check_in(bootstrap_port
, service
, &mp
);
370 if (kr
== KERN_SUCCESS
)
373 #if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
374 /* Pre SnowLeopard version */
375 kr
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &mp
);
376 if (kr
!= KERN_SUCCESS
)
377 return MACH_PORT_NULL
;
379 kr
= mach_port_insert_right(mach_task_self(), mp
, mp
,
380 MACH_MSG_TYPE_MAKE_SEND
);
381 if (kr
!= KERN_SUCCESS
) {
382 mach_port_destroy(mach_task_self(), mp
);
383 return MACH_PORT_NULL
;
386 kr
= bootstrap_register(bootstrap_port
, rk_UNCONST(service
), mp
);
387 if (kr
!= KERN_SUCCESS
) {
388 mach_port_destroy(mach_task_self(), mp
);
389 return MACH_PORT_NULL
;
394 return MACH_PORT_NULL
;
399 #endif /* __APPLE__ && HAVE_GCD */
403 heim_sipc_launchd_mach_init(const char *service
,
404 heim_ipc_callback callback
,
405 void *user
, heim_sipc
*ctx
)
407 #if defined(__APPLE__) && defined(HAVE_GCD)
408 mach_port_t sport
= MACH_PORT_NULL
;
414 sport
= mach_checkin_or_register(service
);
415 if (sport
== MACH_PORT_NULL
) {
420 c
= calloc(1, sizeof(*c
));
425 c
->release
= mach_release
;
427 c
->callback
= callback
;
429 ret
= mach_init(service
, sport
, c
);
438 if (sport
!= MACH_PORT_NULL
)
439 mach_port_mod_refs(mach_task_self(), sport
,
440 MACH_PORT_RIGHT_RECEIVE
, -1);
442 #else /* !(__APPLE__ && HAVE_GCD) */
445 #endif /* __APPLE__ && HAVE_GCD */
450 heim_ipc_callback callback
;
453 #define LISTEN_SOCKET 1
454 #define WAITING_READ 2
455 #define WAITING_WRITE 4
456 #define WAITING_CLOSE 8
458 #define HTTP_REPLY 16
460 #define INHERIT_MASK 0xffff0000
461 #define INCLUDE_ERROR_CODE (1 << 16)
462 #define ALLOW_HTTP (1<<17)
463 #define UNIX_SOCKET (1<<18)
470 dispatch_source_t in
;
471 dispatch_source_t out
;
481 static unsigned num_clients
= 0;
482 static struct client
**clients
= NULL
;
485 static void handle_read(struct client
*);
486 static void handle_write(struct client
*);
487 static int maybe_close(struct client
*);
490 * Update peer credentials from socket.
492 * SCM_CREDS can only be updated the first time there is read data to
493 * read from the filedescriptor, so if we read do it before this
494 * point, the cred data might not be is not there yet.
498 update_client_creds(struct client
*c
)
500 #ifdef HAVE_GETPEERUCRED
505 if (getpeerucred(c
->fd
, &peercred
) != 0) {
506 c
->unixrights
.uid
= ucred_geteuid(peercred
);
507 c
->unixrights
.gid
= ucred_getegid(peercred
);
508 c
->unixrights
.pid
= 0;
509 ucred_free(peercred
);
514 #ifdef HAVE_GETPEEREID
515 /* FreeBSD, OpenBSD */
520 if (getpeereid(c
->fd
, &uid
, &gid
) == 0) {
521 c
->unixrights
.uid
= uid
;
522 c
->unixrights
.gid
= gid
;
523 c
->unixrights
.pid
= 0;
528 #if defined(SO_PEERCRED) && defined(__linux__)
532 socklen_t pclen
= sizeof(pc
);
534 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_PEERCRED
, (void *)&pc
, &pclen
) == 0) {
535 c
->unixrights
.uid
= pc
.uid
;
536 c
->unixrights
.gid
= pc
.gid
;
537 c
->unixrights
.pid
= pc
.pid
;
542 #if defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
544 struct xucred peercred
;
545 socklen_t peercredlen
= sizeof(peercred
);
547 if (getsockopt(c
->fd
, LOCAL_PEERCRED
, 1,
548 (void *)&peercred
, &peercredlen
) == 0
549 && peercred
.cr_version
== XUCRED_VERSION
)
551 c
->unixrights
.uid
= peercred
.cr_uid
;
552 c
->unixrights
.gid
= peercred
.cr_gid
;
553 c
->unixrights
.pid
= 0;
558 #if defined(SOCKCREDSIZE) && defined(SCM_CREDS)
560 if (c
->unixrights
.uid
== (uid_t
)-1) {
567 memset(&msg
, 0, sizeof(msg
));
568 crmsgsize
= CMSG_SPACE(SOCKCREDSIZE(NGROUPS
));
572 crmsg
= malloc(crmsgsize
);
574 goto failed_scm_creds
;
576 memset(crmsg
, 0, crmsgsize
);
578 msg
.msg_control
= crmsg
;
579 msg
.msg_controllen
= crmsgsize
;
581 if (recvmsg(c
->fd
, &msg
, 0) < 0) {
583 goto failed_scm_creds
;
586 if (msg
.msg_controllen
== 0 || (msg
.msg_flags
& MSG_CTRUNC
) != 0) {
588 goto failed_scm_creds
;
591 cmp
= CMSG_FIRSTHDR(&msg
);
592 if (cmp
->cmsg_level
!= SOL_SOCKET
|| cmp
->cmsg_type
!= SCM_CREDS
) {
594 goto failed_scm_creds
;
597 sc
= (struct sockcred
*)(void *)CMSG_DATA(cmp
);
599 c
->unixrights
.uid
= sc
->sc_euid
;
600 c
->unixrights
.gid
= sc
->sc_egid
;
601 c
->unixrights
.pid
= 0;
606 /* we already got the cred, just return it */
615 static struct client
*
616 add_new_socket(int fd
,
618 heim_ipc_callback callback
,
624 c
= calloc(1, sizeof(*c
));
628 if (flags
& LISTEN_SOCKET
) {
631 c
->fd
= accept(fd
, NULL
, NULL
);
639 c
->callback
= callback
;
640 c
->userctx
= userctx
;
642 fileflags
= fcntl(c
->fd
, F_GETFL
, 0);
643 fcntl(c
->fd
, F_SETFL
, fileflags
| O_NONBLOCK
);
648 c
->in
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
,
650 c
->out
= dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE
,
653 dispatch_source_set_event_handler(c
->in
, ^{
654 int rw
= (c
->flags
& WAITING_WRITE
);
656 if (rw
== 0 && (c
->flags
& WAITING_WRITE
))
657 dispatch_resume(c
->out
);
658 if ((c
->flags
& WAITING_READ
) == 0)
659 dispatch_suspend(c
->in
);
662 dispatch_source_set_event_handler(c
->out
, ^{
664 if ((c
->flags
& WAITING_WRITE
) == 0) {
665 dispatch_suspend(c
->out
);
670 dispatch_resume(c
->in
);
672 clients
= erealloc(clients
, sizeof(clients
[0]) * (num_clients
+ 1));
673 clients
[num_clients
] = c
;
681 maybe_close(struct client
*c
)
685 if (c
->flags
& (WAITING_READ
|WAITING_WRITE
))
689 dispatch_source_cancel(c
->in
);
690 if ((c
->flags
& WAITING_READ
) == 0)
691 dispatch_resume(c
->in
);
692 dispatch_release(c
->in
);
694 dispatch_source_cancel(c
->out
);
695 if ((c
->flags
& WAITING_WRITE
) == 0)
696 dispatch_resume(c
->out
);
697 dispatch_release(c
->out
);
699 close(c
->fd
); /* ref count fd close */
712 output_data(struct client
*c
, const void *data
, size_t len
)
714 if (c
->olen
+ len
< c
->olen
)
716 c
->outmsg
= erealloc(c
->outmsg
, c
->olen
+ len
);
717 memcpy(&c
->outmsg
[c
->olen
], data
, len
);
719 c
->flags
|= WAITING_WRITE
;
723 socket_complete(heim_sipc_call ctx
, int returnvalue
, heim_idata
*reply
)
725 struct socket_call
*sc
= (struct socket_call
*)ctx
;
726 struct client
*c
= sc
->c
;
728 /* double complete ? */
732 if ((c
->flags
& WAITING_CLOSE
) == 0) {
736 u32
= htonl(reply
->length
);
737 output_data(c
, &u32
, sizeof(u32
));
740 if (c
->flags
& INCLUDE_ERROR_CODE
) {
741 u32
= htonl(returnvalue
);
742 output_data(c
, &u32
, sizeof(u32
));
746 output_data(c
, reply
->data
, reply
->length
);
748 /* if HTTP, close connection */
749 if (c
->flags
& HTTP_REPLY
) {
750 c
->flags
|= WAITING_CLOSE
;
751 c
->flags
&= ~WAITING_READ
;
757 heim_ipc_free_cred(sc
->cred
);
759 sc
->c
= NULL
; /* so we can catch double complete */
765 /* remove HTTP %-quoting from buf */
769 unsigned char *p
, *q
;
770 for(p
= q
= (unsigned char *)buf
; *p
; p
++, q
++) {
771 if(*p
== '%' && isxdigit(p
[1]) && isxdigit(p
[2])) {
773 if(sscanf((char *)p
+ 1, "%2x", &x
) != 1)
784 static struct socket_call
*
785 handle_http_tcp(struct client
*c
)
787 struct socket_call
*cs
;
793 s
= (char *)c
->inmsg
;
795 p
= strstr(s
, "\r\n");
802 t
= strtok_r(s
, " \t", &p
);
806 t
= strtok_r(NULL
, " \t", &p
);
810 data
= malloc(strlen(t
));
816 if(de_http(t
) != 0) {
820 proto
= strtok_r(NULL
, " \t", &p
);
825 len
= rk_base64_decode(t
, data
);
829 "Server: Heimdal/" VERSION
"\r\n"
830 "Cache-Control: no-cache\r\n"
831 "Pragma: no-cache\r\n"
832 "Content-type: text/html\r\n"
833 "Content-transfer-encoding: 8bit\r\n\r\n"
834 "<TITLE>404 Not found</TITLE>\r\n"
835 "<H1>404 Not found</H1>\r\n"
836 "That page doesn't exist, maybe you are looking for "
837 "<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n";
839 output_data(c
, proto
, strlen(proto
));
840 output_data(c
, msg
, strlen(msg
));
844 cs
= emalloc(sizeof(*cs
));
853 "Server: Heimdal/" VERSION
"\r\n"
854 "Cache-Control: no-cache\r\n"
855 "Pragma: no-cache\r\n"
856 "Content-type: application/octet-stream\r\n"
857 "Content-transfer-encoding: binary\r\n\r\n";
858 output_data(c
, proto
, strlen(proto
));
859 output_data(c
, msg
, strlen(msg
));
867 handle_read(struct client
*c
)
872 if (c
->flags
& LISTEN_SOCKET
) {
873 add_new_socket(c
->fd
,
874 WAITING_READ
| (c
->flags
& INHERIT_MASK
),
880 if (c
->ptr
- c
->len
< 1024) {
881 c
->inmsg
= erealloc(c
->inmsg
,
886 len
= read(c
->fd
, c
->inmsg
+ c
->ptr
, c
->len
- c
->ptr
);
888 c
->flags
|= WAITING_CLOSE
;
889 c
->flags
&= ~WAITING_READ
;
896 while (c
->ptr
>= sizeof(dlen
)) {
897 struct socket_call
*cs
;
899 if((c
->flags
& ALLOW_HTTP
) && c
->ptr
>= 4 &&
900 strncmp((char *)c
->inmsg
, "GET ", 4) == 0 &&
901 strncmp((char *)c
->inmsg
+ c
->ptr
- 4, "\r\n\r\n", 4) == 0) {
903 /* remove the trailing \r\n\r\n so the string is NUL terminated */
904 c
->inmsg
[c
->ptr
- 4] = '\0';
906 c
->flags
|= HTTP_REPLY
;
908 cs
= handle_http_tcp(c
);
910 c
->flags
|= WAITING_CLOSE
;
911 c
->flags
&= ~WAITING_READ
;
915 memcpy(&dlen
, c
->inmsg
, sizeof(dlen
));
918 if (dlen
> MAX_PACKET_SIZE
) {
919 c
->flags
|= WAITING_CLOSE
;
920 c
->flags
&= ~WAITING_READ
;
923 if (dlen
> c
->ptr
- sizeof(dlen
)) {
927 cs
= emalloc(sizeof(*cs
));
929 cs
->in
.data
= emalloc(dlen
);
930 memcpy(cs
->in
.data
, c
->inmsg
+ sizeof(dlen
), dlen
);
931 cs
->in
.length
= dlen
;
933 c
->ptr
-= sizeof(dlen
) + dlen
;
935 c
->inmsg
+ sizeof(dlen
) + dlen
,
941 if ((c
->flags
& UNIX_SOCKET
) != 0) {
942 if (update_client_creds(c
))
943 _heim_ipc_create_cred(c
->unixrights
.uid
, c
->unixrights
.gid
,
944 c
->unixrights
.pid
, -1, &cs
->cred
);
947 c
->callback(c
->userctx
, &cs
->in
,
948 cs
->cred
, socket_complete
,
954 handle_write(struct client
*c
)
958 len
= write(c
->fd
, c
->outmsg
, c
->olen
);
960 c
->flags
|= WAITING_CLOSE
;
961 c
->flags
&= ~(WAITING_WRITE
);
962 } else if (c
->olen
!= (size_t)len
) {
963 memmove(&c
->outmsg
[0], &c
->outmsg
[len
], c
->olen
- len
);
969 c
->flags
&= ~(WAITING_WRITE
);
983 while(num_clients
> 0) {
985 fds
= malloc(num_clients
* sizeof(fds
[0]));
989 num_fds
= num_clients
;
991 for (n
= 0 ; n
< num_fds
; n
++) {
992 fds
[n
].fd
= clients
[n
]->fd
;
994 if (clients
[n
]->flags
& WAITING_READ
)
995 fds
[n
].events
|= POLLIN
;
996 if (clients
[n
]->flags
& WAITING_WRITE
)
997 fds
[n
].events
|= POLLOUT
;
1002 poll(fds
, num_fds
, -1);
1004 for (n
= 0 ; n
< num_fds
; n
++) {
1005 if (clients
[n
] == NULL
)
1007 if (fds
[n
].revents
& POLLERR
) {
1008 clients
[n
]->flags
|= WAITING_CLOSE
;
1012 if (fds
[n
].revents
& POLLIN
)
1013 handle_read(clients
[n
]);
1014 if (fds
[n
].revents
& POLLOUT
)
1015 handle_write(clients
[n
]);
1019 while (n
< num_clients
) {
1020 struct client
*c
= clients
[n
];
1021 if (maybe_close(c
)) {
1022 if (n
< num_clients
- 1)
1023 clients
[n
] = clients
[num_clients
- 1];
1036 socket_release(heim_sipc ctx
)
1038 struct client
*c
= ctx
->mech
;
1039 c
->flags
|= WAITING_CLOSE
;
1044 heim_sipc_stream_listener(int fd
, int type
,
1045 heim_ipc_callback callback
,
1046 void *user
, heim_sipc
*ctx
)
1048 heim_sipc ct
= calloc(1, sizeof(*ct
));
1051 if ((type
& HEIM_SIPC_TYPE_IPC
) && (type
& (HEIM_SIPC_TYPE_UINT32
|HEIM_SIPC_TYPE_HTTP
)))
1055 case HEIM_SIPC_TYPE_IPC
:
1056 c
= add_new_socket(fd
, LISTEN_SOCKET
|WAITING_READ
|INCLUDE_ERROR_CODE
, callback
, user
);
1058 case HEIM_SIPC_TYPE_UINT32
:
1059 c
= add_new_socket(fd
, LISTEN_SOCKET
|WAITING_READ
, callback
, user
);
1061 case HEIM_SIPC_TYPE_HTTP
:
1062 case HEIM_SIPC_TYPE_UINT32
|HEIM_SIPC_TYPE_HTTP
:
1063 c
= add_new_socket(fd
, LISTEN_SOCKET
|WAITING_READ
|ALLOW_HTTP
, callback
, user
);
1071 ct
->release
= socket_release
;
1073 c
->unixrights
.uid
= (uid_t
) -1;
1074 c
->unixrights
.gid
= (gid_t
) -1;
1075 c
->unixrights
.pid
= (pid_t
) 0;
1082 heim_sipc_service_unix(const char *service
,
1083 heim_ipc_callback callback
,
1084 void *user
, heim_sipc
*ctx
)
1086 struct sockaddr_un un
;
1089 un
.sun_family
= AF_UNIX
;
1091 snprintf(un
.sun_path
, sizeof(un
.sun_path
),
1092 "/var/run/.heim_%s-socket", service
);
1093 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1097 socket_set_reuseaddr(fd
, 1);
1101 setsockopt(fd
, 0, LOCAL_CREDS
, (void *)&one
, sizeof(one
));
1105 unlink(un
.sun_path
);
1107 if (bind(fd
, (struct sockaddr
*)&un
, sizeof(un
)) < 0) {
1112 if (listen(fd
, SOMAXCONN
) < 0) {
1117 chmod(un
.sun_path
, 0666);
1119 ret
= heim_sipc_stream_listener(fd
, HEIM_SIPC_TYPE_IPC
,
1120 callback
, user
, ctx
);
1122 struct client
*c
= (*ctx
)->mech
;
1123 c
->flags
|= UNIX_SOCKET
;
1130 * Set the idle timeout value
1132 * The timeout event handler is triggered recurrently every idle
1133 * period `t'. The default action is rather draconian and just calls
1134 * exit(0), so you might want to change this to something more
1135 * graceful using heim_sipc_set_timeout_handler().
1139 heim_sipc_timeout(time_t t
)
1142 static dispatch_once_t timeoutonce
;
1144 dispatch_sync(timerq
, ^{
1148 dispatch_once(&timeoutonce
, ^{ dispatch_resume(timer
); });
1155 * Set the timeout event handler
1157 * Replaces the default idle timeout action.
1161 heim_sipc_set_timeout_handler(void (*func
)(void))
1165 dispatch_sync(timerq
, ^{ timer_ev
= func
; });
1173 heim_sipc_free_context(heim_sipc ctx
)
1175 (ctx
->release
)(ctx
);