+/*
+ * Routine: mach_port_peek [kernel call]
+ * Purpose:
+ * Peek at the message queue for the specified receive
+ * right and return info about a message in the queue.
+ *
+ * On input, seqnop points to a sequence number value
+ * to match the message being peeked. If zero is specified
+ * as the seqno, the first message in the queue will be
+ * peeked.
+ *
+ * Only the following trailer types are currently supported:
+ * MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)
+ *
+ * or'ed with one of these element types:
+ * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_NULL)
+ * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SEQNO)
+ * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)
+ * MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)
+ *
+ * On input, the value pointed to by trailer_sizep must be
+ * large enough to hold the requested trailer size.
+ *
+ * The message sequence number, id, size, requested trailer info
+ * and requested trailer size are returned in their respective
+ * output parameters upon success.
+ *
+ * Conditions:
+ * Nothing locked.
+ * Returns:
+ * KERN_SUCCESS Matching message found, out parameters set.
+ * KERN_INVALID_TASK The space is null or dead.
+ * KERN_INVALID_NAME The name doesn't denote a right.
+ * KERN_INVALID_RIGHT Name doesn't denote receive rights.
+ * KERN_INVALID_VALUE The input parameter values are out of bounds.
+ * KERN_FAILURE The requested message was not found.
+ */
+
+kern_return_t
+mach_port_peek(
+ ipc_space_t space,
+ mach_port_name_t name,
+ mach_msg_trailer_type_t trailer_type,
+ mach_port_seqno_t *seqnop,
+ mach_msg_size_t *msg_sizep,
+ mach_msg_id_t *msg_idp,
+ mach_msg_trailer_info_t trailer_infop,
+ mach_msg_type_number_t *trailer_sizep)
+{
+ ipc_port_t port;
+ kern_return_t kr;
+ boolean_t found;
+ mach_msg_max_trailer_t max_trailer;
+
+ if (space == IS_NULL)
+ return KERN_INVALID_TASK;
+
+ if (!MACH_PORT_VALID(name))
+ return KERN_INVALID_RIGHT;
+
+ /*
+ * We don't allow anything greater than the audit trailer - to avoid
+ * leaking the context pointer and to avoid variable-sized context issues.
+ */
+ if (GET_RCV_ELEMENTS(trailer_type) > MACH_RCV_TRAILER_AUDIT ||
+ REQUESTED_TRAILER_SIZE(TRUE, trailer_type) > *trailer_sizep)
+ return KERN_INVALID_VALUE;
+
+ *trailer_sizep = REQUESTED_TRAILER_SIZE(TRUE, trailer_type);
+
+ kr = ipc_port_translate_receive(space, name, &port);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ /* Port locked and active */
+
+ found = ipc_mqueue_peek(&port->ip_messages, seqnop,
+ msg_sizep, msg_idp, &max_trailer);
+ ip_unlock(port);
+
+ if (found != TRUE)
+ return KERN_FAILURE;
+
+ max_trailer.msgh_seqno = *seqnop;
+ memcpy(trailer_infop, &max_trailer, *trailer_sizep);
+
+ return KERN_SUCCESS;
+}
+