Blame mach/msgserver.c

Packit 6c4009
/* Copyright (C) 1993-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* Based on CMU's mach_msg_server.c revision 2.4 of 91/05/14, and thus
Packit 6c4009
   under the following copyright.  Rewritten by Roland McGrath (FSF)
Packit 6c4009
   93/12/06 to use stack space instead of malloc, and to handle
Packit 6c4009
   large messages with MACH_RCV_LARGE.  */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Mach Operating System
Packit 6c4009
 * Copyright (c) 1991,1990 Carnegie Mellon University
Packit 6c4009
 * All Rights Reserved.
Packit 6c4009
 *
Packit 6c4009
 * Permission to use, copy, modify and distribute this software and its
Packit 6c4009
 * documentation is hereby granted, provided that both the copyright
Packit 6c4009
 * notice and this permission notice appear in all copies of the
Packit 6c4009
 * software, derivative works or modified versions, and any portions
Packit 6c4009
 * thereof, and that both notices appear in supporting documentation.
Packit 6c4009
 *
Packit 6c4009
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
Packit 6c4009
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
Packit 6c4009
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
Packit 6c4009
 *
Packit 6c4009
 * Carnegie Mellon requests users of this software to return to
Packit 6c4009
 *
Packit 6c4009
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
Packit 6c4009
 *  School of Computer Science
Packit 6c4009
 *  Carnegie Mellon University
Packit 6c4009
 *  Pittsburgh PA 15213-3890
Packit 6c4009
 *
Packit 6c4009
 * any improvements or extensions that they make and grant Carnegie Mellon
Packit 6c4009
 * the rights to redistribute these changes.
Packit 6c4009
 */
Packit 6c4009
/*
Packit 6c4009
 * (pre-GNU) HISTORY
Packit 6c4009
 *
Packit 6c4009
 * Revision 2.4  91/05/14  17:53:22  mrt
Packit 6c4009
 * 	Correcting copyright
Packit 6c4009
 *
Packit 6c4009
 * Revision 2.3  91/02/14  14:17:47  mrt
Packit 6c4009
 * 	Added new Mach copyright
Packit 6c4009
 * 	[91/02/13  12:44:20  mrt]
Packit 6c4009
 *
Packit 6c4009
 * Revision 2.2  90/08/06  17:23:58  rpd
Packit 6c4009
 * 	Created.
Packit 6c4009
 *
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
Packit 6c4009
#include <mach.h>
Packit 6c4009
#include <mach/mig_errors.h>
Packit 6c4009
#include <stdlib.h>		/* For malloc and free.  */
Packit 6c4009
#include <assert.h>
Packit 6c4009
Packit 6c4009
#ifdef NDR_CHAR_ASCII		/* OSF Mach flavors have different names.  */
Packit 6c4009
# define mig_reply_header_t	mig_reply_error_t
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
mach_msg_return_t
Packit 6c4009
__mach_msg_server_timeout (boolean_t (*demux) (mach_msg_header_t *request,
Packit 6c4009
					       mach_msg_header_t *reply),
Packit 6c4009
			   mach_msg_size_t max_size,
Packit 6c4009
			   mach_port_t rcv_name,
Packit 6c4009
			   mach_msg_option_t option,
Packit 6c4009
			   mach_msg_timeout_t timeout)
Packit 6c4009
{
Packit 6c4009
  mig_reply_header_t *request, *reply;
Packit 6c4009
  mach_msg_return_t mr;
Packit 6c4009
Packit 6c4009
  if (max_size == 0)
Packit 6c4009
    {
Packit 6c4009
#ifdef MACH_RCV_LARGE
Packit 6c4009
      option |= MACH_RCV_LARGE;
Packit 6c4009
      max_size = 2 * __vm_page_size; /* Generic.  Good? XXX */
Packit 6c4009
#else
Packit 6c4009
      max_size = 4 * __vm_page_size; /* XXX */
Packit 6c4009
#endif
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  request = __alloca (max_size);
Packit 6c4009
  reply = __alloca (max_size);
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
    get_request:
Packit 6c4009
      mr = __mach_msg (&request->Head, MACH_RCV_MSG|option,
Packit 6c4009
		       0, max_size, rcv_name,
Packit 6c4009
		       timeout, MACH_PORT_NULL);
Packit 6c4009
      while (mr == MACH_MSG_SUCCESS)
Packit 6c4009
	{
Packit 6c4009
	  /* We have a request message.
Packit 6c4009
	     Pass it to DEMUX for processing.  */
Packit 6c4009
Packit 6c4009
	  (void) (*demux) (&request->Head, &reply->Head);
Packit 6c4009
	  assert (reply->Head.msgh_size <= max_size);
Packit 6c4009
Packit 6c4009
	  switch (reply->RetCode)
Packit 6c4009
	    {
Packit 6c4009
	    case KERN_SUCCESS:
Packit 6c4009
	      /* Hunky dory.  */
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    case MIG_NO_REPLY:
Packit 6c4009
	      /* The server function wanted no reply sent.
Packit 6c4009
		 Loop for another request.  */
Packit 6c4009
	      goto get_request;
Packit 6c4009
Packit 6c4009
	    default:
Packit 6c4009
	      /* Some error; destroy the request message to release any
Packit 6c4009
		 port rights or VM it holds.  Don't destroy the reply port
Packit 6c4009
		 right, so we can send an error message.  */
Packit 6c4009
	      request->Head.msgh_remote_port = MACH_PORT_NULL;
Packit 6c4009
	      __mach_msg_destroy (&request->Head);
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
Packit 6c4009
	    {
Packit 6c4009
	      /* No reply port, so destroy the reply.  */
Packit 6c4009
	      if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
Packit 6c4009
		__mach_msg_destroy (&reply->Head);
Packit 6c4009
	      goto get_request;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Send the reply and the get next request.  */
Packit 6c4009
Packit 6c4009
	  {
Packit 6c4009
	    /* Swap the request and reply buffers.  mach_msg will read the
Packit 6c4009
	       reply message from the buffer we pass and write the new
Packit 6c4009
	       request message to the same buffer.  */
Packit 6c4009
	    void *tmp = request;
Packit 6c4009
	    request = reply;
Packit 6c4009
	    reply = tmp;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	  mr = __mach_msg (&request->Head,
Packit 6c4009
			   MACH_SEND_MSG|MACH_RCV_MSG|option,
Packit 6c4009
			   request->Head.msgh_size, max_size, rcv_name,
Packit 6c4009
			   timeout, MACH_PORT_NULL);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* A message error occurred.  */
Packit 6c4009
Packit 6c4009
      switch (mr)
Packit 6c4009
	{
Packit 6c4009
	case MACH_RCV_TOO_LARGE:
Packit 6c4009
#ifdef MACH_RCV_LARGE
Packit 6c4009
	  /* The request message is larger than MAX_SIZE, and has not
Packit 6c4009
	     been dequeued.  The message header has the actual size of
Packit 6c4009
	     the message.  We recurse here in hopes that the compiler
Packit 6c4009
	     will optimize the tail-call and allocate some more stack
Packit 6c4009
	     space instead of way too much.  */
Packit 6c4009
	  return __mach_msg_server_timeout (demux, request->Head.msgh_size,
Packit 6c4009
					    rcv_name, option, timeout);
Packit 6c4009
#else
Packit 6c4009
	  /* XXX the kernel has destroyed the msg */
Packit 6c4009
	  break;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	case MACH_SEND_INVALID_DEST:
Packit 6c4009
	  /* The reply can't be delivered, so destroy it.  This error
Packit 6c4009
	     indicates only that the requester went away, so we
Packit 6c4009
	     continue and get the next request.  */
Packit 6c4009
	  __mach_msg_destroy (&request->Head);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	  /* Some other form of lossage; return to caller.  */
Packit 6c4009
	  return mr;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
weak_alias (__mach_msg_server_timeout, mach_msg_server_timeout)
Packit 6c4009
Packit 6c4009
mach_msg_return_t
Packit 6c4009
__mach_msg_server (boolean_t (*demux) (mach_msg_header_t *in,
Packit 6c4009
				       mach_msg_header_t *out),
Packit 6c4009
		   mach_msg_size_t max_size,
Packit 6c4009
		   mach_port_t rcv_name)
Packit 6c4009
{
Packit 6c4009
  return __mach_msg_server_timeout (demux, max_size, rcv_name,
Packit 6c4009
				    MACH_MSG_OPTION_NONE,
Packit 6c4009
				    MACH_MSG_TIMEOUT_NONE);
Packit 6c4009
}
Packit 6c4009
weak_alias (__mach_msg_server, mach_msg_server)