- 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));
- mach_msg_destroy_port(msg->msgh_voucher_port, MACH_MSGH_BITS_VOUCHER(mbits));
-
- if (mbits & MACH_MSGH_BITS_COMPLEX) {
- mach_msg_base_t *base;
- mach_msg_type_number_t count, i;
- mach_msg_descriptor_t *daddr;
-
- base = (mach_msg_base_t *) msg;
- count = base->body.msgh_descriptor_count;
-
- daddr = (mach_msg_descriptor_t *) (base + 1);
- for (i = 0; i < count; i++) {
-
- switch (daddr->type.type) {
-
- case MACH_MSG_PORT_DESCRIPTOR: {
- mach_msg_port_descriptor_t *dsc;
-
- /*
- * Destroy port rights carried in the message
- */
- dsc = &daddr->port;
- mach_msg_destroy_port(dsc->name, dsc->disposition);
- daddr = (mach_msg_descriptor_t *)(dsc + 1);
- break;
- }
-
- case MACH_MSG_OOL_DESCRIPTOR: {
- mach_msg_ool_descriptor_t *dsc;
-
- /*
- * Destroy memory carried in the message
- */
- dsc = &daddr->out_of_line;
- if (dsc->deallocate) {
- mach_msg_destroy_memory((vm_offset_t)dsc->address,
- dsc->size);
- }
- daddr = (mach_msg_descriptor_t *)(dsc + 1);
- break;
- }
-
- case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: {
- mach_msg_ool_descriptor_t *dsc;
-
- /*
- * Just skip it.
- */
- dsc = &daddr->out_of_line;
- daddr = (mach_msg_descriptor_t *)(dsc + 1);
- 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 = &daddr->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));
- }
- daddr = (mach_msg_descriptor_t *)(dsc + 1);
- break;
- }
- }
+ 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));
+ mach_msg_destroy_port(msg->msgh_voucher_port, MACH_MSGH_BITS_VOUCHER(mbits));
+
+ if (mbits & MACH_MSGH_BITS_COMPLEX) {
+ mach_msg_base_t *base;
+ mach_msg_type_number_t count, i;
+ mach_msg_descriptor_t *daddr;
+
+ base = (mach_msg_base_t *) msg;
+ count = base->body.msgh_descriptor_count;
+
+ daddr = (mach_msg_descriptor_t *) (base + 1);
+ for (i = 0; i < count; i++) {
+ switch (daddr->type.type) {
+ case MACH_MSG_PORT_DESCRIPTOR: {
+ mach_msg_port_descriptor_t *dsc;
+
+ /*
+ * Destroy port rights carried in the message
+ */
+ dsc = &daddr->port;
+ mach_msg_destroy_port(dsc->name, dsc->disposition);
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
+ break;
+ }
+
+ case MACH_MSG_OOL_DESCRIPTOR: {
+ mach_msg_ool_descriptor_t *dsc;
+
+ /*
+ * Destroy memory carried in the message
+ */
+ dsc = &daddr->out_of_line;
+ if (dsc->deallocate) {
+ mach_msg_destroy_memory((vm_offset_t)dsc->address,
+ dsc->size);
+ }
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
+ break;
+ }
+
+ case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: {
+ mach_msg_ool_descriptor_t *dsc;
+
+ /*
+ * Just skip it.
+ */
+ dsc = &daddr->out_of_line;
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
+ 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 = &daddr->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));
+ }
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
+ break;
+ }
+
+ case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
+ mach_msg_guarded_port_descriptor_t *dsc;
+ mach_msg_guard_flags_t flags;
+ /*
+ * Destroy port right carried in the message
+ */
+ dsc = &daddr->guarded_port;
+ flags = dsc->flags;
+ if ((flags & MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND) == 0) {
+ /* Need to unguard before destroying the port */
+ mach_port_unguard(mach_task_self_, dsc->name, (uint64_t)dsc->context);
+ }
+ mach_msg_destroy_port(dsc->name, dsc->disposition);
+ daddr = (mach_msg_descriptor_t *)(dsc + 1);
+ break;
+ }
+ }
+ }
+ }
+}
+
+static inline boolean_t
+mach_msg_server_is_recoverable_send_error(kern_return_t kr)
+{
+ switch (kr) {
+ case MACH_SEND_INVALID_DEST:
+ case MACH_SEND_TIMED_OUT:
+ case MACH_SEND_INTERRUPTED:
+ return TRUE;
+ default:
+ /*
+ * Other errors mean that the message may have been partially destroyed
+ * by the kernel, and these can't be recovered and may leak resources.
+ */
+ return FALSE;
+ }
+}
+
+static kern_return_t
+mach_msg_server_mig_return_code(mig_reply_error_t *reply)
+{
+ /*
+ * If the message is complex, it is assumed that the reply was successful,
+ * as the RetCode is where the count of out of line descriptors is.
+ *
+ * If not, we read RetCode.
+ */
+ if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+ return KERN_SUCCESS;
+ }
+ return reply->RetCode;
+}
+
+static void
+mach_msg_server_consume_unsent_message(mach_msg_header_t *hdr)
+{
+ /* mach_msg_destroy doesn't handle the local port */
+ mach_port_t port = hdr->msgh_local_port;
+ if (MACH_PORT_VALID(port)) {
+ switch (MACH_MSGH_BITS_LOCAL(hdr->msgh_bits)) {
+ 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);
+ hdr->msgh_local_port = MACH_PORT_NULL;
+ break;
+ }