我试图理解在启动守护进程(以root身份运行)和另一个进程(以user-content运行)之间使用Mach messages进行IPC的底层机制。
假设使用以下数据结构:
struct MACH_MSG_BASE
{
mach_msg_header_t hdr;
mach_msg_body_t body;
};
struct MACH_MSG_UINT32
{
MACH_MSG_BASE base;
unsigned int val; //Sending this value as a test
};
因此,我在守护进程中运行以下代码:
//Server:
//No error checks for brevity
mach_port_t port = MACH_PORT_NULL;
mach_port_t task = mach_task_self();
mach_port_allocate(task,
MACH_PORT_RIGHT_RECEIVE,
&port);
mach_port_insert_right(task,
port,
port,
MACH_MSG_TYPE_MAKE_SEND);
MACH_MSG_UINT32 msg = {};
msg.base.hdr.msgh_local_port = port;
msg.base.hdr.msgh_size = sizeof(msg.base);
mach_msg(&msg.base.hdr,
MACH_RCV_MSG,
0,
sizeof(msg),
port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
当我运行上面的代码时,它在mach_msg
调用时进入等待模式,正如我所预料的那样。
但是,第一个问题是-如何从另一个进程获取守护进程的端口号?我假设使用task_for_pid
,如下所示:
//Client(s):
//No error checks for brevity
mach_port_t port = MACH_PORT_NULL;
mach_port_t task;
task_for_pid(mach_task_self(), server_pid, &task); //I guess we get server_pid by daemon process name?
mach_port_allocate(task,
MACH_PORT_RIGHT_RECEIVE,
&port);
MACH_MSG_UINT32 msg = {};
msg.base.hdr.msgh_remote_port = _port;
msg.base.hdr.msgh_local_port = MACH_PORT_NULL;
msg.base.hdr.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MAKE_SEND);
msg.base.hdr.msgh_size = sizeof(msg.base);
msg.val = 0x12345678;
mach_msg(&msg.base.hdr,
MACH_SEND_MSG,
sizeof(msg),
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
但是当我运行上面的代码时,mach_msg
返回0x 10000003或MACH_SEND_INVALID_DEST
。
我哪里做错了?
1条答案
按热度按时间hgb9j2n61#
task_for_pid
几乎从来没有工作这些天,苹果已显着限制它出于安全原因。查找Mach服务器的方法是让它注册一个端口名,然后让客户端在特权或用户名称空间中查找端口。对于启动守护进程或代理,您可以在launchd plist的
MachServices
部分指定它提供的端口:然后,客户端将查找这些端口以使用引导API获得发送权限:
尽管如此,使用低级Mach端口是非常麻烦的。我强烈建议使用XPC,除非你有一些遗留的或系统级的Mach服务需要接口。使用XPC,你仍然可以在launchd plist中注册
MachServices
,尽管代码端更容易使用。当你使用C++时,你的起点将是xpc_connection_create_mach_service()
函数。