From: Alexandra Ellwood Date: Wed, 15 Oct 2008 21:35:23 +0000 (+0000) Subject: Merge KerberosIPC into k5_mig support X-Git-Tag: krb5-1.7-alpha1~307 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=f393a36a63846b24219d510d41011e0d2a91d2bb;p=krb5.git Merge KerberosIPC into k5_mig support Now that there are no servers using only kipc_* calls, merge them into the k5_mig_* calls. ticket: new git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@20873 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/include/k5-thread.h b/src/include/k5-thread.h index a3fb13dcd..821fe8457 100644 --- a/src/include/k5-thread.h +++ b/src/include/k5-thread.h @@ -411,12 +411,7 @@ typedef enum { K5_KEY_GSS_KRB5_ERROR_MESSAGE, K5_KEY_KIM_ERROR_MESSAGE, #if defined(__MACH__) && defined(__APPLE__) - K5_KEY_CCAPI_REQUEST_PORT, - K5_KEY_CCAPI_REPLY_STREAM, - K5_KEY_CCAPI_SERVER_DIED, - K5_KEY_IPC_REQUEST_PORTS, - K5_KEY_IPC_REPLY_STREAM, - K5_KEY_IPC_SERVER_DIED, + K5_KEY_IPC_CONNECTION_INFO, K5_KEY_COM_ERR_REENTER, #endif K5_KEY_MAX diff --git a/src/util/mac/k5_mig_client.c b/src/util/mac/k5_mig_client.c index 6bb3b3dd9..7d57468bb 100644 --- a/src/util/mac/k5_mig_client.c +++ b/src/util/mac/k5_mig_client.c @@ -27,43 +27,131 @@ #ifndef LEAN_CLIENT #include "k5_mig_client.h" - -#include #include "k5_mig_request.h" #include "k5_mig_replyServer.h" #include "k5-thread.h" -#define KIPC_SERVICE_COUNT 3 +#include +#include -typedef struct k5_ipc_request_port { - char *service_id; - mach_port_t port; -} k5_ipc_request_port; -static k5_ipc_request_port k5_ipc_known_ports[KIPC_SERVICE_COUNT] = { + +/* Number of services available. Update if modifying the lists below */ +#define KIPC_SERVICE_COUNT 2 + +/* ------------------------------------------------------------------------ */ + +/* This struct exists to store the global service port shared between all + * threads. Note that there is one of these ports per server, whereas + * there is one connection port per thread. Thus this is global and mutexed, + * whereas the connection ports below are in TLS */ + +typedef struct k5_ipc_service_port { + const char *service_id; + mach_port_t service_port; +} k5_ipc_service_port; + +/* global service ports and mutex to protect it */ +static k5_mutex_t g_service_ports_mutex = K5_MUTEX_PARTIAL_INITIALIZER; +static k5_ipc_service_port g_service_ports[KIPC_SERVICE_COUNT] = { { "edu.mit.Kerberos.CCacheServer", MACH_PORT_NULL }, -{ "edu.mit.Kerberos.KerberosAgent", MACH_PORT_NULL }, -{ "edu.mit.Kerberos.OldKerberosAgent", MACH_PORT_NULL } }; +{ "edu.mit.Kerberos.KerberosAgent", MACH_PORT_NULL } }; -MAKE_INIT_FUNCTION(k5_cli_ipc_thread_init); -MAKE_FINI_FUNCTION(k5_cli_ipc_thread_fini); +/* ------------------------------------------------------------------------ */ + +/* This struct exists to hold the per-thread connection port used for ipc + * messages to the server. Each thread is issued a separate connection + * port so that the server can distinguish between threads in the same + * application. */ + +typedef struct k5_ipc_connection { + const char *service_id; + mach_port_t port; +} *k5_ipc_connection; + +typedef struct k5_ipc_connection_info { + struct k5_ipc_connection connections[KIPC_SERVICE_COUNT]; + boolean_t server_died; + k5_ipc_stream reply_stream; +} *k5_ipc_connection_info; + +/* initializer for k5_ipc_request_port to fill in server names in TLS */ +static const char *k5_ipc_known_services[KIPC_SERVICE_COUNT] = { +"edu.mit.Kerberos.CCacheServer", +"edu.mit.Kerberos.KerberosAgent" }; /* ------------------------------------------------------------------------ */ -static int k5_cli_ipc_thread_init (void) +static void k5_ipc_client_cinfo_free (void *io_cinfo) { - int err = 0; + if (io_cinfo) { + k5_ipc_connection_info cinfo = io_cinfo; + int i; + + for (i = 0; i < KIPC_SERVICE_COUNT; i++) { + if (MACH_PORT_VALID (cinfo->connections[i].port)) { + mach_port_mod_refs (mach_task_self(), + cinfo->connections[i].port, + MACH_PORT_RIGHT_SEND, -1 ); + cinfo->connections[i].port = MACH_PORT_NULL; + } + } + /* reply_stream will always be freed by k5_ipc_send_request() */ + free (cinfo); + } +} - err = k5_key_register (K5_KEY_IPC_REQUEST_PORTS, free); +/* ------------------------------------------------------------------------ */ + +static int k5_ipc_client_cinfo_allocate (k5_ipc_connection_info *out_cinfo) +{ + int err = 0; + k5_ipc_connection_info cinfo = NULL; + + cinfo = malloc (sizeof (*cinfo)); + if (!cinfo) { err = ENOMEM; } if (!err) { - err = k5_key_register (K5_KEY_IPC_REPLY_STREAM, NULL); + int i; + + cinfo->server_died = 0; + cinfo->reply_stream = NULL; + + for (i = 0; i < KIPC_SERVICE_COUNT; i++) { + cinfo->connections[i].service_id = k5_ipc_known_services[i]; + cinfo->connections[i].port = MACH_PORT_NULL; + } } if (!err) { - err = k5_key_register (K5_KEY_IPC_SERVER_DIED, NULL); + *out_cinfo = cinfo; + cinfo = NULL; } + k5_ipc_client_cinfo_free (cinfo); + + return err; +} + + +#pragma mark - + +MAKE_INIT_FUNCTION(k5_cli_ipc_thread_init); +MAKE_FINI_FUNCTION(k5_cli_ipc_thread_fini); + +/* ------------------------------------------------------------------------ */ + +static int k5_cli_ipc_thread_init (void) +{ + int err = 0; + + err = k5_key_register (K5_KEY_IPC_CONNECTION_INFO, + k5_ipc_client_cinfo_free); + + if (!err) { + err = k5_mutex_finish_init (&g_service_ports_mutex); + } + return err; } @@ -71,9 +159,102 @@ static int k5_cli_ipc_thread_init (void) static void k5_cli_ipc_thread_fini (void) { - k5_key_delete (K5_KEY_IPC_REQUEST_PORTS); - k5_key_delete (K5_KEY_IPC_REPLY_STREAM); - k5_key_delete (K5_KEY_IPC_SERVER_DIED); + k5_key_delete (K5_KEY_IPC_CONNECTION_INFO); + k5_mutex_destroy (&g_service_ports_mutex); +} + +#pragma mark - + +/* ------------------------------------------------------------------------ */ + +static kern_return_t k5_ipc_client_lookup_server (const char *in_service_id, + boolean_t in_launch_if_necessary, + boolean_t in_use_cached_port, + mach_port_t *out_service_port) +{ + kern_return_t err = 0; + kern_return_t lock_err = 0; + mach_port_t k5_service_port = MACH_PORT_NULL; + boolean_t found_entry = 0; + int i; + + if (!in_service_id ) { err = EINVAL; } + if (!out_service_port) { err = EINVAL; } + + if (!err) { + lock_err = k5_mutex_lock (&g_service_ports_mutex); + if (lock_err) { err = lock_err; } + } + + for (i = 0; !err && i < KIPC_SERVICE_COUNT; i++) { + if (!strcmp (in_service_id, g_service_ports[i].service_id)) { + found_entry = 1; + if (in_use_cached_port) { + k5_service_port = g_service_ports[i].service_port; + } + break; + } + } + + if (!err && (!MACH_PORT_VALID (k5_service_port) || !in_use_cached_port)) { + mach_port_t boot_port = MACH_PORT_NULL; + char *service = NULL; + + /* Get our bootstrap port */ + err = task_get_bootstrap_port (mach_task_self (), &boot_port); + + if (!err && !in_launch_if_necessary) { + char *lookup = NULL; + mach_port_t lookup_port = MACH_PORT_NULL; + + int w = asprintf (&lookup, "%s%s", + in_service_id, K5_MIG_LOOKUP_SUFFIX); + if (w < 0) { err = ENOMEM; } + + if (!err) { + /* Use the lookup name because the service name will return + * a valid port even if the server isn't running */ + err = bootstrap_look_up (boot_port, lookup, &lookup_port); + } + + free (lookup); + if (MACH_PORT_VALID (lookup_port)) { + mach_port_deallocate (mach_task_self (), lookup_port); + } + } + + if (!err) { + int w = asprintf (&service, "%s%s", + in_service_id, K5_MIG_SERVICE_SUFFIX); + if (w < 0) { err = ENOMEM; } + } + + if (!err) { + err = bootstrap_look_up (boot_port, service, &k5_service_port); + + if (!err && found_entry) { + /* Free old port if it is valid */ + if (!err && MACH_PORT_VALID (g_service_ports[i].service_port)) { + mach_port_deallocate (mach_task_self (), + g_service_ports[i].service_port); + } + + g_service_ports[i].service_port = k5_service_port; + } + } + + free (service); + if (MACH_PORT_VALID (boot_port)) { mach_port_deallocate (mach_task_self (), + boot_port); } + } + + if (!err) { + *out_service_port = k5_service_port; + } + + if (!lock_err) { k5_mutex_unlock (&g_service_ports_mutex); } + + return err; } #pragma mark - @@ -90,9 +271,9 @@ static boolean_t k5_ipc_reply_demux (mach_msg_header_t *request, } if (!handled && request->msgh_id == MACH_NOTIFY_NO_SENDERS) { - int32_t *server_died = k5_getspecific (K5_KEY_IPC_SERVER_DIED); - if (!server_died) { - *server_died = 1; + k5_ipc_connection_info cinfo = k5_getspecific (K5_KEY_IPC_CONNECTION_INFO); + if (cinfo) { + cinfo->server_died = 1; } handled = 1; /* server died */ @@ -114,30 +295,34 @@ kern_return_t k5_ipc_client_reply (mach_port_t in_reply_port, mach_msg_type_number_t in_ool_replyCnt) { kern_return_t err = KERN_SUCCESS; - k5_ipc_stream reply_stream = NULL; + k5_ipc_connection_info cinfo = NULL; if (!err) { err = CALL_INIT_FUNCTION (k5_cli_ipc_thread_init); } if (!err) { - reply_stream = k5_getspecific (K5_KEY_IPC_REPLY_STREAM); - if (!reply_stream) { err = EINVAL; } + cinfo = k5_getspecific (K5_KEY_IPC_CONNECTION_INFO); + if (!cinfo || !cinfo->reply_stream) { err = EINVAL; } } if (!err) { if (in_inl_replyCnt) { - err = k5_ipc_stream_write (reply_stream, in_inl_reply, in_inl_replyCnt); + err = k5_ipc_stream_write (cinfo->reply_stream, + in_inl_reply, in_inl_replyCnt); } else if (in_ool_replyCnt) { - err = k5_ipc_stream_write (reply_stream, in_ool_reply, in_ool_replyCnt); + err = k5_ipc_stream_write (cinfo->reply_stream, + in_ool_reply, in_ool_replyCnt); } else { err = EINVAL; } } - if (in_ool_replyCnt) { vm_deallocate (mach_task_self (), (vm_address_t) in_ool_reply, in_ool_replyCnt); } + if (in_ool_replyCnt) { vm_deallocate (mach_task_self (), + (vm_address_t) in_ool_reply, + in_ool_replyCnt); } return err; } @@ -154,16 +339,15 @@ int32_t k5_ipc_send_request (const char *in_service_id, int err = 0; int32_t done = 0; int32_t try_count = 0; - int32_t server_died = 0; mach_port_t server_port = MACH_PORT_NULL; - mach_port_t *request_port = NULL; + k5_ipc_connection_info cinfo = NULL; + k5_ipc_connection connection = NULL; mach_port_t reply_port = MACH_PORT_NULL; const char *inl_request = NULL; /* char * so we can pass the buffer in directly */ mach_msg_type_number_t inl_request_length = 0; k5_ipc_ool_request_t ool_request = NULL; mach_msg_type_number_t ool_request_length = 0; - k5_ipc_stream reply_stream = NULL; - + if (!in_request_stream) { err = EINVAL; } if (!out_reply_stream ) { err = EINVAL; } @@ -176,16 +360,18 @@ int32_t k5_ipc_send_request (const char *in_service_id, * the slow dynamically allocated buffer */ mach_msg_type_number_t request_length = k5_ipc_stream_size (in_request_stream); - if (request_length > K5_IPC_MAX_MSG_SIZE) { - //dprintf ("%s choosing out of line buffer (size is %d)", - // __FUNCTION__, request_length); + if (request_length > K5_IPC_MAX_INL_MSG_SIZE) { + /*dprintf ("%s choosing out of line buffer (size is %d)", + * __FUNCTION__, request_length); */ err = vm_read (mach_task_self (), - (vm_address_t) k5_ipc_stream_data (in_request_stream), request_length, - (vm_address_t *) &ool_request, &ool_request_length); + (vm_address_t) k5_ipc_stream_data (in_request_stream), + request_length, + (vm_address_t *) &ool_request, + &ool_request_length); } else { - //dprintf ("%s choosing in line buffer (size is %d)", - // __FUNCTION__, request_length); + /*dprintf ("%s choosing in line buffer (size is %d)", + * __FUNCTION__, request_length); */ inl_request_length = request_length; inl_request = k5_ipc_stream_data (in_request_stream); @@ -193,25 +379,13 @@ int32_t k5_ipc_send_request (const char *in_service_id, } if (!err) { - k5_ipc_request_port *port_list = NULL; - - port_list = k5_getspecific (K5_KEY_IPC_REQUEST_PORTS); + cinfo = k5_getspecific (K5_KEY_IPC_CONNECTION_INFO); + + if (!cinfo) { + err = k5_ipc_client_cinfo_allocate (&cinfo); - if (!port_list) { - int size = sizeof (*port_list) * KIPC_SERVICE_COUNT; - - port_list = malloc (size); - if (!port_list) { err = ENOMEM; } - if (!err) { - int i; - - for (i = 0; i < KIPC_SERVICE_COUNT; i++) { - port_list[i].service_id = k5_ipc_known_ports[i].service_id; - port_list[i].port = k5_ipc_known_ports[i].port; - } - - err = k5_setspecific (K5_KEY_IPC_REQUEST_PORTS, port_list); + err = k5_setspecific (K5_KEY_IPC_CONNECTION_INFO, cinfo); } } @@ -219,9 +393,9 @@ int32_t k5_ipc_send_request (const char *in_service_id, int i, found = 0; for (i = 0; i < KIPC_SERVICE_COUNT; i++) { - if (!strcmp (in_service_id, port_list[i].service_id)) { + if (!strcmp (in_service_id, cinfo->connections[i].service_id)) { found = 1; - request_port = &port_list[i].port; + connection = &cinfo->connections[i]; break; } } @@ -231,21 +405,23 @@ int32_t k5_ipc_send_request (const char *in_service_id, } if (!err) { - err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &reply_port); + err = k5_ipc_client_lookup_server (in_service_id, in_launch_server, + TRUE, &server_port); } if (!err) { - err = kipc_client_lookup_server (in_service_id, in_launch_server, - TRUE, &server_port); + err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, + &reply_port); } while (!err && !done) { - if (!err && !MACH_PORT_VALID (*request_port)) { - err = k5_ipc_client_create_client_connection (server_port, request_port); + if (!err && !MACH_PORT_VALID (connection->port)) { + err = k5_ipc_client_create_client_connection (server_port, + &connection->port); } if (!err) { - err = k5_ipc_client_request (*request_port, reply_port, + err = k5_ipc_client_request (connection->port, reply_port, inl_request, inl_request_length, ool_request, ool_request_length); @@ -257,15 +433,16 @@ int32_t k5_ipc_send_request (const char *in_service_id, err = 0; } - if (request_port && MACH_PORT_VALID (*request_port)) { - mach_port_mod_refs (mach_task_self(), *request_port, MACH_PORT_RIGHT_SEND, -1 ); - *request_port = MACH_PORT_NULL; + if (MACH_PORT_VALID (connection->port)) { + mach_port_mod_refs (mach_task_self(), connection->port, + MACH_PORT_RIGHT_SEND, -1 ); + connection->port = MACH_PORT_NULL; } /* Look up server name again without using the cached copy */ - err = kipc_client_lookup_server (in_service_id, - in_launch_server, - FALSE, &server_port); + err = k5_ipc_client_lookup_server (in_service_id, + in_launch_server, + FALSE, &server_port); } else { /* Talked to server, though we may have gotten an error */ @@ -279,23 +456,16 @@ int32_t k5_ipc_send_request (const char *in_service_id, } if (!err) { - err = k5_ipc_stream_new (&reply_stream); - } - - if (!err) { - err = k5_setspecific (K5_KEY_IPC_REPLY_STREAM, reply_stream); - } - - if (!err) { - err = k5_setspecific (K5_KEY_IPC_SERVER_DIED, &server_died); + err = k5_ipc_stream_new (&cinfo->reply_stream); } if (!err) { mach_port_t old_notification_target = MACH_PORT_NULL; - /* request no-senders notification so we can get a message when server dies */ + /* request no-senders notification so we know when server dies */ err = mach_port_request_notification (mach_task_self (), reply_port, - MACH_NOTIFY_NO_SENDERS, 1, reply_port, + MACH_NOTIFY_NO_SENDERS, 1, + reply_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &old_notification_target); @@ -305,28 +475,36 @@ int32_t k5_ipc_send_request (const char *in_service_id, } if (!err) { - err = mach_msg_server_once (k5_ipc_reply_demux, kkipc_max_message_size, + cinfo->server_died = 0; + + err = mach_msg_server_once (k5_ipc_reply_demux, K5_IPC_MAX_MSG_SIZE, reply_port, MACH_MSG_TIMEOUT_NONE); - } - - if (!err && server_died) { - err = ENOTCONN; + + if (!err && cinfo->server_died) { + err = ENOTCONN; + } } if (err == BOOTSTRAP_UNKNOWN_SERVICE && !in_launch_server) { - err = 0; /* If the server is not running just return an empty stream. */ + err = 0; /* If server is not running just return an empty stream. */ } if (!err) { - *out_reply_stream = reply_stream; - reply_stream = NULL; + *out_reply_stream = cinfo->reply_stream; + cinfo->reply_stream = NULL; + } + + if (reply_port != MACH_PORT_NULL) { + mach_port_destroy (mach_task_self (), reply_port); + } + if (ool_request_length) { + vm_deallocate (mach_task_self (), + (vm_address_t) ool_request, ool_request_length); + } + if (cinfo && cinfo->reply_stream) { + k5_ipc_stream_release (cinfo->reply_stream); + cinfo->reply_stream = NULL; } - - k5_setspecific (K5_KEY_IPC_REPLY_STREAM, NULL); - k5_setspecific (K5_KEY_IPC_SERVER_DIED, NULL); - if (reply_port != MACH_PORT_NULL) { mach_port_destroy (mach_task_self (), reply_port); } - if (ool_request_length ) { vm_deallocate (mach_task_self (), (vm_address_t) ool_request, ool_request_length); } - if (reply_stream ) { k5_ipc_stream_release (reply_stream); } return err; } diff --git a/src/util/mac/k5_mig_server.c b/src/util/mac/k5_mig_server.c index a320ad528..45f1b31af 100644 --- a/src/util/mac/k5_mig_server.c +++ b/src/util/mac/k5_mig_server.c @@ -27,30 +27,48 @@ #include "k5_mig_server.h" #include -#include #include "k5_mig_requestServer.h" #include "k5_mig_reply.h" +#include +#include +#include +#include + +/* Global variables for servers (used by k5_ipc_request_demux) */ +static mach_port_t g_service_port = MACH_PORT_NULL; +static mach_port_t g_notify_port = MACH_PORT_NULL; +static mach_port_t g_listen_port_set = MACH_PORT_NULL; +static boolean_t g_ready_to_quit = 0; + /* ------------------------------------------------------------------------ */ static boolean_t k5_ipc_request_demux (mach_msg_header_t *request, mach_msg_header_t *reply) { - boolean_t handled = false; + boolean_t handled = 0; if (!handled) { handled = k5_ipc_request_server (request, reply); } + /* Our session has a send right. If that goes away it's time to quit. */ + if (!handled && (request->msgh_id == MACH_NOTIFY_NO_SENDERS && + request->msgh_local_port == g_notify_port)) { + g_ready_to_quit = 1; + handled = 1; + } + + /* Check here for a client death. If so remove it */ if (!handled && request->msgh_id == MACH_NOTIFY_NO_SENDERS) { kern_return_t err = KERN_SUCCESS; err = k5_ipc_server_remove_client (request->msgh_local_port); if (!err) { - /* Check here for a client in our table and free rights associated with it */ - err = mach_port_mod_refs (mach_task_self (), request->msgh_local_port, + err = mach_port_mod_refs (mach_task_self (), + request->msgh_local_port, MACH_PORT_RIGHT_RECEIVE, -1); } @@ -58,7 +76,7 @@ static boolean_t k5_ipc_request_demux (mach_msg_header_t *request, handled = 1; /* was a port we are tracking */ } } - + return handled; } @@ -72,18 +90,23 @@ kern_return_t k5_ipc_server_create_client_connection (mach_port_t in_server_p mach_port_t old_notification_target = MACH_PORT_NULL; if (!err) { - err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &connection_port); + err = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_RECEIVE, &connection_port); } if (!err) { - err = mach_port_move_member (mach_task_self (), connection_port, kipc_server_get_listen_portset ()); + err = mach_port_move_member (mach_task_self (), + connection_port, g_listen_port_set); } if (!err) { /* request no-senders notification so we can tell when client quits/crashes */ - err = mach_port_request_notification (mach_task_self (), connection_port, - MACH_NOTIFY_NO_SENDERS, 1, connection_port, - MACH_MSG_TYPE_MAKE_SEND_ONCE, &old_notification_target ); + err = mach_port_request_notification (mach_task_self (), + connection_port, + MACH_NOTIFY_NO_SENDERS, 1, + connection_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &old_notification_target ); } if (!err) { @@ -138,6 +161,71 @@ kern_return_t k5_ipc_server_request (mach_port_t in_connection_port, return err; } +/* ------------------------------------------------------------------------ */ + +static kern_return_t k5_ipc_server_get_lookup_and_service_names (char **out_lookup, + char **out_service) +{ + kern_return_t err = KERN_SUCCESS; + CFBundleRef bundle = NULL; + CFStringRef id_string = NULL; + CFIndex len = 0; + char *service_id = NULL; + char *lookup = NULL; + char *service = NULL; + + if (!out_lookup ) { err = EINVAL; } + if (!out_service) { err = EINVAL; } + + if (!err) { + bundle = CFBundleGetMainBundle (); + if (!bundle) { err = ENOENT; } + } + + if (!err) { + id_string = CFBundleGetIdentifier (bundle); + if (!id_string) { err = ENOMEM; } + } + + if (!err) { + len = CFStringGetMaximumSizeForEncoding (CFStringGetLength (id_string), + kCFStringEncodingUTF8) + 1; + } + + if (!err) { + service_id = calloc (len, sizeof (char)); + if (!service_id) { err = errno; } + } + + if (!err && !CFStringGetCString (id_string, service_id, len, + kCFStringEncodingUTF8)) { + err = ENOMEM; + } + + if (!err) { + int w = asprintf (&lookup, "%s%s", service_id, K5_MIG_LOOKUP_SUFFIX); + if (w < 0) { err = ENOMEM; } + } + + if (!err) { + int w = asprintf (&service, "%s%s", service_id, K5_MIG_SERVICE_SUFFIX); + if (w < 0) { err = ENOMEM; } + } + + if (!err) { + *out_lookup = lookup; + lookup = NULL; + *out_service = service; + service = NULL; + } + + free (service); + free (lookup); + free (service_id); + + return err; +} + #pragma mark - /* ------------------------------------------------------------------------ */ @@ -148,7 +236,97 @@ int32_t k5_ipc_server_listen_loop (void) * This will call k5_ipc_server_create_client_connection for new clients * and k5_ipc_server_request for existing clients */ - return kipc_server_run_server (k5_ipc_request_demux); + kern_return_t err = KERN_SUCCESS; + char *service = NULL; + char *lookup = NULL; + mach_port_t lookup_port = MACH_PORT_NULL; + mach_port_t boot_port = MACH_PORT_NULL; + mach_port_t previous_notify_port = MACH_PORT_NULL; + + if (!err) { + err = k5_ipc_server_get_lookup_and_service_names (&lookup, &service); + } + + if (!err) { + /* Get the bootstrap port */ + err = task_get_bootstrap_port (mach_task_self (), &boot_port); + } + + if (!err) { + /* We are an on-demand server so our lookup port already exists. */ + err = bootstrap_check_in (boot_port, lookup, &lookup_port); + } + + if (!err) { + /* We are an on-demand server so our service port already exists. */ + err = bootstrap_check_in (boot_port, service, &g_service_port); + } + + if (!err) { + /* Create the port set that the server will listen on */ + err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, + &g_notify_port); + } + + if (!err) { + /* Ask for notification when the server port has no more senders + * A send-once right != a send right so our send-once right will + * not interfere with the notification */ + err = mach_port_request_notification (mach_task_self (), g_service_port, + MACH_NOTIFY_NO_SENDERS, true, + g_notify_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, + &previous_notify_port); + } + + if (!err) { + /* Create the port set that the server will listen on */ + err = mach_port_allocate (mach_task_self (), + MACH_PORT_RIGHT_PORT_SET, &g_listen_port_set); + } + + if (!err) { + /* Add the lookup port to the port set */ + err = mach_port_move_member (mach_task_self (), + lookup_port, g_listen_port_set); + } + + if (!err) { + /* Add the service port to the port set */ + err = mach_port_move_member (mach_task_self (), + g_service_port, g_listen_port_set); + } + + if (!err) { + /* Add the notify port to the port set */ + err = mach_port_move_member (mach_task_self (), + g_notify_port, g_listen_port_set); + } + + while (!err && !g_ready_to_quit) { + /* Handle one message at a time so we can check to see if + * the server wants to quit */ + err = mach_msg_server_once (k5_ipc_request_demux, K5_IPC_MAX_MSG_SIZE, + g_listen_port_set, MACH_MSG_OPTION_NONE); + } + + /* Clean up the ports and strings */ + if (MACH_PORT_VALID (g_notify_port)) { + mach_port_destroy (mach_task_self (), g_notify_port); + g_notify_port = MACH_PORT_NULL; + } + if (MACH_PORT_VALID (g_listen_port_set)) { + mach_port_destroy (mach_task_self (), g_listen_port_set); + g_listen_port_set = MACH_PORT_NULL; + } + if (MACH_PORT_VALID (boot_port)) { + mach_port_deallocate (mach_task_self (), boot_port); + } + + free (service); + free (lookup); + + return err; } /* ------------------------------------------------------------------------ */ @@ -170,7 +348,7 @@ int32_t k5_ipc_server_send_reply (mach_port_t in_reply_port, * the slow dynamically allocated buffer */ mach_msg_type_number_t reply_length = k5_ipc_stream_size (in_reply_stream); - if (reply_length > K5_IPC_MAX_MSG_SIZE) { + if (reply_length > K5_IPC_MAX_INL_MSG_SIZE) { //dprintf ("%s choosing out of line buffer (size is %d)", // __FUNCTION__, reply_length); @@ -203,3 +381,10 @@ int32_t k5_ipc_server_send_reply (mach_port_t in_reply_port, return err; } + +/* ------------------------------------------------------------------------ */ + +void k5_ipc_server_quit (void) +{ + g_ready_to_quit = 1; +} diff --git a/src/util/mac/k5_mig_server.h b/src/util/mac/k5_mig_server.h index 94a68e9a8..0c66ae5bf 100644 --- a/src/util/mac/k5_mig_server.h +++ b/src/util/mac/k5_mig_server.h @@ -41,9 +41,12 @@ int32_t k5_ipc_server_handle_request (mach_port_t in_connection_port, /* Server control functions */ +/* WARNING: Currently only supports running server loop on a single thread! */ int32_t k5_ipc_server_listen_loop (void); int32_t k5_ipc_server_send_reply (mach_port_t in_reply_pipe, k5_ipc_stream in_reply_stream); +void k5_ipc_server_quit (void); + #endif /* K5_MIG_SERVER */ diff --git a/src/util/mac/k5_mig_types.h b/src/util/mac/k5_mig_types.h index 4c8ddb73b..0f877a314 100644 --- a/src/util/mac/k5_mig_types.h +++ b/src/util/mac/k5_mig_types.h @@ -44,12 +44,16 @@ #ifndef K5_MIG_TYPES_H #define K5_MIG_TYPES_H +#define K5_IPC_MAX_MSG_SIZE 2048 + MAX_TRAILER_SIZE -#define K5_IPC_MAX_MSG_SIZE 1024 +#define K5_MIG_LOOKUP_SUFFIX ".ipcLookup" +#define K5_MIG_SERVICE_SUFFIX ".ipcService" -typedef const char k5_ipc_inl_request_t[K5_IPC_MAX_MSG_SIZE]; +#define K5_IPC_MAX_INL_MSG_SIZE 1024 + +typedef const char k5_ipc_inl_request_t[K5_IPC_MAX_INL_MSG_SIZE]; typedef const char *k5_ipc_ool_request_t; -typedef char k5_ipc_inl_reply_t[K5_IPC_MAX_MSG_SIZE]; +typedef char k5_ipc_inl_reply_t[K5_IPC_MAX_INL_MSG_SIZE]; typedef char *k5_ipc_ool_reply_t; #endif /* K5_MIG_TYPES_H */