Merge KerberosIPC into k5_mig support
authorAlexandra Ellwood <lxs@mit.edu>
Wed, 15 Oct 2008 21:35:23 +0000 (21:35 +0000)
committerAlexandra Ellwood <lxs@mit.edu>
Wed, 15 Oct 2008 21:35:23 +0000 (21:35 +0000)
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

src/include/k5-thread.h
src/util/mac/k5_mig_client.c
src/util/mac/k5_mig_server.c
src/util/mac/k5_mig_server.h
src/util/mac/k5_mig_types.h

index a3fb13dcdd7ad24975301e16d61b17fffb376a49..821fe8457a2309b9a73fe7200d5b9cf3ef456bb8 100644 (file)
@@ -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
index 6bb3b3dd99f4eb8aa7c607066e7fb2d91bb13d14..7d57468bbc4e3a4561af891044c5354ccc05873a 100644 (file)
 #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;
 }
 
@@ -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;    
 }
index a320ad5286028c7e6ae0a454eea8ace847e7eabd..45f1b31afbfb12e232ec7b7763bf4b94061eb9de 100644 (file)
 #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);
         }
         
@@ -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;
+}
index 94a68e9a8bdec78020632617e5d82808d4c8130f..0c66ae5bfe104830817cf50bbc3862b645f75a62 100644 (file)
@@ -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 */
index 4c8ddb73b150f28b1697cac9fdc35de2da0165b5..0f877a3144ed6e7b59959a33f70e0a3f61583474 100644 (file)
 #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 */