#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>

void sender() {
    // 从 bootstrap 中查询并获取一个 mach port
    mach_port_t port;
    // 这里利用 bootstarp_look_up 函数在 bootstrap 中找名字为 io.github.0xc4m3l 的程序  
    //( 所以这里我们要先向 bootstrap 注册我们的接受程序 io.github.0xc4m3l
    // 因为我们注册到 bootstrap 中的 io.github.0xc4m3l 名字的 mach port 是有 send right 的
    // bootstrap 会将所注册的 mach port 的 send right 复制给我们的 sender
    if (bootstrap_look_up(bootstrapPort, "io.github.0xc4m3l", &port) != KERN_SUCCESS) {
        return EXIT_FAILURE;
    }
    printf("bootstrap_look_up() returned port right name %d\\n", port);

    // 这是我们要返送的 信息的结构体 
    struct {
        mach_msg_header_t header;
        char texts[20];
        int integer;
    } message;

    message.header.msgh_bits =  MACH_MSGH_BITS_SET(
                                /* remote */ MACH_MSG_TYPE_COPY_SEND,  
                                /* local */ 0,
                                /* voucher */ 0,
                                /* other */ 0);  // 设置下面对应 port 的 mach 信息类型
    message.header.msgh_remote_port = port;      // 设置发送端口为目标 port 
    message.header.msgh_local_port = MACH_PORT_NULL; // 没有辅助端口
    message.header.msgh_size = sizeof(message);

    strcpy(message.texts, "0xc4m3l_texts");
    message.integer = 123;
    // 将其发送
    mach_msg_return_t mr = mach_msg_send(&message.header);
    assert(mr == KERN_SUCCESS);
    printf("message is sent.\\n ============ \\n");
}

void receiver() {
    // 创建一个带有接收权限的 mach port
    mach_port_t port;
    // 利用 mach_port_allocate 创建一个 有指定权限的 mach port 
    // 第二个参数 指定为 拥有 RECVIVE 的权限
    // 权限有这几种
    /* 
    - `MACH_PORT_RIGHT_RECEIVE`:创建一个新端口,且当前只有接收权限
    - `MACH_PORT_RIGHT_PORT_SET`:创建一个空的端口集,其中端口集里没有任何成员
    - `MACH_PORT_RIGHT_DEAD_NAME` :创建一个新的 dead name
    */
    kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
    assert(kr == KERN_SUCCESS);
    printf("mach_port_allocate() created port right name %d\\n", port);
    
    // 给该 port 再增加一个发送权限
    kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
    assert (kr == KERN_SUCCESS);
    printf("mach_port_insert_right() inserted a send right\\n");

    // 将我们这个端口 注册到 bootstrap 从而让我们的 sender 能查询到
    // 保存在一个 itk_registered 数组中 
    kr = bootstrap_register(bootstrap_port, "io.github.0xc4m3l", port);
    assert (kr == KERN_SUCCESS);
    printf("bootstrap_register()'ed our port\\n");

    // 等待接受的 message 格式
    struct {
        mach_msg_header_t header;
        char texts[20];
        int integer;
        mach_msg_trailer_t trailer;
    } message;

    message.header.msgh_size = sizeof(message);
    message.header.msgh_local_port = port;
    kr = mach_msg_receive(&message.header);
    assert (kr == KERN_SUCCESS);
    printf("Got a message\\n ============\\n");

    printf("Text: %s, number: %d\\n", message.texts, message.integer);
}

int main(int argc, const char * argv[]) {
    if(fork() == 0) {
        // 等待 receiver 注册好 port 后再发送信息
        sleep(1);
        sender();
    }
    else {
        receiver();
    }
    return 0;
}

Untitled