| /* | 
 |  * Mach Operating System | 
 |  * Copyright (c) 1991,1990 Carnegie Mellon University | 
 |  * All Rights Reserved. | 
 |  * | 
 |  * Permission to use, copy, modify and distribute this software and its | 
 |  * documentation is hereby granted, provided that both the copyright | 
 |  * notice and this permission notice appear in all copies of the | 
 |  * software, derivative works or modified versions, and any portions | 
 |  * thereof, and that both notices appear in supporting documentation. | 
 |  * | 
 |  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | 
 |  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | 
 |  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | 
 |  * | 
 |  * Carnegie Mellon requests users of this software to return to | 
 |  * | 
 |  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU | 
 |  *  School of Computer Science | 
 |  *  Carnegie Mellon University | 
 |  *  Pittsburgh PA 15213-3890 | 
 |  * | 
 |  * any improvements or extensions that they make and grant Carnegie Mellon | 
 |  * the rights to redistribute these changes. | 
 |  */ | 
 | /* | 
 |  * (pre-GNU) HISTORY | 
 |  * | 
 |  * Revision 2.4  91/05/14  17:53:15  mrt | 
 |  * 	Correcting copyright | 
 |  * | 
 |  * Revision 2.3  91/02/14  14:17:43  mrt | 
 |  * 	Added new Mach copyright | 
 |  * 	[91/02/13  12:44:15  mrt] | 
 |  * | 
 |  * Revision 2.2  90/08/06  17:24:22  rpd | 
 |  * 	Created. | 
 |  * | 
 |  */ | 
 |  | 
 | #if 1 | 
 | #include <mach.h> | 
 | #else | 
 | /* This is what CMU did, but that fails to declare some used functions.  */ | 
 | #include <mach/port.h> | 
 | #include <mach/message.h> | 
 | #include <mach_init.h> | 
 | #endif | 
 |  | 
 | static void mach_msg_destroy_port(mach_port_t, mach_msg_type_name_t); | 
 | static void mach_msg_destroy_memory(vm_offset_t, vm_size_t); | 
 |  | 
 | /* | 
 |  *	Routine:	mach_msg_destroy | 
 |  *	Purpose: | 
 |  *		Deallocates all port rights and out-of-line memory | 
 |  *		found in a received message. | 
 |  */ | 
 |  | 
 | void | 
 | __mach_msg_destroy (mach_msg_header_t *msg) | 
 | { | 
 |     mach_msg_bits_t mbits = msg->msgh_bits; | 
 |  | 
 |     /* | 
 |      *	The msgh_local_port field doesn't hold a port right. | 
 |      *	The receive operation consumes the destination port right. | 
 |      */ | 
 |  | 
 |     mach_msg_destroy_port(msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(mbits)); | 
 |  | 
 |     if (mbits & MACH_MSGH_BITS_COMPLEX) { | 
 | #ifdef MACH_MSG_PORT_DESCRIPTOR | 
 | 	mach_msg_body_t		*body; | 
 | 	mach_msg_descriptor_t	*saddr, *eaddr; | 
 |  | 
 | 	body = (mach_msg_body_t *) (msg + 1); | 
 | 	saddr = (mach_msg_descriptor_t *) | 
 | 			((mach_msg_base_t *) msg + 1); | 
 | 	eaddr =  saddr + body->msgh_descriptor_count; | 
 |  | 
 | 	for  ( ; saddr < eaddr; saddr++) { | 
 | 	    switch (saddr->type.type) { | 
 |  | 
 | 	        case MACH_MSG_PORT_DESCRIPTOR: { | 
 | 		    mach_msg_port_descriptor_t *dsc; | 
 |  | 
 | 		    /* | 
 | 		     * Destroy port rights carried in the message | 
 | 		     */ | 
 | 		    dsc = &saddr->port; | 
 | 		    mach_msg_destroy_port(dsc->name, dsc->disposition); | 
 | 		    break; | 
 | 	        } | 
 |  | 
 | 	        case MACH_MSG_OOL_DESCRIPTOR : { | 
 | 		    mach_msg_ool_descriptor_t *dsc; | 
 |  | 
 | 		    /* | 
 | 		     * Destroy memory carried in the message | 
 | 		     */ | 
 | 		    dsc = &saddr->out_of_line; | 
 | 		    if (dsc->deallocate) { | 
 | 		        mach_msg_destroy_memory((vm_offset_t)dsc->address, | 
 | 						dsc->size); | 
 | 		    } | 
 | 		    break; | 
 | 	        } | 
 |  | 
 | 	        case MACH_MSG_OOL_PORTS_DESCRIPTOR : { | 
 | 		    mach_port_t             		*ports; | 
 | 		    mach_msg_ool_ports_descriptor_t	*dsc; | 
 | 		    mach_msg_type_number_t   		j; | 
 |  | 
 | 		    /* | 
 | 		     * Destroy port rights carried in the message | 
 | 		     */ | 
 | 		    dsc = &saddr->ool_ports; | 
 | 		    ports = (mach_port_t *) dsc->address; | 
 | 		    for (j = 0; j < dsc->count; j++, ports++)  { | 
 | 		        mach_msg_destroy_port(*ports, dsc->disposition); | 
 | 		    } | 
 |  | 
 | 		    /* | 
 | 		     * Destroy memory carried in the message | 
 | 		     */ | 
 | 		    if (dsc->deallocate) { | 
 | 		        mach_msg_destroy_memory((vm_offset_t)dsc->address, | 
 | 					dsc->count * sizeof(mach_port_t)); | 
 | 		    } | 
 | 		    break; | 
 | 	        } | 
 | 	    } | 
 | 	} | 
 | #else | 
 | 	vm_offset_t saddr; | 
 | 	vm_offset_t eaddr; | 
 |  | 
 | 	saddr = (vm_offset_t) (msg + 1); | 
 | 	eaddr = (vm_offset_t) msg + msg->msgh_size; | 
 |  | 
 | 	while (saddr < eaddr) { | 
 | 	    mach_msg_type_long_t *type; | 
 | 	    mach_msg_type_name_t name; | 
 | 	    mach_msg_type_size_t size; | 
 | 	    mach_msg_type_number_t number; | 
 | 	    boolean_t is_inline; | 
 | 	    vm_size_t length; | 
 | 	    vm_offset_t addr; | 
 |  | 
 | 	    type = (mach_msg_type_long_t *) saddr; | 
 | 	    is_inline = type->msgtl_header.msgt_inline; | 
 | 	    if (type->msgtl_header.msgt_longform) { | 
 | 		    name = type->msgtl_name; | 
 | 		    size = type->msgtl_size; | 
 | 		    number = type->msgtl_number; | 
 | 		    saddr += sizeof(mach_msg_type_long_t); | 
 | 	    } else { | 
 | 		    name = type->msgtl_header.msgt_name; | 
 | 		    size = type->msgtl_header.msgt_size; | 
 | 		    number = type->msgtl_header.msgt_number; | 
 | 		    saddr += sizeof(mach_msg_type_t); | 
 | 	    } | 
 |  | 
 | 	    /* calculate length of data in bytes, rounding up */ | 
 | 	    length = (((((number * size) + 7) >> 3) + sizeof (int) - 1) | 
 | 		      &~ (sizeof (int) - 1)); | 
 |  | 
 | 	    addr = is_inline ? saddr : * (vm_offset_t *) saddr; | 
 |  | 
 | 	    if (MACH_MSG_TYPE_PORT_ANY(name)) { | 
 | 		mach_port_t *ports = (mach_port_t *) addr; | 
 | 		mach_msg_type_number_t i; | 
 |  | 
 | 		for (i = 0; i < number; i++) | 
 | 		    mach_msg_destroy_port(*ports++, name); | 
 | 	    } | 
 |  | 
 | 	    if (is_inline) { | 
 | 		/* inline data sizes round up to int boundaries */ | 
 | 		saddr += length; | 
 | 	    } else { | 
 | 		mach_msg_destroy_memory(addr, length); | 
 | 		saddr += sizeof(vm_offset_t); | 
 | 	    } | 
 | 	} | 
 | #endif | 
 |     } | 
 | } | 
 |  | 
 | weak_alias (__mach_msg_destroy, mach_msg_destroy) | 
 |  | 
 | static void | 
 | mach_msg_destroy_port (mach_port_t port, mach_msg_type_name_t type) | 
 | { | 
 |     if (MACH_PORT_VALID(port)) switch (type) { | 
 |       case MACH_MSG_TYPE_MOVE_SEND: | 
 |       case MACH_MSG_TYPE_MOVE_SEND_ONCE: | 
 | 	/* destroy the send/send-once right */ | 
 | 	(void) __mach_port_deallocate(mach_task_self(), port); | 
 | 	break; | 
 |  | 
 |       case MACH_MSG_TYPE_MOVE_RECEIVE: | 
 | 	/* destroy the receive right */ | 
 | 	(void) __mach_port_mod_refs(mach_task_self(), port, | 
 | 				    MACH_PORT_RIGHT_RECEIVE, -1); | 
 | 	break; | 
 |  | 
 |       case MACH_MSG_TYPE_MAKE_SEND: | 
 | 	/* create a send right and then destroy it */ | 
 | 	(void) __mach_port_insert_right(mach_task_self(), port, | 
 | 					port, MACH_MSG_TYPE_MAKE_SEND); | 
 | 	(void) __mach_port_deallocate(mach_task_self(), port); | 
 | 	break; | 
 |  | 
 |       case MACH_MSG_TYPE_MAKE_SEND_ONCE: | 
 | 	/* create a send-once right and then destroy it */ | 
 | 	(void) __mach_port_extract_right(mach_task_self(), port, | 
 | 					 MACH_MSG_TYPE_MAKE_SEND_ONCE, | 
 | 					 &port, &type); | 
 | 	(void) __mach_port_deallocate(mach_task_self(), port); | 
 | 	break; | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | mach_msg_destroy_memory (vm_offset_t addr, vm_size_t size) | 
 | { | 
 |     if (size > 0) | 
 | 	(void) __vm_deallocate(__mach_task_self(), addr, size); | 
 | } |