#ifndef LEAN_CLIENT
#include "k5_mig_client.h"
-
-#include <Kerberos/kipc_client.h>
#include "k5_mig_request.h"
#include "k5_mig_replyServer.h"
#include "k5-thread.h"
-#define KIPC_SERVICE_COUNT 3
+#include <mach/mach.h>
+#include <servers/bootstrap.h>
-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;
}
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 -
}
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 */
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;
}
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; }
* 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);
}
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);
}
}
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;
}
}
}
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);
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 */
}
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);
}
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;
}
#include "k5_mig_server.h"
#include <syslog.h>
-#include <Kerberos/kipc_server.h>
#include "k5_mig_requestServer.h"
#include "k5_mig_reply.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <mach/mach.h>
+#include <servers/bootstrap.h>
+#include <string.h>
+
+/* 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);
}
handled = 1; /* was a port we are tracking */
}
}
-
+
return handled;
}
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) {
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 -
/* ------------------------------------------------------------------------ */
* 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;
}
/* ------------------------------------------------------------------------ */
* 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);
return err;
}
+
+/* ------------------------------------------------------------------------ */
+
+void k5_ipc_server_quit (void)
+{
+ g_ready_to_quit = 1;
+}