#ifndef _H_MACHPP
#define _H_MACHPP
#include <security_utilities/utilities.h>
#include <security_utilities/errors.h>
#include <security_utilities/threading.h>
#include <security_utilities/globalizer.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include <set>
#include <sys/types.h>
#include <unistd.h>
namespace Security {
namespace MachPlusPlus {
class Error : public CommonError {
protected:
Error(kern_return_t err);
public:
virtual ~Error() throw();
virtual OSStatus osStatus() const;
virtual int unixError() const;
const kern_return_t error;
static void check(kern_return_t err);
static void throwMe(kern_return_t err) __attribute__((noreturn));
};
inline void check(kern_return_t status)
{ Error::check(status); }
void *allocate(size_t size);
void deallocate(vm_address_t addr, size_t size);
inline void deallocate(const void *addr, size_t size)
{ deallocate(reinterpret_cast<vm_address_t>(addr), size); }
class Port {
protected:
static mach_port_t self() { return mach_task_self(); }
public:
Port() { mPort = MACH_PORT_NULL; }
Port(mach_port_t port) { mPort = port; }
operator mach_port_t () const { return mPort; }
mach_port_t &port () { return mPort; }
const mach_port_t &port () const { return mPort; }
mach_port_type_t type() const
{ mach_port_type_t typ; check(mach_port_type(self(), mPort, &typ)); return typ; }
bool isType(mach_port_type_t typ) const { return type() & typ; }
bool isDead() const { return isType(MACH_PORT_TYPE_DEAD_NAME); }
void allocate(mach_port_right_t right = MACH_PORT_RIGHT_RECEIVE)
{ check(mach_port_allocate(self(), right, &mPort)); }
void deallocate() { check(mach_port_deallocate(self(), mPort)); }
void destroy() { check(mach_port_destroy(self(), mPort)); }
void insertRight(mach_msg_type_name_t type)
{ check(mach_port_insert_right(self(), mPort, mPort, type)); }
void modRefs(mach_port_right_t right, mach_port_delta_t delta = 1)
{ check(mach_port_mod_refs(self(), mPort, right, delta)); }
mach_port_urefs_t getRefs(mach_port_right_t right);
mach_port_t requestNotify(mach_port_t notify,
mach_msg_id_t type = MACH_NOTIFY_DEAD_NAME, mach_port_mscount_t sync = 1);
mach_port_t cancelNotify(mach_msg_id_t type = MACH_NOTIFY_DEAD_NAME);
mach_port_msgcount_t qlimit() const;
void qlimit(mach_port_msgcount_t limit);
IFDUMP(void dump(const char *name = NULL));
protected:
mach_port_t mPort;
};
class AutoPort : public Port {
public:
AutoPort() { }
AutoPort(mach_port_t port) : Port(port) { }
~AutoPort() { if (mPort != MACH_PORT_NULL) deallocate(); }
};
class PortSet : public Port {
public:
PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET); }
~PortSet() { destroy(); }
void operator += (const Port &port)
{ check(mach_port_move_member(self(), port, mPort)); }
void operator -= (const Port &port)
{ check(mach_port_move_member(self(), port, MACH_PORT_NULL)); }
set<Port> members() const;
bool contains(Port member) const; };
class Bootstrap : public Port {
public:
Bootstrap() { check(task_get_bootstrap_port(mach_task_self(), &mPort)); }
Bootstrap(mach_port_t bootp) : Port(bootp) { }
mach_port_t checkIn(const char *name) const;
mach_port_t checkInOptional(const char *name) const;
void registerAs(mach_port_t port, const char *name) const;
mach_port_t lookup(const char *name) const;
mach_port_t lookup2(const char *name) const;
mach_port_t lookupOptional(const char *name) const;
Bootstrap subset(Port requestor);
IFDUMP(void dump());
private:
mutable char nameBuffer[BOOTSTRAP_MAX_NAME_LEN];
protected:
char *makeName(const char *s) const
{ return strncpy(nameBuffer, s, BOOTSTRAP_MAX_NAME_LEN); }
};
class TaskPort : public Port {
public:
TaskPort() { mPort = self(); }
TaskPort(mach_port_t p) : Port(p) { }
TaskPort(const Port &p) : Port(p) { }
TaskPort(pid_t pid);
Bootstrap bootstrap() const
{ mach_port_t boot; check(task_get_bootstrap_port(mPort, &boot)); return boot; }
void bootstrap(Bootstrap boot)
{ check(task_set_bootstrap_port(mPort, boot)); }
pid_t pid() const;
};
class ReceivePort : public Port {
public:
ReceivePort() { allocate(); }
ReceivePort(const char *name, const Bootstrap &bootstrap, bool tryCheckin = true);
~ReceivePort() { destroy(); }
};
class StBootstrap {
public:
StBootstrap(const Bootstrap &boot, const TaskPort &task = TaskPort());
~StBootstrap();
private:
Bootstrap mOldBoot;
TaskPort mTask;
StLock<Mutex> locker;
static ModuleNexus<Mutex> critical; };
class VMGuard {
public:
VMGuard(void *addr, size_t length) : mAddr(addr), mLength(length) { }
~VMGuard() { deallocate(mAddr, mLength); }
private:
void *mAddr;
size_t mLength;
};
class Message {
public:
Message(void *buffer, size_t size); Message(size_t size); Message(); virtual ~Message();
void setBuffer(void *buffer, size_t size); void setBuffer(size_t size); void release();
operator mig_reply_error_t & () const { return *mBuffer; }
operator mach_msg_header_t & () const { return mBuffer->Head; }
operator mig_reply_error_t * () const { return mBuffer; }
operator mach_msg_header_t * () const { return &mBuffer->Head; }
operator NDR_record_t & () const { return mBuffer->NDR; }
void *data() const { return mBuffer; }
size_t length() const { return mBuffer->Head.msgh_size; }
Port localPort() const { return mBuffer->Head.msgh_local_port; }
Port remotePort() const { return mBuffer->Head.msgh_remote_port; }
mach_msg_id_t msgId() const { return mBuffer->Head.msgh_id; }
mach_msg_bits_t bits() const { return mBuffer->Head.msgh_bits; }
kern_return_t returnCode() const { return mBuffer->RetCode; }
void localPort(mach_port_t p) { mBuffer->Head.msgh_local_port = p; }
void remotePort(mach_port_t p) { mBuffer->Head.msgh_remote_port = p; }
public:
bool send(mach_msg_option_t options = 0,
mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE,
mach_port_name_t notify = MACH_PORT_NULL);
bool receive(mach_port_t receivePort,
mach_msg_option_t options = 0,
mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE,
mach_port_name_t notify = MACH_PORT_NULL);
bool sendReceive(mach_port_t receivePort,
mach_msg_option_t options = 0,
mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE,
mach_port_name_t notify = MACH_PORT_NULL);
void destroy() { mach_msg_destroy(*this); }
protected:
bool check(kern_return_t status);
private:
mig_reply_error_t *mBuffer;
size_t mSize;
bool mRelease;
};
} }
#endif //_H_MACHPP