#include "ccapi_os_ipc.h"
#include <Kerberos/kipc_client.h>
#include "cci_mig.h"
#include "k5-thread.h"
#include "k5-platform.h"
#define cci_server_bundle_id "edu.mit.Kerberos.CCacheServer"
#define cci_server_path "/System/Library/CoreServices/CCacheServer.app/Contents/MacOS/CCacheServer"
static mach_port_t g_connection_port = MACH_PORT_NULL;
static k5_mutex_t g_connection_port_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
MAKE_INIT_FUNCTION(cci_os_ipc_init);
static int cci_os_ipc_init (void)
{
return k5_mutex_finish_init(&g_connection_port_mutex);
}
cc_int32 cci_os_ipc (cc_int32 in_launch_server,
cci_stream_t in_request_stream,
cci_stream_t *out_reply_stream)
{
cc_int32 err = ccNoError;
mach_port_t server_port = MACH_PORT_NULL;
const char *inl_request = NULL;
mach_msg_type_number_t inl_request_length = 0;
cci_mipc_ool_request_t ool_request = NULL;
mach_msg_type_number_t ool_request_length = 0;
cci_mipc_inl_reply_t inl_reply;
mach_msg_type_number_t inl_reply_length = 0;
cci_mipc_ool_reply_t ool_reply = NULL;
mach_msg_type_number_t ool_reply_length = 0;
cci_stream_t reply_stream = NULL;
if (!in_request_stream) { err = cci_check_error (ccErrBadParam); }
if (!out_reply_stream ) { err = cci_check_error (ccErrBadParam); }
if (!err) {
err = cci_stream_new (&reply_stream);
}
if (!err) {
err = kipc_client_lookup_server (cci_server_bundle_id, cci_server_path,
in_launch_server, &server_port);
}
if (!err) {
mach_msg_type_number_t request_length = cci_stream_size (in_request_stream);
if (request_length > kCCAPIMaxILMsgSize) {
cci_debug_printf ("%s choosing out of line buffer (size is %d)",
__FUNCTION__, request_length);
err = vm_read (mach_task_self (),
(vm_address_t) cci_stream_data (in_request_stream), request_length,
(vm_address_t *) &ool_request, &ool_request_length);
} else {
inl_request_length = request_length;
inl_request = cci_stream_data (in_request_stream);
}
}
if (!err) {
cc_int32 sent_message = 0;
cc_int32 try_count = 0;
err = k5_mutex_lock (&g_connection_port_mutex);
while (!err && !sent_message) {
if (g_connection_port == MACH_PORT_NULL) {
err = cci_mipc_create_client_connection (server_port, &g_connection_port);
}
if (!err) {
err = cci_mipc_handle_message (g_connection_port,
inl_request, inl_request_length,
ool_request, ool_request_length,
inl_reply, &inl_reply_length,
&ool_reply, &ool_reply_length);
}
if (err == MACH_SEND_INVALID_DEST) {
mach_port_mod_refs (mach_task_self(), g_connection_port, MACH_PORT_RIGHT_SEND, -1 );
g_connection_port = MACH_PORT_NULL;
if (try_count < 2) {
try_count++;
err = ccNoError;
}
} else {
sent_message = 1;
ool_request = NULL;
ool_request_length = 0;
}
}
k5_mutex_unlock (&g_connection_port_mutex);
}
if (!err) {
if (inl_reply_length) {
err = cci_stream_write (reply_stream, inl_reply, inl_reply_length);
} else if (ool_reply_length) {
err = cci_stream_write (reply_stream, ool_reply, ool_reply_length);
} else {
err = cci_check_error (ccErrBadInternalMessage);
}
}
if (err == BOOTSTRAP_UNKNOWN_SERVICE && !in_launch_server) {
err = ccNoError;
}
if (!err) {
*out_reply_stream = reply_stream;
reply_stream = NULL;
}
if (ool_reply_length ) { vm_deallocate (mach_task_self (), (vm_address_t) ool_reply, ool_reply_length); }
if (ool_request_length) { vm_deallocate (mach_task_self (), (vm_address_t) ool_request, ool_request_length); }
if (reply_stream ) { cci_stream_release (reply_stream); }
return cci_check_error (err);
}