static boolean_t handle_server_message(struct DummyMsg_t *requestMsg, struct DummyMsg_t *replyMsg) { mig_reply_error_t * request = (mig_reply_error_t *)requestMsg; mig_reply_error_t * reply = (mig_reply_error_t *)replyMsg; mach_msg_return_t r = MACH_MSG_SUCCESS; mach_msg_options_t options = 0; boolean_t handled = iHaxGamezHelper_server((mach_msg_header_t *)request, (mach_msg_header_t *)reply); //if (ERR_FILE) fprintf(ERR_FILE, "Got back %d\n", handled); if (handled) { /* Copied from Libc/mach/mach_msg.c:mach_msg_server_once(): Start */ if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { if (reply->RetCode == MIG_NO_REPLY) reply->Head.msgh_remote_port = MACH_PORT_NULL; else if ((reply->RetCode != KERN_SUCCESS) && (request->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { /* destroy the request - but not the reply port */ request->Head.msgh_remote_port = MACH_PORT_NULL; mach_msg_destroy(&request->Head); } } /* * We don't want to block indefinitely because the client * isn't receiving messages from the reply port. * If we have a send-once right for the reply port, then * this isn't a concern because the send won't block. * If we have a send right, we need to use MACH_SEND_TIMEOUT. * To avoid falling off the kernel's fast RPC path unnecessarily, * we only supply MACH_SEND_TIMEOUT when absolutely necessary. */ if (reply->Head.msgh_remote_port != MACH_PORT_NULL) { r = mach_msg(&reply->Head, (MACH_MSGH_BITS_REMOTE(reply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) ? MACH_SEND_MSG|options : MACH_SEND_MSG|MACH_SEND_TIMEOUT|options, reply->Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if ((r != MACH_SEND_INVALID_DEST) && (r != MACH_SEND_TIMED_OUT)) goto done_once; } if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) mach_msg_destroy(&reply->Head); done_once: /* Copied from Libc/mach/mach_msg.c:mach_msg_server_once(): End */ ; } return handled; }
/* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ void server_handle_request(CFMachPortRef port, void *msg, CFIndex size, void *info) { mach_msg_return_t r; mach_msg_header_t * request = (mach_msg_header_t *)msg; mach_msg_header_t * reply; char reply_s[128] __attribute__ ((aligned (4))); // Wcast-align fix - force alignment if (process_notification(request) == FALSE) { if (_pppcontroller_subsystem.maxsize > sizeof(reply_s)) { syslog(LOG_ERR, "PPPController: %d > %ld", _pppcontroller_subsystem.maxsize, sizeof(reply_s)); reply = (mach_msg_header_t *) malloc(_pppcontroller_subsystem.maxsize); } else { reply = ALIGNED_CAST(mach_msg_header_t *)reply_s; } if (pppcontroller_server(request, reply) == FALSE) { syslog(LOG_INFO, "unknown message ID (%d) received", request->msgh_id); mach_msg_destroy(request); } else { int options; options = MACH_SEND_MSG; if (MACH_MSGH_BITS_REMOTE(reply->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND) { options |= MACH_SEND_TIMEOUT; } r = mach_msg(reply, options, reply->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (r != MACH_MSG_SUCCESS) { syslog(LOG_INFO, "PPPController: mach_msg(send): %s", mach_error_string(r)); mach_msg_destroy(reply); } } if (reply != ALIGNED_CAST(mach_msg_header_t *)reply_s) { free(reply); } } return; }
void _SC_sendMachMessage(mach_port_t port, mach_msg_id_t msg_id) { mach_msg_empty_send_t msg; mach_msg_option_t options; kern_return_t status; msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); msg.header.msgh_size = sizeof(msg); msg.header.msgh_remote_port = port; msg.header.msgh_local_port = MACH_PORT_NULL; msg.header.msgh_id = msg_id; options = MACH_SEND_TIMEOUT; status = mach_msg(&msg.header, /* msg */ MACH_SEND_MSG|options, /* options */ msg.header.msgh_size, /* send_size */ 0, /* rcv_size */ MACH_PORT_NULL, /* rcv_name */ 0, /* timeout */ MACH_PORT_NULL); /* notify */ if (status != MACH_MSG_SUCCESS) { mach_msg_destroy(&msg.header); } return; }
STATIC void server_handle_request(CFMachPortRef port, void * msg, CFIndex size, void * info) { mach_msg_return_t r; mach_msg_header_t * request = (mach_msg_header_t *)msg; mach_msg_header_t * reply; char reply_s[eapolcfg_auth_subsystem.maxsize]; if (process_notification(request) == FALSE) { reply = (mach_msg_header_t *)reply_s; if (eapolcfg_auth_server(request, reply) == FALSE) { syslog(LOG_NOTICE, "eapolcfg_auth: unknown message ID (%d)", request->msgh_id); mach_msg_destroy(request); } else { int options; S_handled_request = TRUE; options = MACH_SEND_MSG; if (MACH_MSGH_BITS_REMOTE(reply->msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) { options |= MACH_SEND_TIMEOUT; } r = mach_msg(reply, options, reply->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (r != MACH_MSG_SUCCESS) { syslog(LOG_NOTICE, "eapolcfg_auth: mach_msg(send): %s", mach_error_string(r)); mach_msg_destroy(reply); } } } return; }
/* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ void mach_client_notify (mach_port_t port, CFStringRef serviceID, u_long event, u_long error) { mach_msg_empty_send_t msg; kern_return_t status; /* Post notification as mach message */ msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); msg.header.msgh_size = sizeof(msg); msg.header.msgh_remote_port = port; msg.header.msgh_local_port = MACH_PORT_NULL; msg.header.msgh_id = 0; status = mach_msg(&msg.header, /* msg */ MACH_SEND_MSG|MACH_SEND_TIMEOUT, /* options */ msg.header.msgh_size, /* send_size */ 0, /* rcv_size */ MACH_PORT_NULL, /* rcv_name */ 0, /* timeout */ MACH_PORT_NULL); /* notify */ if (status == MACH_SEND_TIMEOUT) mach_msg_destroy(&msg.header); }
static void __DACommandSignal( int sig ) { /* * Process a SIGCHLD signal. mach_msg() is safe from a signal handler. */ mach_msg_header_t message; kern_return_t status; message.msgh_bits = MACH_MSGH_BITS( MACH_MSG_TYPE_COPY_SEND, 0 ); message.msgh_id = 0; message.msgh_local_port = MACH_PORT_NULL; message.msgh_remote_port = CFMachPortGetPort( __gDACommandRunLoopSourcePort ); message.msgh_reserved = 0; message.msgh_size = sizeof( message ); status = mach_msg( &message, MACH_SEND_MSG | MACH_SEND_TIMEOUT, message.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL ); if ( status == MACH_SEND_TIMED_OUT ) { mach_msg_destroy( &message ); } }
static void si_async_launchpad(si_async_workunit_t *r) { kern_return_t status; mach_msg_empty_send_t msg; #ifdef CALL_TRACE fprintf(stderr, "** %s starting worklist item %p\n", __func__, r); #endif if (r->flags & WORKUNIT_CANCELLED) { si_async_workunit_release(r); #ifdef CALL_TRACE fprintf(stderr, "** %s worklist item %p was cancelled early\n", __func__, r); #endif return; } if (r->flags & WORKUNIT_RETURNS_LIST) r->reslist = si_list_call(r->si, r->call, r->str1, r->str2, r->str3, r->num1, r->num2, r->num3, r->num4, &(r->err)); else r->resitem = si_item_call(r->si, r->call, r->str1, r->str2, r->str3, r->num1, r->num2, &(r->err)); /* * Test and set the cancelled flag. * If it was set, then this work item was cancelled. * Otherwise, setting it here prevents si_async_cancel from cancelling: * too late to cancel now! */ if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS, &(r->flags)) == 1) { si_async_workunit_release(r); #ifdef CALL_TRACE fprintf(stderr, "** %s worklist item %p was cancelled in flight\n", __func__, r); #endif return; } #ifdef CALL_TRACE else fprintf(stderr, "** %s worklist item %p flags are now 0x%08x\n", __func__, r, r->flags); #endif memset(&msg, 0, sizeof(mach_msg_empty_send_t)); msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, MACH_MSGH_BITS_ZERO); msg.header.msgh_remote_port = r->send; r->send = MACH_PORT_NULL; msg.header.msgh_local_port = MACH_PORT_NULL; msg.header.msgh_size = sizeof(mach_msg_empty_send_t); msg.header.msgh_id = r->call; status = mach_msg(&(msg.header), MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (status != MACH_MSG_SUCCESS) { /* receiver failed - clean up to avoid a port leak */ mach_msg_destroy(&(msg.header)); #ifdef CALL_TRACE fprintf(stderr, "** %s mach message send failed for worklist item %p\n", __func__, r); #endif } si_async_workunit_release(r); /* * The client is now responsible for calling si_async_handle_reply, * which will invoke the client's callback and then release the workunit. */ #ifdef CALL_TRACE fprintf(stderr, "** %s completed async worklist item %p\n", __func__, r); #endif }
void MachServer::runServerThread(bool doTimeout) { // allocate request/reply buffers Message bufRequest(mMaxSize); Message bufReply(mMaxSize); // all exits from runServerThread are through exceptions try { // register as a worker thread perThread().server = this; for (;;) { // progress hook eventDone(); // process all pending timers while (processTimer()) {} // check for worker idle timeout { StLock<Mutex> _(managerLock); // record idle thread low-water mark in scan interval if (idleCount < leastIdleWorkers) leastIdleWorkers = idleCount; // perform self-timeout processing if (doTimeout) { if (workerCount > maxWorkerCount) // someone reduced maxWorkerCount recently... break; // ... so release this thread immediately Time::Absolute rightNow = Time::now(); if (rightNow >= nextCheckTime) { // reaping period complete; process UInt32 idlers = leastIdleWorkers; secinfo("machserver", "reaping workers: %d %d", (uint32_t) workerCount, (uint32_t) idlers); nextCheckTime = rightNow + workerTimeout; leastIdleWorkers = INT_MAX; if (idlers > 1) // multiple idle threads throughout measuring interval... break; // ... so release this thread now } } } // determine next timeout (if any) bool indefinite = false; Time::Interval timeout = workerTimeout; { StLock<Mutex> _(managerLock); if (timers.empty()) { indefinite = !doTimeout; } else { timeout = max(Time::Interval(0), timers.next() - Time::now()); if (doTimeout && workerTimeout < timeout) timeout = workerTimeout; } } // receive next IPC request (or wait for timeout) mach_msg_return_t mr = indefinite ? mach_msg_overwrite(bufRequest, MACH_RCV_MSG | mMsgOptions, 0, mMaxSize, mPortSet, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, (mach_msg_header_t *) 0, 0) : mach_msg_overwrite(bufRequest, MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_INTERRUPT | mMsgOptions, 0, mMaxSize, mPortSet, mach_msg_timeout_t(timeout.mSeconds()), MACH_PORT_NULL, (mach_msg_header_t *) 0, 0); switch (mr) { case MACH_MSG_SUCCESS: // process received request message below break; default: secinfo("machserver", "received error: %d", mr); continue; } // process received message if (bufRequest.msgId() >= MACH_NOTIFY_FIRST && bufRequest.msgId() <= MACH_NOTIFY_LAST) { // mach kernel notification message // we assume this is quick, so no thread arbitration here cdsa_notify_server(bufRequest, bufReply); } else { // normal request message StLock<MachServer, &MachServer::busy, &MachServer::idle> _(*this); secinfo("machserver", "begin request: %d, %d", bufRequest.localPort().port(), bufRequest.msgId()); // try subsidiary handlers first bool handled = false; for (HandlerSet::const_iterator it = mHandlers.begin(); it != mHandlers.end(); it++) if (bufRequest.localPort() == (*it)->port()) { (*it)->handle(bufRequest, bufReply); handled = true; } if (!handled) { // unclaimed, send to main handler handle(bufRequest, bufReply); } secinfo("machserver", "end request"); } // process reply generated by handler if (!(bufReply.bits() & MACH_MSGH_BITS_COMPLEX) && bufReply.returnCode() != KERN_SUCCESS) { if (bufReply.returnCode() == MIG_NO_REPLY) continue; // don't destroy the reply port right, so we can send an error message bufRequest.remotePort(MACH_PORT_NULL); mach_msg_destroy(bufRequest); } if (bufReply.remotePort() == MACH_PORT_NULL) { // no reply port, so destroy the reply if (bufReply.bits() & MACH_MSGH_BITS_COMPLEX) bufReply.destroy(); continue; } /* * We don't want to block indefinitely because the client * isn't receiving messages from the reply port. * If we have a send-once right for the reply port, then * this isn't a concern because the send won't block. * If we have a send right, we need to use MACH_SEND_TIMEOUT. * To avoid falling off the kernel's fast RPC path unnecessarily, * we only supply MACH_SEND_TIMEOUT when absolutely necessary. */ mr = mach_msg_overwrite(bufReply, (MACH_MSGH_BITS_REMOTE(bufReply.bits()) == MACH_MSG_TYPE_MOVE_SEND_ONCE) ? MACH_SEND_MSG | mMsgOptions : MACH_SEND_MSG | MACH_SEND_TIMEOUT | mMsgOptions, bufReply.length(), 0, MACH_PORT_NULL, 0, MACH_PORT_NULL, NULL, 0); switch (mr) { case MACH_MSG_SUCCESS: break; default: secinfo("machserver", "send error: %d %d", mr, bufReply.remotePort().port()); bufReply.destroy(); break; } // clean up after the transaction releaseDeferredAllocations(); } perThread().server = NULL; } catch (...) { perThread().server = NULL; throw; } }
__private_extern__ void configdCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) { mig_reply_error_t * bufRequest = msg; uint32_t bufReply_q[MACH_MSG_BUFFER_SIZE/sizeof(uint32_t)]; mig_reply_error_t * bufReply = (mig_reply_error_t *)bufReply_q; static CFIndex bufSize = 0; mach_msg_return_t mr; int options; if (bufSize == 0) { // get max size for MiG reply buffers bufSize = _config_subsystem.maxsize; // check if our on-the-stack reply buffer will be big enough if (bufSize > sizeof(bufReply_q)) { SCLog(TRUE, LOG_NOTICE, CFSTR("configdCallback(): buffer size should be increased > %d"), _config_subsystem.maxsize); } } if (bufSize > sizeof(bufReply_q)) { bufReply = CFAllocatorAllocate(NULL, _config_subsystem.maxsize, 0); } bufReply->RetCode = 0; /* we have a request message */ (void) config_demux(&bufRequest->Head, &bufReply->Head); if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { if (bufReply->RetCode == MIG_NO_REPLY) { bufReply->Head.msgh_remote_port = MACH_PORT_NULL; } else if ((bufReply->RetCode != KERN_SUCCESS) && (bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { /* * destroy the request - but not the reply port */ bufRequest->Head.msgh_remote_port = MACH_PORT_NULL; mach_msg_destroy(&bufRequest->Head); } } if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) { /* * send reply. * * We don't want to block indefinitely because the client * isn't receiving messages from the reply port. * If we have a send-once right for the reply port, then * this isn't a concern because the send won't block. * If we have a send right, we need to use MACH_SEND_TIMEOUT. * To avoid falling off the kernel's fast RPC path unnecessarily, * we only supply MACH_SEND_TIMEOUT when absolutely necessary. */ options = MACH_SEND_MSG; if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) { options |= MACH_SEND_TIMEOUT; } mr = mach_msg(&bufReply->Head, /* msg */ options, /* option */ bufReply->Head.msgh_size, /* send_size */ 0, /* rcv_size */ MACH_PORT_NULL, /* rcv_name */ MACH_MSG_TIMEOUT_NONE, /* timeout */ MACH_PORT_NULL); /* notify */ /* Has a message error occurred? */ switch (mr) { case MACH_SEND_INVALID_DEST: case MACH_SEND_TIMED_OUT: break; default : /* Includes success case. */ goto done; } } if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) { mach_msg_destroy(&bufReply->Head); } done : if (bufReply != (mig_reply_error_t *)bufReply_q) CFAllocatorDeallocate(NULL, bufReply); return; }
/* * Send notification to a subscriber */ static uint32_t _internal_send(notify_state_t *ns, client_t *c) { uint32_t send; portproc_data_t *pdata; if (ns == NULL) return NOTIFY_STATUS_FAILED; if (c == NULL) return NOTIFY_STATUS_FAILED; if (c->state & NOTIFY_CLIENT_STATE_SUSPENDED) { c->state |= NOTIFY_CLIENT_STATE_PENDING; return NOTIFY_STATUS_OK; } pdata = _nc_table_find_n(ns->proc_table, c->pid); if ((pdata != NULL) && (pdata->flags & NOTIFY_PORT_PROC_STATE_SUSPENDED)) { c->suspend_count++; c->state |= NOTIFY_CLIENT_STATE_SUSPENDED; c->state |= NOTIFY_CLIENT_STATE_PENDING; return NOTIFY_STATUS_OK; } send = c->send_val; switch (c->notify_type) { case NOTIFY_TYPE_SIGNAL: { int rc = 0; if (c->pid == NOTIFY_CLIENT_SELF) rc = kill(getpid(), c->sig); else rc = kill(c->pid, c->sig); if (rc != 0) return NOTIFY_STATUS_FAILED; c->state &= ~NOTIFY_CLIENT_STATE_PENDING; c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; return NOTIFY_STATUS_OK; } case NOTIFY_TYPE_FILE: { ssize_t len; if (c->fd >= 0) { send = htonl(send); len = write(c->fd, &send, sizeof(uint32_t)); if (len != sizeof(uint32_t)) { close(c->fd); c->fd = -1; return NOTIFY_STATUS_FAILED; } } c->state &= ~NOTIFY_CLIENT_STATE_PENDING; c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; return NOTIFY_STATUS_OK; } case NOTIFY_TYPE_PORT: { kern_return_t kstatus; mach_msg_empty_send_t msg; mach_msg_option_t opts = MACH_SEND_MSG | MACH_SEND_TIMEOUT; pdata = _nc_table_find_n(ns->port_table, c->port); if ((pdata != NULL) && (pdata->flags & NOTIFY_PORT_PROC_STATE_SUSPENDED)) { c->suspend_count++; c->state |= NOTIFY_CLIENT_STATE_SUSPENDED; c->state |= NOTIFY_CLIENT_STATE_PENDING; return NOTIFY_STATUS_OK; } if (ns->flags & NOTIFY_STATE_ENABLE_RESEND) opts |= MACH_SEND_NOTIFY; memset(&msg, 0, sizeof(mach_msg_empty_send_t)); msg.header.msgh_size = sizeof(mach_msg_empty_send_t); msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSGH_BITS_ZERO); msg.header.msgh_local_port = MACH_PORT_NULL; msg.header.msgh_remote_port = c->port; msg.header.msgh_id = (mach_msg_id_t)send; kstatus = mach_msg(&msg.header, opts, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kstatus == MACH_SEND_TIMED_OUT) { /* deallocate port rights obtained via pseudo-receive after failed mach_msg() send */ mach_msg_destroy(&msg.header); if (ns->flags & NOTIFY_STATE_ENABLE_RESEND) { /* * Suspend on timeout. * notifyd will get a MACH_NOTIFY_SEND_POSSIBLE and trigger a retry. * c->suspend_count must be zero, or we would not be trying to send. */ c->suspend_count++; c->state |= NOTIFY_CLIENT_STATE_SUSPENDED; c->state |= NOTIFY_CLIENT_STATE_PENDING; c->state |= NOTIFY_CLIENT_STATE_TIMEOUT; return NOTIFY_STATUS_OK; } return NOTIFY_STATUS_FAILED; } else if (kstatus != KERN_SUCCESS) return NOTIFY_STATUS_FAILED; c->state &= ~NOTIFY_CLIENT_STATE_PENDING; c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; return NOTIFY_STATUS_OK; } default: { break; } } c->state &= ~NOTIFY_CLIENT_STATE_PENDING; c->state &= ~NOTIFY_CLIENT_STATE_TIMEOUT; return NOTIFY_STATUS_OK; }
mach_msg_return_t mach_msg_server( boolean_t (*demux)(mach_msg_header_t *, mach_msg_header_t *), mach_msg_size_t max_size, mach_port_t rcv_name, mach_msg_options_t server_options) { mig_reply_error_t *bufRequest, *bufReply, *bufTemp; mach_msg_return_t mr; mach_msg_options_t options; static char here[] = "mach_msg_server"; bufRequest = (mig_reply_error_t *)kalloc(max_size + MAX_TRAILER_SIZE); if (bufRequest == 0) return KERN_RESOURCE_SHORTAGE; bufReply = (mig_reply_error_t *)kalloc(max_size + MAX_TRAILER_SIZE); if (bufReply == 0) return KERN_RESOURCE_SHORTAGE; for (;;) { get_request: mr = mach_msg(&bufRequest->Head, MACH_RCV_MSG | server_options, 0, max_size, rcv_name, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); while (mr == MACH_MSG_SUCCESS) { /* we have a request message */ (void) (*demux)(&bufRequest->Head, &bufReply->Head); if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && bufReply->RetCode != KERN_SUCCESS) { if (bufReply->RetCode == MIG_NO_REPLY) goto get_request; /* * Don't destroy the reply port right, * so we can send an error message */ bufRequest->Head.msgh_remote_port = MACH_PORT_NULL; mach_msg_destroy(&bufRequest->Head); } if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) { /* no reply port, so destroy the reply */ if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) mach_msg_destroy(&bufReply->Head); goto get_request; } /* send reply and get next request */ bufTemp = bufRequest; bufRequest = bufReply; bufReply = bufTemp; /* * We don't want to block indefinitely because the * client isn't receiving messages from the reply port. * If we have a send-once right for the reply port, * then this isn't a concern because the send won't * block. * If we have a send right, we need to use * MACH_SEND_TIMEOUT. * To avoid falling off the kernel's fast RPC path * unnecessarily, we only supply MACH_SEND_TIMEOUT when * absolutely necessary. */ options = MACH_SEND_MSG | MACH_RCV_MSG | server_options; if (MACH_MSGH_BITS_REMOTE(bufRequest->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) { options |= MACH_SEND_TIMEOUT; } mr = mach_msg(&bufRequest->Head, options, bufRequest->Head.msgh_size, max_size, rcv_name, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); } /* a message error occurred */ switch (mr) { case MACH_SEND_INVALID_DEST: case MACH_SEND_TIMED_OUT: /* the reply can't be delivered, so destroy it */ mach_msg_destroy(&bufRequest->Head); break; case MACH_RCV_TOO_LARGE: /* the kernel destroyed the request */ break; default: dprintf(("mach_msg_overwrite_trap returned 0x%x %s\n", mr, mach_error_string(mr))); Panic("mach_msg failed"); /* should only happen if the server is buggy */ kfree((char *) bufRequest, max_size + MAX_TRAILER_SIZE); kfree((char *) bufReply, max_size + MAX_TRAILER_SIZE); return mr; } } }
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // SendFrameArrivedMessage() //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void ClientStream::SendFrameArrivedMessage(mach_port_t& recipient, Frame& frame) { // Setup the message FrameArrivedMessage message = { { MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND) | MACH_MSGH_BITS_COMPLEX, // mHeader.msgh_bits sizeof(FrameArrivedMessage), // mHeader.msgh_size recipient, // mHeader.msgh_remote_port MACH_PORT_NULL, // mHeader.msgh_local_port 0, // mHeader.msgh_reserved kFrameArrived // mHeader.msgh_id }, { 1 // mBody.msgh_descriptor_count }, { // The mach_msg_ool_descriptor_t structure is layed out differently for 32 vs 64 bit architectures, so it is not intialiazed here }, frame.GetFrameType(), // mFrameType frame.GetHostTime(), // mHostTime frame.GetTimingInfo(), // mTimingInfo frame.GetDiscontinuityFlags() | GetDiscontinuityFlags(), // mDiscontinuityFlags frame.GetDroppedFrameCount(), // mDroppedFrameCount frame.GetFirstFrameTime() // mFirstFrameTime }; // Initialize the mach_msg_ool_descriptor_t portion of the message message.mDescriptor.address = frame.Get(); message.mDescriptor.size = frame.Size(); message.mDescriptor.deallocate = false; message.mDescriptor.copy = MACH_MSG_VIRTUAL_COPY; message.mDescriptor.type = MACH_MSG_OOL_DESCRIPTOR; // If this frame or the ClientStream has any "hard" discontinuities in it, "extended duration" timing can't be used if (~kCMIOSampleBufferDiscontinuityFlag_DurationWasExtended & (frame.GetDiscontinuityFlags() | GetDiscontinuityFlags())) mExtendedFrameHostTime = 0; // Use the "extended duration" timing if needed (indicated by a non-zero value for mExtendedFrameHostTime) if (0 != mExtendedFrameHostTime) { // Use the extended frame host & cycle time message.mHostTime = mExtendedFrameHostTime; // Use the extended frame timing info & add the current frame's duration to the extended frame's duration message.mTimingInfo = mExtendedFrameTimingInfo; message.mTimingInfo.duration = CMTimeAdd(message.mTimingInfo.duration, frame.GetTimingInfo().duration); // Indicate this frame has an extended duration message.mDiscontinuityFlags |= kCMIOSampleBufferDiscontinuityFlag_DurationWasExtended; } // Send the message mach_msg_return_t err = mach_msg(&message.mHeader, MACH_SEND_MSG | MACH_SEND_TIMEOUT, message.mHeader.msgh_size, 0, MACH_PORT_NULL, 15, MACH_PORT_NULL); if (MACH_MSG_SUCCESS == err) { // The message was sent successfully, so clear the discontinuity flags SetDiscontinuityFlags(kCMIOSampleBufferNoDiscontinuities); // Reset the extended frame host time to 0 to signify that no extension is needed mExtendedFrameHostTime = 0; } else { DebugMessage("SendFrameArrivedMessage() - Error sending frame to port %d 0x%08X", recipient, err); // Something went wrong, so destroy the message so that all of its resources will be properly released mach_msg_destroy(&message.mHeader); // Update the recipient since it might have a new value since the send failed recipient = message.mHeader.msgh_remote_port; // Try and use "extended duration" timing if this frame and the ClientStream lacks any "hard" discontinuities if (~kCMIOSampleBufferDiscontinuityFlag_DurationWasExtended & (frame.GetDiscontinuityFlags() | GetDiscontinuityFlags())) { // The were hard discontinuities, so update the ClientStream's discontinuity flags so they logical sum can be passed on with the next frame SetDiscontinuityFlags(GetDiscontinuityFlags() | frame.GetDiscontinuityFlags() | kCMIOSampleBufferDiscontinuityFlag_StreamDiscontinuity); } else { // Rather than mark a "hard" discontinuity, remember the frame's duration and so the NEXT frame's can be extended accordingly if (0 == mExtendedFrameHostTime) { // This is the first extension needed, so use this frame's host & cycle time for the next frame mExtendedFrameHostTime = frame.GetHostTime(); mExtendedFrameTimingInfo = frame.GetTimingInfo(); } else { // An extension is already taking place, so simply add this frame's duration to the extended frame's duration mExtendedFrameTimingInfo.duration = CMTimeAdd(mExtendedFrameTimingInfo.duration, frame.GetTimingInfo().duration); } } } // Remove this client from the set of the native frame needs to message frame.RemoveClient(mClient); }
//------------------------------------------------------------------------------ // __IOMIGMachPortPortCallback //------------------------------------------------------------------------------ void __IOMIGMachPortPortCallback(CFMachPortRef port __unused, void *msg, CFIndex size __unused, void *info) { IOMIGMachPortRef migPort = (IOMIGMachPortRef)info; mig_reply_error_t * bufRequest = msg; mig_reply_error_t * bufReply = NULL; mach_msg_return_t mr; int options; require(migPort, exit); CFRetain(migPort); bufReply = CFAllocatorAllocate(NULL, migPort->maxMessageSize, 0); require(bufReply, exit); // let's see if we have no more senders if ( __NoMoreSenders(&bufRequest->Head, &bufReply->Head) ) { if ( migPort->terminationCallback ) (*migPort->terminationCallback)(migPort, migPort->terminationRefcon); else { goto exit; } } else { if ( migPort->demuxCallback ) (*migPort->demuxCallback)(migPort, &bufRequest->Head, &bufReply->Head, migPort->demuxRefcon); else { mach_msg_destroy(&bufRequest->Head); goto exit; } } if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (bufReply->RetCode != KERN_SUCCESS)) { //This return code is a little tricky -- it appears that the //demux routine found an error of some sort, but since that //error would not normally get returned either to the local //user or the remote one, we pretend it's ok. require(bufReply->RetCode != MIG_NO_REPLY, exit); // destroy any out-of-line data in the request buffer but don't destroy // the reply port right (since we need that to send an error message). bufRequest->Head.msgh_remote_port = MACH_PORT_NULL; mach_msg_destroy(&bufRequest->Head); } if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) { //no reply port, so destroy the reply if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) { mach_msg_destroy(&bufReply->Head); } goto exit; } // send reply. // We don't want to block indefinitely because the migPort // isn't receiving messages from the reply port. // If we have a send-once right for the reply port, then // this isn't a concern because the send won't block. // If we have a send right, we need to use MACH_SEND_TIMEOUT. // To avoid falling off the kernel's fast RPC path unnecessarily, // we only supply MACH_SEND_TIMEOUT when absolutely necessary. options = MACH_SEND_MSG; if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) { options |= MACH_SEND_TIMEOUT; } mr = mach_msg(&bufReply->Head, options, bufReply->Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); // Has a message error occurred? switch (mr) { case MACH_SEND_INVALID_DEST: case MACH_SEND_TIMED_OUT: // the reply can't be delivered, so destroy it mach_msg_destroy(&bufReply->Head); break; default : // Includes success case. break; } exit: if ( bufReply ) CFAllocatorDeallocate(NULL, bufReply); if ( migPort ) CFRelease(migPort); }