void *server_thread(void *arg) { mach_port_t exc_port = *(mach_port_t *)arg; kern_return_t kr; while(1) { if ((kr = mach_msg_server_once(mach_exc_server, 4096, exc_port, 0)) != KERN_SUCCESS) { fprintf(stderr, "mach_msg_server_once: error %#x\n", kr); exit(1); } } return (NULL); }
void *server_thread(void *arg) { kern_return_t kr; while(1) { /* Handle exceptions on exc_port */ if ((kr = mach_msg_server_once(mach_exc_server, 4096, exc_port, 0)) != KERN_SUCCESS) { fprintf(stderr, "mach_msg_server_once: error %#x\n", kr); exit(1); } } return (NULL); }
int32_t k5_ipc_send_request (const char *in_service_id, int32_t in_launch_server, k5_ipc_stream in_request_stream, k5_ipc_stream *out_reply_stream) { int err = 0; int32_t done = 0; int32_t try_count = 0; mach_port_t server_port = MACH_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; if (!in_request_stream) { err = EINVAL; } if (!out_reply_stream ) { err = EINVAL; } if (!err) { err = CALL_INIT_FUNCTION (k5_cli_ipc_thread_init); } if (!err) { /* depending on how big the message is, use the fast inline buffer or * 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_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); } else { /*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) { cinfo = k5_getspecific (K5_KEY_IPC_CONNECTION_INFO); if (!cinfo) { err = k5_ipc_client_cinfo_allocate (&cinfo); if (!err) { err = k5_setspecific (K5_KEY_IPC_CONNECTION_INFO, cinfo); } } if (!err) { int i, found = 0; for (i = 0; i < KIPC_SERVICE_COUNT; i++) { if (!strcmp (in_service_id, cinfo->connections[i].service_id)) { found = 1; connection = &cinfo->connections[i]; break; } } if (!found) { err = EINVAL; } } } if (!err) { err = k5_ipc_client_lookup_server (in_service_id, in_launch_server, TRUE, &server_port); } if (!err) { err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &reply_port); } while (!err && !done) { 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 (connection->port, reply_port, inl_request, inl_request_length, ool_request, ool_request_length); } if (err == MACH_SEND_INVALID_DEST) { if (try_count < 2) { try_count++; err = 0; } 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 = 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 */ done = 1; /* Because we use ",dealloc" ool_request will be freed by mach. * Don't double free it. */ ool_request = NULL; ool_request_length = 0; } } if (!err) { 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 know when server dies */ err = mach_port_request_notification (mach_task_self (), reply_port, MACH_NOTIFY_NO_SENDERS, 1, reply_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &old_notification_target); if (!err && old_notification_target != MACH_PORT_NULL) { mach_port_deallocate (mach_task_self (), old_notification_target); } } if (!err) { 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 && cinfo->server_died) { err = ENOTCONN; } } if (err == BOOTSTRAP_UNKNOWN_SERVICE && !in_launch_server) { err = 0; /* If server is not running just return an empty stream. */ } if (!err) { *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; } return err; }
int32_t k5_ipc_server_listen_loop (void) { /* Run the Mach IPC listen loop. * This will call k5_ipc_server_create_client_connection for new clients * and k5_ipc_server_request for existing clients */ 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; }
void *wait_for_exception() { while (1) { mach_msg_server_once(mach_exc_server, 4096, g_exception_port, MACH_MSG_OPTION_NONE); } }
int main(int ac, char *av[]) { char *p = NULL; kern_return_t kr = KERN_FAILURE; long n; int ch; mach_msg_header_t hdr; while ((ch = getopt(ac, av, "dt:")) != -1) switch (ch) { case 'd': opt_debug = 1; break; case 't': n = strtol(optarg, &p, 0); if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0) { fprintf(stderr, "Invalid idle timeout: %s\n", optarg); exit(EXIT_FAILURE); } maxidle = n; break; case '?': default: fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n"); exit(EXIT_FAILURE); } ac -= optind; av += optind; (void)ac; // Unused (void)av; // Unused initialize_logging(); helplog(ASL_LEVEL_INFO, "Starting"); initialize_id(); #ifndef NO_SECURITYFRAMEWORK // We should normally be running as a system daemon. However, that might not be the case in some scenarios (e.g. debugging). // Explicitly ensure that our Keychain operations utilize the system domain. if (opt_debug) SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); #endif gPort = register_service(kmDNSHelperServiceName); if (!gPort) exit(EXIT_FAILURE); if (maxidle) actualidle = maxidle; signal(SIGTERM, handle_sigterm); if (initialize_timer()) exit(EXIT_FAILURE); for (n=0; n<100000; n++) if (!gRunLoop) usleep(100); if (!gRunLoop) { helplog(ASL_LEVEL_ERR, "gRunLoop not set after waiting"); exit(EXIT_FAILURE); } for(;;) { hdr.msgh_bits = 0; hdr.msgh_local_port = gPort; hdr.msgh_remote_port = MACH_PORT_NULL; hdr.msgh_size = sizeof(hdr); hdr.msgh_id = 0; kr = mach_msg(&hdr, MACH_RCV_LARGE | MACH_RCV_MSG, 0, hdr.msgh_size, gPort, 0, 0); if (MACH_RCV_TOO_LARGE != kr) helplog(ASL_LEVEL_ERR, "main MACH_RCV_MSG error: %d %X %s", kr, kr, mach_error_string(kr)); kr = mach_msg_server_once(helper_server, MAX_MSG_SIZE, gPort, MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); if (KERN_SUCCESS != kr) { helplog(ASL_LEVEL_ERR, "mach_msg_server: %d %X %s", kr, kr, mach_error_string(kr)); exit(EXIT_FAILURE); } } exit(EXIT_SUCCESS); }