2023-01-28 04:54:20 +00:00
|
|
|
|
// Copyright 2014 The Crashpad Authors
|
2022-04-02 01:21:55 +00:00
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
#ifndef CRASHPAD_UTIL_MACH_NOTIFY_SERVER_H_
|
|
|
|
|
#define CRASHPAD_UTIL_MACH_NOTIFY_SERVER_H_
|
|
|
|
|
|
|
|
|
|
#include <mach/mach.h>
|
|
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
|
|
#include "util/mach/mach_message_server.h"
|
|
|
|
|
|
|
|
|
|
namespace crashpad {
|
|
|
|
|
|
|
|
|
|
//! \brief A server interface for the `notify` Mach subsystem.
|
|
|
|
|
//!
|
|
|
|
|
//! The <a
|
|
|
|
|
//! href="https://lists.apple.com/archives/darwin-development/2001/Sep/msg00451.html">mach
|
|
|
|
|
//! port notifications</a> thread on the <a
|
|
|
|
|
//! href="https://lists.apple.com/archives/darwin-development/">darwin-development</a>
|
|
|
|
|
//! mailing list (now known as <a
|
|
|
|
|
//! href="https://lists.apple.com/mailman/listinfo/darwin-dev">darwin-dev</a>)
|
|
|
|
|
//! is good background for the various notification types.
|
|
|
|
|
class NotifyServer : public MachMessageServer::Interface {
|
|
|
|
|
public:
|
|
|
|
|
//! \brief An interface that the different request messages that are a part of
|
|
|
|
|
//! the `notify` Mach subsystem can be dispatched to.
|
|
|
|
|
//!
|
|
|
|
|
//! Default implementations of all methods are available in the
|
|
|
|
|
//! DefaultInterface class.
|
|
|
|
|
class Interface {
|
|
|
|
|
public:
|
|
|
|
|
//! \brief Handles port-deleted notifications sent by
|
|
|
|
|
//! `mach_notify_port_deleted()`.
|
|
|
|
|
//!
|
|
|
|
|
//! A port-deleted notification is generated when a port with a dead-name
|
|
|
|
|
//! notification request is destroyed and the port name becomes available
|
|
|
|
|
//! for reuse.
|
|
|
|
|
//!
|
|
|
|
|
//! This behaves equivalently to a `do_mach_notify_port_deleted()` function
|
|
|
|
|
//! used with `notify_server()`.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] notify The Mach port that the notification was sent to.
|
|
|
|
|
//! \param[in] name The name that formerly referenced the deleted port. When
|
|
|
|
|
//! this method is called, \a name no longer corresponds to the port
|
|
|
|
|
//! that has been deleted, and may be reused for another purpose.
|
|
|
|
|
//! \param[in] trailer The trailer received with the notification message.
|
|
|
|
|
virtual kern_return_t DoMachNotifyPortDeleted(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
mach_port_name_t name,
|
|
|
|
|
const mach_msg_trailer_t* trailer) = 0;
|
|
|
|
|
|
|
|
|
|
//! \brief Handles port-destroyed notifications sent by
|
|
|
|
|
//! `mach_notify_port_destroyed()`.
|
|
|
|
|
//!
|
|
|
|
|
//! A port-destroyed notification is generated when a receive right with a
|
|
|
|
|
//! port-destroyed notification request is destroyed. Rather than destroying
|
|
|
|
|
//! the receive right, it is transferred via this notification’s \a rights
|
|
|
|
|
//! parameter.
|
|
|
|
|
//!
|
|
|
|
|
//! This behaves equivalently to a `do_mach_notify_port_destroyed()`
|
|
|
|
|
//! function used with `notify_server()`.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] notify The Mach port that the notification was sent to.
|
|
|
|
|
//! \param[in] rights A receive right for the port that would have been
|
|
|
|
|
//! destroyed. The callee takes ownership of this port, however, if the
|
|
|
|
|
//! callee does not wish to take ownership, it may set \a
|
|
|
|
|
//! destroy_request to `true`.
|
|
|
|
|
//! \param[in] trailer The trailer received with the notification message.
|
|
|
|
|
//! \param[out] destroy_request `true` if the request message is to be
|
|
|
|
|
//! destroyed even when this method returns success. See
|
|
|
|
|
//! MachMessageServer::Interface.
|
|
|
|
|
virtual kern_return_t DoMachNotifyPortDestroyed(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
mach_port_t rights,
|
|
|
|
|
const mach_msg_trailer_t* trailer,
|
|
|
|
|
bool* destroy_request) = 0;
|
|
|
|
|
|
|
|
|
|
//! \brief Handles no-senders notifications sent by
|
|
|
|
|
//! `mach_notify_no_senders()`.
|
|
|
|
|
//!
|
|
|
|
|
//! A no-senders notification is generated when a receive right with a
|
|
|
|
|
//! no-senders notification request loses its last corresponding send right.
|
|
|
|
|
//!
|
|
|
|
|
//! This behaves equivalently to a `do_mach_notify_no_senders()` function
|
|
|
|
|
//! used with `notify_server()`.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] notify The Mach port that the notification was sent to.
|
|
|
|
|
//! \param[in] mscount The value of the sender-less port’s make-send count
|
|
|
|
|
//! at the time the notification was generated.
|
|
|
|
|
//! \param[in] trailer The trailer received with the notification message.
|
|
|
|
|
virtual kern_return_t DoMachNotifyNoSenders(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
mach_port_mscount_t mscount,
|
|
|
|
|
const mach_msg_trailer_t* trailer) = 0;
|
|
|
|
|
|
|
|
|
|
//! \brief Handles send-once notifications sent by
|
|
|
|
|
//! `mach_notify_send_once()`.
|
|
|
|
|
//!
|
|
|
|
|
//! A send-once notification is generated when a send-once right is
|
|
|
|
|
//! destroyed without being used.
|
|
|
|
|
//!
|
|
|
|
|
//! This behaves equivalently to a `do_mach_notify_send_once()` function
|
|
|
|
|
//! used with `notify_server()`.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] notify The Mach port that the notification was sent to.
|
|
|
|
|
//! \param[in] trailer The trailer received with the notification message.
|
|
|
|
|
//!
|
|
|
|
|
//! \note Unlike the other notifications in the `notify` subsystem,
|
|
|
|
|
//! send-once notifications are not generated as a result of a
|
|
|
|
|
//! notification request, but are generated any time a send-once right
|
|
|
|
|
//! is destroyed rather than being used. The notification is sent via
|
|
|
|
|
//! the send-once right to its receiver. These notifications are more
|
|
|
|
|
//! useful for clients, not servers. Send-once notifications are
|
|
|
|
|
//! normally handled by MIG-generated client routines, which make
|
|
|
|
|
//! send-once rights for their reply ports and interpret send-once
|
|
|
|
|
//! notifications as a signal that there will be no reply. Although not
|
|
|
|
|
//! expected to be primarily useful for servers, this method is provided
|
|
|
|
|
//! because send-once notifications are defined as a part of the
|
|
|
|
|
//! `notify` subsystem.
|
|
|
|
|
virtual kern_return_t DoMachNotifySendOnce(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
const mach_msg_trailer_t* trailer) = 0;
|
|
|
|
|
|
|
|
|
|
//! \brief Handles dead-name notifications sent by
|
|
|
|
|
//! `mach_notify_dead_name()`.
|
|
|
|
|
//!
|
|
|
|
|
//! A dead-name notification is generated when a port with a dead-name
|
|
|
|
|
//! notification request is destroyed and the right becomes a dead name.
|
|
|
|
|
//!
|
|
|
|
|
//! This behaves equivalently to a `do_mach_notify_dead_name()` function
|
|
|
|
|
//! used with `notify_server()`.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] notify The Mach port that the notification was sent to.
|
|
|
|
|
//! \param[in] name The dead name. Although this is transferred as a
|
|
|
|
|
//! `mach_port_name_t` and not a `mach_port_t`, the callee assumes an
|
|
|
|
|
//! additional reference to this port when this method is called. See
|
|
|
|
|
//! the note below.
|
|
|
|
|
//! \param[in] trailer The trailer received with the notification message.
|
|
|
|
|
//!
|
|
|
|
|
//! \note When a dead-name notification is generated, the user reference
|
|
|
|
|
//! count of the dead name is incremented. A send right with one
|
|
|
|
|
//! reference that becomes a dead name will have one dead-name
|
|
|
|
|
//! reference, and the dead-name notification will add another dead-name
|
|
|
|
|
//! reference, for a total of 2. DoMachNotifyDeadName() implementations
|
|
|
|
|
//! must take care to deallocate this extra reference. There is no \a
|
|
|
|
|
//! destroy_request parameter to simplify this operation because
|
|
|
|
|
//! dead-name notifications carry a port name only (\a name is of type
|
|
|
|
|
//! `mach_port_name_t`) without transferring port rights, and are thus
|
|
|
|
|
//! not complex Mach messages.
|
|
|
|
|
virtual kern_return_t DoMachNotifyDeadName(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
mach_port_name_t name,
|
|
|
|
|
const mach_msg_trailer_t* trailer) = 0;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
~Interface() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//! \brief A concrete implementation of Interface that provides a default
|
|
|
|
|
//! behavior for all `notify` routines.
|
|
|
|
|
//!
|
|
|
|
|
//! The Mach `notify` subsystem contains a collection of unrelated routines,
|
|
|
|
|
//! and a single server would rarely need to implement all of them. To make it
|
|
|
|
|
//! easier to use NotifyServer, a server can inherit from DefaultInterface
|
|
|
|
|
//! instead of Interface. Unless overridden, each routine in DefaultInterface
|
|
|
|
|
//! returns `MIG_BAD_ID` to indicate to the caller that the `notify` message
|
|
|
|
|
//! was unexpected and not processed.
|
|
|
|
|
class DefaultInterface : public Interface {
|
|
|
|
|
public:
|
|
|
|
|
DefaultInterface(const DefaultInterface&) = delete;
|
|
|
|
|
DefaultInterface& operator=(const DefaultInterface&) = delete;
|
|
|
|
|
|
|
|
|
|
// Interface:
|
|
|
|
|
|
|
|
|
|
kern_return_t DoMachNotifyPortDeleted(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
mach_port_name_t name,
|
|
|
|
|
const mach_msg_trailer_t* trailer) override;
|
|
|
|
|
|
|
|
|
|
kern_return_t DoMachNotifyPortDestroyed(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
mach_port_t rights,
|
|
|
|
|
const mach_msg_trailer_t* trailer,
|
|
|
|
|
bool* destroy_request) override;
|
|
|
|
|
|
|
|
|
|
kern_return_t DoMachNotifyNoSenders(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
mach_port_mscount_t mscount,
|
|
|
|
|
const mach_msg_trailer_t* trailer) override;
|
|
|
|
|
|
|
|
|
|
kern_return_t DoMachNotifySendOnce(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
const mach_msg_trailer_t* trailer) override;
|
|
|
|
|
|
|
|
|
|
kern_return_t DoMachNotifyDeadName(
|
|
|
|
|
notify_port_t notify,
|
|
|
|
|
mach_port_name_t name,
|
|
|
|
|
const mach_msg_trailer_t* trailer) override;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
DefaultInterface() : Interface() {}
|
|
|
|
|
~DefaultInterface() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//! \brief Constructs an object of this class.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] interface The interface to dispatch requests to. Weak.
|
|
|
|
|
explicit NotifyServer(Interface* interface);
|
|
|
|
|
|
|
|
|
|
NotifyServer(const NotifyServer&) = delete;
|
|
|
|
|
NotifyServer& operator=(const NotifyServer&) = delete;
|
|
|
|
|
|
|
|
|
|
// MachMessageServer::Interface:
|
|
|
|
|
|
|
|
|
|
bool MachMessageServerFunction(const mach_msg_header_t* in_header,
|
|
|
|
|
mach_msg_header_t* out_header,
|
|
|
|
|
bool* destroy_complex_request) override;
|
|
|
|
|
|
|
|
|
|
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override;
|
|
|
|
|
|
|
|
|
|
mach_msg_size_t MachMessageServerRequestSize() override;
|
|
|
|
|
mach_msg_size_t MachMessageServerReplySize() override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Interface* interface_; // weak
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace crashpad
|
|
|
|
|
|
|
|
|
|
#endif // CRASHPAD_UTIL_MACH_NOTIFY_SERVER_H_
|