Пример #1
0
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;
    
}
Пример #2
0
/* -----------------------------------------------------------------------------
----------------------------------------------------------------------------- */
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
/* -----------------------------------------------------------------------------
----------------------------------------------------------------------------- */
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);
}
Пример #6
0
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
}
Пример #8
0
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;
	}
}
Пример #9
0
__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;
}
Пример #10
0
/*
 * 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;
}
Пример #11
0
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);
	}
Пример #13
0
//------------------------------------------------------------------------------
// __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);
}